fix ugly code compiler warning: empty body in an if-statement
[blender.git] / source / blender / blenkernel / intern / BME_tools.c
1 /**
2  * BME_tools.c    jan 2007
3  *
4  *      Functions for changing the topology of a mesh.
5  *
6  * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
7  *
8  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version. The Blender
14  * Foundation also sells licenses for use in proprietary software under
15  * the Blender License.  See http://www.blender.org/BL/ for information
16  * about this.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  *
27  * The Original Code is Copyright (C) 2004 Blender Foundation.
28  * All rights reserved.
29  *
30  * The Original Code is: all of this file.
31  *
32  * Contributor(s): Geoffrey Bantle and Levi Schooley.
33  *
34  * ***** END GPL/BL DUAL LICENSE BLOCK *****
35  */
36
37 #include <math.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_listBase.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_mesh_types.h"
44
45 #include "BKE_utildefines.h"
46 #include "BKE_bmesh.h"
47 #include "BLI_arithb.h"
48 #include "BLI_blenlib.h"
49
50 #include "blendef.h"
51
52 /*split this all into a seperate bevel.c file in src*/
53
54 /* ------- Bevel code starts here -------- */
55
56 BME_TransData_Head *BME_init_transdata(int bufsize) {
57         BME_TransData_Head *td;
58
59         td = MEM_callocN(sizeof(BME_TransData_Head), "BMesh transdata header");
60         td->gh = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp);
61         td->ma = BLI_memarena_new(bufsize);
62         BLI_memarena_use_calloc(td->ma);
63
64         return td;
65 }
66
67 void BME_free_transdata(BME_TransData_Head *td) {
68         BLI_ghash_free(td->gh,NULL,NULL);
69         BLI_memarena_free(td->ma);
70         MEM_freeN(td);
71 }
72
73 BME_TransData *BME_assign_transdata(BME_TransData_Head *td, BME_Mesh *bm, BME_Vert *v,
74                 float *co, float *org, float *vec, float *loc,
75                 float factor, float weight, float maxfactor, float *max) {
76         BME_TransData *vtd;
77         int is_new = 0;
78
79         if (v == NULL) return NULL;
80
81         if ((vtd = BLI_ghash_lookup(td->gh, v)) == NULL && bm != NULL) {
82                 vtd = BLI_memarena_alloc(td->ma, sizeof(*vtd));
83                 BLI_ghash_insert(td->gh, v, vtd);
84                 td->len++;
85                 is_new = 1;
86         }
87
88         vtd->bm = bm;
89         vtd->v = v;
90         if (co != NULL) VECCOPY(vtd->co,co);
91         if (org == NULL && is_new) { VECCOPY(vtd->org,v->co); } /* default */
92         else if (org != NULL) VECCOPY(vtd->org,org);
93         if (vec != NULL) {
94                 VECCOPY(vtd->vec,vec);
95                 Normalize(vtd->vec);
96         }
97         vtd->loc = loc;
98
99         vtd->factor = factor;
100         vtd->weight = weight;
101         vtd->maxfactor = maxfactor;
102         vtd->max = max;
103
104         return vtd;
105 }
106
107 BME_TransData *BME_get_transdata(BME_TransData_Head *td, BME_Vert *v) {
108         BME_TransData *vtd;
109         vtd = BLI_ghash_lookup(td->gh, v);
110         return vtd;
111 }
112
113 /* a hack (?) to use the transdata memarena to allocate floats for use with the max limits */
114 float *BME_new_transdata_float(BME_TransData_Head *td) {
115         return BLI_memarena_alloc(td->ma, sizeof(float));
116 }
117
118 static int BME_is_nonmanifold_vert(BME_Mesh *bm, BME_Vert *v) {
119         BME_Edge *e, *oe;
120         BME_Loop *l;
121         int len, count, flag;
122
123         if (v->edge == NULL) {
124                 /* loose vert */
125                 return 1;
126         }
127
128         /* count edges while looking for non-manifold edges */
129         oe = v->edge;
130         for (len=0,e=v->edge; e != oe || (e == oe && len == 0); len++,e=BME_disk_nextedge(e,v)) {
131                 if (e->loop == NULL) {
132                         /* loose edge */
133                         return 1;
134                 }
135
136                 if (BME_cycle_length(&(e->loop->radial)) > 2) {
137                         /* edge shared by more than two faces */
138                         return 1;
139                 }
140         }
141
142         count = 1;
143         flag = 1;
144         e = NULL;
145         oe = v->edge;
146         l = oe->loop;
147         while(e != oe) {
148                 if (l->v == v) l = l->prev;
149                 else l = l->next;
150                 e = l->e;
151                 count++; /* count the edges */
152
153                 if (flag && l->radial.next->data == l) {
154                         /* we've hit the edge of an open mesh, reset once */
155                         flag = 0;
156                         count = 1;
157                         oe = e;
158                         e = NULL;
159                         l = oe->loop;
160                 }
161                 else if (l->radial.next->data == l) {
162                         /* break the loop */
163                         e = oe;
164                 }
165                 else {
166                         l = l->radial.next->data;
167                 }
168         }
169
170         if (count < len) {
171                 /* vert shared by multiple regions */
172                 return 1;
173         }
174
175         return 0;
176 }
177
178 /* a wrapper for BME_JFKE that [for now just] checks to
179  * make sure loop directions are compatible */
180 static BME_Poly *BME_JFKE_safe(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e) {
181         BME_Loop *l1, *l2;
182
183         l1 = e->loop;
184         l2 = l1->radial.next->data;
185         if (l1->v == l2->v) {
186                 BME_loop_reverse(bm, f2);
187         }
188
189         return BME_JFKE(bm, f1, f2, e);
190 }
191
192 /* a wrapper for BME_SFME that transfers element flags */
193 static BME_Poly *BME_split_face(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **nl, BME_Edge *example) {
194         BME_Poly *nf;
195         nf = BME_SFME(bm,f,v1,v2,nl);
196         nf->flag = f->flag;
197         /* if the edge was selected, select this face, too */
198         if (example->flag & SELECT) f->flag |= ME_FACE_SEL;
199         nf->h = f->h;
200         nf->mat_nr = f->mat_nr;
201         if (nl && example) {
202                 (*nl)->e->flag = example->flag;
203                 (*nl)->e->h = example->h;
204                 (*nl)->e->crease = example->crease;
205                 (*nl)->e->bweight = example->bweight;
206         }
207
208         return nf;
209 }
210
211 /* a wrapper for BME_SEMV that transfers element flags */
212 static BME_Vert *BME_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Edge **ne, float percent) {
213         BME_Vert *nv, *v2;
214         float len;
215
216         v2 = BME_edge_getothervert(e,v);
217         nv = BME_SEMV(bm,v,e,ne);
218         if (nv == NULL) return NULL;
219         VECSUB(nv->co,v2->co,v->co);
220         len = VecLength(nv->co);
221         VECADDFAC(nv->co,v->co,nv->co,len*percent);
222         nv->flag = v->flag;
223         nv->bweight = v->bweight;
224         if (ne) {
225                 (*ne)->flag = e->flag;
226                 (*ne)->h = e->h;
227                 (*ne)->crease = e->crease;
228                 (*ne)->bweight = e->bweight;
229         }
230
231         return nv;
232 }
233
234 static int BME_bevel_is_split_vert(BME_Loop *l) {
235         /* look for verts that have already been added to the edge when
236          * beveling other polys; this can be determined by testing the
237          * vert and the edges around it for originality
238          */
239         if ((l->v->tflag1 & BME_BEVEL_ORIG)==0
240                         && (l->e->tflag1 & BME_BEVEL_ORIG)
241                         && (l->prev->e->tflag1 & BME_BEVEL_ORIG))
242         {
243                 return 1;
244         }
245         return 0;
246 }
247
248 /* get a vector, vec, that points from v1->co to wherever makes sense to
249  * the bevel operation as a whole based on the relationship between v1 and v2
250  * (won't necessarily be a vec from v1->co to v2->co, though it probably will be);
251  * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */
252 static int BME_bevel_get_vec(float *vec, BME_Vert *v1, BME_Vert *v2, BME_TransData_Head *td) {
253         BME_TransData *vtd1, *vtd2;
254
255         vtd1 = BME_get_transdata(td,v1);
256         vtd2 = BME_get_transdata(td,v2);
257         if (!vtd1 || !vtd2) {
258                 //printf("BME_bevel_get_vec() got called without proper BME_TransData\n");
259                 return -1;
260         }
261
262         /* compare the transform origins to see if we can use the vert co's;
263          * if they belong to different origins, then we will use the origins to determine
264          * the vector */
265         if (VecCompare(vtd1->org,vtd2->org,0.000001f)) {
266                 VECSUB(vec,v2->co,v1->co);
267                 if (VecLength(vec) < 0.000001f) {
268                         VecMulf(vec,0);
269                 }
270                 return 0;
271         }
272         else {
273                 VECSUB(vec,vtd2->org,vtd1->org);
274                 if (VecLength(vec) < 0.000001f) {
275                         VecMulf(vec,0);
276                 }
277                 return 1;
278         }
279 }
280
281 /* "Projects" a vector perpendicular to vec2 against vec1, such that
282  * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2.
283  * note: the direction, is_forward, is used in conjunction with up_vec to determine
284  * whether this is a convex or concave corner. If it is a concave corner, it will
285  * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards).
286  * vec1 is the vector to project onto (expected to be normalized)
287  * vec2 is the direction of projection (pointing away from vec1)
288  * up_vec is used for orientation (expected to be normalized)
289  * returns the length of the projected vector that lies along vec1 */
290 static float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *td) {
291         float factor, vec3[3], tmp[3],c1,c2;
292
293         Crossf(tmp,vec1,vec2);
294         Normalize(tmp);
295         factor = Inpf(up_vec,tmp);
296         if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) {
297                 Crossf(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */
298         }
299         else {
300                 Crossf(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */
301         }
302         Normalize(vec3);
303         c1 = Inpf(vec3,vec1);
304         c2 = Inpf(vec1,vec1);
305         if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) {
306                 factor = 0.0f;
307         }
308         else {
309                 factor = c2/c1;
310         }
311
312         return factor;
313 }
314
315 /* BME_bevel_split_edge() is the main math work-house; its responsibilities are:
316  * using the vert and the loop passed, get or make the split vert, set its coordinates
317  * and transform properties, and set the max limits.
318  * Finally, return the split vert. */
319 static BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, BME_Loop *l, float *up_vec, float value, BME_TransData_Head *td) {
320         BME_TransData *vtd, *vtd1, *vtd2;
321         BME_Vert *sv, *v2, *v3;
322         BME_Loop *lv1, *lv2;
323         BME_Edge *ne, *e1, *e2;
324         float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3];
325         int is_edge, forward, is_split_vert;
326
327         if (l == NULL) {
328                 /* what you call operator overloading in C :)
329                  * I wanted to use the same function for both wire edges and poly loops
330                  * so... here we walk around edges to find the needed verts */
331                 forward = 1;
332                 is_split_vert = 0;
333                 if (v->edge == NULL) {
334                         //printf("We can't split a loose vert's edge!\n");
335                         return NULL;
336                 }
337                 e1 = v->edge; /* we just use the first two edges */
338                 e2 = BME_disk_nextedge(v->edge, v);
339                 if (e1 == e2) {
340                         //printf("You need at least two edges to use BME_bevel_split_edge()\n");
341                         return NULL;
342                 }
343                 v2 = BME_edge_getothervert(e1, v);
344                 v3 = BME_edge_getothervert(e2, v);
345                 if (v1 != v2 && v1 != v3) {
346                         //printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n");
347                         return NULL;
348                 }
349                 if (v1 == v2) {
350                         v2 = v3;
351                 }
352                 else {
353                         e1 = e2;
354                 }
355                 sv = BME_split_edge(bm,v,e1,&ne,0);
356                 BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
357                 sv->tflag1 |= BME_BEVEL_BEVEL;
358                 ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
359                 BME_bevel_get_vec(vec1,v1,v,td);
360                 BME_bevel_get_vec(vec2,v2,v,td);
361                 Crossf(t_up_vec,vec1,vec2);
362                 Normalize(t_up_vec);
363                 up_vec = t_up_vec;
364         }
365         else {
366                 /* establish loop direction */
367                 if (l->v == v) {
368                         forward = 1;
369                         lv1 = l->next;
370                         lv2 = l->prev;
371                         v1 = l->next->v;
372                         v2 = l->prev->v;
373                 }
374                 else if (l->next->v == v) {
375                         forward = 0;
376                         lv1 = l;
377                         lv2 = l->next->next;
378                         v1 = l->v;
379                         v2 = l->next->next->v;
380                 }
381                 else {
382                         //printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n");
383                         return NULL;
384                 }
385
386                 if (BME_bevel_is_split_vert(lv1)) {
387                         is_split_vert = 1;
388                         sv = v1;
389                         if (forward) v1 = l->next->next->v;
390                         else v1 = l->prev->v;
391                 }
392                 else {
393                         is_split_vert = 0;
394                         sv = BME_split_edge(bm,v,l->e,&ne,0);
395                         BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
396                         sv->tflag1 |= BME_BEVEL_BEVEL;
397                         ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
398                 }
399
400                 if (BME_bevel_is_split_vert(lv2)) {
401                         if (forward) v2 = lv2->prev->v;
402                         else v2 = lv2->next->v;
403                 }
404         }
405
406         is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */
407         BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */
408         len = VecLength(vec1);
409         Normalize(vec1);
410
411         vtd = BME_get_transdata(td, sv);
412         vtd1 = BME_get_transdata(td, v);
413         vtd2 = BME_get_transdata(td,v1);
414
415         if (vtd1->loc == NULL) {
416                 /* this is a vert with data only for calculating initial weights */
417                 if (vtd1->weight < 0) {
418                         vtd1->weight = 0;
419                 }
420                 scale = vtd1->weight/vtd1->factor;
421                 if (!vtd1->max) {
422                         vtd1->max = BME_new_transdata_float(td);
423                         *vtd1->max = -1;
424                 }
425         }
426         else {
427                 scale = vtd1->weight;
428         }
429         vtd->max = vtd1->max;
430
431         if (is_edge && vtd1->loc != NULL) {
432                 maxfactor = vtd1->maxfactor;
433         }
434         else {
435                 maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td);
436                 if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) {
437                         maxfactor = vtd->maxfactor;
438                 }
439         }
440
441         dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2;
442         if (is_edge || dis > maxfactor*value) {
443                 dis = maxfactor*value;
444         }
445         VECADDFAC(sv->co,v->co,vec1,dis);
446         VECSUB(vec1,sv->co,vtd1->org);
447         dis = VecLength(vec1);
448         Normalize(vec1);
449         BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max);
450
451         return sv;
452 }
453
454 static float BME_bevel_set_max(BME_Vert *v1, BME_Vert *v2, float value, BME_TransData_Head *td) {
455         BME_TransData *vtd1, *vtd2;
456         float max, fac1, fac2, vec1[3], vec2[3], vec3[3];
457
458         BME_bevel_get_vec(vec1,v1,v2,td);
459         vtd1 = BME_get_transdata(td,v1);
460         vtd2 = BME_get_transdata(td,v2);
461
462         if (vtd1->loc == NULL) {
463                 fac1 = 0;
464         }
465         else {
466                 VECCOPY(vec2,vtd1->vec);
467                 VecMulf(vec2,vtd1->factor);
468                 if (Inpf(vec1, vec1)) {
469                         Projf(vec2,vec2,vec1);
470                         fac1 = VecLength(vec2)/value;
471                 }
472                 else {
473                         fac1 = 0;
474                 }
475         }
476
477         if (vtd2->loc == NULL) {
478                 fac2 = 0;
479         }
480         else {
481                 VECCOPY(vec3,vtd2->vec);
482                 VecMulf(vec3,vtd2->factor);
483                 if (Inpf(vec1, vec1)) {
484                         Projf(vec2,vec3,vec1);
485                         fac2 = VecLength(vec2)/value;
486                 }
487                 else {
488                         fac2 = 0;
489                 }
490         }
491
492         if (fac1 || fac2) {
493                 max = VecLength(vec1)/(fac1 + fac2);
494                 if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
495                         *vtd1->max = max;
496                 }
497                 if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
498                         *vtd2->max = max;
499                 }
500         }
501         else {
502                 max = -1;
503         }
504
505         return max;
506 }
507
508 static BME_Vert *BME_bevel_wire(BME_Mesh *bm, BME_Vert *v, float value, int res, int options, BME_TransData_Head *td) {
509         BME_Vert *ov1, *ov2, *v1, *v2;
510
511         ov1 = BME_edge_getothervert(v->edge, v);
512         ov2 = BME_edge_getothervert(BME_disk_nextedge(v->edge, v), v);
513
514         /* split the edges */
515         v1 = BME_bevel_split_edge(bm,v,ov1,NULL,NULL,value,td);
516         v1->tflag1 |= BME_BEVEL_NONMAN;
517         v2 = BME_bevel_split_edge(bm,v,ov2,NULL,NULL,value,td);
518         v2->tflag1 |= BME_BEVEL_NONMAN;
519
520         if (value > 0.5) {
521                 BME_bevel_set_max(v1,ov1,value,td);
522                 BME_bevel_set_max(v2,ov2,value,td);
523         }
524
525         /* remove the original vert */
526         if (res) {
527                 BME_JEKV(bm,v->edge,v);
528         }
529
530         return v1;
531 }
532
533 static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
534         BME_Vert *v1, *v2, *kv;
535         BME_Loop *kl=NULL, *nl;
536         BME_Edge *e;
537         BME_Poly *f;
538
539         f = l->f;
540         e = l->e;
541
542         if ((l->e->tflag1 & BME_BEVEL_BEVEL) == 0
543                 && ((l->v->tflag1 & BME_BEVEL_BEVEL) || (l->next->v->tflag1 & BME_BEVEL_BEVEL)))
544         { /* sanity check */
545                 return l;
546         }
547
548         /* checks and operations for prev edge */
549         /* first, check to see if this edge was inset previously */
550         if ((l->prev->e->tflag1 & BME_BEVEL_ORIG) == 0
551                 && (l->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
552                 kl = l->prev->radial.next->data;
553                 if (kl->v == l->v) kl = kl->prev;
554                 else kl = kl->next;
555                 kv = l->v;
556         }
557         else {
558                 kv = NULL;
559         }
560         /* get/make the first vert to be used in SFME */
561         if (l->v->tflag1 & BME_BEVEL_NONMAN){
562                 v1 = l->v;
563         }
564         else { /* we'll need to split the previous edge */
565                 v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td);
566         }
567         /* if we need to clean up geometry... */
568         if (kv) {
569                 l = l->next;
570                 if (kl->v == kv) {
571                         BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
572                         BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
573                         BME_JEKV(bm,kl->e,kv);
574                 }
575                 else {
576                         BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
577                         BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
578                         BME_JEKV(bm,kl->e,kv);
579                 }
580                 l = l->prev;
581         }
582
583         /* checks and operations for the next edge */
584         /* first, check to see if this edge was inset previously  */
585         if ((l->next->e->tflag1 & BME_BEVEL_ORIG) == 0
586                 && (l->next->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
587                 kl = l->next->radial.next->data;
588                 if (kl->v == l->next->v) kl = kl->prev;
589                 else kl = kl->next;
590                 kv = l->next->v;
591         }
592         else {
593                 kv = NULL;
594         }
595         /* get/make the second vert to be used in SFME */
596         if (l->next->v->tflag1 & BME_BEVEL_NONMAN) {
597                 v2 = l->next->v;
598         }
599         else { /* we'll need to split the next edge */
600                 v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td);
601         }
602         /* if we need to clean up geometry... */
603         if (kv) {
604                 if (kl->v == kv) {
605                         BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
606                         BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
607                         BME_JEKV(bm,kl->e,kv);
608                 }
609                 else {
610                         BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
611                         BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
612                         BME_JEKV(bm,kl->e,kv);
613                 }
614         }
615
616         if ((v1->tflag1 & BME_BEVEL_NONMAN)==0 || (v2->tflag1 & BME_BEVEL_NONMAN)==0) {
617                 BME_split_face(bm,f,v2,v1,&l,e);
618                 l->e->tflag1 = BME_BEVEL_BEVEL;
619                 l = l->radial.next->data;
620         }
621
622         if (l->f != f){
623                 //printf("Whoops! You got something out of order in BME_bevel_edge()!\n");
624         }
625
626         return l;
627 }
628
629 static BME_Loop *BME_bevel_vert(BME_Mesh *bm, BME_Loop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
630         BME_Vert *v1, *v2;
631         BME_Poly *f;
632
633         /* get/make the first vert to be used in SFME */
634         /* may need to split the previous edge */
635         v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td);
636
637         /* get/make the second vert to be used in SFME */
638         /* may need to split this edge (so move l) */
639         l = l->prev;
640         v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td);
641         l = l->next->next;
642
643         /* "cut off" this corner */
644         f = BME_split_face(bm,l->f,v2,v1,NULL,l->e);
645
646         return l;
647 }
648
649 /**
650  *                      BME_bevel_poly
651  *
652  *      Polygon inset tool:
653  *
654  *      Insets a polygon/face based on the tflag1's of its vertices
655  *      and edges. Used by the bevel tool only, for now.
656  *  The parameter "value" is the distance to inset (should be negative).
657  *  The parameter "options" is not currently used.
658  *
659  *      Returns -
660  *  A BME_Poly pointer to the resulting inner face.
661 */
662 static BME_Poly *BME_bevel_poly(BME_Mesh *bm, BME_Poly *f, float value, int options, BME_TransData_Head *td) {
663         BME_Loop *l, *ol;
664         BME_TransData *vtd1, *vtd2;
665         float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1;
666         int len, i;
667
668         up_vec[0] = 0.0f;
669         up_vec[1] = 0.0f;
670         up_vec[2] = 0.0f;
671         /* find a good normal for this face (there's better ways, I'm sure) */
672         ol = f->loopbase;
673         l = ol->next;
674         for (i=0,ol=f->loopbase,l=ol->next; l->next!=ol; l=l->next) {
675                 BME_bevel_get_vec(vec1,l->next->v,ol->v,td);
676                 BME_bevel_get_vec(vec2,l->v,ol->v,td);
677                 Crossf(vec3,vec2,vec1);
678                 VECADD(up_vec,up_vec,vec3);
679                 i++;
680         }
681         VecMulf(up_vec,1.0f/i);
682         Normalize(up_vec);
683
684         for (i=0,len=f->len; i<len; i++,l=l->next) {
685                 if ((l->e->tflag1 & BME_BEVEL_BEVEL) && (l->e->tflag1 & BME_BEVEL_ORIG)) {
686                         max = 1.0f;
687                         l = BME_bevel_edge(bm, l, value, options, up_vec, td);
688                 }
689                 else if ((l->v->tflag1 & BME_BEVEL_BEVEL) && (l->v->tflag1 & BME_BEVEL_ORIG) && (l->prev->e->tflag1 & BME_BEVEL_BEVEL) == 0) {
690                         max = 1.0f;
691                         l = BME_bevel_vert(bm, l, value, options, up_vec, td);
692                 }
693         }
694
695         /* max pass */
696         if (value > 0.5 && max > 0) {
697                 max = -1;
698                 for (i=0,len=f->len; i<len; i++,l=l->next) {
699                         if ((l->e->tflag1 & BME_BEVEL_BEVEL) || (l->e->tflag1 & BME_BEVEL_ORIG)) {
700                                 BME_bevel_get_vec(vec1,l->v,l->next->v,td);
701                                 vtd1 = BME_get_transdata(td,l->v);
702                                 vtd2 = BME_get_transdata(td,l->next->v);
703                                 if (vtd1->loc == NULL) {
704                                         fac1 = 0;
705                                 }
706                                 else {
707                                         VECCOPY(vec2,vtd1->vec);
708                                         VecMulf(vec2,vtd1->factor);
709                                         if (Inpf(vec1, vec1)) {
710                                                 Projf(vec2,vec2,vec1);
711                                                 fac1 = VecLength(vec2)/value;
712                                         }
713                                         else {
714                                                 fac1 = 0;
715                                         }
716                                 }
717                                 if (vtd2->loc == NULL) {
718                                         fac2 = 0;
719                                 }
720                                 else {
721                                         VECCOPY(vec3,vtd2->vec);
722                                         VecMulf(vec3,vtd2->factor);
723                                         if (Inpf(vec1, vec1)) {
724                                                 Projf(vec2,vec3,vec1);
725                                                 fac2 = VecLength(vec2)/value;
726                                         }
727                                         else {
728                                                 fac2 = 0;
729                                         }
730                                 }
731                                 if (fac1 || fac2) {
732                                         max = VecLength(vec1)/(fac1 + fac2);
733                                         if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
734                                                 *vtd1->max = max;
735                                         }
736                                         if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
737                                                 *vtd2->max = max;
738                                         }
739                                 }
740                         }
741                 }
742         }
743
744         return l->f;
745 }
746
747 static void BME_bevel_add_vweight(BME_TransData_Head *td, BME_Mesh *bm, BME_Vert *v, float weight, float factor, int options) {
748         BME_TransData *vtd;
749
750         if (v->tflag1 & BME_BEVEL_NONMAN) return;
751         v->tflag1 |= BME_BEVEL_BEVEL;
752         if ( (vtd = BME_get_transdata(td, v)) ) {
753                 if (options & BME_BEVEL_EMIN) {
754                         vtd->factor = 1.0;
755                         if (vtd->weight < 0 || weight < vtd->weight) {
756                                 vtd->weight = weight;
757                         }
758                 }
759                 else if (options & BME_BEVEL_EMAX) {
760                         vtd->factor = 1.0;
761                         if (weight > vtd->weight) {
762                                 vtd->weight = weight;
763                         }
764                 }
765                 else if (vtd->weight < 0) {
766                         vtd->factor = factor;
767                         vtd->weight = weight;
768                 }
769                 else {
770                         vtd->factor += factor; /* increment number of edges with weights (will be averaged) */
771                         vtd->weight += weight; /* accumulate all the weights */
772                 }
773         }
774         else {
775                 /* we'll use vtd->loc == NULL to mark that this vert is not moving */
776                 vtd = BME_assign_transdata(td, bm, v, v->co, NULL, NULL, NULL, factor, weight, -1, NULL);
777         }
778 }
779
780 static float BME_bevel_get_angle(BME_Mesh *bm, BME_Edge *e, BME_Vert *v) {
781         BME_Vert *v1, *v2;
782         BME_Loop *l1, *l2;
783         float vec1[3], vec2[3], vec3[3], vec4[3];
784
785         l1 = e->loop;
786         l2 = e->loop->radial.next->data;
787         if (l1->v == v) {
788                 v1 = l1->prev->v;
789                 v2 = l1->next->v;
790         }
791         else {
792                 v1 = l1->next->next->v;
793                 v2 = l1->v;
794         }
795         VECSUB(vec1,v1->co,v->co);
796         VECSUB(vec2,v2->co,v->co);
797         Crossf(vec3,vec1,vec2);
798
799         l1 = l2;
800         if (l1->v == v) {
801                 v1 = l1->prev->v;
802                 v2 = l1->next->v;
803         }
804         else {
805                 v1 = l1->next->next->v;
806                 v2 = l1->v;
807         }
808         VECSUB(vec1,v1->co,v->co);
809         VECSUB(vec2,v2->co,v->co);
810         Crossf(vec4,vec2,vec1);
811
812         Normalize(vec3);
813         Normalize(vec4);
814
815         return Inpf(vec3,vec4);
816 }
817
818 /**
819  *                      BME_bevel_initialize
820  *
821  *      Prepare the mesh for beveling:
822  *
823  *      Sets the tflag1's of the mesh elements based on the options passed.
824  *
825  *      Returns -
826  *  A BME_Mesh pointer to the BMesh passed as a parameter.
827 */
828 static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int defgrp_index, float angle, BME_TransData_Head *td) {
829         BME_Vert *v;
830         BME_Edge *e;
831         BME_Poly *f;
832         BME_TransData *vtd;
833         MDeformVert *dvert;
834         MDeformWeight *dw;
835         int len;
836         float weight, threshold;
837
838         /* vert pass */
839         for (v=bm->verts.first; v; v=v->next) {
840                 dvert = NULL;
841                 dw = NULL;
842                 v->tflag1 = BME_BEVEL_ORIG;
843                 /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if
844                  * the vert is manifold (or is shared by only two edges - wire bevel)
845                  * BME_BEVEL_SELECT is passed and the vert has v->flag&SELECT or
846                  * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight
847                  * BME_BEVEL_ANGLE is not passed
848                  * BME_BEVEL_EWEIGHT is not passed
849                  */
850                 /* originally coded, a vertex gets tagged with BME_BEVEL_NONMAN in this pass if
851                  * the vert is loose, shared by multiple regions, or is shared by wire edges
852                  * note: verts belonging to edges of open meshes are not tagged with BME_BEVEL_NONMAN
853                  */
854                 /* originally coded, a vertex gets a transform weight set in this pass if
855                  * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight
856                  */
857
858                 /* get disk cycle length */
859                 if (v->edge == NULL) {
860                         len = 0;
861                 }
862                 else {
863                         len = BME_cycle_length(BME_disk_getpointer(v->edge,v));
864                         /* we'll assign a default transform data to every vert (except the loose ones) */
865                         vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL);
866                 }
867
868                 /* check for non-manifold vert */
869                 if (BME_is_nonmanifold_vert(bm,v)) {
870                         v->tflag1 |= BME_BEVEL_NONMAN;
871                 }
872
873                 /* BME_BEVEL_BEVEL tests */
874                 if ((v->tflag1 & BME_BEVEL_NONMAN) == 0 || len == 2) { /* either manifold vert, or wire vert */
875                         if (((options & BME_BEVEL_SELECT) && (v->flag & SELECT))
876                                 || ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT)) /* use weights for verts */
877                                 || ((options & BME_BEVEL_ANGLE) == 0
878                                         && (options & BME_BEVEL_SELECT) == 0
879                                         && (options & BME_BEVEL_WEIGHT) == 0))
880                         {
881                                 if (options & BME_BEVEL_WEIGHT) {
882                                         /* do vert weight stuff */
883                                         //~ dvert = CustomData_em_get(&bm->vdata,v->data,CD_MDEFORMVERT);
884                                         //~ if (!dvert) continue;
885                                         //~ for (i = 0; i < dvert->totweight; ++i) {
886                                                 //~ if(dvert->dw[i].def_nr == defgrp_index) {
887                                                         //~ dw = &dvert->dw[i];
888                                                         //~ break;
889                                                 //~ }
890                                         //~ }
891                                         //~ if (!dw || dw->weight == 0.0) continue;
892                                         if (v->bweight == 0.0) continue;
893                                         vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, v->bweight, -1, NULL);
894                                         v->tflag1 |= BME_BEVEL_BEVEL;
895                                 }
896                                 else {
897                                         vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, 1.0, -1, NULL);
898                                         v->tflag1 |= BME_BEVEL_BEVEL;
899                                 }
900                         }
901                 }
902         }
903
904         /* edge pass */
905         threshold = (float)cos((angle + 0.00001) * M_PI / 180.0);
906         for (e=bm->edges.first; e; e=e->next) {
907                 e->tflag1 = BME_BEVEL_ORIG;
908                 weight = 0.0;
909                 /* originally coded, an edge gets tagged with BME_BEVEL_BEVEL in this pass if
910                  * BME_BEVEL_VERT is not set
911                  * the edge is manifold (shared by exactly two faces)
912                  * BME_BEVEL_SELECT is passed and the edge has e->flag&SELECT or
913                  * BME_BEVEL_EWEIGHT is passed, and the edge has the crease set or
914                  * BME_BEVEL_ANGLE is passed, and the edge is sharp enough
915                  * BME_BEVEL_VWEIGHT is passed, and both verts are set for bevel
916                  */
917                 /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if
918                  * the vert belongs to the edge
919                  * the vert is not tagged with BME_BEVEL_NONMAN
920                  * the edge is eligible for bevel (even if BME_BEVEL_VERT is set, or the edge is shared by less than 2 faces)
921                  */
922                 /* originally coded, a vertex gets a transform weight set in this pass if
923                  * the vert belongs to the edge
924                  * the edge has a weight
925                  */
926                 /* note: edge weights are cumulative at the verts,
927                  * i.e. the vert's weight is the average of the weights of its weighted edges
928                  */
929
930                 if (e->loop == NULL) {
931                         len = 0;
932                         e->v1->tflag1 |= BME_BEVEL_NONMAN;
933                         e->v2->tflag1 |= BME_BEVEL_NONMAN;
934                 }
935                 else {
936                         len = BME_cycle_length(&(e->loop->radial));
937                 }
938
939                 if (len > 2) {
940                         /* non-manifold edge of the worst kind */
941                         continue;
942                 }
943
944                 if ((options & BME_BEVEL_SELECT) && (e->flag & SELECT)) {
945                         weight = 1.0;
946                         /* stupid editmode doesn't always flush selections, or something */
947                         e->v1->flag |= SELECT;
948                         e->v2->flag |= SELECT;
949                 }
950                 else if ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT) == 0) {
951                         weight = e->bweight;
952                 }
953                 else if (options & BME_BEVEL_ANGLE) {
954                         if ((e->v1->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v1) < threshold) {
955                                 e->tflag1 |= BME_BEVEL_BEVEL;
956                                 e->v1->tflag1 |= BME_BEVEL_BEVEL;
957                                 BME_bevel_add_vweight(td, bm, e->v1, 1.0, 1.0, options);
958                         }
959                         else {
960                                 BME_bevel_add_vweight(td, bm, e->v1, 0.0, 1.0, options);
961                         }
962                         if ((e->v2->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v2) < threshold) {
963                                 e->tflag1 |= BME_BEVEL_BEVEL;
964                                 e->v2->tflag1 |= BME_BEVEL_BEVEL;
965                                 BME_bevel_add_vweight(td, bm, e->v2, 1.0, 1.0, options);
966                         }
967                         else {
968                                 BME_bevel_add_vweight(td, bm, e->v2, 0.0, 1.0, options);
969                         }
970                 }
971                 //~ else if ((options & BME_BEVEL_VWEIGHT) && (options & BME_BEVEL_VERT) == 0) {
972                         //~ if ((e->v1->tflag1 & BME_BEVEL_BEVEL) && (e->v2->tflag1 & BME_BEVEL_BEVEL)) {
973                                 //~ e->tflag1 |= BME_BEVEL_BEVEL;
974                         //~ }
975                 //~ }
976                 else if ((options & BME_BEVEL_SELECT) == 0
977                         && (options & BME_BEVEL_VERT) == 0)
978                 {
979                         weight = 1.0;
980                 }
981
982                 if (weight > 0.0) {
983                         e->tflag1 |= BME_BEVEL_BEVEL;
984                         BME_bevel_add_vweight(td, bm, e->v1, weight, 1.0, options);
985                         BME_bevel_add_vweight(td, bm, e->v2, weight, 1.0, options);
986                 }
987
988                 if (len != 2 || options & BME_BEVEL_VERT) {
989                         e->tflag1 &= ~BME_BEVEL_BEVEL;
990                 }
991         }
992
993         /* face pass */
994         for (f=bm->polys.first; f; f=f->next) f->tflag1 = BME_BEVEL_ORIG;
995
996         return bm;
997 }
998
999 /* tags all elements as originals */
1000 static BME_Mesh *BME_bevel_reinitialize(BME_Mesh *bm) {
1001         BME_Vert *v;
1002         BME_Edge *e;
1003         BME_Poly *f;
1004
1005         for (v = bm->verts.first; v; v=v->next) {
1006                 v->tflag1 |= BME_BEVEL_ORIG;
1007         }
1008
1009         for (e=bm->edges.first; e; e=e->next) {
1010                 e->tflag1 |= BME_BEVEL_ORIG;
1011         }
1012
1013         for (f=bm->polys.first; f; f=f->next) {
1014                 f->tflag1 |= BME_BEVEL_ORIG;
1015         }
1016
1017         return bm;
1018 }
1019
1020 /**
1021  *                      BME_bevel_mesh
1022  *
1023  *      Mesh beveling tool:
1024  *
1025  *      Bevels an entire mesh. It currently uses the tflag1's of
1026  *      its vertices and edges to track topological changes.
1027  *  The parameter "value" is the distance to inset (should be negative).
1028  *  The parameter "options" is not currently used.
1029  *
1030  *      Returns -
1031  *  A BME_Mesh pointer to the BMesh passed as a parameter.
1032 */
1033
1034 static void bmesh_dissolve_disk(BME_Mesh *bm, BME_Vert *v){
1035         BME_Poly *f;
1036         BME_Edge *e;
1037         int done, len;
1038         
1039         if(v->edge){
1040                 done = 0;
1041                 while(!done){
1042                         done = 1;
1043                         e = v->edge; /*loop the edge looking for a edge to dissolve*/
1044                         do{
1045                                 f = NULL;
1046                                 len = BME_cycle_length(&(e->loop->radial));
1047                                 if(len == 2){
1048                                         f = BME_JFKE_safe(bm,e->loop->f, ((BME_Loop*)(e->loop->radial.next->data))->f, e);
1049                                 }
1050                                 if(f){ 
1051                                         done = 0;
1052                                         break;
1053                                 }
1054                                 e = BME_disk_nextedge(e,v);
1055                         }while(e != v->edge);
1056                 }
1057                 BME_JEKV(bm,v->edge,v);
1058         }
1059 }
1060 static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options, int defgrp_index, BME_TransData_Head *td) {
1061         BME_Vert *v, *nv;
1062         BME_Edge *e, *oe;
1063         BME_Loop *l, *l2;
1064         BME_Poly *f;
1065         unsigned int i, len;
1066
1067         for (f=bm->polys.first; f; f=f->next) {
1068                 if(f->tflag1 & BME_BEVEL_ORIG) {
1069                         BME_bevel_poly(bm,f,value,options,td);
1070                 }
1071         }
1072
1073         /* here we will loop through all the verts to clean up the left over geometry */
1074         /* crazy idea. when res == 0, don't remove the original geometry */
1075         for (v = bm->verts.first; v; /* we may kill v, so increment in-loop */) {
1076                 nv = v->next;
1077                 if ((v->tflag1 & BME_BEVEL_NONMAN) && (v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG)) {
1078                         v = BME_bevel_wire(bm, v, value, res, options, td);
1079                 }
1080                 else if (res && ((v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG))) {
1081                         
1082                         /* first, make sure we're not sitting on an edge to be removed */
1083                         oe = v->edge;
1084                         e = BME_disk_nextedge(oe,v);
1085                         while ((e->tflag1 & BME_BEVEL_BEVEL) && (e->tflag1 & BME_BEVEL_ORIG)) {
1086                                 e = BME_disk_nextedge(e,v);
1087                                 if (e == oe) {
1088                                         //printf("Something's wrong! We can't remove every edge here!\n");
1089                                         break;
1090                                 }
1091                         }
1092                         /* look for original edges, and remove them */
1093                         oe = e;
1094                         while ( (e = BME_disk_next_edgeflag(oe, v, 0, BME_BEVEL_ORIG | BME_BEVEL_BEVEL)) ) {
1095                                 /* join the faces (we'll split them later) */
1096                                 f = BME_JFKE_safe(bm,e->loop->f,((BME_Loop*)e->loop->radial.next->data)->f,e);
1097                                 if (!f){
1098                                         //printf("Non-manifold geometry not getting tagged right?\n");
1099                                 }
1100                         }
1101
1102                         /* all original edges marked to be beveled have been removed;
1103                          * now we need to link up the edges for this "corner" */
1104                         len = BME_cycle_length(BME_disk_getpointer(v->edge, v));
1105                         for (i=0,e=v->edge; i < len; i++,e=BME_disk_nextedge(e,v)) {
1106                                 l = e->loop;
1107                                 l2 = l->radial.next->data;
1108                                 if (l->v != v) l = l->next;
1109                                 if (l2->v != v) l2 = l2->next;
1110                                 /* look for faces that have had the original edges removed via JFKE */
1111                                 if (l->f->len > 3) {
1112                                         BME_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */
1113                                         if (len > 2) {
1114                                                 l->e->tflag1 |= BME_BEVEL_BEVEL;
1115                                         }
1116                                 }
1117                                 if (l2->f->len > 3) {
1118                                         BME_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */
1119                                         if (len > 2) {
1120                                                 l->e->tflag1 |= BME_BEVEL_BEVEL;
1121                                         }
1122                                 }
1123                         }
1124                         bmesh_dissolve_disk(bm, v);
1125                 }
1126                 v = nv;
1127         }
1128
1129         return bm;
1130 }
1131
1132 static BME_Mesh *BME_tesselate(BME_Mesh *bm) {
1133         BME_Loop *l, *nextloop;
1134         BME_Poly *f;
1135
1136         for (f=bm->polys.first; f; f=f->next) {
1137                 l = f->loopbase;
1138                 while (l->f->len > 4) {
1139                         nextloop = l->next->next->next;
1140                         /* make a quad */
1141                         BME_split_face(bm,l->f,l->v,nextloop->v,NULL,l->e);
1142                         l = nextloop;
1143                 }
1144         }
1145         return bm;
1146 }
1147
1148
1149 /*Main bevel function:
1150         Should be only one exported
1151
1152 */
1153
1154 /* options that can be passed:
1155  * BME_BEVEL_VWEIGHT    <---- v, Look at vertex weights; use defgrp_index if option is present
1156  * BME_BEVEL_SELECT             <---- v,e, check selection for verts and edges
1157  * BME_BEVEL_ANGLE              <---- v,e, don't bevel-tag verts - tag verts per edge
1158  * BME_BEVEL_VERT               <---- e, don't tag edges
1159  * BME_BEVEL_EWEIGHT    <---- e, use crease flag for now
1160  * BME_BEVEL_PERCENT    <---- Will need to think about this one; will probably need to incorporate into actual bevel routine
1161  * BME_BEVEL_RADIUS             <---- Will need to think about this one; will probably need to incorporate into actual bevel routine
1162  * All weights/limits are stored per-vertex
1163  */
1164 BME_Mesh *BME_bevel(BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) {
1165         BME_Vert *v;
1166         BME_TransData_Head *td;
1167         BME_TransData *vtd;
1168         int i;
1169         float fac=1, d;
1170
1171         td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE);
1172
1173         BME_bevel_initialize(bm, options, defgrp_index, angle, td);
1174
1175         /* recursion math courtesy of Martin Poirier (theeth) */
1176         for (i=0; i<res-1; i++) {
1177                 if (i==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * i * 2.0f);
1178         }
1179         d = 1.0f/fac;
1180         /* crazy idea. if res == 0, don't remove original geometry */
1181         for (i=0; i<res || (res==0 && i==0); i++) {
1182                 if (i != 0) BME_bevel_reinitialize(bm);
1183                 BME_model_begin(bm);
1184                 BME_bevel_mesh(bm,d,res,options,defgrp_index,td);
1185                 BME_model_end(bm);
1186                 if (i==0) d /= 3; else d /= 2;
1187         }
1188
1189         BME_tesselate(bm);
1190
1191         if (rtd) {
1192                 *rtd = td;
1193                 return bm;
1194         }
1195
1196         /* transform pass */
1197         for (v = bm->verts.first; v; v=v->next) {
1198                 if ( (vtd = BME_get_transdata(td, v)) ) {
1199                         if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) {
1200                                 d = *vtd->max;
1201                         }
1202                         else {
1203                                 d = value;
1204                         }
1205                         VECADDFAC(v->co,vtd->org,vtd->vec,vtd->factor*d);
1206                 }
1207                 v->tflag1 = 0;
1208         }
1209
1210         BME_free_transdata(td);
1211         return bm;
1212 }