-> Bevel tools and Bmesh kernel
authorGeoffrey Bantle <hairbat@yahoo.com>
Sat, 23 Feb 2008 22:11:16 +0000 (22:11 +0000)
committerGeoffrey Bantle <hairbat@yahoo.com>
Sat, 23 Feb 2008 22:11:16 +0000 (22:11 +0000)
The following is a commit of Levi Schooley's bevel code and
the bmesh library it depends on. The current editmode bevel has
been replaced with a new per edge bevel function. Vertex beveling is
also availible.

To set weights for the modifier to use, use the ctrl-shift-e shortcut on either edges
or vertices.

Recursive beveling is turned of for the time being.

23 files changed:
source/blender/blenkernel/BKE_bmesh.h [new file with mode: 0644]
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/intern/BME_conversions.c [new file with mode: 0644]
source/blender/blenkernel/intern/BME_eulers.c [new file with mode: 0644]
source/blender/blenkernel/intern/BME_mesh.c [new file with mode: 0644]
source/blender/blenkernel/intern/BME_structure.c [new file with mode: 0644]
source/blender/blenkernel/intern/BME_tools.c [new file with mode: 0644]
source/blender/blenkernel/intern/bmesh_private.h [new file with mode: 0644]
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenlib/BLI_editVert.h
source/blender/include/BIF_transform.h
source/blender/include/butspace.h
source/blender/include/transform.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/src/buttons_editing.c
source/blender/src/drawobject.c
source/blender/src/editmesh.c
source/blender/src/editmesh_tools.c
source/blender/src/header_view3d.c
source/blender/src/space.c
source/blender/src/transform.c

diff --git a/source/blender/blenkernel/BKE_bmesh.h b/source/blender/blenkernel/BKE_bmesh.h
new file mode 100644 (file)
index 0000000..6a22096
--- /dev/null
@@ -0,0 +1,250 @@
+/**
+ * BKE_bmesh.h    jan 2007
+ *
+ *     BMesh modeler structure and functions.
+ *
+ * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_BMESH_H
+#define BKE_BMESH_H
+
+#include "DNA_listBase.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "DNA_customdata_types.h"
+#include "BLI_editVert.h"
+#include "BKE_DerivedMesh.h"
+#include "transform.h"
+
+struct BME_Vert;
+struct BME_Edge;
+struct BME_Poly;
+struct BME_Loop;
+struct RetopoPaintData;
+struct DerivedMesh;
+
+typedef struct BME_CycleNode{
+       struct BME_CycleNode *next, *prev;
+       void *data;
+} BME_CycleNode;
+
+typedef struct BME_Mesh
+{
+       ListBase verts, edges, polys, loops;
+       int lock;                                                                               /*if set, all calls to eulers will fail.*/
+       struct BME_Mesh *backup;                                                /*full copy of the mesh*/
+       int totvert, totedge, totpoly, totloop;                 /*record keeping*/
+       int nextv, nexte, nextp, nextl;                                 /*Next element ID for verts/edges/faces/loops. Never reused*/
+       struct CustomData vdata, edata, pdata, ldata;   /*Custom Data Layer information*/
+       struct DerivedMesh *derivedFinal, *derivedCage;
+       struct RetopoPaintData *retopo_paint_data; /*here for temporary code compatibility only*/
+       //BME_ElementList selection;
+       int lastDataMask;
+} BME_Mesh;
+
+//60, 52, 52, 12 704
+//60, 52, 84 
+
+
+typedef struct BME_Vert
+{
+       struct BME_Vert *next, *prev;
+       int     EID;
+       float co[3];                                                                    /*vertex location. Actually pointer to custom data block*/
+       float no[3];                                                                    /*vertex normal. Actually pointer to custom data block*/
+       struct BME_Edge *edge;                                                  /*first edge in the disk cycle for this vertex*/
+       void *data;                                                                             /*custom vertex data*/
+       int eflag1, eflag2;                                                             /*reserved for use by eulers*/
+       int tflag1, tflag2;                                                             /*reserved for use by tools*/
+       unsigned short flag, h;
+       float bweight;
+} BME_Vert;
+
+typedef struct BME_Edge
+{
+       struct BME_Edge *next, *prev;
+       int EID;
+       struct BME_Vert *v1, *v2;                                               /*note that order of vertex pointers means nothing to eulers*/
+       struct BME_CycleNode d1, d2;                                    /*disk cycle nodes for v1 and v2 respectivley*/
+       struct BME_Loop *loop;                                                  /*first BME_Loop in the radial cycle around this edge*/
+       void *data;                                                                             /*custom edge data*/
+       int eflag1, eflag2;                                                             /*reserved for use by eulers*/
+       int tflag1, tflag2;                                                             /*reserved for use by tools*/
+       unsigned char flag, h;
+       float crease, bweight;
+} BME_Edge;
+
+typedef struct BME_Loop 
+{      
+       struct BME_Loop *next, *prev;                                   /*circularly linked list around face*/
+       int EID;
+       struct BME_CycleNode radial;                                    /*circularly linked list used to find faces around an edge*/
+       struct BME_CycleNode *gref;                                             /*pointer to loop ref. Nasty.*/
+       struct BME_Vert *v;                                                             /*vertex that this loop starts at.*/
+       struct BME_Edge *e;                                                             /*edge this loop belongs to*/
+       struct BME_Poly *f;                                                             /*face this loop belongs to*/   
+       void *data;                                                                             /*custom per face vertex data*/
+       int eflag1, eflag2;                                                             /*reserved for use by eulers*/
+       int tflag1, tflag2;                                                             /*reserved for use by tools*/
+       unsigned short flag, h;
+} BME_Loop;
+
+typedef struct BME_Poly
+{
+       struct BME_Poly *next, *prev;
+       int EID;
+       //~ float no[3];
+       struct BME_Loop *loopbase;                                              /*First editloop around Polygon.*/
+       struct ListBase holes;                                                  /*list of inner loops in the face*/
+       unsigned int len;                                                               /*total length of the face. Eulers should preserve this data*/
+       void *data;                                                                             /*custom face data*/
+       int eflag1, eflag2;                                                             /*reserved for use by eulers*/
+       int tflag1, tflag2;                                                             /*reserved for use by tools*/
+       unsigned short flag, h, mat_nr;
+} BME_Poly;
+
+//*EDGE UTILITIES*/
+int BME_verts_in_edge(struct BME_Vert *v1, struct BME_Vert *v2, struct BME_Edge *e);
+int BME_vert_in_edge(struct BME_Edge *e, BME_Vert *v);
+struct BME_Vert *BME_edge_getothervert(struct BME_Edge *e, struct BME_Vert *v);
+
+/*GENERAL CYCLE*/
+int BME_cycle_length(void *h);
+
+/*DISK CYCLE*/
+struct BME_Edge *BME_disk_nextedge(struct BME_Edge *e, struct BME_Vert *v); 
+struct BME_CycleNode *BME_disk_getpointer(struct BME_Edge *e, struct BME_Vert *v);
+struct BME_Edge *BME_disk_next_edgeflag(struct BME_Edge *e, struct BME_Vert *v, int eflag, int tflag);
+int BME_disk_count_edgeflag(struct BME_Vert *v, int eflag, int tflag);
+
+/*RADIAL CYCLE*/
+struct BME_Loop *BME_radial_nextloop(struct BME_Loop *l);
+int BME_radial_find_face(struct BME_Edge *e,struct BME_Poly *f);
+
+/*LOOP CYCLE*/
+struct BME_Loop *BME_loop_find_loop(struct BME_Poly *f, struct BME_Vert *v);
+
+/*MESH CREATION/DESTRUCTION*/
+struct BME_Mesh *BME_make_mesh(void);
+void BME_free_mesh(struct BME_Mesh *bm);
+struct BME_Mesh *BME_copy_mesh(struct BME_Mesh *bm);
+/*FULL MESH VALIDATION*/
+int BME_validate_mesh(struct BME_Mesh *bm, int halt);
+/*ENTER/EXIT MODELLING LOOP*/
+int BME_model_begin(struct BME_Mesh *bm);
+void BME_model_end(struct BME_Mesh *bm);
+
+/*MESH CONSTRUCTION API.*/
+/*MAKE*/
+struct BME_Vert *BME_MV(struct BME_Mesh *bm, float *vec);
+struct BME_Edge *BME_ME(struct BME_Mesh *bm, struct BME_Vert *v1, struct BME_Vert *v2);
+struct BME_Poly *BME_MF(struct BME_Mesh *bm, struct BME_Vert *v1, struct BME_Vert *v2, struct BME_Edge **elist, int len);
+/*KILL*/
+int BME_KV(struct BME_Mesh *bm, struct BME_Vert *v);
+int BME_KE(struct BME_Mesh *bm, struct BME_Edge *e);
+int BME_KF(struct BME_Mesh *bm, struct BME_Poly *bply);
+/*SPLIT*/
+struct BME_Vert *BME_SEMV(struct BME_Mesh *bm, struct BME_Vert *tv, struct BME_Edge *e, struct BME_Edge **re);
+struct BME_Poly *BME_SFME(struct BME_Mesh *bm, struct BME_Poly *f, struct BME_Vert *v1, struct BME_Vert *v2, struct BME_Loop **rl);
+/*JOIN*/
+int BME_JEKV(struct BME_Mesh *bm, struct BME_Edge *ke, struct BME_Vert *kv);
+struct BME_Poly *BME_JFKE(struct BME_Mesh *bm, struct BME_Poly *f1, struct BME_Poly *f2,struct BME_Edge *e); /*no reason to return BME_Poly pointer?*/
+/*NORMAL FLIP(Is its own inverse)*/
+int BME_loop_reverse(struct BME_Mesh *bm, struct BME_Poly *f);
+
+/*TOOLS CODE*/
+struct BME_Loop *BME_inset_edge(struct BME_Mesh *bm, struct BME_Loop *l, struct BME_Poly *f);
+struct BME_Poly *BME_inset_poly(struct BME_Mesh *bm, struct BME_Poly *f);
+
+/* bevel tool defines */
+/* element flags */
+#define BME_BEVEL_ORIG                 1
+#define BME_BEVEL_BEVEL                        (1<<1)
+#define BME_BEVEL_NONMAN               (1<<2)
+#define BME_BEVEL_WIRE                 (1<<3)
+
+/* tool options */
+#define BME_BEVEL_SELECT               1
+#define BME_BEVEL_VERT                 (1<<1)
+#define BME_BEVEL_RADIUS               (1<<2)
+#define BME_BEVEL_ANGLE                        (1<<3)
+#define BME_BEVEL_WEIGHT               (1<<4)
+//~ #define BME_BEVEL_EWEIGHT          (1<<4)
+//~ #define BME_BEVEL_VWEIGHT          (1<<5)
+#define BME_BEVEL_PERCENT              (1<<6)
+#define BME_BEVEL_EMIN                 (1<<7)
+#define BME_BEVEL_EMAX                 (1<<8)
+#define BME_BEVEL_RUNNING              (1<<9)
+#define BME_BEVEL_RES                  (1<<10)
+
+typedef struct BME_TransData {
+       BME_Mesh *bm; /* the bmesh the vert belongs to */
+       BME_Vert *v;  /* pointer to the vert this tdata applies to */
+       float co[3];  /* the original coordinate */
+       float org[3]; /* the origin */
+       float vec[3]; /* a directional vector; always, always normalize! */
+       void *loc;    /* a pointer to the data to transform (likely the vert's cos) */
+       float factor; /* primary scaling factor; also accumulates number of weighted edges for beveling tool */
+       float weight; /* another scaling factor; used primarily for propogating vertex weights to transforms; */
+                     /* weight is also used across recursive bevels to help with the math */
+       float maxfactor; /* the unscaled, original factor (used only by "edge verts" in recursive beveling) */
+       float *max;   /* the maximum distance this vert can be transformed; negative is infinite
+                      * it points to the "parent" maxfactor (where maxfactor makes little sense)
+                      * where the max limit is stored (limits are stored per-corner) */
+} BME_TransData;
+
+typedef struct BME_TransData_Head {
+       GHash *gh;       /* the hash structure for element lookup */
+       MemArena *ma;    /* the memory "pool" we will be drawing individual elements from */
+       int len;
+} BME_TransData_Head;
+
+typedef struct BME_Glob { /* stored in Global G for Transform() purposes */
+       BME_Mesh *bm;
+       BME_TransData_Head *td;
+       struct TransInfo *Trans; /* a pointer to the global Trans struct */
+       int imval[2]; /* for restoring original mouse co when initTransform() is called multiple times */
+       int options;
+       int res;
+} BME_Glob;
+
+struct BME_TransData *BME_get_transdata(struct BME_TransData_Head *td, struct BME_Vert *v);
+void BME_free_transdata(struct BME_TransData_Head *td);
+float *BME_bevel_calc_polynormal(struct BME_Poly *f, struct BME_TransData_Head *td);
+struct BME_Mesh *BME_bevel(struct BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd);
+
+/*CONVERSION FUNCTIONS*/
+struct BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em, struct BME_Mesh *bm);
+struct EditMesh *BME_bmesh_to_editmesh(struct BME_Mesh *bm, BME_TransData_Head *td);
+struct BME_Mesh *BME_derivedmesh_to_bmesh(struct DerivedMesh *dm, struct BME_Mesh *bm);
+struct DerivedMesh *BME_bmesh_to_derivedmesh(struct BME_Mesh *bm, struct DerivedMesh *dm);
+#endif
index 8aaa9e4228934d6ce3ee07cc094652dd36179f45..7019eb26bcb03725bbf8a0d2c5efa9eb669056d6 100644 (file)
@@ -62,6 +62,7 @@ struct Object;
 struct bSoundListener;
 struct BMF_Font;
 struct EditMesh;
+struct BME_Glob;
 
 typedef struct Global {
 
@@ -111,6 +112,9 @@ typedef struct Global {
 
        /* Editmode lists */
        struct EditMesh *editMesh;
+       
+       /* Used for BMesh transformations */
+       struct BME_Glob *editBMesh;
     
        float textcurs[4][2];
     
@@ -191,6 +195,7 @@ typedef struct Global {
 
 /* #define G_AUTOMATKEYS       (1 << 30)   also removed */
 #define G_HIDDENHANDLES (1 << 31) /* used for curves only */
+#define G_DRAWBWEIGHTS (1 << 31)
 
 /* macro for testing face select mode
  * Texture paint could be removed since selected faces are not used
diff --git a/source/blender/blenkernel/intern/BME_conversions.c b/source/blender/blenkernel/intern/BME_conversions.c
new file mode 100644 (file)
index 0000000..ee8c652
--- /dev/null
@@ -0,0 +1,406 @@
+/**
+ * BME_mesh.c    jan 2007
+ *
+ *     BMesh mesh level functions.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_bmesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+#include "BIF_editmesh.h"
+#include "editmesh.h"
+#include "bmesh_private.h"
+
+#include "BSE_edit.h"
+
+BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em, BME_Mesh *bm) {
+       BME_Vert *v1, *v2;
+       BME_Edge *e, *edar[4];
+       BME_Poly *f;
+
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+
+       int len;
+
+       BME_model_begin(bm);
+       /*custom data*/
+       
+       /*add verts*/
+       CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       eve= em->verts.first;
+       while(eve) {
+               v1 = BME_MV(bm,eve->co);
+               VECCOPY(v1->no,eve->no);
+               v1->flag = eve->f;
+               v1->h = eve->h;
+               v1->bweight = eve->bweight;
+
+               /* link the verts for edge and face construction;
+                * kind of a dangerous thing - remember to cast back to BME_Vert before using! */
+               eve->tmp.v = (EditVert*)v1;
+
+               CustomData_em_copy_data(&em->vdata, &bm->vdata, eve->data, &v1->data);
+               
+               eve = eve->next;
+       }
+       
+       /*add edges*/
+       CustomData_copy(&em->edata, &bm->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       eed= em->edges.first;
+       while(eed) {
+               v1 = (BME_Vert*)eed->v1->tmp.v;
+               v2 = (BME_Vert*)eed->v2->tmp.v;
+               e = BME_ME(bm, v1, v2);
+               e->crease = eed->crease;
+               e->bweight = eed->bweight;
+               e->flag = eed->f & SELECT;
+               if(eed->sharp) e->flag |= ME_SHARP;
+               if(eed->seam) e->flag |= ME_SEAM;
+               if(eed->h & EM_FGON) e->flag |= ME_FGON;
+               if(eed->h & 1) e->flag |= ME_HIDE;
+               CustomData_em_copy_data(&em->edata, &bm->edata, eed->data, &e->data);
+
+               /* link the edges for face construction;
+                * kind of a dangerous thing - remember to cast back to BME_Edge before using! */
+               eed->tmp.e = (EditEdge*)e;
+               eed = eed->next;
+       }
+
+       /*add faces.*/
+       CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       efa= em->faces.first;
+       while(efa) {
+               if(efa->v4) len = 4;
+               else len = 3;
+               
+               edar[0] = (BME_Edge*)efa->e1->tmp.e;
+               edar[1] = (BME_Edge*)efa->e2->tmp.e;
+               edar[2] = (BME_Edge*)efa->e3->tmp.e;
+               if(len == 4){
+                       edar[3] = (BME_Edge*)efa->e4->tmp.e;
+               }
+               
+               /*find v1 and v2*/
+               v1 = (BME_Vert*)efa->v1->tmp.v;
+               v2 = (BME_Vert*)efa->v2->tmp.v;
+               
+               f = BME_MF(bm,v1,v2,edar,len);
+               f->mat_nr = efa->mat_nr;
+               f->flag = efa->flag;
+               if(efa->h) {
+                       f->flag |= ME_HIDE;
+                       f->flag &= ~ME_FACE_SEL;
+               }
+               else {
+                       if(efa->f & 1) f->flag |= ME_FACE_SEL;
+                       else f->flag &= ~ME_FACE_SEL;
+               }
+               CustomData_em_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data);
+               
+               efa = efa->next;
+       }
+       BME_model_end(bm);
+       return bm;
+}
+
+/* adds the geometry in the bmesh to G.editMesh (does not free G.editMesh)
+ * if td != NULL, the transdata will be mapped to the EditVert's co */
+EditMesh *BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td) {
+       BME_Vert *v1;
+       BME_Edge *e;
+       BME_Poly *f;
+       
+       BME_TransData *vtd;
+
+       EditMesh *em;
+       EditVert *eve1, *eve2, *eve3, *eve4, **evlist;
+       EditEdge *eed;
+       EditFace *efa;
+
+       int totvert, len, i;
+
+       em = G.editMesh;
+
+       if (em == NULL) return NULL;
+
+       /* convert to EditMesh */
+       /* make editverts */
+       CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       totvert = BLI_countlist(&(bm->verts));
+       evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist");
+       for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) {
+               v1->tflag1 = i;
+               eve1 = addvertlist(v1->co,NULL);
+               if (td && (vtd = BME_get_transdata(td,v1))) {
+                       vtd->loc = eve1->co;
+               }
+               eve1->keyindex = i;
+               evlist[i]= eve1;
+               eve1->f = (unsigned char)v1->flag;
+               eve1->h = (unsigned char)v1->h;
+               eve1->bweight = v1->bweight;
+               CustomData_em_copy_data(&bm->vdata, &em->vdata, v1->data, &eve1->data);
+       }
+       
+       /* make edges */
+       CustomData_copy(&bm->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       for (e=bm->edges.first;e;e=e->next) {
+               eed= addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL);
+               eed->crease = e->crease;
+               eed->bweight = e->bweight;
+               if(e->flag & ME_SEAM) eed->seam = 1;
+               if(e->flag & ME_SHARP) eed->sharp = 1;
+               if(e->flag & SELECT) eed->f |= SELECT;
+               if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
+               if(e->flag & ME_HIDE) eed->h |= 1;
+               if(G.scene->selectmode==SCE_SELECT_EDGE) 
+                       EM_select_edge(eed, eed->f & SELECT);
+               CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data);
+       }
+
+       /* make faces */
+       CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       for (f=bm->polys.first;f;f=f->next) {
+               len = BME_cycle_length(f->loopbase);
+               if (len==3 || len==4) {
+                       eve1= evlist[f->loopbase->v->tflag1];
+                       eve2= evlist[f->loopbase->next->v->tflag1];
+                       eve3= evlist[f->loopbase->next->next->v->tflag1];
+                       if (len == 4) {
+                               eve4= evlist[f->loopbase->prev->v->tflag1];
+                       }
+                       else {
+                               eve4= NULL;
+                       }
+
+                       efa = addfacelist(eve1, eve2, eve3, eve4, NULL, NULL);
+                       CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
+                       efa->mat_nr = (unsigned char)f->mat_nr;
+                       efa->flag= f->flag & ~ME_HIDE;
+                       if(f->flag & ME_FACE_SEL) {
+                               efa->f |= SELECT;
+                       }
+                       if(f->flag & ME_HIDE) efa->h= 1;
+                       if((G.f & G_FACESELECT) && (efa->f & SELECT))
+                               EM_select_face(efa, 1); /* flush down */
+               }
+       }
+
+       MEM_freeN(evlist);
+
+       countall();
+
+       return em;
+}
+
+/* Adds the geometry found in dm to bm
+ * NOTE: it does not allocate a new BME_Mesh!
+ */
+BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm, BME_Mesh *bm)
+{
+       MVert *mvert, *mv;
+       MEdge *medge, *me;
+       MFace *mface, *mf;
+       int totface,totedge,totvert,i,len;
+
+       BME_Vert *v1=NULL,*v2=NULL, **vert_array;
+       BME_Edge *e=NULL;
+       BME_Poly *f=NULL;
+       
+       EdgeHash *edge_hash = BLI_edgehash_new();
+       
+       totvert = dm->getNumVerts(dm);
+       totedge = dm->getNumEdges(dm);
+       totface = dm->getNumFaces(dm);
+       mvert = dm->getVertArray(dm);
+       medge = dm->getEdgeArray(dm);
+       mface = dm->getFaceArray(dm);
+
+       vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array");
+
+       /*custom data*/
+       /* NOTE: I haven't tested whether or not custom data is being copied correctly */
+       CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH,
+                       CD_CALLOC, 0);
+       CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH,
+                       CD_CALLOC, 0);
+       CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_DERIVEDMESH,
+                       CD_CALLOC, 0);
+       /*add verts*/
+       for(i=0,mv = mvert; i < totvert;i++,mv++){
+               v1 = BME_MV(bm,mv->co);
+               vert_array[i] = v1;
+               v1->flag = mv->flag;
+               v1->bweight = mv->bweight/255.0f;
+               CustomData_to_em_block(&dm->vertData, &bm->vdata, i, &v1->data);
+       }
+       /*add edges*/
+       for(i=0,me = medge; i < totedge;i++,me++){
+               v1 = vert_array[me->v1];
+               v2 = vert_array[me->v2];
+               e = BME_ME(bm, v1, v2);
+               e->crease = me->crease/255.0f;
+               e->bweight = me->bweight/255.0f;
+               e->flag = (unsigned char)me->flag;
+               BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
+               CustomData_to_em_block(&dm->edgeData, &bm->edata, i, &e->data);
+       }
+       /*add faces.*/
+       for(i=0,mf = mface; i < totface;i++,mf++){
+               BME_Edge *edar[4];
+               if(mf->v4) len = 4;
+               else len = 3;
+               
+               edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2);
+               edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3);
+               if(len == 4){
+                       edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4);
+                       edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1);
+               }
+               else
+                       edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1);
+               
+               /*find v1 and v2*/
+               v1 = vert_array[mf->v1];
+               v2 = vert_array[mf->v2];
+               
+               f = BME_MF(bm,v1,v2,edar,len);
+               f->mat_nr = mf->mat_nr;
+               f->flag = mf->flag;
+               CustomData_to_em_block(&dm->faceData, &bm->pdata, i, &f->data);
+       }
+       
+       BLI_edgehash_free(edge_hash, NULL);
+       MEM_freeN(vert_array);
+       return bm;
+}
+
+DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
+{
+       MFace *mface, *mf;
+       MEdge *medge, *me;
+       MVert *mvert, *mv;
+       int totface,totedge,totvert,i,bmeshok,len;
+
+       BME_Vert *v1=NULL;
+       BME_Edge *e=NULL;
+       BME_Poly *f=NULL;
+       
+       DerivedMesh *result;
+       
+       totvert = BLI_countlist(&(bm->verts));
+       totedge = BLI_countlist(&(bm->edges));
+       /*count quads and tris*/
+       totface = 0;
+       bmeshok = 1;
+       for(f=bm->polys.first;f;f=f->next){
+               len = BME_cycle_length(f->loopbase);
+               if(len == 3 || len == 4) totface++;
+       }
+       
+       /*convert back to mesh*/
+       result = CDDM_from_template(dm,totvert,totedge,totface);
+       /*custom data*/
+       /* NOTE: I haven't tested whether or not custom data is being copied correctly */
+       CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_DERIVEDMESH,
+                       CD_CALLOC, totvert);
+       CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_DERIVEDMESH,
+                       CD_CALLOC, totedge);
+       CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_DERIVEDMESH,
+                       CD_CALLOC, totface);
+       /*Make Verts*/
+       mvert = CDDM_get_verts(result);
+       for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){
+               v1->tflag1 = i;
+               VECCOPY(mv->co,v1->co);
+               mv->flag = (unsigned char)v1->flag;
+               mv->bweight = (char)(255.0*v1->bweight);
+               CustomData_from_em_block(&bm->vdata, &result->vertData, v1->data, i);
+       }
+       medge = CDDM_get_edges(result);
+       for(i=0,e=bm->edges.first,me=medge;e;e=e->next,me++,i++){
+               if(e->v1->tflag1 < e->v2->tflag1){
+                       me->v1 = e->v1->tflag1;
+                       me->v2 = e->v2->tflag1;
+               }
+               else{
+                       me->v1 = e->v2->tflag1;
+                       me->v2 = e->v1->tflag1;
+               }
+               me->crease = (char)(255.0*e->crease);
+               me->bweight = (char)(255.0*e->bweight);
+               me->flag = e->flag;
+               CustomData_from_em_block(&bm->edata, &result->edgeData, e->data, i);
+       }
+       if(totface){
+               mface = CDDM_get_faces(result);
+               /*make faces*/
+               for(i=0,f=bm->polys.first;f;f=f->next,i++){
+                       mf = &mface[i];
+                       len = BME_cycle_length(f->loopbase);
+                       if(len==3 || len==4){
+                               mf->v1 = f->loopbase->v->tflag1;
+                               mf->v2 = f->loopbase->next->v->tflag1;
+                               mf->v3 = f->loopbase->next->next->v->tflag1;
+                               if(len == 4){
+                                       mf->v4 = f->loopbase->prev->v->tflag1;
+                               }
+                               /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
+                               if(mf->v3 == 0 || (len == 4 && mf->v4 == 0)){
+                                       test_index_face(mf, NULL, i, len);
+                               }
+                       }
+                       mf->mat_nr = (unsigned char)f->mat_nr;
+                       mf->flag = (unsigned char)f->flag;
+                       CustomData_from_em_block(&bm->pdata, &result->faceData, f->data, i);
+               }
+       }
+
+       return result;
+}
\ No newline at end of file
diff --git a/source/blender/blenkernel/intern/BME_eulers.c b/source/blender/blenkernel/intern/BME_eulers.c
new file mode 100644 (file)
index 0000000..34187e7
--- /dev/null
@@ -0,0 +1,1007 @@
+/**
+ * BME_eulers.c    jan 2007
+ *
+ *     BMesh Euler construction API.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+
+#include "BLI_blenlib.h"
+#include "bmesh_private.h"
+#include "BLI_ghash.h"
+
+/*********************************************************
+ *                    "Euler API"                        *
+ *                                                       *
+ *                                                       *
+ *      Primitive construction operators for mesh tools.    *
+ *                                                       *
+ **********************************************************/
+
+
+/*
+       The functions in this file represent the 'primitive' or 'atomic' operators that
+       mesh tools use to manipulate the topology of the structure.* The purpose of these
+       functions is to provide a trusted set of operators to manipulate the mesh topology
+       and which can also be combined together like building blocks to create more 
+       sophisticated tools. It needs to be stressed that NO manipulation of an existing 
+       mesh structure should be done outside of these functions.
+       
+       In the BMesh system, each euler is named by an ancronym which describes what it actually does.
+       Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that
+       through a Euler's logical inverse you can 'undo' an operation. (Special note should
+       be taken of BME_loop_reverse, which is its own inverse).
+               
+       BME_MF/KF: Make Face and Kill Face
+       BME_ME/KE: Make Edge and Kill Edge
+       BME_MV/KV: Make Vert and Kill Vert
+       BME_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
+       BME_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
+       BME_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one)
+       
+       Using a combination of these eleven eulers any non-manifold modelling operation can be achieved.
+       Each Euler operator has a detailed explanation of what is does in the comments preceding its 
+       code. 
+
+   *The term "Euler Operator" is actually a misnomer when referring to a non-manifold 
+    data structure. Its use is in keeping with the convention established by others.
+
+       TODO:
+       -Finish inserting 'strict' validation in all Eulers
+*/
+
+void *BME_exit(char *s) {
+       if (s) printf("%s\n",s);
+       return NULL;
+}
+
+#define RETCLEAR(bm) {bm->rval->v = bm->rval->e = bm->rval->f = bm->rva->l = NULL;}
+/*MAKE Eulers*/
+
+/**
+ *                     BME_MV
+ *
+ *     MAKE VERT EULER:
+ *     
+ *     Makes a single loose vertex.
+ *
+ *     Returns -
+ *     A BME_Vert pointer.
+ */
+
+BME_Vert *BME_MV(BME_Mesh *bm, float *vec){
+       BME_Vert *v = BME_addvertlist(bm, NULL);        
+       VECCOPY(v->co,vec);
+       return v;
+}
+
+/**
+ *                     BME_ME
+ *
+ *     MAKE EDGE EULER:
+ *     
+ *     Makes a single wire edge between two vertices.
+ *     If the caller does not want there to be duplicate
+ *     edges between the vertices, it is up to them to check 
+ *     for this condition beforehand.
+ *
+ *     Returns -
+ *     A BME_Edge pointer.
+ */
+
+BME_Edge *BME_ME(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2){
+       BME_Edge *e=NULL;
+       BME_CycleNode *d1=NULL, *d2=NULL;
+       int valance1=0, valance2=0, edok;
+       
+       /*edge must be between two distinct vertices...*/
+       if(v1 == v2) return BME_exit("ME returned NULL");
+       
+       #ifndef BME_FASTEULER
+       /*count valance of v1*/
+       if(v1->edge){ 
+               d1 = BME_disk_getpointer(v1->edge,v1);
+               if(d1) valance1 = BME_cycle_length(d1);
+               else BME_error();
+       }
+       if(v2->edge){
+               d2 = BME_disk_getpointer(v2->edge,v2);
+               if(d2) valance2 = BME_cycle_length(d2);
+               else BME_error();
+       }
+       #endif
+       
+       /*go ahead and add*/
+       e = BME_addedgelist(bm, v1, v2, NULL);
+       BME_disk_append_edge(e, e->v1);
+       BME_disk_append_edge(e, e->v2);
+       
+       #ifndef BME_FASTEULER
+       /*verify disk cycle lengths*/
+       d1 = BME_disk_getpointer(e, e->v1);
+       edok = BME_cycle_validate(valance1+1, d1);
+       if(!edok) BME_error();
+       d2 = BME_disk_getpointer(e, e->v2);
+       edok = BME_cycle_validate(valance2+1, d2);
+       if(!edok) BME_error();
+       
+       /*verify that edge actually made it into the cycle*/
+       edok = BME_disk_hasedge(v1, e);
+       if(!edok) BME_error();
+       edok = BME_disk_hasedge(v2, e);
+       if(!edok) BME_error();
+       #endif
+       return e;
+}
+
+
+
+/**
+ *                     BME_MF
+ *
+ *     MAKE FACE EULER:
+ *     Takes a list of edge pointers which form a closed loop and makes a face 
+ *  from them. The first edge in elist is considered to be the start of the 
+ *     polygon, and v1 and v2 are its vertices and determine the winding of the face 
+ *  Other than the first edge, no other assumptions are made about the order of edges
+ *  in the elist array. To verify that it is a single closed loop and derive the correct 
+ *  order a simple series of verifications is done and all elements are visited.
+ *             
+ *  Returns -
+ *     A BME_Poly pointer
+ */
+
+#define MF_CANDIDATE   1
+#define MF_VISITED             2
+#define MF_TAKEN               4 
+
+BME_Poly *BME_MF(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge **elist, int len)
+{
+       BME_Poly *f = NULL;
+       BME_Edge *curedge;
+       BME_Vert *curvert, *tv, *nextv,**vlist;
+       int i, j, done, cont, edok,vlen;
+       
+       if(len < 2) return BME_exit("MF returned NULL");
+       
+       /*make sure that v1 and v2 are in elist[0]*/
+       if(BME_verts_in_edge(v1,v2,elist[0]) == 0) return BME_exit("MF returned NULL");
+       
+       /*clear euler flags*/
+       for(i=0;i<len;i++) elist[i]->eflag1=elist[i]->eflag2 = 0;
+       for(i=0;i<len;i++){
+               elist[i]->eflag1 |= MF_CANDIDATE;
+               
+               /*if elist[i] has a loop, count its radial length*/
+               if(elist[i]->loop) elist[i]->eflag2 = BME_cycle_length(&(elist[i]->loop->radial));
+               else elist[i]->eflag2 = 0;
+       }
+       
+       /*      For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it
+               Note that this does not gauruntee that face is a single closed loop. At best it gauruntees
+               that elist contains a finite number of seperate closed loops.
+       */
+       for(i=0; i<len; i++){
+               edok = BME_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
+               if(edok != 2) return BME_exit("MF returned NULL");
+               edok = BME_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
+               if(edok != 2) return BME_exit("MF returned NULL");
+       }
+       
+       /*set start edge, start vert and target vert for our loop traversal*/
+       curedge = elist[0];
+       tv = v1;
+       curvert = v2;
+       
+       /*insert tv into vlist since its the first vertex in face*/
+       i=0;
+       vlist=MEM_callocN(sizeof(BME_Vert*)*len,"BME_MF vlist array");
+       vlist[i] = tv;
+
+       /*      Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't 
+               been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE
+               edge, loop until we find TV. We know TV is reachable because of test we did earlier.
+       */
+       done=0;
+       while(!done){
+               /*add curvert to vlist*/
+               /*insert some error cheking here for overflows*/
+               i++;
+               vlist[i] = curvert;
+               
+               /*mark curedge as visited*/
+               curedge->eflag1 |= MF_VISITED;
+               
+               /*find next edge and vert*/
+               curedge = BME_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
+               curvert = BME_edge_getothervert(curedge, curvert);
+               if(curvert == tv){
+                       curedge->eflag1 |= MF_VISITED;
+                       done=1;
+               }
+       }
+
+       /*      Verify that all edges have been visited It's possible that we did reach tv 
+               from sv, but that several unconnected loops were passed in via elist.
+       */
+       cont=1;
+       for(i=0; i<len; i++){
+               if((elist[i]->eflag1 & MF_VISITED) == 0) cont = 0;
+       }
+       
+       /*if we get this far, its ok to allocate the face and add the loops*/
+       if(cont){
+               BME_Loop *l;
+               BME_Edge *e;
+               f = BME_addpolylist(bm, NULL);
+               f->len = len;
+               for(i=0;i<len;i++){
+                       curvert = vlist[i];
+                       l = BME_create_loop(bm,curvert,NULL,f,NULL);
+                       if(!(f->loopbase)) f->loopbase = l;
+                       BME_cycle_append(f->loopbase, l);
+               }
+               
+               /*take care of edge pointers and radial cycle*/
+               for(i=0, l = f->loopbase; i<len; i++, l=l->next){
+                       e = NULL;
+                       if(l == f->loopbase) e = elist[0]; /*first edge*/
+                       
+                       else{/*search elist for others*/
+                               for(j=1; j<len; j++){
+                                       edok = BME_verts_in_edge(l->v, l->next->v, elist[j]);
+                                       if(edok){ 
+                                               e = elist[j];
+                                               break;
+                                       }
+                               }
+                       }
+                       l->e = e; /*set pointer*/
+                       BME_radial_append(e, l); /*append into radial*/
+               }
+
+               f->len = len;
+               
+               /*Validation Loop cycle*/
+               edok = BME_cycle_validate(len, f->loopbase);
+               if(!edok) BME_error();
+               for(i=0, l = f->loopbase; i<len; i++, l=l->next){
+                       /*validate loop vert pointers*/
+                       edok = BME_verts_in_edge(l->v, l->next->v, l->e);
+                       if(!edok) BME_error();
+                       /*validate the radial cycle of each edge*/
+                       edok = BME_cycle_length(&(l->radial));
+                       if(edok != (l->e->eflag2 + 1)) BME_error();
+               }
+       }
+       
+       MEM_freeN(vlist);
+       return f;
+}
+
+/* KILL Eulers */
+
+/**
+ *                     BME_KV
+ *
+ *     KILL VERT EULER:
+ *     
+ *     Kills a single loose vertex.
+ *
+ *     Returns -
+ *     1 for success, 0 for failure.
+ */
+
+int BME_KV(BME_Mesh *bm, BME_Vert *v){
+       if(v->edge == NULL){ 
+               BLI_remlink(&(bm->verts), v);
+               BME_free_vert(bm,v);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ *                     BME_KE
+ *
+ *     KILL EDGE EULER:
+ *     
+ *     Kills a wire edge.
+ *
+ *     Returns -
+ *     1 for success, 0 for failure.
+ */
+
+int BME_KE(BME_Mesh *bm, BME_Edge *e){
+       int edok;
+       
+       /*Make sure that no faces!*/
+       if(e->loop == NULL){
+               BME_disk_remove_edge(e, e->v1);
+               BME_disk_remove_edge(e, e->v2);
+               
+               /*verify that edge out of disk*/
+               edok = BME_disk_hasedge(e->v1, e);
+               if(edok) BME_error();
+               edok = BME_disk_hasedge(e->v2, e);
+               if(edok) BME_error();
+               
+               /*remove and deallocate*/
+               BLI_remlink(&(bm->edges), e);
+               BME_free_edge(bm, e);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ *                     BME_KF
+ *
+ *     KILL FACE EULER:
+ *     
+ *     The logical inverse of BME_MF.
+ *     Kills a face and removes each of its loops from the radial that it belongs to.
+ *
+ *  Returns -
+ *     1 for success, 0 for failure.
+*/
+
+int BME_KF(BME_Mesh *bm, BME_Poly *bply){
+       BME_Loop *newbase,*oldbase, *curloop;
+       int i,len=0;
+       
+       /*add validation to make sure that radial cycle is cleaned up ok*/
+       /*deal with radial cycle first*/
+       len = BME_cycle_length(bply->loopbase);
+       for(i=0, curloop=bply->loopbase; i < len; i++, curloop = curloop->next) 
+               BME_radial_remove_loop(curloop, curloop->e);
+       
+       /*now deallocate the editloops*/
+       for(i=0; i < len; i++){
+               newbase = bply->loopbase->next;
+               oldbase = bply->loopbase;
+               BME_cycle_remove(oldbase, oldbase);
+               BME_free_loop(bm, oldbase);
+               bply->loopbase = newbase;
+       }
+       
+       BLI_remlink(&(bm->polys), bply);
+       BME_free_poly(bm, bply);
+       return 1;
+}
+
+/*SPLIT Eulers*/
+
+/**
+ *                     BME_SEMV
+ *
+ *     SPLIT EDGE MAKE VERT:
+ *     Takes a given edge and splits it into two, creating a new vert.
+ *
+ *
+ *             Before: OV---------TV   
+ *             After:  OV----NV---TV
+ *
+ *  Returns -
+ *     BME_Vert pointer.
+ *
+*/
+
+BME_Vert *BME_SEMV(BME_Mesh *bm, BME_Vert *tv, BME_Edge *e, BME_Edge **re){
+       BME_Vert *nv, *ov;
+       BME_CycleNode *diskbase;
+       BME_Edge *ne;
+       int i, radlen, edok, valance1=0, valance2=0;
+       
+       if(BME_vert_in_edge(e,tv) == 0) return BME_exit("SEMV returned NULL");
+       ov = BME_edge_getothervert(e,tv);
+       //v2 = tv;
+
+       /*count valance of v1*/
+       diskbase = BME_disk_getpointer(e, ov);
+       valance1 = BME_cycle_length(diskbase);
+       /*count valance of v2*/
+       diskbase = BME_disk_getpointer(e, tv);
+       valance2 = BME_cycle_length(diskbase);
+       
+       nv = BME_addvertlist(bm, tv);
+       ne = BME_addedgelist(bm, nv, tv, e);
+       
+       //e->v2 = nv;
+       /*remove e from v2's disk cycle*/
+       BME_disk_remove_edge(e, tv);
+       /*swap out tv for nv in e*/
+       BME_edge_swapverts(e, tv, nv);
+       /*add e to nv's disk cycle*/
+       BME_disk_append_edge(e, nv);
+       /*add ne to nv's disk cycle*/
+       BME_disk_append_edge(ne, nv);
+       /*add ne to tv's disk cycle*/
+       BME_disk_append_edge(ne, tv);
+       /*verify disk cycles*/
+       diskbase = BME_disk_getpointer(ov->edge,ov);
+       edok = BME_cycle_validate(valance1, diskbase);
+       if(!edok) BME_error();
+       diskbase = BME_disk_getpointer(tv->edge,tv);
+       edok = BME_cycle_validate(valance2, diskbase);
+       if(!edok) BME_error();
+       diskbase = BME_disk_getpointer(nv->edge,nv);
+       edok = BME_cycle_validate(2, diskbase);
+       if(!edok) BME_error();
+       
+       /*Split the radial cycle if present*/
+       if(e->loop){
+               BME_Loop *nl,*l;
+               BME_CycleNode *radEBase=NULL, *radNEBase=NULL;
+               int radlen = BME_cycle_length(&(e->loop->radial));
+               /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
+               while(e->loop){
+                       l=e->loop;
+                       l->f->len++;
+                       BME_radial_remove_loop(l,e);
+                       
+                       nl = BME_create_loop(bm,NULL,NULL,l->f,l);
+                       nl->prev = l;
+                       nl->next = l->next;
+                       nl->prev->next = nl;
+                       nl->next->prev = nl;
+                       nl->v = nv;
+                       
+                       /*assign the correct edge to the correct loop*/
+                       if(BME_verts_in_edge(nl->v, nl->next->v, e)){
+                               nl->e = e;
+                               l->e = ne;
+                               
+                               /*append l into ne's rad cycle*/
+                               if(!radNEBase){
+                                       radNEBase = &(l->radial);
+                                       radNEBase->next = NULL;
+                                       radNEBase->prev = NULL;
+                               }
+                               
+                               if(!radEBase){
+                                       radEBase = &(nl->radial);
+                                       radEBase->next = NULL;
+                                       radEBase->prev = NULL;
+                               }
+                               
+                               BME_cycle_append(radEBase,&(nl->radial));
+                               BME_cycle_append(radNEBase,&(l->radial));
+                                       
+                       }
+                       else if(BME_verts_in_edge(nl->v,nl->next->v,ne)){
+                               nl->e = ne;
+                               l->e = e;
+                               
+                               if(!radNEBase){
+                                       radNEBase = &(nl->radial);
+                                       radNEBase->next = NULL;
+                                       radNEBase->prev = NULL;
+                               }
+                               if(!radEBase){
+                                       radEBase = &(l->radial);
+                                       radEBase->next = NULL;
+                                       radEBase->prev = NULL;
+                               }
+                               BME_cycle_append(radEBase,&(l->radial));
+                               BME_cycle_append(radNEBase,&(nl->radial));
+                       }
+                                       
+               }
+               
+               e->loop = radEBase->data;
+               ne->loop = radNEBase->data;
+               
+               /*verify length of radial cycle*/
+               edok = BME_cycle_validate(radlen,&(e->loop->radial));
+               if(!edok) BME_error();
+               edok = BME_cycle_validate(radlen,&(ne->loop->radial));
+               if(!edok) BME_error();
+               
+               /*verify loop->v and loop->next->v pointers for e*/
+               for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){
+                       if(!(l->e == e)) BME_error();
+                       if(!(l->radial.data == l)) BME_error();
+                       if(l->prev->e != ne && l->next->e != ne) BME_error();
+                       edok = BME_verts_in_edge(l->v, l->next->v, e);
+                       if(!edok) BME_error();
+                       if(l->v == l->next->v) BME_error();
+                       if(l->e == l->next->e) BME_error();
+                       /*verify loop cycle for kloop->f*/
+                       edok = BME_cycle_validate(l->f->len, l->f->loopbase);
+                       if(!edok) BME_error();
+               }
+               /*verify loop->v and loop->next->v pointers for ne*/
+               for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){
+                       if(!(l->e == ne)) BME_error();
+                       if(!(l->radial.data == l)) BME_error();
+                       if(l->prev->e != e && l->next->e != e) BME_error();
+                       edok = BME_verts_in_edge(l->v, l->next->v, ne);
+                       if(!edok) BME_error();
+                       if(l->v == l->next->v) BME_error();
+                       if(l->e == l->next->e) BME_error();
+                       /*verify loop cycle for kloop->f. Redundant*/
+                       edok = BME_cycle_validate(l->f->len, l->f->loopbase);
+                       if(!edok) BME_error();
+               }
+       }
+       
+       if(re) *re = ne;
+       return nv;
+}
+
+/**
+ *                     BME_SFME
+ *
+ *     SPLIT FACE MAKE EDGE:
+ *
+ *     Takes as input two vertices in a single face. An edge is created which divides the original face
+ *     into two distinct regions. One of the regions is assigned to the original face and it is closed off.
+ *     The second region has a new face assigned to it.
+ *
+ *     Examples:
+ *     
+ *     Before:               After:
+ *      ----------           ----------
+ *      |                |           |        | 
+ *      |        |           |   f1   |
+ *     v1   f1   v2          v1======v2
+ *      |        |           |   f2   |
+ *      |        |           |        |
+ *      ----------           ---------- 
+ *
+ *     Note that the input vertices can be part of the same edge. This will result in a two edged face.
+ *  This is desirable for advanced construction tools and particularly essential for edge bevel. Because
+ *  of this it is up to the caller to decide what to do with the extra edge.
+ *
+ *     Returns -
+ *  A BME_Poly pointer
+ */
+BME_Poly *BME_SFME(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **rl){
+
+       BME_Poly *f2;
+       BME_Loop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
+       BME_Edge *e;
+       int i, len, f1len, f2len;
+       
+       if(f->holes.first) return BME_exit("SFME returned NULL"); //not good, fix me
+       
+       /*verify that v1 and v2 are in face.*/
+       len = BME_cycle_length(f->loopbase);
+       for(i = 0, curloop = f->loopbase; i < len; i++, curloop = curloop->next){
+               if(curloop->v == v1) v1loop = curloop;
+               else if(curloop->v == v2) v2loop = curloop;
+       }
+       
+       if(!v1loop || !v2loop) return BME_exit("SFME returned NULL");
+       
+       /*allocate new edge between v1 and v2*/
+       e = BME_addedgelist(bm, v1, v2,NULL);
+       BME_disk_append_edge(e, v1);
+       BME_disk_append_edge(e, v2);
+       
+       f2 = BME_addpolylist(bm,f);
+       f1loop = BME_create_loop(bm,v2,e,f,NULL);
+       f2loop = BME_create_loop(bm,v1,e,f2,NULL);
+       
+       f1loop->prev = v2loop->prev;
+       f2loop->prev = v1loop->prev;
+       v2loop->prev->next = f1loop;
+       v1loop->prev->next = f2loop;
+       
+       f1loop->next = v1loop;
+       f2loop->next = v2loop;
+       v1loop->prev = f1loop;
+       v2loop->prev = f2loop;
+       
+       f2->loopbase = f2loop;
+       f->loopbase = f1loop;
+       
+       /*validate both loops*/
+       /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
+       
+       /*go through all of f2's loops and make sure they point to it properly.*/
+       f2len = BME_cycle_length(f2->loopbase);
+       for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next) curloop->f = f2;
+       
+       /*link up the new loops into the new edges radial*/
+       BME_radial_append(e, f1loop);
+       BME_radial_append(e, f2loop);
+       
+       
+       f2->len = f2len;
+       
+       f1len = BME_cycle_length(f->loopbase);
+       f->len = f1len;
+       
+       if(rl) *rl = f2loop;
+       return f2;
+}
+
+
+/**
+ *                     BME_JEKV
+ *
+ *     JOIN EDGE KILL VERT:
+ *     Takes a an edge and pointer to one of its vertices and collapses
+ *     the edge on that vertex.
+ *     
+ *     Before:             OE      KE
+ *                      ------- -------
+ *               |     ||      |
+ *                             OV     KV      TV
+ *
+ *
+ *   After:             OE      
+ *                      ---------------
+ *               |             |
+ *                             OV             TV
+ *
+ *
+ *     Restrictions:
+ *     KV is a vertex that must have a valance of exactly two. Furthermore
+ *  both edges in KV's disk cycle (OE and KE) must be unique (no double
+ *  edges).
+ *
+ *     It should also be noted that this euler has the possibility of creating
+ *     faces with just 2 edges. It is up to the caller to decide what to do with
+ *  these faces.
+ *
+ *  Returns -
+ *     1 for success, 0 for failure.
+ */
+int BME_JEKV(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv)
+{
+       BME_Edge *oe;
+       BME_Vert *ov, *tv;
+       BME_CycleNode *diskbase;
+       BME_Loop *killoop,*nextl;
+       int len,radlen=0, halt = 0, i, valance1, valance2,edok;
+       
+       if(BME_vert_in_edge(ke,kv) == 0) return 0;
+       diskbase = BME_disk_getpointer(kv->edge, kv);
+       len = BME_cycle_length(diskbase);
+       
+       if(len == 2){
+               oe = BME_disk_nextedge(ke, kv);
+               tv = BME_edge_getothervert(ke, kv);
+               ov = BME_edge_getothervert(oe, kv);             
+               halt = BME_verts_in_edge(kv, tv, oe); //check for double edges
+               
+               if(halt) return 0;
+               else{
+                       
+                       /*For verification later, count valance of ov and tv*/
+                       diskbase = BME_disk_getpointer(ov->edge, ov);
+                       valance1 = BME_cycle_length(diskbase);
+                       diskbase = BME_disk_getpointer(tv->edge, tv);
+                       valance2 = BME_cycle_length(diskbase);
+                       
+                       /*remove oe from kv's disk cycle*/
+                       BME_disk_remove_edge(oe,kv);
+                       /*relink oe->kv to be oe->tv*/
+                       BME_edge_swapverts(oe, kv, tv);
+                       /*append oe to tv's disk cycle*/
+                       BME_disk_append_edge(oe, tv);
+                       /*remove ke from tv's disk cycle*/
+                       BME_disk_remove_edge(ke, tv);
+               
+                       /*deal with radial cycle of ke*/
+                       if(ke->loop){
+                               /*first step, fix the neighboring loops of all loops in ke's radial cycle*/
+                               radlen = BME_cycle_length(&(ke->loop->radial));
+                               for(i=0,killoop = ke->loop; i<radlen; i++, killoop = BME_radial_nextloop(killoop)){
+                                       /*relink loops and fix vertex pointer*/
+                                       killoop->next->prev = killoop->prev;
+                                       killoop->prev->next = killoop->next;
+                                       if(killoop->next->v == kv) killoop->next->v = tv;
+                                       
+                                       /*fix len attribute of face*/
+                                       killoop->f->len--;
+                                       if(killoop->f->loopbase == killoop) killoop->f->loopbase = killoop->next;
+                               }
+                               /*second step, remove all the hanging loops attached to ke*/
+                               killoop = ke->loop;
+                               radlen = BME_cycle_length(&(ke->loop->radial));
+                               i=0;
+                               while(i<radlen){
+                                       nextl = killoop->radial.next->data;
+                                       BME_free_loop(bm, killoop);
+                                       killoop = nextl;
+                                       i++;
+                               }       
+                               /*Validate radial cycle of oe*/
+                               edok = BME_cycle_validate(radlen,&(oe->loop->radial));
+                               
+                       }
+                       
+                       /*Validate disk cycles*/
+                       diskbase = BME_disk_getpointer(ov->edge,ov);
+                       edok = BME_cycle_validate(valance1, diskbase);
+                       if(!edok) BME_error();
+                       diskbase = BME_disk_getpointer(tv->edge,tv);
+                       edok = BME_cycle_validate(valance2, diskbase);
+                       if(!edok) BME_error();
+                       
+                       /*Validate loop cycle of all faces attached to oe*/
+                       for(i=0,nextl = oe->loop; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){
+                               edok = BME_cycle_validate(nextl->f->len,nextl->f->loopbase);
+                               if(!edok) BME_error();
+                       }
+                       /*deallocate edge*/
+                       BLI_remlink(&(bm->edges), ke);
+                       BME_free_edge(bm, ke);
+                       /*deallocate vertex*/
+                       BLI_remlink(&(bm->verts), kv);
+                       BME_free_vert(bm, kv);  
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+
+/**
+ *                     BME_loop_reverse
+ *
+ *     FLIP FACE EULER
+ *
+ *     Changes the winding order of a face from CW to CCW or vice versa.
+ *     This euler is a bit peculiar in compairson to others as it is its
+ *     own inverse.
+ *
+ *     TODO: reinsert validation code.
+ *
+ *  Returns -
+ *     1 for success, 0 for failure.
+ */
+
+int BME_loop_reverse(BME_Mesh *bm, BME_Poly *f){
+       BME_Loop *l = f->loopbase, *curloop, *oldprev, *oldnext;
+       BME_Edge **elist;
+       int i, j, edok, len = 0;
+
+       len = BME_cycle_length(l);
+       elist = MEM_callocN(sizeof(BME_Edge *)*len, "BME Loop Reverse edge array");
+       
+       for(i=0, curloop = l; i< len; i++, curloop=curloop->next){
+               BME_radial_remove_loop(curloop, curloop->e);
+               curloop->e->eflag1 = 0;
+               elist[i] = curloop->e;
+       }
+       
+       /*actually reverse the loop. This belongs in BME_cycle_reverse!*/
+       for(i=0, curloop = l; i < len; i++){
+               oldnext = curloop->next;
+               oldprev = curloop->prev;
+               curloop->next = oldprev;
+               curloop->prev = oldnext;
+               curloop = oldnext;
+       }
+
+       if(len == 2){ //two edged face
+               //do some verification here!
+               l->e = elist[1];
+               l->next->e = elist[0];
+       }
+       else{
+               for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
+                       edok = 0;
+                       for(j=0; j < len; j++){
+                               edok = BME_verts_in_edge(curloop->v, curloop->next->v, elist[j]);
+                               if(edok){
+                                       curloop->e = elist[j];
+                                       break;
+                               }
+                       }
+               }
+       }
+       /*rebuild radial*/
+       for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
+               BME_radial_append(curloop->e, curloop);
+               //radok = BME_cycle_validate(curloop->e->tmp.l, &(curloop->radial));
+               //if(!radok || curloop->e->loop == NULL) BME_error();
+       }
+       MEM_freeN(elist);
+       return 1;
+}
+
+/**
+ *                     BME_JFKE
+ *
+ *     JOIN FACE KILL EDGE:
+ *     
+ *     Takes two faces joined by a single 2-manifold edge and fuses them togather.
+ *     The edge shared by the faces must not be connected to any other edges which have
+ *     Both faces in its radial cycle
+ *
+ *     Examples:
+ *     
+ *        A                   B
+ *      ----------           ----------
+ *      |                |           |        | 
+ *      |   f1   |           |   f1   |
+ *     v1========v2 = Ok!    v1==V2==v3 == Wrong!
+ *      |   f2   |           |   f2   |
+ *      |        |           |        |
+ *      ----------           ---------- 
+ *
+ *     In the example A, faces f1 and f2 are joined by a single edge, and the euler can safely be used.
+ *     In example B however, f1 and f2 are joined by multiple edges and will produce an error. The caller
+ *     in this case should call BME_JEKV on the extra edges before attempting to fuse f1 and f2.
+ *
+ *     Also note that the order of arguments decides whether or not certain per-face attributes are present
+ *     in the resultant face. For instance vertex winding, material index, smooth flags, ect are inherited
+ *     from f1, not f2.
+ *
+ *  Returns -
+ *     A BME_Poly pointer
+*/
+
+BME_Poly *BME_JFKE(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e)
+{
+       
+       BME_Loop *curloop, *f1loop=NULL, *f2loop=NULL;
+       int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, valance1,valance2,edok;
+       
+       if(f1->holes.first || f2->holes.first) return BME_exit("JFKE returned NULL"); //dont operate on faces with holes. Not best solution but tolerable.
+       if(f1 == f2) return BME_exit("JFKE returned NULL"); //can't join a face to itself
+       /*verify that e is in both f1 and f2*/
+       f1len = BME_cycle_length(f1->loopbase);
+       f2len = BME_cycle_length(f2->loopbase);
+       for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = curloop->next){
+               if(curloop->e == e){ 
+                       f1loop = curloop;
+                       break;
+               }
+       }
+       for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = curloop->next){
+               if(curloop->e==e){
+                       f2loop = curloop;
+                       break;
+               }
+       }
+       if(!(f1loop && f2loop)) return BME_exit("JFKE returned NULL");
+       
+       /*validate that edge is 2-manifold edge*/
+       radlen = BME_cycle_length(&(f1loop->radial));
+       if(radlen != 2) return BME_exit("JFKE returned NULL");
+
+       /*validate direction of f2's loop cycle is compatible.*/
+       if(f1loop->v == f2loop->v) return BME_exit("JFKE returned NULL");
+       
+       /*
+               Finally validate that for each face, each vertex has another edge in its disk cycle that is 
+               not e, and not shared.
+       */
+       if(BME_radial_find_face(f1loop->next->e,f2)) return BME_exit("JFKE returned NULL");
+       if(BME_radial_find_face(f1loop->prev->e,f2)) return BME_exit("JFKE returned NULL");
+       if(BME_radial_find_face(f2loop->next->e,f1)) return BME_exit("JFKE returned NULL");
+       if(BME_radial_find_face(f2loop->prev->e,f1)) return BME_exit("JFKE returned NULL");
+       
+       /*join the two loops*/
+       f1loop->prev->next = f2loop->next;
+       f2loop->next->prev = f1loop->prev;
+       
+       f1loop->next->prev = f2loop->prev;
+       f2loop->prev->next = f1loop->next;
+       
+       /*if f1loop was baseloop, give f1loop->next the base.*/
+       if(f1->loopbase == f1loop) f1->loopbase = f1loop->next;
+       
+       /*validate the new loop*/
+       loopok = BME_cycle_validate((f1len+f2len)-2, f1->loopbase);
+       if(!loopok) BME_error();
+       
+       /*make sure each loop points to the proper face*/
+       newlen = BME_cycle_length(f1->loopbase);
+       for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = curloop->next) curloop->f = f1;
+       
+       f1->len = newlen;
+       
+       edok = BME_cycle_validate(f1->len, f1->loopbase);
+       if(!edok) BME_error();
+       
+       /*remove edge from the disk cycle of its two vertices.*/
+       BME_disk_remove_edge(f1loop->e, f1loop->e->v1);
+       BME_disk_remove_edge(f1loop->e, f1loop->e->v2);
+       
+       /*deallocate edge and its two loops as well as f2*/
+       BLI_remlink(&(bm->edges), f1loop->e);
+       BLI_remlink(&(bm->polys), f2);
+       BME_free_edge(bm, f1loop->e);
+       BME_free_loop(bm, f1loop);
+       BME_free_loop(bm, f2loop);
+       BME_free_poly(bm, f2);  
+       return f1;
+}
+
+/**
+ *                     BME_MEKL
+ *
+ *     MAKE EDGE KILL LOOP:
+ *     
+ *     Bridges a perphiary loop of a face with an internal loop
+ *
+ *     Examples:
+ *
+ *     ----------------                ----------------
+ *     |      f1      |                |      f1      |
+ *     |     -----    |                |     -----    |
+ *     |     |   |    |                |     |   |    |
+ *     X     X   |    |        X-----X   |    |
+ *     |     |   |    |                |     |   |    |
+ *     |     -----    |                |     -----    |
+ *     |                          |            |                          |
+ *     ----------------                ----------------
+ *
+ *
+ *  Returns -
+ *     A BME_Poly pointer
+ */
+
+/**
+ *                     BME_KEML
+ *
+ *     KILL EDGE MAKE LOOP:
+ *     
+ *     Kills an edge and splits the loose loops off into an internal loop
+ *
+ *     Examples:
+ *
+ *     ----------------                ----------------
+ *     |      f1      |                |      f1      |
+ *     |     -----    |                |     -----    |
+ *     |     |   |    |                |     |   |    |
+ *     X ----X   |    |        X     X   |    |
+ *     |     |   |    |                |     |   |    |
+ *     |     -----    |                |     -----    |
+ *     |                          |            |                          |
+ *     ----------------                ----------------
+ *
+ *     The tool author should take care to realize that although a face may have 
+ *     a hole in its topology, that hole may be filled with one or many other faces.
+ *     Regardless, this does not imply a parent child relationship.
+ *
+ *
+ *  Returns -
+ *     A BME_Poly pointer
+ */
+
diff --git a/source/blender/blenkernel/intern/BME_mesh.c b/source/blender/blenkernel/intern/BME_mesh.c
new file mode 100644 (file)
index 0000000..26aa3e8
--- /dev/null
@@ -0,0 +1,334 @@
+/**
+ * BME_mesh.c    jan 2007
+ *
+ *     BMesh mesh level functions.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_global.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BIF_editmesh.h"
+#include "BIF_space.h"
+#include "editmesh.h"
+#include "bmesh_private.h"
+#include "mydevice.h"
+
+#include "BSE_edit.h"
+
+
+/*     
+ *     BME MAKE MESH
+ *
+ *  Allocates a new BME_Mesh structure
+*/
+
+BME_Mesh *BME_make_mesh(void){
+       BME_Mesh *bm = MEM_callocN(sizeof(BME_Mesh),"BMesh");
+       return bm;
+}
+
+/*     
+ *     BME FREE MESH
+ *
+ *     Frees a BME_Mesh structure.
+*/
+
+void BME_free_mesh(BME_Mesh *bm)
+{
+       BME_Poly *bf, *nextf;
+       BME_Edge *be, *nexte;
+       BME_Vert *bv, *nextv;
+       BME_CycleNode *loopref;
+       int loopcount=0;
+       
+       /*destroy polygon data*/
+       bf = bm->polys.first;
+       while(bf){
+               nextf = bf->next;
+               BLI_remlink(&(bm->polys), bf);
+               if(bf->holes.first)
+                       BLI_freelistN(&(bf->holes));
+               BME_free_poly(bm, bf);
+               
+               bf = nextf;
+       }
+       /*destroy edge data*/
+       be = bm->edges.first;
+       while(be){
+               nexte = be->next;
+               BLI_remlink(&(bm->edges), be);
+               BME_free_edge(bm, be);
+               be = nexte;
+       }
+       /*destroy vert data*/
+       bv = bm->verts.first;
+       while(bv){
+               nextv = bv->next;
+               BLI_remlink(&(bm->verts), bv);
+               BME_free_vert(bm, bv);
+               bv = nextv; 
+       }
+       
+       if (bm->derivedFinal) {
+               bm->derivedFinal->needsFree = 1;
+               bm->derivedFinal->release(bm->derivedFinal);
+       }
+       
+       if (bm->derivedCage && bm->derivedCage != bm->derivedFinal) {
+               bm->derivedCage->needsFree = 1;
+               bm->derivedCage->release(bm->derivedCage);
+       }
+       
+       for(loopref=bm->loops.first;loopref;loopref=loopref->next) BME_delete_loop(bm,loopref->data);
+       BLI_freelistN(&(bm->loops));
+       
+       CustomData_free(&bm->vdata, 0);
+       CustomData_free(&bm->edata, 0);
+       CustomData_free(&bm->ldata, 0);
+       CustomData_free(&bm->pdata, 0);
+       
+       MEM_freeN(bm);  
+}
+
+/*     
+ *     BME COPY MESH
+ *
+ *     Copies a BME_Mesh structure.
+ *
+ *  This is probably more low level than any mesh manipulation routine should be
+ *  and somewhat violates the rule about modifying/creating mesh structures outside
+ *  of the euler API. Regardless, its much more effecient than rebuilding the mesh
+ *  from scratch. 
+*/
+
+BME_Mesh *BME_copy_mesh(BME_Mesh *bm){
+       
+       BME_Vert *v, *cv;
+       BME_Edge *e, *ce;
+       BME_Poly *f, *cf;
+       BME_Loop *l, *cl;
+       BME_Mesh *meshcopy;
+       meshcopy = BME_make_mesh();
+       
+
+       return meshcopy;
+}
+
+/*     
+ *     BME MODEL BEGIN AND END
+ *
+ *     These two functions represent the 'point of entry' for tools. Every BMesh tool
+ *     must begin with a call to BME_model_end() and finish with a call to BME_model_end().
+ *     No modification of mesh data is allowed except in between these two calls.
+ *
+ *     TODO 
+ *             FOR BME_MODEL_BEGIN:
+ *             -integrate euler undo system.
+ *             -make full copy of structure to safely recover from errors.
+ *             -accept a toolname string.
+ *             -accept param to turn off full copy if just selection tool. (perhaps check for this in eulers...)
+ *
+ *             BME_MODEL_END:
+ *             -full mesh validation if debugging turned on
+ *             -free structure copy or use it to restore.
+ *             -do euler undo push.
+ *
+*/
+
+int BME_model_begin(BME_Mesh *bm){
+       if(bm->lock) return 0;
+       bm->lock = 1;
+       bm->backup = BME_copy_mesh(bm);
+       return 1;
+}
+
+void BME_model_end(BME_Mesh *bm){
+       BME_Mesh *badmesh;
+       int meshok,backupok, totvert, totedge, totpoly, totloop;
+
+       totvert = BLI_countlist(&(bm->verts));
+       totedge = BLI_countlist(&(bm->edges));
+       totpoly = BLI_countlist(&(bm->polys));
+       totloop = BLI_countlist(&(bm->loops));
+       
+       if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totpoly!=totpoly || bm->totloop!=totloop)
+               BME_error();
+       
+       meshok = BME_validate_mesh(bm, 1);
+       if(!meshok){
+               printf("Warning, Mesh failed validation, restoring from backup");
+               badmesh = bm;
+               bm= badmesh->backup;
+               bm->backup = badmesh;
+               backupok = BME_validate_mesh(bm,1);
+               if(!backupok) printf("Backup corrupted too, Briggs did something stupid!");
+       }
+       BME_free_mesh(bm->backup);
+       bm->lock = 0;
+}
+
+
+/*     
+ *     BME VALIDATE MESH
+ *
+ *     There are several levels of validation for meshes. At the 
+ *  Euler level, some basic validation is done to local topology.
+ *  To catch more subtle problems however, BME_validate_mesh() is 
+ *  called by BME_model_end() whenever a tool is done executing.
+ *  The purpose of this function is to insure that during the course 
+ *  of tool execution that nothing has been done to invalidate the 
+ *  structure, and if it has, provide a way of reporting that so that
+ *  we can restore the proper structure from a backup. Since a full mesh
+ *  validation would be too expensive, this is presented as a compromise.
+ *
+ *     TODO 
+ *     
+ *     -Add validation for hole loops (which are experimental anyway)
+ *     -Write a full mesh validation function for debugging purposes.
+ */
+
+#define VHALT(halt) {BME_error(); if(halt) return 0;}
+
+int BME_validate_mesh(struct BME_Mesh *bm, int halt)
+{
+       BME_Vert *v;
+       BME_Edge *e;
+       BME_Poly *f;
+       BME_Loop *l;
+       BME_CycleNode *diskbase;
+       int i, ok;
+       
+       /*Simple edge verification*/
+       for(e=bm->edges.first; e; e=e->next){
+               if(e->v1 == e->v2) VHALT(halt);
+               /*validate e->d1.data and e->d2.data*/
+               if(e->d1.data != e || e->d2.data != e) VHALT(halt);
+               /*validate e->loop->e*/
+               if(e->loop){
+                       if(e->loop->e != e) VHALT(halt);
+               }
+       }
+       
+       /*calculate disk cycle lengths*/
+       for(v=bm->verts.first; v; v=v->next) v->tflag1 = v->tflag2 = 0;
+       for(e=bm->edges.first; e; e=e->next){ 
+               e->v1->tflag1++;
+               e->v2->tflag1++;
+       }
+       /*Validate vertices and disk cycle*/
+       for(v=bm->verts.first; v; v=v->next){
+               /*validate v->edge pointer*/
+               if(v->tflag1){
+                       if(v->edge){
+                               ok = BME_vert_in_edge(v->edge,v);
+                               if(!ok) VHALT(halt);
+                               /*validate length of disk cycle*/
+                               diskbase = BME_disk_getpointer(v->edge, v);
+                               ok = BME_cycle_validate(v->tflag1, diskbase);
+                               if(!ok) VHALT(halt);
+                               /*validate that each edge in disk cycle contains V*/
+                               for(i=0, e=v->edge; i < v->tflag1; i++, e = BME_disk_nextedge(e,v)){
+                                       ok = BME_vert_in_edge(e, v);
+                                       if(!ok) VHALT(halt);
+                               }
+                       }
+                       else VHALT(halt);
+               }
+       }
+       /*validate edges*/
+       for(e=bm->edges.first; e; e=e->next){
+               /*seperate these into BME_disk_hasedge (takes pointer to edge)*/
+               /*search v1 disk cycle for edge*/
+               ok = BME_disk_hasedge(e->v1,e);
+               if(!ok) VHALT(halt);
+               /*search v2 disk cycle for edge*/
+               ok = BME_disk_hasedge(e->v2,e);
+               if(!ok) VHALT(halt);
+       }
+       
+       for(e=bm->edges.first; e; e=e->next) e->tflag2 = 0; //store incident faces
+       /*Validate the loop cycle integrity.*/
+       for(f=bm->polys.first; f; f=f->next){
+               ok = BME_cycle_length(f->loopbase);
+               if(ok > 1){
+                       f->tflag1 = ok;
+               }
+               else VHALT(halt);
+               for(i=0, l=f->loopbase; i < f->tflag1; i++, l=l->next){
+                       /*verify loop->v pointers*/
+                       ok = BME_verts_in_edge(l->v, l->next->v, l->e);
+                       if(!ok) VHALT(halt);
+                       /*verify radial node data pointer*/
+                       if(l->radial.data != l) VHALT(halt);
+                       /*validate l->e->loop poitner*/
+                       if(l->e->loop == NULL) VHALT(halt);
+                       /*validate l->f pointer*/
+                       if(l->f != f) VHALT(halt);
+                       /*see if l->e->loop is actually in radial cycle*/
+                       
+                       l->e->tflag2++;
+                }
+       }
+       
+       /*validate length of radial cycle*/
+       for(e=bm->edges.first; e; e=e->next){
+               if(e->loop){
+                       ok = BME_cycle_validate(e->tflag2,&(e->loop->radial));
+                       if(!ok) VHALT(halt);
+               }
+       }
+       
+       /*if we get this far, pretty safe to return 1*/
+       return 1;
+}
+
+/*     Currently just a convient place for a breakpoint.
+       Probably should take an error string
+*/
+void BME_error(void){
+       printf("BME modelling error!");
+}
diff --git a/source/blender/blenkernel/intern/BME_structure.c b/source/blender/blenkernel/intern/BME_structure.c
new file mode 100644 (file)
index 0000000..17f91c1
--- /dev/null
@@ -0,0 +1,618 @@
+/**
+ * BME_structure.c    jan 2007
+ *
+ *     Low level routines for manipulating the BMesh structure.
+ *
+ * $Id: BME_structure.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <limits.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_ghash.h"
+
+#include "BKE_customdata.h"
+/**
+ *     MISC utility functions.
+ *
+ */
+int BME_vert_in_edge(BME_Edge *e, BME_Vert *v){
+       if(e->v1 == v || e->v2 == v) return 1;
+       return 0;
+}
+int BME_verts_in_edge(BME_Vert *v1, BME_Vert *v2, BME_Edge *e){
+       if(e->v1 == v1 && e->v2 == v2) return 1;
+       else if(e->v1 == v2 && e->v2 == v1) return 1;
+       return 0;
+}
+
+BME_Vert *BME_edge_getothervert(BME_Edge *e, BME_Vert *v){
+       if(e->v1 == v) return e->v2;
+       else if(e->v2 == v) return e->v1;
+       return NULL;
+}
+
+int BME_edge_swapverts(BME_Edge *e, BME_Vert *orig, BME_Vert *new){
+       if(e->v1 == orig){ 
+               e->v1 = new;
+               e->d1.next = NULL;
+               e->d1.prev = NULL;
+               return 1;
+       }
+       else if(e->v2 == orig){
+               e->v2 = new;
+               e->d2.next = NULL;
+               e->d2.prev = NULL;
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ *     ALLOCATION/DEALLOCATION FUNCTIONS
+ */
+
+BME_Vert *BME_addvertlist(BME_Mesh *bm, BME_Vert *example){
+       BME_Vert *v=NULL;
+       v = MEM_callocN(sizeof(BME_Vert), "BME Vertex");
+       BLI_addtail(&(bm->verts), v);
+       v->EID = bm->nextv;
+       bm->nextv++;
+       bm->totvert++;
+
+       if(example)
+               VECCOPY(v->co,example->co);
+       if(example)
+               CustomData_em_copy_data(&bm->vdata, &bm->vdata, example->data, &v->data);
+       else
+               CustomData_em_set_default(&bm->vdata, &v->data);
+
+       return v;
+}
+BME_Edge *BME_addedgelist(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Edge *example){
+       BME_Edge *e=NULL;
+       e = MEM_callocN(sizeof(BME_Edge), "BME_Edge");
+       e->v1 = v1;
+       e->v2 = v2;
+       e->d1.data = e;
+       e->d2.data = e;
+       e->EID = bm->nexte;
+       bm->nexte++;
+       bm->totedge++;
+       BLI_addtail(&(bm->edges), e);
+       
+       if(example)
+               CustomData_em_copy_data(&bm->edata, &bm->edata, example->data, &e->data);
+       else
+               CustomData_em_set_default(&bm->edata, &e->data);
+
+
+       return e;
+}
+BME_Loop *BME_create_loop(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Poly *f, BME_Loop *example){
+       /*allocate a BME_Loop and add it to the loophash*/
+       BME_Loop *l=NULL;
+       BME_CycleNode *loopnode = MEM_callocN(sizeof(BME_CycleNode),"BME Loop Reference");
+       l = MEM_callocN(sizeof(BME_Loop), "BME_Loop");
+       l->radial.data = l;
+       l->v = v;
+       l->e = e;
+       l->f = f;
+       l->EID = bm->nextl;
+       l->gref = loopnode;
+       loopnode->data = l;
+       BLI_addtail(&(bm->loops),loopnode);
+       bm->nextl++;
+       bm->totloop++;
+       
+
+/*     if(example)
+               BME_CustomData_copy_data(&bm->ldata, &bm->ldata, example->data, &l->data);
+       else
+               BME_CustomData_set_default(&bm->ldata, &l->data);
+*/
+       return l;
+}
+
+BME_Poly *BME_addpolylist(BME_Mesh *bm, BME_Poly *example){
+       BME_Poly *f = NULL;
+       f= MEM_callocN(sizeof(BME_Poly),"BME_Poly");
+       BLI_addtail(&(bm->polys),f);
+       f->EID = bm->nextp;
+       bm->nextp++;
+       bm->totpoly++;
+
+       if(example)
+               CustomData_em_copy_data(&bm->pdata, &bm->pdata, example->data, &f->data);
+       else
+               CustomData_em_set_default(&bm->pdata, &f->data);
+
+
+       return f;
+}
+
+/*     free functions dont do much *yet*. When per-vertex, per-edge and per-face/faceloop
+       data is added though these will be needed.
+*/
+void BME_free_vert(BME_Mesh *bm, BME_Vert *v){
+       bm->totvert--;
+       CustomData_em_free_block(&bm->vdata, &v->data);
+       MEM_freeN(v);
+}
+void BME_free_edge(BME_Mesh *bm, BME_Edge *e){
+       bm->totedge--;
+       CustomData_em_free_block(&bm->edata, &e->data);
+       MEM_freeN(e);
+}
+void BME_free_poly(BME_Mesh *bm, BME_Poly *f){
+       bm->totpoly--;
+       CustomData_em_free_block(&bm->pdata, &f->data);
+       MEM_freeN(f);
+}
+void BME_delete_loop(BME_Mesh *bm, BME_Loop *l){
+       bm->totloop--;
+       CustomData_em_free_block(&bm->ldata, &l->data);
+       MEM_freeN(l);
+}
+void BME_free_loop(BME_Mesh *bm, BME_Loop *l){
+       BME_CycleNode *loopref = l->gref;
+       BLI_freelinkN(&(bm->loops),loopref);
+       BME_delete_loop(bm,l);
+}
+
+
+/**
+ *     BMESH CYCLES
+ *
+ *     Cycles are circular doubly linked lists that form the basis of adjacency
+ *     information in the BME modeller. Full adjacency relations can be derived
+ *     from examining these cycles very quickly. Although each cycle is a double
+ *  circular linked list, each one is considered to have a 'base' or 'head',
+ *     and care must be taken by Euler code when modifying the contents of a cycle.
+ *
+ *     The contents of this file are split into two parts. First there are the 
+ *     BME_cycle family of functions which are generic circular double linked list 
+ *     procedures. The second part contains higher level procedures for supporting 
+ *     modification of specific cycle types.
+ *
+ *     The three cycles explicitly stored in the BMesh data structure are as follows:
+ *
+ *     1: The Disk Cycle - A circle of edges around a vertex
+ *     Base: vertex->edge pointer.
+ *        
+ *     This cycle is the most complicated in terms of its structure. Each BME_Edge contains    
+ *        two BME_CycleNode structures to keep track of that edge's membership in the disk cycle
+ *        of each of its vertices. However for any given vertex it may be the first in some edges
+ *        in its disk cycle and the second for others. The BME_disk_XXX family of functions contain
+ *        some nice utilities for navigating disk cycles in a way that hides this detail from the 
+ *        tool writer.
+ *
+ *             Note that the disk cycle is completley independant from face data. One advantage of this
+ *             is that wire edges are fully integrated into the topology database. Another is that the 
+ *         the disk cycle has no problems dealing with non-manifold conditions involving faces.
+ *
+ *             Functions relating to this cycle:
+ *             
+ *                     BME_disk_append_edge
+ *                     BME_disk_remove_edge
+ *                     BME_disk_nextedge
+ *                     BME_disk_getpointer
+ *
+ *     2: The Radial Cycle - A circle of face edges (BME_Loop) around an edge
+ *        Base: edge->loop->radial structure.
+ *
+ *             The radial cycle is similar to the radial cycle in the radial edge data structure.*
+ *             Unlike the radial edge however, the radial cycle does not require a large amount of memory 
+ *             to store non-manifold conditions since BMesh does not keep track of region/shell
+ *             information.
+ *             
+ *             Functions relating to this cycle:
+ *                     
+ *                     BME_radial_append
+ *                     BME_radial_remove_loop
+ *                     BME_radial_nextloop
+ *                     BME_radial_find_face
+ *             
+ *
+ *     3: The Loop Cycle - A circle of face edges around a polygon.
+ *     Base: polygon->loopbase.
+ *
+ *        The loop cycle keeps track of a faces vertices and edges. It should be noted that the
+ *     direction of a loop cycle is either CW or CCW depending on the face normal, and is 
+ *     not oriented to the faces editedges. 
+ *
+ *             Functions relating to this cycle:
+ *             
+ *                     BME_cycle_XXX family of functions.
+ *
+ *     
+ *     Note that the order of elements in all cycles except the loop cycle is undefined. This 
+ *  leads to slightly increased seek time for deriving some adjacency relations, however the 
+ *  advantage is that no intrinsic properties of the data structures are dependant upon the 
+ *  cycle order and all non-manifold conditions are represented trivially.
+ *
+*/
+void BME_cycle_append(void *h, void *nt)
+{
+       BME_CycleNode *oldtail, *head, *newtail;
+       
+       head = (BME_CycleNode*)h;
+       newtail = (BME_CycleNode*)nt;
+       
+       if(head->next == NULL){
+               head->next = newtail;
+               head->prev = newtail;
+               newtail->next = head;
+               newtail->prev = head;
+       }
+       else{
+               oldtail = head->prev;
+               oldtail->next = newtail;
+               newtail->next = head;
+               newtail->prev = oldtail;
+               head->prev = newtail;
+               
+       }
+}
+
+/**
+ *                     BME_cycle_length
+ *
+ *     Count the nodes in a cycle.
+ *
+ *  Returns -
+ *     Integer
+ */
+
+int BME_cycle_length(void *h){
+       
+       int len = 0;
+       BME_CycleNode *head, *curnode;
+       head = (BME_CycleNode*)h;
+       
+       if(head){ 
+               len = 1;
+               for(curnode = head->next; curnode != head; curnode=curnode->next){ 
+                       if(len == INT_MAX){ //check for infinite loop/corrupted cycle
+                                       return -1;
+                       }
+                       len++;
+               }
+       }
+       return len;
+}
+
+
+/**
+ *                     BME_cycle_remove
+ *
+ *     Removes a node from a cycle.
+ *
+ *  Returns -
+ *     1 for success, 0 for failure.
+ */
+
+int BME_cycle_remove(void *h, void *remn)
+{
+       int i, len;
+       BME_CycleNode *head, *remnode, *curnode;
+       
+       head = (BME_CycleNode*)h;
+       remnode = (BME_CycleNode*)remn;
+       len = BME_cycle_length(h);
+       
+       if(len == 1 && head == remnode){
+               head->next = NULL;
+               head->prev = NULL;
+               return 1;
+       }
+       else{
+               for(i=0, curnode = head; i < len; curnode = curnode->next){
+                       if(curnode == remnode){
+                               remnode->prev->next = remnode->next;
+                               remnode->next->prev = remnode->prev;
+                               /*zero out remnode pointers, important!*/
+                               //remnode->next = NULL;
+                               //remnode->prev = NULL;
+                               return 1;
+               
+                       }
+               }
+       }
+       return 0;
+}
+
+/**
+ *                     BME_cycle_validate
+ *
+ *     Validates a cycle. Takes as an argument the expected length of the cycle and
+ *     a pointer to the cycle head or base.
+ *
+ *
+ *  Returns -
+ *     1 for success, 0 for failure.
+ */
+
+int BME_cycle_validate(int len, void *h){
+       int i;
+       BME_CycleNode *curnode, *head;
+       head = (BME_CycleNode*)h;
+       
+       /*forward validation*/
+       for(i = 0, curnode = head; i < len; i++, curnode = curnode->next);
+       if(curnode != head) return 0;
+       
+       /*reverse validation*/
+       for(i = 0, curnode = head; i < len; i++, curnode = curnode->prev);
+       if(curnode != head) return 0;
+       
+       return 1;
+}
+
+/*Begin Disk Cycle routines*/
+
+/**
+ *                     BME_disk_nextedge
+ *
+ *     Find the next edge in a disk cycle
+ *
+ *  Returns -
+ *     Pointer to the next edge in the disk cycle for the vertex v.
+ */
+BME_Edge *BME_disk_nextedge(BME_Edge *e, BME_Vert *v)
+{      
+       if(BME_vert_in_edge(e, v)){
+               if(e->v1 == v) return e->d1.next->data;
+               else if(e->v2 == v) return e->d2.next->data;
+       }
+       return NULL;
+}
+
+/**
+ *                     BME_disk_getpointer
+ *
+ *     Given an edge and one of its vertices, find the apporpriate CycleNode
+ *
+ *  Returns -
+ *     Pointer to BME_CycleNode.
+ */
+BME_CycleNode *BME_disk_getpointer(BME_Edge *e, BME_Vert *v){
+       /*returns pointer to the cycle node for the appropriate vertex in this disk*/
+       if(e->v1 == v) return &(e->d1);
+       else if (e->v2 == v) return &(e->d2);
+       return NULL;
+}
+
+/**
+ *                     BME_disk_append_edge
+ *
+ *     Appends edge to the end of a vertex disk cycle.
+ *
+ *  Returns -
+ *     1 for success, 0 for failure
+ */
+
+int BME_disk_append_edge(BME_Edge *e, BME_Vert *v)
+{ 
+       
+       BME_CycleNode *base, *tail;
+       
+       if(BME_vert_in_edge(e, v) == 0) return 0; /*check to make sure v is in e*/
+       
+       /*check for loose vert first*/
+       if(v->edge == NULL){
+               v->edge = e;
+               base = tail = BME_disk_getpointer(e, v);
+               BME_cycle_append(base, tail); /*circular reference is ok!*/
+               return 1;
+       }
+       
+       /*insert e at the end of disk cycle and make it the new v->edge*/
+       base = BME_disk_getpointer(v->edge, v);
+       tail = BME_disk_getpointer(e, v);
+       BME_cycle_append(base, tail);
+       return 1;
+}
+
+/**
+ *                     BME_disk_remove_edge
+ *
+ *     Removes an edge from a disk cycle. If the edge to be removed is
+ *     at the base of the cycle, the next edge becomes the new base.
+ *
+ *
+ *  Returns -
+ *     Nothing
+ */
+
+void BME_disk_remove_edge(BME_Edge *e, BME_Vert *v)
+{
+       BME_CycleNode *base, *remnode;
+       BME_Edge *newbase;
+       int len;
+       
+       base = BME_disk_getpointer(v->edge, v);
+       remnode = BME_disk_getpointer(e, v);
+       
+       /*first deal with v->edge pointer...*/
+       len = BME_cycle_length(base);
+       if(len == 1) newbase = NULL;
+       else if(v->edge == e) newbase = base->next-> data;
+       else newbase = v->edge;
+       
+       /*remove and rebase*/
+       BME_cycle_remove(base, remnode);
+       v->edge = newbase;
+}
+
+/**
+ *                     BME_disk_next_edgeflag
+ *
+ *     Searches the disk cycle of v, starting with e, for the 
+ *  next edge that has either eflag or tflag.
+ *
+ *     BME_Edge pointer.
+ */
+
+BME_Edge *BME_disk_next_edgeflag(BME_Edge *e, BME_Vert *v, int eflag, int tflag){
+       
+       BME_CycleNode *diskbase;
+       BME_Edge *curedge;
+       int len, ok;
+       
+       if(eflag && tflag) return NULL;
+       
+       ok = BME_vert_in_edge(e,v);
+       if(ok){
+               diskbase = BME_disk_getpointer(e, v);
+               len = BME_cycle_length(diskbase);
+               curedge = BME_disk_nextedge(e,v);
+               while(curedge != e){
+                       if(tflag){
+                               if(curedge->tflag1 == tflag) return curedge;
+                       }
+                       else if(eflag){
+                               if(curedge->eflag1 == eflag) return curedge;
+                       }
+                       curedge = BME_disk_nextedge(curedge, v);
+               }
+       }
+       return NULL;
+}
+
+/**
+ *                     BME_disk_count_edgeflag
+ *
+ *     Counts number of edges in this verts disk cycle which have 
+ *     either eflag or tflag (but not both!)
+ *
+ *  Returns -
+ *     Integer.
+ */
+
+int BME_disk_count_edgeflag(BME_Vert *v, int eflag, int tflag){
+       BME_CycleNode *diskbase;
+       BME_Edge *curedge;
+       int i, len=0, count=0;
+       
+       if(v->edge){
+               if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/
+               diskbase = BME_disk_getpointer(v->edge, v);
+               len = BME_cycle_length(diskbase);
+               
+               for(i = 0, curedge=v->edge; i<len; i++){
+                       if(tflag){
+                               if(curedge->tflag1 == tflag) count++;
+                       }
+                       else if(eflag){
+                               if(curedge->eflag1 == eflag) count++;
+                       }
+                       curedge = BME_disk_nextedge(curedge, v);
+               }
+       }
+       return count;
+}
+
+int BME_disk_hasedge(BME_Vert *v, BME_Edge *e){
+       BME_CycleNode *diskbase;
+       BME_Edge *curedge;
+       int i, len=0;
+       
+       if(v->edge){
+               diskbase = BME_disk_getpointer(v->edge,v);
+               len = BME_cycle_length(diskbase);
+               
+               for(i = 0, curedge=v->edge; i<len; i++){
+                       if(curedge == e) return 1;
+                       else curedge=BME_disk_nextedge(curedge, v);
+               }
+       }
+       return 0;
+}
+/*end disk cycle routines*/
+
+BME_Loop *BME_radial_nextloop(BME_Loop *l){
+       return (BME_Loop*)(l->radial.next->data);
+}
+
+void BME_radial_append(BME_Edge *e, BME_Loop *l){
+       if(e->loop == NULL) e->loop = l;
+       BME_cycle_append(&(e->loop->radial), &(l->radial));
+}
+
+void BME_radial_remove_loop(BME_Loop *l, BME_Edge *e)
+{
+       BME_Loop *newbase;
+       int len;
+       
+       /*deal with edge->loop pointer*/
+       len = BME_cycle_length(&(e->loop->radial));
+       if(len == 1) newbase = NULL;
+       else if(e->loop == l) newbase = e->loop->radial.next->data;
+       else newbase = e->loop;
+       
+       /*remove and rebase*/
+       BME_cycle_remove(&(e->loop->radial), &(l->radial));
+       e->loop = newbase;
+}
+
+int BME_radial_find_face(BME_Edge *e,BME_Poly *f)
+{
+               
+       BME_Loop *curloop;
+       int i, len;
+       
+       len = BME_cycle_length(&(e->loop->radial));
+       for(i = 0, curloop = e->loop; i < len; i++, curloop = curloop->radial.next->data){
+               if(curloop->f == f) return 1;
+       }
+       return 0;
+}
+
+struct BME_Loop *BME_loop_find_loop(struct BME_Poly *f, struct BME_Vert *v) {
+       BME_Loop *l;
+       int i, len;
+       
+       len = BME_cycle_length(f->loopbase);
+       for (i = 0, l=f->loopbase; i < len; i++, l=l->next) {
+               if (l->v == v) return l;
+       }
+       return NULL;
+}
diff --git a/source/blender/blenkernel/intern/BME_tools.c b/source/blender/blenkernel/intern/BME_tools.c
new file mode 100644 (file)
index 0000000..441a8f5
--- /dev/null
@@ -0,0 +1,1326 @@
+/**
+ * BME_tools.c    jan 2007
+ *
+ *     Functions for changing the topology of a mesh.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle and Levi Schooley.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "blendef.h"
+
+/**
+ *                     BME_dissolve_edge
+ *
+ *     Edge Dissolve Function:
+ *
+ *     Dissolves a 2-manifold edge by joining it's two faces. if
+ *     they have opposite windings it first makes them consistent
+ *     by calling BME_loop_reverse()
+ *
+ *     Returns -
+*/
+
+/**
+ *                     BME_inset_edge
+ *
+ *     Edge Inset Function:
+ *
+ *     Splits a face in two along an edge and returns the next loop
+ *
+ *     Returns -
+ *     A BME_Poly pointer.
+ */
+
+BME_Loop *BME_inset_edge(BME_Mesh *bm, BME_Loop *l, BME_Poly *f){
+       BME_Loop *nloop;
+       BME_SFME(bm, f, l->v, l->next->v, &nloop);
+       return nloop->next;
+}
+
+/**
+ *                     BME_inset_poly
+ *
+ *     Face Inset Tool:
+ *
+ *     Insets a single face and returns a pointer to the face at the
+ *     center of the newly created region
+ *
+ *     Returns -
+ *     A BME_Poly pointer.
+ */
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+BME_Poly *BME_inset_poly(BME_Mesh *bm,BME_Poly *f){
+
+       BME_Vert *v;
+       BME_Loop *l,*nextloop, *killoop, *sloop;
+
+       int len,i;
+       float max[3],min[3],cent[3]; //center of original face
+
+       /*get bounding box for face*/
+       VECCOPY(max,f->loopbase->v->co);
+       VECCOPY(min,f->loopbase->v->co);
+       len = f->len;
+       for(i=0,l=f->loopbase;i<len;i++,l=l->next){
+               max[0] = MAX(max[0],l->v->co[0]);
+               max[1] = MAX(max[1],l->v->co[1]);
+               max[2] = MAX(max[2],l->v->co[2]);
+
+               min[0] = MIN(min[0],l->v->co[0]);
+               min[1] = MIN(min[1],l->v->co[1]);
+               min[2] = MIN(min[2],l->v->co[2]);
+       }
+
+       cent[0] = (min[0] + max[0]) / 2.0f;
+       cent[1] = (min[1] + max[1]) / 2.0f;
+       cent[2] = (min[2] + max[2]) / 2.0f;
+
+       /*inset each edge in the polygon.*/
+       len = f->len;
+       for(i=0,l=f->loopbase; i < len; i++){
+               nextloop = l->next;
+               f = BME_SFME(bm,l->f,l->v,l->next->v,NULL);
+               l=nextloop;
+       }
+
+       /*for each new edge, call SEMV on it*/
+       for(i=0,l=f->loopbase; i < len; i++, l=l->next){
+               l->tflag1 = 1; //going to store info that this loops edge still needs split
+               f = BME_SFME(bm,l->f,l->v,l->next->v,NULL);
+               l->tflag2 = l->v->tflag1 = l->v->tflag2 = 0;
+       }
+
+       len = f->len;
+       for(i=0,l=f->loopbase; i < len; i++){
+               if(l->tflag1){
+                       l->tflag1 = 0;
+                       v= BME_SEMV(bm,l->next->v,l->e,NULL);
+                       VECCOPY(v->co,l->v->co);
+                       v->tflag1 = 1;
+                       l = l->next->next;
+               }
+       }
+
+       len = f->len;
+       sloop = NULL;
+       for(i=0,l=f->loopbase; i < len; i++,l=l->next){
+               if(l->v->tflag1 && l->next->next->v->tflag1){
+                       sloop = l;
+                       break;
+               }
+       }
+       if(sloop){
+               for(i=0,l=sloop; i < len; i++){
+                       nextloop = l->next->next;
+                       f = BME_SFME(bm,f,l->v,l->next->next->v,&killoop);
+                       i+=1; //i+=2;
+                       BME_JFKE(bm,l->f,((BME_Loop*)l->radial.next->data)->f,l->e);
+                       l=nextloop;
+               }
+       }
+
+       len = f->len;
+       for(i=0,l=f->loopbase; i < len; i++,l=l->next){
+               l->v->co[0] = (l->v->co[0] + cent[0]) / 2.0f;
+               l->v->co[1] = (l->v->co[1] + cent[1]) / 2.0f;
+               l->v->co[2] = (l->v->co[2] + cent[2]) / 2.0f;
+       }
+       return NULL;
+}
+
+/* ------- Bevel code starts here -------- */
+
+BME_TransData_Head *BME_init_transdata(int bufsize) {
+       BME_TransData_Head *td;
+
+       td = MEM_callocN(sizeof(BME_TransData_Head), "BMesh transdata header");
+       td->gh = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp);
+       td->ma = BLI_memarena_new(bufsize);
+       BLI_memarena_use_calloc(td->ma);
+
+       return td;
+}
+
+void BME_free_transdata(BME_TransData_Head *td) {
+       BLI_ghash_free(td->gh,NULL,NULL);
+       BLI_memarena_free(td->ma);
+       MEM_freeN(td);
+}
+
+BME_TransData *BME_assign_transdata(BME_TransData_Head *td, BME_Mesh *bm, BME_Vert *v,
+               float *co, float *org, float *vec, float *loc,
+               float factor, float weight, float maxfactor, float *max) {
+       BME_TransData *vtd;
+       int is_new = 0;
+
+       if (v == NULL) return NULL;
+
+       if ((vtd = BLI_ghash_lookup(td->gh, v)) == NULL && bm != NULL) {
+               vtd = BLI_memarena_alloc(td->ma, sizeof(*vtd));
+               BLI_ghash_insert(td->gh, v, vtd);
+               td->len++;
+               is_new = 1;
+       }
+
+       vtd->bm = bm;
+       vtd->v = v;
+       if (co != NULL) VECCOPY(vtd->co,co);
+       if (org == NULL && is_new) { VECCOPY(vtd->org,v->co); } /* default */
+       else if (org != NULL) VECCOPY(vtd->org,org);
+       if (vec != NULL) {
+               VECCOPY(vtd->vec,vec);
+               Normalize(vtd->vec);
+       }
+       vtd->loc = loc;
+
+       vtd->factor = factor;
+       vtd->weight = weight;
+       vtd->maxfactor = maxfactor;
+       vtd->max = max;
+
+       return vtd;
+}
+
+BME_TransData *BME_get_transdata(BME_TransData_Head *td, BME_Vert *v) {
+       BME_TransData *vtd;
+       vtd = BLI_ghash_lookup(td->gh, v);
+       return vtd;
+}
+
+/* a hack (?) to use the transdata memarena to allocate floats for use with the max limits */
+float *BME_new_transdata_float(BME_TransData_Head *td) {
+       return BLI_memarena_alloc(td->ma, sizeof(float));
+}
+
+int BME_is_nonmanifold_vert(BME_Mesh *bm, BME_Vert *v) {
+       BME_Edge *e, *oe;
+       BME_Loop *l;
+       int len, count, flag;
+
+       if (v->edge == NULL) {
+               /* loose vert */
+               return 1;
+       }
+
+       /* count edges while looking for non-manifold edges */
+       oe = v->edge;
+       for (len=0,e=v->edge; e != oe || (e == oe && len == 0); len++,e=BME_disk_nextedge(e,v)) {
+               if (e->loop == NULL) {
+                       /* loose edge */
+                       return 1;
+               }
+
+               if (BME_cycle_length(&(e->loop->radial)) > 2) {
+                       /* edge shared by more than two faces */
+                       return 1;
+               }
+       }
+
+       count = 1;
+       flag = 1;
+       e = NULL;
+       oe = v->edge;
+       l = oe->loop;
+       while(e != oe) {
+               if (l->v == v) l = l->prev;
+               else l = l->next;
+               e = l->e;
+               count++; /* count the edges */
+
+               if (flag && l->radial.next->data == l) {
+                       /* we've hit the edge of an open mesh, reset once */
+                       flag = 0;
+                       count = 1;
+                       oe = e;
+                       e = NULL;
+                       l = oe->loop;
+               }
+               else if (l->radial.next->data == l) {
+                       /* break the loop */
+                       e = oe;
+               }
+               else {
+                       l = l->radial.next->data;
+               }
+       }
+
+       if (count < len) {
+               /* vert shared by multiple regions */
+               return 1;
+       }
+
+       return 0;
+}
+
+/* a wrapper for BME_JFKE that [for now just] checks to
+ * make sure loop directions are compatible */
+BME_Poly *BME_JFKE_safe(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e) {
+       BME_Loop *l1, *l2;
+
+       l1 = e->loop;
+       l2 = l1->radial.next->data;
+       if (l1->v == l2->v) {
+               BME_loop_reverse(bm, f2);
+       }
+
+       return BME_JFKE(bm, f1, f2, e);
+}
+
+/* a wrapper for BME_SFME that transfers element flags */
+BME_Poly *BME_split_face(BME_Mesh *bm, BME_Poly *f, BME_Vert *v1, BME_Vert *v2, BME_Loop **nl, BME_Edge *example) {
+       BME_Poly *nf;
+       nf = BME_SFME(bm,f,v1,v2,nl);
+       nf->flag = f->flag;
+       /* if the edge was selected, select this face, too */
+       if (example->flag & SELECT) f->flag |= ME_FACE_SEL;
+       nf->h = f->h;
+       nf->mat_nr = f->mat_nr;
+       if (nl && example) {
+               (*nl)->e->flag = example->flag;
+               (*nl)->e->h = example->h;
+               (*nl)->e->crease = example->crease;
+               (*nl)->e->bweight = example->bweight;
+       }
+
+       return nf;
+}
+
+/* a wrapper for BME_SEMV that transfers element flags */
+BME_Vert *BME_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Edge **ne, float percent) {
+       BME_Vert *nv, *v2;
+       float len;
+
+       v2 = BME_edge_getothervert(e,v);
+       nv = BME_SEMV(bm,v,e,ne);
+       if (nv == NULL) return NULL;
+       VECSUB(nv->co,v2->co,v->co);
+       len = VecLength(nv->co);
+       VECADDFAC(nv->co,v->co,nv->co,len*percent);
+       nv->flag = v->flag;
+       nv->bweight = v->bweight;
+       if (ne) {
+               (*ne)->flag = e->flag;
+               (*ne)->h = e->h;
+               (*ne)->crease = e->crease;
+               (*ne)->bweight = e->bweight;
+       }
+
+       return nv;
+}
+
+int BME_bevel_is_split_vert(BME_Loop *l) {
+       /* look for verts that have already been added to the edge when
+        * beveling other polys; this can be determined by testing the
+        * vert and the edges around it for originality
+        */
+       if ((l->v->tflag1 & BME_BEVEL_ORIG)==0
+                       && (l->e->tflag1 & BME_BEVEL_ORIG)
+                       && (l->prev->e->tflag1 & BME_BEVEL_ORIG))
+       {
+               return 1;
+       }
+       return 0;
+}
+
+/* get a vector, vec, that points from v1->co to wherever makes sense to
+ * the bevel operation as a whole based on the relationship between v1 and v2
+ * (won't necessarily be a vec from v1->co to v2->co, though it probably will be);
+ * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */
+int BME_bevel_get_vec(float *vec, BME_Vert *v1, BME_Vert *v2, BME_TransData_Head *td) {
+       BME_TransData *vtd1, *vtd2;
+
+       vtd1 = BME_get_transdata(td,v1);
+       vtd2 = BME_get_transdata(td,v2);
+       if (!vtd1 || !vtd2) {
+               printf("BME_bevel_get_vec() got called without proper BME_TransData\n");
+               return -1;
+       }
+
+       /* compare the transform origins to see if we can use the vert co's;
+        * if they belong to different origins, then we will use the origins to determine
+        * the vector */
+       if (VecCompare(vtd1->org,vtd2->org,0.000001f)) {
+               VECSUB(vec,v2->co,v1->co);
+               if (VecLength(vec) < 0.000001f) {
+                       VecMulf(vec,0);
+               }
+               return 0;
+       }
+       else {
+               VECSUB(vec,vtd2->org,vtd1->org);
+               if (VecLength(vec) < 0.000001f) {
+                       VecMulf(vec,0);
+               }
+               return 1;
+       }
+}
+
+/* "Projects" a vector perpendicular to vec2 against vec1, such that
+ * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2.
+ * note: the direction, is_forward, is used in conjunction with up_vec to determine
+ * whether this is a convex or concave corner. If it is a concave corner, it will
+ * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards).
+ * vec1 is the vector to project onto (expected to be normalized)
+ * vec2 is the direction of projection (pointing away from vec1)
+ * up_vec is used for orientation (expected to be normalized)
+ * returns the length of the projected vector that lies along vec1 */
+float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *td) {
+       float factor, vec3[3], tmp[3],c1,c2;
+
+       Crossf(tmp,vec1,vec2);
+       Normalize(tmp);
+       factor = Inpf(up_vec,tmp);
+       if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) {
+               Crossf(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */
+       }
+       else {
+               Crossf(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */
+       }
+       Normalize(vec3);
+       c1 = Inpf(vec3,vec1);
+       c2 = Inpf(vec1,vec1);
+       if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) {
+               factor = 0.0f;
+       }
+       else {
+               factor = c2/c1;
+       }
+
+       return factor;
+}
+
+/* BME_bevel_split_edge() is the main math work-house; its responsibilities are:
+ * using the vert and the loop passed, get or make the split vert, set its coordinates
+ * and transform properties, and set the max limits.
+ * Finally, return the split vert. */
+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) {
+       BME_TransData *vtd, *vtd1, *vtd2;
+       BME_Vert *sv, *v2, *v3;
+       BME_Loop *lv1, *lv2;
+       BME_Edge *ne, *e1, *e2;
+       float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3];
+       int is_edge, forward, is_split_vert;
+
+       if (l == NULL) {
+               /* what you call operator overloading in C :)
+                * I wanted to use the same function for both wire edges and poly loops
+                * so... here we walk around edges to find the needed verts */
+               forward = 1;
+               is_split_vert = 0;
+               if (v->edge == NULL) {
+                       printf("We can't split a loose vert's edge!\n");
+                       return NULL;
+               }
+               e1 = v->edge; /* we just use the first two edges */
+               e2 = BME_disk_nextedge(v->edge, v);
+               if (e1 == e2) {
+                       printf("You need at least two edges to use BME_bevel_split_edge()\n");
+                       return NULL;
+               }
+               v2 = BME_edge_getothervert(e1, v);
+               v3 = BME_edge_getothervert(e2, v);
+               if (v1 != v2 && v1 != v3) {
+                       printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n");
+                       return NULL;
+               }
+               if (v1 == v2) {
+                       v2 = v3;
+               }
+               else {
+                       e1 = e2;
+               }
+               sv = BME_split_edge(bm,v,e1,&ne,0);
+               BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
+               sv->tflag1 |= BME_BEVEL_BEVEL;
+               ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
+               BME_bevel_get_vec(vec1,v1,v,td);
+               BME_bevel_get_vec(vec2,v2,v,td);
+               Crossf(t_up_vec,vec1,vec2);
+               Normalize(t_up_vec);
+               up_vec = t_up_vec;
+       }
+       else {
+               /* establish loop direction */
+               if (l->v == v) {
+                       forward = 1;
+                       lv1 = l->next;
+                       lv2 = l->prev;
+                       v1 = l->next->v;
+                       v2 = l->prev->v;
+               }
+               else if (l->next->v == v) {
+                       forward = 0;
+                       lv1 = l;
+                       lv2 = l->next->next;
+                       v1 = l->v;
+                       v2 = l->next->next->v;
+               }
+               else {
+                       printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n");
+                       return NULL;
+               }
+
+               if (BME_bevel_is_split_vert(lv1)) {
+                       is_split_vert = 1;
+                       sv = v1;
+                       if (forward) v1 = l->next->next->v;
+                       else v1 = l->prev->v;
+               }
+               else {
+                       is_split_vert = 0;
+                       sv = BME_split_edge(bm,v,l->e,&ne,0);
+                       BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
+                       sv->tflag1 |= BME_BEVEL_BEVEL;
+                       ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
+               }
+
+               if (BME_bevel_is_split_vert(lv2)) {
+                       if (forward) v2 = lv2->prev->v;
+                       else v2 = lv2->next->v;
+               }
+       }
+
+       is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */
+       BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */
+       len = VecLength(vec1);
+       Normalize(vec1);
+
+       vtd = BME_get_transdata(td, sv);
+       vtd1 = BME_get_transdata(td, v);
+       vtd2 = BME_get_transdata(td,v1);
+
+       if (vtd1->loc == NULL) {
+               /* this is a vert with data only for calculating initial weights */
+               if (vtd1->weight < 0) {
+                       vtd1->weight = 0;
+               }
+               scale = vtd1->weight/vtd1->factor;
+               if (!vtd1->max) {
+                       vtd1->max = BME_new_transdata_float(td);
+                       *vtd1->max = -1;
+               }
+       }
+       else {
+               scale = vtd1->weight;
+       }
+       vtd->max = vtd1->max;
+
+       if (is_edge && vtd1->loc != NULL) {
+               maxfactor = vtd1->maxfactor;
+       }
+       else {
+               maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td);
+               if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) {
+                       maxfactor = vtd->maxfactor;
+               }
+       }
+
+       dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2;
+       if (is_edge || dis > maxfactor*value) {
+               dis = maxfactor*value;
+       }
+       VECADDFAC(sv->co,v->co,vec1,dis);
+       VECSUB(vec1,sv->co,vtd1->org);
+       dis = VecLength(vec1);
+       Normalize(vec1);
+       BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max);
+
+       return sv;
+}
+
+float BME_bevel_set_max(BME_Vert *v1, BME_Vert *v2, float value, BME_TransData_Head *td) {
+       BME_TransData *vtd1, *vtd2;
+       float max, fac1, fac2, vec1[3], vec2[3], vec3[3];
+
+       BME_bevel_get_vec(vec1,v1,v2,td);
+       vtd1 = BME_get_transdata(td,v1);
+       vtd2 = BME_get_transdata(td,v2);
+
+       if (vtd1->loc == NULL) {
+               fac1 = 0;
+       }
+       else {
+               VECCOPY(vec2,vtd1->vec);
+               VecMulf(vec2,vtd1->factor);
+               if (Inpf(vec1, vec1)) {
+                       Projf(vec2,vec2,vec1);
+                       fac1 = VecLength(vec2)/value;
+               }
+               else {
+                       fac1 = 0;
+               }
+       }
+
+       if (vtd2->loc == NULL) {
+               fac2 = 0;
+       }
+       else {
+               VECCOPY(vec3,vtd2->vec);
+               VecMulf(vec3,vtd2->factor);
+               if (Inpf(vec1, vec1)) {
+                       Projf(vec2,vec3,vec1);
+                       fac2 = VecLength(vec2)/value;
+               }
+               else {
+                       fac2 = 0;
+               }
+       }
+
+       if (fac1 || fac2) {
+               max = VecLength(vec1)/(fac1 + fac2);
+               if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
+                       *vtd1->max = max;
+               }
+               if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
+                       *vtd2->max = max;
+               }
+       }
+       else {
+               max = -1;
+       }
+
+       return max;
+}
+
+BME_Vert *BME_bevel_wire(BME_Mesh *bm, BME_Vert *v, float value, int res, int options, BME_TransData_Head *td) {
+       BME_Vert *ov1, *ov2, *v1, *v2;
+
+       ov1 = BME_edge_getothervert(v->edge, v);
+       ov2 = BME_edge_getothervert(BME_disk_nextedge(v->edge, v), v);
+
+       /* split the edges */
+       v1 = BME_bevel_split_edge(bm,v,ov1,NULL,NULL,value,td);
+       v1->tflag1 |= BME_BEVEL_NONMAN;
+       v2 = BME_bevel_split_edge(bm,v,ov2,NULL,NULL,value,td);
+       v2->tflag1 |= BME_BEVEL_NONMAN;
+
+       if (value > 0.5) {
+               BME_bevel_set_max(v1,ov1,value,td);
+               BME_bevel_set_max(v2,ov2,value,td);
+       }
+
+       /* remove the original vert */
+       if (res) {
+               BME_JEKV(bm,v->edge,v);
+       }
+
+       return v1;
+}
+
+BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
+       BME_Vert *v1, *v2, *kv;
+       BME_Loop *kl, *nl;
+       BME_Edge *e;
+       BME_Poly *f;
+       float factor=1;
+
+       f = l->f;
+       e = l->e;
+
+       if ((l->e->tflag1 & BME_BEVEL_BEVEL) == 0
+               && ((l->v->tflag1 & BME_BEVEL_BEVEL) || (l->next->v->tflag1 & BME_BEVEL_BEVEL)))
+       { /* sanity check */
+               return l;
+       }
+
+       /* checks and operations for prev edge */
+       /* first, check to see if this edge was inset previously */
+       if ((l->prev->e->tflag1 & BME_BEVEL_ORIG) == 0
+               && (l->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
+               kl = l->prev->radial.next->data;
+               if (kl->v == l->v) kl = kl->prev;
+               else kl = kl->next;
+               kv = l->v;
+       }
+       else {
+               kv = NULL;
+       }
+       /* get/make the first vert to be used in SFME */
+       if (l->v->tflag1 & BME_BEVEL_NONMAN){
+               v1 = l->v;
+       }
+       else { /* we'll need to split the previous edge */
+               v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td);
+       }
+       /* if we need to clean up geometry... */
+       if (kv) {
+               l = l->next;
+               if (kl->v == kv) {
+                       BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
+                       BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
+                       BME_JEKV(bm,kl->e,kv);
+               }
+               else {
+                       BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
+                       BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
+                       BME_JEKV(bm,kl->e,kv);
+               }
+               l = l->prev;
+       }
+
+       /* checks and operations for the next edge */
+       /* first, check to see if this edge was inset previously  */
+       if ((l->next->e->tflag1 & BME_BEVEL_ORIG) == 0
+               && (l->next->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
+               kl = l->next->radial.next->data;
+               if (kl->v == l->next->v) kl = kl->prev;
+               else kl = kl->next;
+               kv = l->next->v;
+       }
+       else {
+               kv = NULL;
+       }
+       /* get/make the second vert to be used in SFME */
+       if (l->next->v->tflag1 & BME_BEVEL_NONMAN) {
+               v2 = l->next->v;
+       }
+       else { /* we'll need to split the next edge */
+               v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td);
+       }
+       /* if we need to clean up geometry... */
+       if (kv) {
+               if (kl->v == kv) {
+                       BME_split_face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
+                       BME_JFKE(bm,((BME_Loop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
+                       BME_JEKV(bm,kl->e,kv);
+               }
+               else {
+                       BME_split_face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
+                       BME_JFKE(bm,((BME_Loop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
+                       BME_JEKV(bm,kl->e,kv);
+               }
+       }
+
+       if ((v1->tflag1 & BME_BEVEL_NONMAN)==0 || (v2->tflag1 & BME_BEVEL_NONMAN)==0) {
+               BME_split_face(bm,f,v2,v1,&l,e);
+               l->e->tflag1 = BME_BEVEL_BEVEL;
+               l = l->radial.next->data;
+       }
+
+       if (l->f != f) printf("Whoops! You got something out of order in BME_bevel_edge()!\n");
+
+       return l;
+}
+
+BME_Loop *BME_bevel_vert(BME_Mesh *bm, BME_Loop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
+       BME_Vert *v1, *v2;
+       BME_Poly *f;
+
+       /* get/make the first vert to be used in SFME */
+       /* may need to split the previous edge */
+       v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td);
+
+       /* get/make the second vert to be used in SFME */
+       /* may need to split this edge (so move l) */
+       l = l->prev;
+       v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td);
+       l = l->next->next;
+
+       /* "cut off" this corner */
+       f = BME_split_face(bm,l->f,v2,v1,NULL,l->e);
+
+       return l;
+}
+
+/**
+ *                     BME_bevel_poly
+ *
+ *     Polygon inset tool:
+ *
+ *     Insets a polygon/face based on the tflag1's of its vertices
+ *     and edges. Used by the bevel tool only, for now.
+ *  The parameter "value" is the distance to inset (should be negative).
+ *  The parameter "options" is not currently used.
+ *
+ *     Returns -
+ *  A BME_Poly pointer to the resulting inner face.
+*/
+BME_Poly *BME_bevel_poly(BME_Mesh *bm, BME_Poly *f, float value, int options, BME_TransData_Head *td) {
+       BME_Loop *l, *ol;
+       BME_TransData *vtd1, *vtd2;
+       float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1;
+       int len, i;
+
+       up_vec[0] = 0.0f;
+       up_vec[1] = 0.0f;
+       up_vec[2] = 0.0f;
+       /* find a good normal for this face (there's better ways, I'm sure) */
+       ol = f->loopbase;
+       l = ol->next;
+       for (i=0,ol=f->loopbase,l=ol->next; l->next!=ol; l=l->next) {
+               BME_bevel_get_vec(vec1,l->next->v,ol->v,td);
+               BME_bevel_get_vec(vec2,l->v,ol->v,td);
+               Crossf(vec3,vec2,vec1);
+               VECADD(up_vec,up_vec,vec3);
+               i++;
+       }
+       VecMulf(up_vec,1.0f/i);
+       Normalize(up_vec);
+
+       for (i=0,len=f->len; i<len; i++,l=l->next) {
+               if ((l->e->tflag1 & BME_BEVEL_BEVEL) && (l->e->tflag1 & BME_BEVEL_ORIG)) {
+                       max = 1.0f;
+                       l = BME_bevel_edge(bm, l, value, options, up_vec, td);
+               }
+               else if ((l->v->tflag1 & BME_BEVEL_BEVEL) && (l->v->tflag1 & BME_BEVEL_ORIG) && (l->prev->e->tflag1 & BME_BEVEL_BEVEL) == 0) {
+                       max = 1.0f;
+                       l = BME_bevel_vert(bm, l, value, options, up_vec, td);
+               }
+       }
+
+       /* max pass */
+       if (value > 0.5 && max > 0) {
+               max = -1;
+               for (i=0,len=f->len; i<len; i++,l=l->next) {
+                       if ((l->e->tflag1 & BME_BEVEL_BEVEL) || (l->e->tflag1 & BME_BEVEL_ORIG)) {
+                               BME_bevel_get_vec(vec1,l->v,l->next->v,td);
+                               vtd1 = BME_get_transdata(td,l->v);
+                               vtd2 = BME_get_transdata(td,l->next->v);
+                               if (vtd1->loc == NULL) {
+                                       fac1 = 0;
+                               }
+                               else {
+                                       VECCOPY(vec2,vtd1->vec);
+                                       VecMulf(vec2,vtd1->factor);
+                                       if (Inpf(vec1, vec1)) {
+                                               Projf(vec2,vec2,vec1);
+                                               fac1 = VecLength(vec2)/value;
+                                       }
+                                       else {
+                                               fac1 = 0;
+                                       }
+                               }
+                               if (vtd2->loc == NULL) {
+                                       fac2 = 0;
+                               }
+                               else {
+                                       VECCOPY(vec3,vtd2->vec);
+                                       VecMulf(vec3,vtd2->factor);
+                                       if (Inpf(vec1, vec1)) {
+                                               Projf(vec2,vec3,vec1);
+                                               fac2 = VecLength(vec2)/value;
+                                       }
+                                       else {
+                                               fac2 = 0;
+                                       }
+                               }
+                               if (fac1 || fac2) {
+                                       max = VecLength(vec1)/(fac1 + fac2);
+                                       if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
+                                               *vtd1->max = max;
+                                       }
+                                       if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
+                                               *vtd2->max = max;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return l->f;
+}
+
+void BME_bevel_add_vweight(BME_TransData_Head *td, BME_Mesh *bm, BME_Vert *v, float weight, float factor, int options) {
+       BME_TransData *vtd;
+
+       if (v->tflag1 & BME_BEVEL_NONMAN) return;
+       v->tflag1 |= BME_BEVEL_BEVEL;
+       if (vtd = BME_get_transdata(td, v)) {
+               if (options & BME_BEVEL_EMIN) {
+                       vtd->factor = 1.0;
+                       if (vtd->weight < 0 || weight < vtd->weight) {
+                               vtd->weight = weight;
+                       }
+               }
+               else if (options & BME_BEVEL_EMAX) {
+                       vtd->factor = 1.0;
+                       if (weight > vtd->weight) {
+                               vtd->weight = weight;
+                       }
+               }
+               else if (vtd->weight < 0) {
+                       vtd->factor = factor;
+                       vtd->weight = weight;
+               }
+               else {
+                       vtd->factor += factor; /* increment number of edges with weights (will be averaged) */
+                       vtd->weight += weight; /* accumulate all the weights */
+               }
+       }
+       else {
+               /* we'll use vtd->loc == NULL to mark that this vert is not moving */
+               vtd = BME_assign_transdata(td, bm, v, v->co, NULL, NULL, NULL, factor, weight, -1, NULL);
+       }
+}
+
+float BME_bevel_get_angle(BME_Mesh *bm, BME_Edge *e, BME_Vert *v) {
+       BME_Vert *v1, *v2;
+       BME_Loop *l1, *l2;
+       float vec1[3], vec2[3], vec3[3], vec4[3];
+
+       l1 = e->loop;
+       l2 = e->loop->radial.next->data;
+       if (l1->v == v) {
+               v1 = l1->prev->v;
+               v2 = l1->next->v;
+       }
+       else {
+               v1 = l1->next->next->v;
+               v2 = l1->v;
+       }
+       VECSUB(vec1,v1->co,v->co);
+       VECSUB(vec2,v2->co,v->co);
+       Crossf(vec3,vec1,vec2);
+
+       l1 = l2;
+       if (l1->v == v) {
+               v1 = l1->prev->v;
+               v2 = l1->next->v;
+       }
+       else {
+               v1 = l1->next->next->v;
+               v2 = l1->v;
+       }
+       VECSUB(vec1,v1->co,v->co);
+       VECSUB(vec2,v2->co,v->co);
+       Crossf(vec4,vec2,vec1);
+
+       Normalize(vec3);
+       Normalize(vec4);
+
+       return Inpf(vec3,vec4);
+}
+
+/**
+ *                     BME_bevel_initialize
+ *
+ *     Prepare the mesh for beveling:
+ *
+ *     Sets the tflag1's of the mesh elements based on the options passed.
+ *
+ *     Returns -
+ *  A BME_Mesh pointer to the BMesh passed as a parameter.
+*/
+BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int defgrp_index, float angle, BME_TransData_Head *td) {
+       BME_Vert *v;
+       BME_Edge *e;
+       BME_Poly *f;
+       BME_TransData *vtd;
+       MDeformVert *dvert;
+       MDeformWeight *dw;
+       int i, len;
+       float weight, threshold;
+
+       /* vert pass */
+       for (v=bm->verts.first; v; v=v->next) {
+               dvert = NULL;
+               dw = NULL;
+               v->tflag1 = BME_BEVEL_ORIG;
+               /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if
+                * the vert is manifold (or is shared by only two edges - wire bevel)
+                * BME_BEVEL_SELECT is passed and the vert has v->flag&SELECT or
+                * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight
+                * BME_BEVEL_ANGLE is not passed
+                * BME_BEVEL_EWEIGHT is not passed
+                */
+               /* originally coded, a vertex gets tagged with BME_BEVEL_NONMAN in this pass if
+                * the vert is loose, shared by multiple regions, or is shared by wire edges
+                * note: verts belonging to edges of open meshes are not tagged with BME_BEVEL_NONMAN
+                */
+               /* originally coded, a vertex gets a transform weight set in this pass if
+                * BME_BEVEL_VWEIGHT is passed, and the vert has a defgrp and weight
+                */
+
+               /* get disk cycle length */
+               if (v->edge == NULL) {
+                       len = 0;
+               }
+               else {
+                       len = BME_cycle_length(BME_disk_getpointer(v->edge,v));
+                       /* we'll assign a default transform data to every vert (except the loose ones) */
+                       vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL);
+               }
+
+               /* check for non-manifold vert */
+               if (BME_is_nonmanifold_vert(bm,v)) {
+                       v->tflag1 |= BME_BEVEL_NONMAN;
+               }
+
+               /* BME_BEVEL_BEVEL tests */
+               if ((v->tflag1 & BME_BEVEL_NONMAN) == 0 || len == 2) { /* either manifold vert, or wire vert */
+                       if (((options & BME_BEVEL_SELECT) && (v->flag & SELECT))
+                               || ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT)) /* use weights for verts */
+                               || ((options & BME_BEVEL_ANGLE) == 0
+                                       && (options & BME_BEVEL_SELECT) == 0
+                                       && (options & BME_BEVEL_WEIGHT) == 0))
+                       {
+                               if (options & BME_BEVEL_WEIGHT) {
+                                       /* do vert weight stuff */
+                                       //~ dvert = CustomData_em_get(&bm->vdata,v->data,CD_MDEFORMVERT);
+                                       //~ if (!dvert) continue;
+                                       //~ for (i = 0; i < dvert->totweight; ++i) {
+                                               //~ if(dvert->dw[i].def_nr == defgrp_index) {
+                                                       //~ dw = &dvert->dw[i];
+                                                       //~ break;
+                                               //~ }
+                                       //~ }
+                                       //~ if (!dw || dw->weight == 0.0) continue;
+                                       if (v->bweight == 0.0) continue;
+                                       vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, v->bweight, -1, NULL);
+                                       v->tflag1 |= BME_BEVEL_BEVEL;
+                               }
+                               else {
+                                       vtd = BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0, 1.0, -1, NULL);
+                                       v->tflag1 |= BME_BEVEL_BEVEL;
+                               }
+                       }
+               }
+       }
+
+       /* edge pass */
+       threshold = (float)cos((angle + 0.00001) * M_PI / 180.0);
+       for (e=bm->edges.first; e; e=e->next) {
+               e->tflag1 = BME_BEVEL_ORIG;
+               weight = 0.0;
+               /* originally coded, an edge gets tagged with BME_BEVEL_BEVEL in this pass if
+                * BME_BEVEL_VERT is not set
+                * the edge is manifold (shared by exactly two faces)
+                * BME_BEVEL_SELECT is passed and the edge has e->flag&SELECT or
+                * BME_BEVEL_EWEIGHT is passed, and the edge has the crease set or
+                * BME_BEVEL_ANGLE is passed, and the edge is sharp enough
+                * BME_BEVEL_VWEIGHT is passed, and both verts are set for bevel
+                */
+               /* originally coded, a vertex gets tagged with BME_BEVEL_BEVEL in this pass if
+                * the vert belongs to the edge
+                * the vert is not tagged with BME_BEVEL_NONMAN
+                * the edge is eligible for bevel (even if BME_BEVEL_VERT is set, or the edge is shared by less than 2 faces)
+                */
+               /* originally coded, a vertex gets a transform weight set in this pass if
+                * the vert belongs to the edge
+                * the edge has a weight
+                */
+               /* note: edge weights are cumulative at the verts,
+                * i.e. the vert's weight is the average of the weights of its weighted edges
+                */
+
+               if (e->loop == NULL) {
+                       len = 0;
+                       e->v1->tflag1 |= BME_BEVEL_NONMAN;
+                       e->v2->tflag1 |= BME_BEVEL_NONMAN;
+               }
+               else {
+                       len = BME_cycle_length(&(e->loop->radial));
+               }
+
+               if (len > 2) {
+                       /* non-manifold edge of the worst kind */
+                       continue;
+               }
+
+               if ((options & BME_BEVEL_SELECT) && (e->flag & SELECT)) {
+                       weight = 1.0;
+                       /* stupid editmode doesn't always flush selections, or something */
+                       e->v1->flag |= SELECT;
+                       e->v2->flag |= SELECT;
+               }
+               else if ((options & BME_BEVEL_WEIGHT) && (options & BME_BEVEL_VERT) == 0) {
+                       weight = e->bweight;
+               }
+               else if (options & BME_BEVEL_ANGLE) {
+                       if ((e->v1->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v1) < threshold) {
+                               e->tflag1 |= BME_BEVEL_BEVEL;
+                               e->v1->tflag1 |= BME_BEVEL_BEVEL;
+                               BME_bevel_add_vweight(td, bm, e->v1, 1.0, 1.0, options);
+                       }
+                       else {
+                               BME_bevel_add_vweight(td, bm, e->v1, 0.0, 1.0, options);
+                       }
+                       if ((e->v2->tflag1 & BME_BEVEL_NONMAN) == 0 && BME_bevel_get_angle(bm,e,e->v2) < threshold) {
+                               e->tflag1 |= BME_BEVEL_BEVEL;
+                               e->v2->tflag1 |= BME_BEVEL_BEVEL;
+                               BME_bevel_add_vweight(td, bm, e->v2, 1.0, 1.0, options);
+                       }
+                       else {
+                               BME_bevel_add_vweight(td, bm, e->v2, 0.0, 1.0, options);
+                       }
+               }
+               //~ else if ((options & BME_BEVEL_VWEIGHT) && (options & BME_BEVEL_VERT) == 0) {
+                       //~ if ((e->v1->tflag1 & BME_BEVEL_BEVEL) && (e->v2->tflag1 & BME_BEVEL_BEVEL)) {
+                               //~ e->tflag1 |= BME_BEVEL_BEVEL;
+                       //~ }
+               //~ }
+               else if ((options & BME_BEVEL_SELECT) == 0
+                       && (options & BME_BEVEL_VERT) == 0)
+               {
+                       weight = 1.0;
+               }
+
+               if (weight > 0.0) {
+                       e->tflag1 |= BME_BEVEL_BEVEL;
+                       BME_bevel_add_vweight(td, bm, e->v1, weight, 1.0, options);
+                       BME_bevel_add_vweight(td, bm, e->v2, weight, 1.0, options);
+               }
+
+               if (len != 2 || options & BME_BEVEL_VERT) {
+                       e->tflag1 &= ~BME_BEVEL_BEVEL;
+               }
+       }
+
+       /* face pass */
+       for (f=bm->polys.first; f; f=f->next) f->tflag1 = BME_BEVEL_ORIG;
+
+       return bm;
+}
+
+/* tags all elements as originals */
+BME_Mesh *BME_bevel_reinitialize(BME_Mesh *bm) {
+       BME_Vert *v;
+       BME_Edge *e;
+       BME_Poly *f;
+
+       for (v = bm->verts.first; v; v=v->next) {
+               v->tflag1 |= BME_BEVEL_ORIG;
+       }
+
+       for (e=bm->edges.first; e; e=e->next) {
+               e->tflag1 |= BME_BEVEL_ORIG;
+       }
+
+       for (f=bm->polys.first; f; f=f->next) {
+               f->tflag1 |= BME_BEVEL_ORIG;
+       }
+
+       return bm;
+}
+
+/**
+ *                     BME_bevel_mesh
+ *
+ *     Mesh beveling tool:
+ *
+ *     Bevels an entire mesh. It currently uses the tflag1's of
+ *     its vertices and edges to track topological changes.
+ *  The parameter "value" is the distance to inset (should be negative).
+ *  The parameter "options" is not currently used.
+ *
+ *     Returns -
+ *  A BME_Mesh pointer to the BMesh passed as a parameter.
+*/
+BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options, int defgrp_index, BME_TransData_Head *td) {
+       BME_Vert *v, *nv;
+       BME_Edge *e, *oe;
+       BME_Loop *l, *l2;
+       BME_Poly *f;
+       unsigned int i, len;
+
+       for (f=bm->polys.first; f; f=f->next) {
+               if(f->tflag1 & BME_BEVEL_ORIG) {
+                       BME_bevel_poly(bm,f,value,options,td);
+               }
+       }
+
+       /* here we will loop through all the verts to clean up the left over geometry */
+       /* crazy idea. when res == 0, don't remove the original geometry */
+       for (v = bm->verts.first; v; /* we may kill v, so increment in-loop */) {
+               nv = v->next;
+               if ((v->tflag1 & BME_BEVEL_NONMAN) && (v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG)) {
+                       v = BME_bevel_wire(bm, v, value, res, options, td);
+               }
+               else if (res && ((v->tflag1 & BME_BEVEL_BEVEL) && (v->tflag1 & BME_BEVEL_ORIG))) {
+                       /* first, make sure we're not sitting on an edge to be removed */
+                       oe = v->edge;
+                       e = BME_disk_nextedge(oe,v);
+                       while ((e->tflag1 & BME_BEVEL_BEVEL) && (e->tflag1 & BME_BEVEL_ORIG)) {
+                               e = BME_disk_nextedge(e,v);
+                               if (e == oe) {
+                                       printf("Something's wrong! We can't remove every edge here!\n");
+                                       break;
+                               }
+                       }
+                       /* look for original edges, and remove them */
+                       oe = e;
+                       while (e = BME_disk_next_edgeflag(oe, v, 0, BME_BEVEL_ORIG | BME_BEVEL_BEVEL)) {
+                               /* join the faces (we'll split them later) */
+                               f = BME_JFKE_safe(bm,e->loop->f,((BME_Loop*)e->loop->radial.next->data)->f,e);
+                               if (!f) printf("Non-manifold geometry not getting tagged right?\n");
+                       }
+
+                       /* all original edges marked to be beveled have been removed;
+                        * now we need to link up the edges for this "corner" */
+                       len = BME_cycle_length(BME_disk_getpointer(v->edge, v));
+                       for (i=0,e=v->edge; i < len; i++,e=BME_disk_nextedge(e,v)) {
+                               l = e->loop;
+                               l2 = l->radial.next->data;
+                               if (l->v != v) l = l->next;
+                               if (l2->v != v) l2 = l2->next;
+                               /* look for faces that have had the original edges removed via JFKE */
+                               if (l->f->len > 3) {
+                                       BME_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */
+                                       if (len > 2) {
+                                               l->e->tflag1 |= BME_BEVEL_BEVEL;
+                                       }
+                               }
+                               if (l2->f->len > 3) {
+                                       BME_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */
+                                       if (len > 2) {
+                                               l->e->tflag1 |= BME_BEVEL_BEVEL;
+                                       }
+                               }
+                       }
+
+                       l = v->edge->loop;
+                       if (len > 2) {
+                               f = l->f;
+                               while(f->len <= len) {
+                                       if (l->radial.next->data != l) {
+                                               e = l->e;
+                                               l = l->radial.next->data;
+                                       }
+                                       else {
+                                               e = NULL;
+                                       }
+                                       if (l->v == v) l = l->prev;
+                                       else l = l->next;
+                                       if (e) {
+                                               f = BME_JFKE_safe(bm,e->loop->f,((BME_Loop*)e->loop->radial.next->data)->f,e);
+                                       }
+                               }
+                       }
+                       if (l->v == v) l = l->prev;
+                       l = l->prev;
+                       if (l->next->radial.next->data == l->next) { /* was part of the open end of a mesh */
+                               BME_JEKV(bm,l->next->e,v);
+                               if (len == 2) {
+                                       f = BME_JFKE_safe(bm,l->f,((BME_Loop*)l->radial.next->data)->f,l->e);
+                               }
+                       }
+                       else {
+                               BME_JEKV(bm,l->next->e,v);
+                               f = BME_JFKE_safe(bm,l->f,((BME_Loop*)l->next->radial.next->data)->f,l->next->e);
+                               if (f->len == 2) {
+                                       f = BME_JFKE_safe(bm,f,((BME_Loop*)f->loopbase->radial.next->data)->f,f->loopbase->e);
+                               }
+                       }
+               }
+               v = nv;
+       }
+       return bm;
+}
+
+BME_Mesh *BME_tesselate(BME_Mesh *bm) {
+       BME_Loop *l, *nextloop;
+       BME_Poly *f;
+
+       for (f=bm->polys.first; f; f=f->next) {
+               l = f->loopbase;
+               while (l->f->len > 4) {
+                       nextloop = l->next->next->next;
+                       /* make a quad */
+                       BME_split_face(bm,l->f,l->v,nextloop->v,NULL,l->e);
+                       l = nextloop;
+               }
+       }
+       return bm;
+}
+
+/* options that can be passed:
+ * BME_BEVEL_VWEIGHT   <---- v, Look at vertex weights; use defgrp_index if option is present
+ * BME_BEVEL_SELECT            <---- v,e, check selection for verts and edges
+ * BME_BEVEL_ANGLE             <---- v,e, don't bevel-tag verts - tag verts per edge
+ * BME_BEVEL_VERT              <---- e, don't tag edges
+ * BME_BEVEL_EWEIGHT   <---- e, use crease flag for now
+ * BME_BEVEL_PERCENT   <---- Will need to think about this one; will probably need to incorporate into actual bevel routine
+ * BME_BEVEL_RADIUS            <---- Will need to think about this one; will probably need to incorporate into actual bevel routine
+ * All weights/limits are stored per-vertex
+ */
+BME_Mesh *BME_bevel(BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) {
+       BME_Vert *v;
+       BME_TransData_Head *td;
+       BME_TransData *vtd;
+       int i;
+       float fac=1, d;
+
+       td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE);
+
+       BME_bevel_initialize(bm, options, defgrp_index, angle, td);
+
+       /* recursion math courtesy of Martin Poirier (theeth) */
+       for (i=0; i<res-1; i++) {
+               if (i==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * i * 2.0f);
+       }
+       d = 1.0f/fac;
+       /* crazy idea. if res == 0, don't remove original geometry */
+       for (i=0; i<res || (res==0 && i==0); i++) {
+               if (i != 0) BME_bevel_reinitialize(bm);
+               BME_bevel_mesh(bm,d,res,options,defgrp_index,td);
+               if (i==0) d /= 3; else d /= 2;
+       }
+
+       BME_tesselate(bm);
+
+       if (rtd) {
+               *rtd = td;
+               return bm;
+       }
+
+       /* transform pass */
+       for (v = bm->verts.first; v; v=v->next) {
+               if (vtd = BME_get_transdata(td, v)) {
+                       if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) {
+                               d = *vtd->max;
+                       }
+                       else {
+                               d = value;
+                       }
+                       VECADDFAC(v->co,vtd->org,vtd->vec,vtd->factor*d);
+               }
+               v->tflag1 = 0;
+       }
+
+       BME_free_transdata(td);
+       return bm;
+}
diff --git a/source/blender/blenkernel/intern/bmesh_private.h b/source/blender/blenkernel/intern/bmesh_private.h
new file mode 100644 (file)
index 0000000..4c6460b
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * BME_private.h    jan 2007
+ *
+ *     low level, 'private' function prototypes for bmesh kernel.
+ *
+ * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BMESH_PRIVATE
+#define BMESH_PRIVATE
+
+#include "BKE_bmesh.h"
+
+/*ALLOCATION/DEALLOCATION*/
+struct BME_Vert *BME_addvertlist(struct BME_Mesh *bm, struct BME_Vert *example);
+struct BME_Edge *BME_addedgelist(struct BME_Mesh *bm, struct BME_Vert *v1, struct BME_Vert *v2, struct BME_Edge *example);
+struct BME_Poly *BME_addpolylist(struct BME_Mesh *bm, struct BME_Poly *example); 
+struct BME_Loop *BME_create_loop(struct BME_Mesh *bm, struct BME_Vert *v, struct BME_Edge *e, struct BME_Poly *f, struct BME_Loop *example);
+
+void BME_free_vert(struct BME_Mesh *bm, struct BME_Vert *v);
+void BME_free_edge(struct BME_Mesh *bm, struct BME_Edge *e);
+void BME_free_poly(struct BME_Mesh *bm, struct BME_Poly *f);
+void BME_free_loop(struct BME_Mesh *bm, struct BME_Loop *l);
+void BME_delete_loop(struct BME_Mesh *bm, struct BME_Loop *l);
+
+/*DOUBLE CIRCULAR LINKED LIST FUNCTIONS*/
+void BME_cycle_append(void *h, void *nt);
+int BME_cycle_remove(void *h, void *remn);
+int BME_cycle_validate(int len, void *h);
+/*DISK CYCLE MANAGMENT*/
+int BME_disk_append_edge(struct BME_Edge *e, struct BME_Vert *v);
+void BME_disk_remove_edge(struct BME_Edge *e, struct BME_Vert *v);
+/*RADIAL CYCLE MANAGMENT*/
+void BME_radial_append(struct BME_Edge *e, struct BME_Loop *l);
+void BME_radial_remove_loop(struct BME_Loop *l, struct BME_Edge *e);
+
+/*MISC FUNCTIONS*/
+int BME_edge_swapverts(struct BME_Edge *e, struct BME_Vert *orig, struct BME_Vert *new); /*relink edge*/
+int BME_disk_hasedge(struct BME_Vert *v, struct BME_Edge *e);
+
+/*Error reporting. Shouldnt be called by tools ever.*/
+void BME_error(void);
+#endif
index ebfb96f001dbe7cd9f677bb2b48894de606f2a1b..3dc2fef4f730fc2d36dcb08ada3c624beb015247 100644 (file)
@@ -840,6 +840,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
                mv->no[0] = eve->no[0] * 32767.0;
                mv->no[1] = eve->no[1] * 32767.0;
                mv->no[2] = eve->no[2] * 32767.0;
+               mv->bweight = (unsigned char) (eve->bweight * 255.0f);
 
                mv->mat_nr = 0;
                mv->flag = 0;
@@ -857,6 +858,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
                med->v1 = eed->v1->tmp.l;
                med->v2 = eed->v2->tmp.l;
                med->crease = (unsigned char) (eed->crease * 255.0f);
+               med->bweight = (unsigned char) (eed->bweight * 255.0f);
                med->flag = ME_EDGEDRAW|ME_EDGERENDER;
                
                if(eed->seam) med->flag |= ME_SEAM;
index 91892f59a788f6f96a1febea8c6f89708d4d49f1..6d57c26adc98556857f782690a4c73a16f2e4d58 100644 (file)
@@ -96,6 +96,7 @@
 #include "BKE_pointcache.h"
 #include "BKE_utildefines.h"
 #include "depsgraph_private.h"
+#include "BKE_bmesh.h"
 
 #include "LOD_DependKludge.h"
 #include "LOD_decimation.h"
@@ -2677,6 +2678,92 @@ static DerivedMesh *edgesplitModifier_applyModifierEM(
        return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1);
 }
 
+/* Bevel */
+
+static void bevelModifier_initData(ModifierData *md)
+{
+       BevelModifierData *bmd = (BevelModifierData*) md;
+
+       bmd->value = 0.1f;
+       bmd->res = 1;
+       bmd->flags = 0;
+       bmd->val_flags = 0;
+       bmd->lim_flags = 0;
+       bmd->e_flags = 0;
+       bmd->bevel_angle = 30;
+       bmd->defgrp_name[0] = '\0';
+}
+
+static void bevelModifier_copyData(ModifierData *md, ModifierData *target)
+{
+       BevelModifierData *bmd = (BevelModifierData*) md;
+       BevelModifierData *tbmd = (BevelModifierData*) target;
+
+       tbmd->value = bmd->value;
+       tbmd->res = bmd->res;
+       tbmd->flags = bmd->flags;
+       tbmd->val_flags = bmd->val_flags;
+       tbmd->lim_flags = bmd->lim_flags;
+       tbmd->e_flags = bmd->e_flags;
+       tbmd->bevel_angle = bmd->bevel_angle;
+       strncpy(tbmd->defgrp_name, bmd->defgrp_name, 32);
+}
+
+CustomDataMask bevelModifier_requiredDataMask(ModifierData *md)
+{
+       BevelModifierData *bmd = (BevelModifierData *)md;
+       CustomDataMask dataMask = 0;
+
+       /* ask for vertexgroups if we need them */
+       if(bmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+       return dataMask;
+}
+
+static DerivedMesh *bevelModifier_applyModifier(
+                ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                int useRenderParams, int isFinalCalc)
+{
+       DerivedMesh *result;
+       BME_Mesh *bm;
+       bDeformGroup *def;
+       int i, options, defgrp_index = -1;
+       BevelModifierData *bmd = (BevelModifierData*) md;
+
+       options = bmd->flags|bmd->val_flags|bmd->lim_flags|bmd->e_flags;
+
+       //~ if ((options & BME_BEVEL_VWEIGHT) && bmd->defgrp_name[0]) {
+               //~ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
+                       //~ if (!strcmp(def->name, bmd->defgrp_name)) {
+                               //~ defgrp_index = i;
+                               //~ break;
+                       //~ }
+               //~ }
+               //~ if (defgrp_index < 0) {
+                       //~ options &= ~BME_BEVEL_VWEIGHT;
+               //~ }
+       //~ }
+
+       bm = BME_make_mesh();
+       bm = BME_derivedmesh_to_bmesh(derivedData, bm);
+       BME_model_begin(bm);
+       BME_bevel(bm,bmd->value,bmd->res,options,defgrp_index,bmd->bevel_angle,NULL);
+       BME_model_end(bm);
+       result = BME_bmesh_to_derivedmesh(bm,derivedData);
+       BME_free_mesh(bm);
+
+       CDDM_calc_normals(result);
+
+       return result;
+}
+
+static DerivedMesh *bevelModifier_applyModifierEM(
+                        ModifierData *md, Object *ob, EditMesh *editData,
+                        DerivedMesh *derivedData)
+{
+       return bevelModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
 /* Displace */
 
 static void displaceModifier_initData(ModifierData *md)
@@ -6952,6 +7039,18 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
                mti->applyModifier = edgesplitModifier_applyModifier;
                mti->applyModifierEM = edgesplitModifier_applyModifierEM;
 
+               mti = INIT_TYPE(Bevel);
+               mti->type = eModifierTypeType_Constructive;
+               mti->flags = eModifierTypeFlag_AcceptsMesh
+                            | eModifierTypeFlag_SupportsMapping
+                            | eModifierTypeFlag_SupportsEditmode
+                            | eModifierTypeFlag_EnableInEditmode;
+               mti->initData = bevelModifier_initData;
+               mti->copyData = bevelModifier_copyData;
+               mti->requiredDataMask = bevelModifier_requiredDataMask;
+               mti->applyModifier = bevelModifier_applyModifier;
+               mti->applyModifierEM = bevelModifier_applyModifierEM;
+
                mti = INIT_TYPE(Displace);
                mti->type = eModifierTypeType_OnlyDeform;
                mti->flags = eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsEditmode;
index 795f67818941e743dfd20701f68c6aa67461443e..f9b73d521c9d418f7b6ec00b103a60c6489ae415 100644 (file)
@@ -67,6 +67,7 @@ typedef struct EditVert
        h for hidden. if (!eve->h) {...
        f1 and f2 can be used for temp data, clear them first*/
        unsigned char f, h, f1, f2; 
+       float bweight;
        short fast;     /* only 0 or 1, for editmesh_fastmalloc, do not store temp data here! */
        int hash;
        int keyindex; /* original index #, for restoring  key information */
@@ -103,6 +104,7 @@ typedef struct EditEdge
        short f1, f2;   /* short, f1 is (ab)used in subdiv */
        unsigned char f, h, dir, seam, sharp;
        float crease;
+       float bweight;
        short fast;             /* only 0 or 1, for editmesh_fastmalloc */
        short fgoni;            /* index for fgon, for search */
        HashEdge hash;
index a0f991f2631aeabb3d22321199ad25a733147f93..deebe7c27cbe565fc2bf553b1a061003491e57a8 100644 (file)
@@ -60,6 +60,8 @@
 #define        TFM_TIME_SCALE          21
 #define TFM_TIME_EXTEND                22
 #define TFM_BAKE_TIME          23
+#define TFM_BEVEL                      24
+#define TFM_BWEIGHT                    25
 
 /* TRANSFORM CONTEXTS */
 #define CTX_NONE                       0
@@ -69,6 +71,7 @@
 #define CTX_TWEAK                      8
 #define CTX_NO_MIRROR          16
 #define CTX_AUTOCONFIRM                32
+#define CTX_BMESH                      64
 
 void initTransform(int mode, int context);
 void Transform(void);
index 5a276665240538461440c5991b9e7d204481bd42..a2339f3f1a6683197d464bd80022aad7a56de43f 100644 (file)
@@ -438,6 +438,7 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
 #define B_JOINTRIA                     2081
 #define B_SETTFACE_RND         2082
 #define B_SETMCOL_RND          2083
+#define B_DRAWBWEIGHTS         2084
 
 #define B_GEN_SKELETON         2090
 
index 7ac417fda7ca269fd699c5c2688c57c444bb8e2e..694cfece9894d87094f794862e08dce187767ef2 100644 (file)
@@ -339,6 +339,13 @@ int Trackball(TransInfo *t, short mval[2]);
 void initPushPull(TransInfo *t);
 int PushPull(TransInfo *t, short mval[2]);
 
+void initBevel(TransInfo *t);
+int handleEventBevel(TransInfo *t, unsigned short evenl, short val);
+int Bevel(TransInfo *t, short mval[2]);
+
+void initBevelWeight(TransInfo *t);
+int BevelWeight(TransInfo *t, short mval[2]);
+
 void initCrease(TransInfo *t);
 int Crease(TransInfo *t, short mval[2]);
 
index afb1dfb108caf72840376ee504e87b26bccdc475..7970ccd073cf259a5b4497c4ef09371f3ffe87e3 100644 (file)
@@ -45,7 +45,7 @@ typedef struct MFace {
 
 typedef struct MEdge {
        unsigned int v1, v2;
-       char crease, pad;
+       char crease, bweight;
        short flag;
 } MEdge;
 
@@ -63,7 +63,7 @@ typedef struct MDeformVert {
 typedef struct MVert {
        float   co[3];
        short   no[3];
-       char flag, mat_nr;
+       char flag, mat_nr, bweight, pad[3];
 } MVert;
 
 /* at the moment alpha is abused for vertex painting
index 1c70508509ba9958f390434f23c9be4d9ca1f414..dd1d8eb01b3bf3539b136c7bb4e7914af586cb7a 100644 (file)
@@ -33,7 +33,8 @@ typedef enum ModifierType {
        eModifierType_ParticleInstance,
        eModifierType_Explode,
        eModifierType_Cloth,
-       eModifierType_Collision,
+       eModifierType_Collision,
+       eModifierType_Bevel,
        NUM_MODIFIER_TYPES
 } ModifierType;
 
@@ -187,6 +188,27 @@ typedef struct EdgeSplitModifierData {
 #define MOD_EDGESPLIT_FROMANGLE   1<<1
 #define MOD_EDGESPLIT_FROMFLAG    1<<2
 
+typedef struct BevelModifierData {
+       ModifierData modifier;
+
+       float value;          /* the "raw" bevel value (distance/amount to bevel) */
+       int res;              /* the resolution (as originally coded, it is the number of recursive bevels) */
+       int pad;
+       short flags;          /* general option flags */
+       short val_flags;      /* flags used to interpret the bevel value */
+       short lim_flags;      /* flags to tell the tool how to limit the bevel */
+       short e_flags;        /* flags to direct how edge weights are applied to verts */
+       float bevel_angle;    /* if the BME_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */
+       char defgrp_name[32]; /* if the BME_BEVEL_VWEIGHT option is set, this will be the name of the vert group */
+} BevelModifierData;
+
+typedef struct BMeshModifierData {
+       ModifierData modifier;
+
+       float pad;
+       int type;
+} BMeshModifierData;
+
 typedef struct DisplaceModifierData {
        ModifierData modifier;
 
index e35cc6a04a94a5f0aaab5e80b80df6289107afc9..be6b872774e7006c4ecc822f0eef894516f809e0 100644 (file)
@@ -96,6 +96,7 @@
 #include "BKE_packedFile.h"
 #include "BKE_particle.h"
 #include "BKE_scene.h"
+#include "BKE_bmesh.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_arithb.h"
@@ -1752,6 +1753,10 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                        height = 86;
                } else if (md->type==eModifierType_Mirror) {
                        height = 86;
+               } else if (md->type==eModifierType_Bevel) {
+                       BevelModifierData *bmd = (BevelModifierData*) md;
+                       height = 105; /* height = 124; */
+                       if ((bmd->lim_flags & BME_BEVEL_ANGLE) || ((bmd->lim_flags & BME_BEVEL_WEIGHT) && !(bmd->flags & BME_BEVEL_VERT))) height += 19;
                } else if (md->type==eModifierType_EdgeSplit) {
                        EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
                        height = 48;
@@ -1895,7 +1900,62 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                                       "Ob: ", lx, (cy -= 19), buttonWidth, 19,
                                       &mmd->mirror_ob,
                                       "Object to use as mirror");
-
+               } else if (md->type==eModifierType_Bevel) {
+                       BevelModifierData *bmd = (BevelModifierData*) md;
+                       /*uiDefButS(block, ROW, B_MODIFIER_RECALC, "Distance",
+                                         lx, (cy -= 19), (buttonWidth/2), 19, &bmd->val_flags,
+                                         11.0, 0, 0, 0,
+                                         "Interpret bevel value as a constant distance from each edge");
+                       uiDefButS(block, ROW, B_MODIFIER_RECALC, "Radius",
+                                         (lx+buttonWidth/2), cy, (buttonWidth - buttonWidth/2), 19, &bmd->val_flags,
+                                         11.0, BME_BEVEL_RADIUS, 0, 0,
+                                         "Interpret bevel value as a radius - smaller angles will be beveled more");*/
+                       uiDefButF(block, NUM, B_MODIFIER_RECALC, "Dis",
+                                         lx, (cy -= 19), buttonWidth, 19, &bmd->value,
+                                         0.0, 0.5, 5, 2,
+                                         "Bevel value/amount");
+                       /*uiDefButI(block, NUM, B_MODIFIER_RECALC, "Recurs",
+                                         lx, (cy -= 19), buttonWidth, 19, &bmd->res,
+                                         1, 4, 5, 2,
+                                         "Number of times to bevel");*/
+                       uiDefButBitS(block, TOG, BME_BEVEL_VERT,
+                                         B_MODIFIER_RECALC, "Verts only",
+                                         lx, (cy -= 19), buttonWidth, 19,
+                                         &bmd->flags, 0, 0, 0, 0,
+                                         "Bevel only verts/corners; not edges");
+                       uiDefBut(block, LABEL, 1, "Limit using:",       lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
+                       uiDefButS(block, ROW, B_MODIFIER_RECALC, "None",
+                                         lx, (cy -= 19), (buttonWidth/3), 19, &bmd->lim_flags,
+                                         12.0, 0, 0, 0,
+                                         "Bevel the entire mesh by a constant amount");
+                       uiDefButS(block, ROW, B_MODIFIER_RECALC, "Angle",
+                                         (lx+buttonWidth/3), cy, (buttonWidth/3), 19, &bmd->lim_flags,
+                                         12.0, BME_BEVEL_ANGLE, 0, 0,
+                                         "Only bevel edges with sharp enough angles between faces");
+                       uiDefButS(block, ROW, B_MODIFIER_RECALC, "BevWeight",
+                                         lx+(2*buttonWidth/3), cy, buttonWidth-2*(buttonWidth/3), 19, &bmd->lim_flags,
+                                         12.0, BME_BEVEL_WEIGHT, 0, 0,
+                                         "Use bevel weights to determine how much bevel is applied; apply them separately in vert/edge select mode");
+                       if ((bmd->lim_flags & BME_BEVEL_WEIGHT) && !(bmd->flags & BME_BEVEL_VERT)) {
+                               uiDefButS(block, ROW, B_MODIFIER_RECALC, "Min",
+                                         lx, (cy -= 19), (buttonWidth/3), 19, &bmd->e_flags,
+                                         13.0, BME_BEVEL_EMIN, 0, 0,
+                                         "The sharpest edge's weight is used when weighting a vert");
+                               uiDefButS(block, ROW, B_MODIFIER_RECALC, "Average",
+                                         (lx+buttonWidth/3), cy, (buttonWidth/3), 19, &bmd->e_flags,
+                                         13.0, 0, 0, 0,
+                                         "The edge weights are averaged when weighting a vert");
+                               uiDefButS(block, ROW, B_MODIFIER_RECALC, "Max",
+                                         (lx+2*(buttonWidth/3)), cy, buttonWidth-2*(buttonWidth/3), 19, &bmd->e_flags,
+                                         13.0, BME_BEVEL_EMAX, 0, 0,
+                                         "The largest edge's wieght is used when weighting a vert");
+                       }
+                       else if (bmd->lim_flags & BME_BEVEL_ANGLE) {
+                               uiDefButF(block, NUM, B_MODIFIER_RECALC, "Angle:",
+                                         lx, (cy -= 19), buttonWidth, 19, &bmd->bevel_angle,
+                                         0.0, 180.0, 100, 2,
+                                         "Angle above which to bevel edges");
+                       }
                } else if (md->type==eModifierType_EdgeSplit) {
                        EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
                        uiDefButBitI(block, TOG, MOD_EDGESPLIT_FROMANGLE,
@@ -4788,6 +4848,10 @@ void do_meshbuts(unsigned short event)
                allqueue(REDRAWBUTSEDIT, 0);
                allqueue(REDRAWVIEW3D, 0);
                break;
+       //~ case B_DRAWBWEIGHTS:
+               //~ allqueue(REDRAWBUTSEDIT, 0);
+               //~ allqueue(REDRAWVIEW3D, 0);
+               //~ break;
        case B_JOINTRIA:
                join_triangles();
                break;
@@ -4966,10 +5030,11 @@ static void editing_panel_mesh_tools1(Object *ob, Mesh *me)
        
        uiBlockBeginAlign(block);
        uiDefButBitI(block, TOG, G_DRAWFACES, REDRAWVIEW3D_IMAGE, "Draw Faces",         955,88,150,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades in the 3d view and UV editor");
-       uiDefButBitI(block, TOG, G_DRAWEDGES, REDRAWVIEW3D, "Draw Edges",       955,66,150,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights");
-       uiDefButBitI(block, TOG, G_DRAWCREASES, REDRAWVIEW3D, "Draw Creases",   955,44,150,19, &G.f, 0, 0, 0, 0, "Displays creases created for subsurf weighting");
-       uiDefButBitI(block, TOG, G_DRAWSEAMS, REDRAWVIEW3D, "Draw Seams",       955,22,150,19, &G.f, 0, 0, 0, 0, "Displays UV unwrapping seams");
-       uiDefButBitI(block, TOG, G_DRAWSHARP, REDRAWVIEW3D, "Draw Sharp",       955,0,150,19, &G.f, 0, 0, 0, 0, "Displays sharp edges, used with the EdgeSplit modifier");
+       uiDefButBitI(block, TOG, G_DRAWEDGES, REDRAWVIEW3D, "Draw Edges", 955, 66,150,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights");
+       uiDefButBitI(block, TOG, G_DRAWCREASES, REDRAWVIEW3D, "Draw Creases", 955, 42,150,19, &G.f, 0, 0, 0, 0, "Displays creases created for subsurf weighting");
+       uiDefButBitI(block, TOG, G_DRAWBWEIGHTS, REDRAWVIEW3D, "Draw Bevel Weights", 955, 20,150,19, &G.f, 0, 0, 0, 0, "Displays weights created for the Bevel modifier");
+       uiDefButBitI(block, TOG, G_DRAWSEAMS, REDRAWVIEW3D, "Draw Seams", 955, -2,150,19, &G.f, 0, 0, 0, 0, "Displays UV unwrapping seams");
+       uiDefButBitI(block, TOG, G_DRAWSHARP, REDRAWVIEW3D, "Draw Sharp", 955,  -24,150,19, &G.f, 0, 0, 0, 0, "Displays sharp edges, used with the EdgeSplit modifier");
        uiBlockEndAlign(block);
        
        /* Measurement drawing options */
index 6edb89a10496f6b511976492c0bef583f0c2383b..6375af4d49e07c97a9555c284a5968278f611b85 100644 (file)
@@ -1660,6 +1660,41 @@ static void draw_dm_creases(DerivedMesh *dm)
        glLineWidth(1.0);
 }
 
+static int draw_dm_bweights__setDrawOptions(void *userData, int index)
+{
+       EditEdge *eed = EM_get_edge_for_index(index);
+
+       if (eed->h==0 && eed->bweight!=0.0) {
+               BIF_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
+               return 1;
+       } else {
+               return 0;
+       }
+}
+static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+       EditVert *eve = EM_get_vert_for_index(index);
+
+       if (eve->h==0 && eve->bweight!=0.0) {
+               BIF_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight);
+               bglVertex3fv(co);
+       }
+}
+static void draw_dm_bweights(DerivedMesh *dm)
+{
+       if (G.scene->selectmode & SCE_SELECT_VERTEX) {
+               glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE) + 2);
+               bglBegin(GL_POINTS);
+               dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL);
+               bglEnd();
+       }
+       else {
+               glLineWidth(3.0);
+               dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL);
+               glLineWidth(1.0);
+       }
+}
+
 /* Second section of routines: Combine first sets to form fancy
  * drawing routines (for example rendering twice to get overlays).
  *
@@ -2139,6 +2174,9 @@ static void draw_em_fancy(Object *ob, EditMesh *em, DerivedMesh *cageDM, Derived
                if(G.f & G_DRAWCREASES) {
                        draw_dm_creases(cageDM);
                }
+               if(G.f & G_DRAWBWEIGHTS) {
+                       draw_dm_bweights(cageDM);
+               }
        
                draw_em_fancy_edges(cageDM, 0, eed_act);
        }
index de4bcda157fe864fc5f97983d498cb1f48d02c1e..acb4134a0400cbad6fec1d05c5810a98115e3cb7 100644 (file)
@@ -163,10 +163,13 @@ EditVert *addvertlist(float *vec, EditVert *example)
        createVerseVert(eve);
 #endif
 
-       if(example)
+       if(example) {
                CustomData_em_copy_data(&em->vdata, &em->vdata, example->data, &eve->data);
-       else
+               eve->bweight = example->bweight;
+       }
+       else {
                CustomData_em_set_default(&em->vdata, &eve->data);
+       }
 
        return eve;
 }
@@ -299,6 +302,7 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example)
                   rule is to do this with addedgelist call, before addfacelist */
                if(example) {
                        eed->crease= example->crease;
+                       eed->bweight= example->bweight;
                        eed->sharp = example->sharp;
                        eed->seam = example->seam;
                        eed->h |= (example->h & EM_FGON);
@@ -896,6 +900,8 @@ void make_editMesh()
                eve->no[1]= mvert->no[1]/32767.0;
                eve->no[2]= mvert->no[2]/32767.0;
 
+               eve->bweight= ((float)mvert->bweight)/255.0f;
+
                /* lets overwrite the keyindex of the editvert
                 * with the order it used to be in before
                 * editmode
@@ -915,7 +921,8 @@ void make_editMesh()
                        eed= addedgelist(evlist[medge->v1], evlist[medge->v2], NULL);
                        /* eed can be zero when v1 and v2 are identical, dxf import does this... */
                        if(eed) {
-                               eed->crease= ((float)medge->crease)/255.0;
+                               eed->crease= ((float)medge->crease)/255.0f;
+                               eed->bweight= ((float)medge->bweight)/255.0f;
                                
                                if(medge->flag & ME_SEAM) eed->seam= 1;
                                if(medge->flag & ME_SHARP) eed->sharp = 1;
@@ -1153,7 +1160,8 @@ void load_editMesh(void)
                mvert->flag= 0;
                if(eve->f1==1) mvert->flag |= ME_SPHERETEST;
                mvert->flag |= (eve->f & SELECT);
-               if (eve->h) mvert->flag |= ME_HIDE;                     
+               if (eve->h) mvert->flag |= ME_HIDE;
+               mvert->bweight= (char)(255.0*eve->bweight);
 
 #ifdef WITH_VERSE
                if(eve->vvert) {
@@ -1205,6 +1213,7 @@ void load_editMesh(void)
                if(eed->h & 1) medge->flag |= ME_HIDE;
                
                medge->crease= (char)(255.0*eed->crease);
+               medge->bweight= (char)(255.0*eed->bweight);
                CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);         
 
                eed->tmp.l = a++;
@@ -1926,6 +1935,7 @@ typedef struct EditVertC
        float no[3];
        float co[3];
        unsigned char f, h;
+       short bweight;
        int keyindex;
 } EditVertC;
 
@@ -1933,7 +1943,7 @@ typedef struct EditEdgeC
 {
        int v1, v2;
        unsigned char f, h, seam, sharp, pad;
-       short crease, fgoni;
+       short crease, bweight, fgoni;
 } EditEdgeC;
 
 typedef struct EditFaceC
@@ -2034,6 +2044,7 @@ static void *editMesh_to_undoMesh(void)
                evec->h= eve->h;
                evec->keyindex= eve->keyindex;
                eve->tmp.l = a; /*store index*/
+               evec->bweight= (short)(eve->bweight*255.0);
 
                CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
        }
@@ -2048,6 +2059,7 @@ static void *editMesh_to_undoMesh(void)
                eedc->seam= eed->seam;
                eedc->sharp= eed->sharp;
                eedc->crease= (short)(eed->crease*255.0);
+               eedc->bweight= (short)(eed->bweight*255.0);
                eedc->fgoni= eed->fgoni;
                eed->tmp.l = a; /*store index*/
                CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
@@ -2161,6 +2173,7 @@ static void undoMesh_to_editMesh(void *umv)
                eve->f= evec->f;
                eve->h= evec->h;
                eve->keyindex= evec->keyindex;
+               eve->bweight= ((float)evec->bweight)/255.0f;
 
                CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data);
        }
@@ -2174,7 +2187,8 @@ static void undoMesh_to_editMesh(void *umv)
                eed->seam= eedc->seam;
                eed->sharp= eedc->sharp;
                eed->fgoni= eedc->fgoni;
-               eed->crease= ((float)eedc->crease)/255.0;
+               eed->crease= ((float)eedc->crease)/255.0f;
+               eed->bweight= ((float)eedc->bweight)/255.0f;
                CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
        }
        
index 14b8fe39d4534c5b467cc461fec72cb05a32f90c..a20327dcfac03221360e5adcae2efc37c551dd5b 100644 (file)
@@ -73,6 +73,7 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
 #include "BKE_mesh.h"
 #include "BKE_object.h"
 #include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
 
 #ifdef WITH_VERSE
 #include "BKE_verse.h"
@@ -90,6 +91,7 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
 #include "BIF_resources.h"
 #include "BIF_toolbox.h"
 #include "BIF_transform.h"
+#include "transform.h"
 
 #ifdef WITH_VERSE
 #include "BIF_verse.h"
@@ -3707,6 +3709,7 @@ static void edge_rotate(EditEdge *eed,int dir)
                        srchedge->dir = eed->dir;
                        srchedge->seam = eed->seam;
                        srchedge->crease = eed->crease;
+                       srchedge->bweight = eed->bweight;
                }
        }
        
@@ -4476,7 +4479,52 @@ static void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
        }
 }
 
-void bevel_menu()
+void bevel_menu() {
+       BME_Mesh *bm;
+       BME_TransData_Head *td;
+       TransInfo *t;
+       int options, res, gbm_free = 0;
+
+       t = BIF_GetTransInfo();
+       if (!G.editBMesh) {
+               G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh");
+               gbm_free = 1;
+       }
+
+       G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT;
+       G.editBMesh->res = 1;
+
+       while(G.editBMesh->options & BME_BEVEL_RUNNING) {
+               options = G.editBMesh->options;
+               res = G.editBMesh->res;
+               bm = BME_make_mesh();
+               bm = BME_editmesh_to_bmesh(G.editMesh, bm);
+               BIF_undo_push("Pre-Bevel");
+               free_editMesh(G.editMesh);
+               BME_bevel(bm,0.1f,res,options,0,0,&td);
+               BME_bmesh_to_editmesh(bm, td);
+               G.editBMesh->bm = bm;
+               G.editBMesh->td = td;
+               initTransform(TFM_BEVEL,CTX_BMESH);
+               Transform();
+               BME_free_transdata(td);
+               BME_free_mesh(bm);
+               if (t->state != TRANS_CONFIRM) {
+                       BIF_undo();
+               }
+               if (options == G.editBMesh->options) {
+                       G.editBMesh->options &= ~BME_BEVEL_RUNNING;
+               }
+       }
+
+       if (gbm_free) {
+               MEM_freeN(G.editBMesh);
+               G.editBMesh = NULL;
+       }
+}
+
+
+void bevel_menu_old()
 {
        char Finished = 0, Canceled = 0, str[100], Recalc = 0;
        short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr;
index 34169b428cdaa542321a0d1cb43f82a0e767af4e..7f9a2d02d83315130aafde523264689e17e78b45 100644 (file)
@@ -2688,7 +2688,7 @@ void do_view3d_edit_mesh_edgesmenu(void *arg, int event)
        case 8: /* Clear Seam */
                editmesh_mark_seam(1);
                break;
-       case 9: /* Cease SubSurf */
+       case 9: /* Crease SubSurf */
                if(!multires_level1_test()) {
                        initTransform(TFM_CREASE, CTX_EDGE);
                        Transform();
@@ -2720,6 +2720,12 @@ void do_view3d_edit_mesh_edgesmenu(void *arg, int event)
                BIF_undo_push("Clear Sharp");
                DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
                break;
+       case 17: /* Adjust Bevel Weight */
+               if(!multires_level1_test()) {
+                       initTransform(TFM_BWEIGHT, CTX_EDGE);
+                       Transform();
+               }
+               break;
        }
        allqueue(REDRAWVIEW3D, 0);
 }
@@ -2756,6 +2762,8 @@ static uiBlock *view3d_edit_mesh_edgesmenu(void *arg_unused)
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mark Sharp|Ctrl E",                      0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Sharp|Ctrl E",                     0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
        
+       uiDefBut(block, SEPR, 0, "",                            0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Adjust Bevel Weight|Ctrl Shift E",                       0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
 
        uiDefBut(block, SEPR, 0, "",                            0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Crease SubSurf|Shift E",                 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
index 1994a2fcb7f9d0c2e5daa28c693c8040f3084e30..6dacf38c544a84c9513177803af0e424c8e775ae 100644 (file)
@@ -1896,6 +1896,18 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                                extrude_armature(1);
                                        }
                                }
+                               else if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
+                                       if (G.obedit && G.obedit->type==OB_MESH &&
+                                           !multires_level1_test()) {
+                                               if (G.scene->selectmode & SCE_SELECT_VERTEX) {
+                                                       initTransform(TFM_BWEIGHT, CTX_NONE);
+                                               }
+                                               else {
+                                                       initTransform(TFM_BWEIGHT, CTX_EDGE);
+                                               }
+                                               Transform();
+                                       }
+                               }
                                break;
                        case FKEY:
                                if(G.obedit) {
index 87ca52dcfad67bc720eca3237d11f67290307f70..72d4c418b808cfc0ffb7cadd93cc8b23eedb2dde 100644 (file)
@@ -84,6 +84,7 @@
 #include "BKE_utildefines.h"
 #include "BKE_bad_level_calls.h"/* popmenu and error   */
 #include "BKE_particle.h"
+#include "BKE_bmesh.h"
 
 #include "BSE_drawipo.h"
 #include "BSE_editnla_types.h" /* for NLAWIDTH */
@@ -576,6 +577,10 @@ static char *transform_to_undostr(TransInfo *t)
                        return "Trackball";
                case TFM_PUSHPULL:
                        return "Push/Pull";
+               case TFM_BEVEL:
+                       return "Bevel";
+               case TFM_BWEIGHT:
+                       return "Bevel Weight";
                case TFM_CREASE:
                        return "Crease";
                case TFM_BONESIZE:
@@ -1030,6 +1035,12 @@ void initTransform(int mode, int context) {
        case TFM_MIRROR:
                initMirror(&Trans);
                break;
+       case TFM_BEVEL:
+               initBevel(&Trans);
+               break;
+       case TFM_BWEIGHT:
+               initBevelWeight(&Trans);
+               break;
        }
 }
 
@@ -3232,6 +3243,201 @@ int PushPull(TransInfo *t, short mval[2])
        return 1;
 }
 
+/* ************************** BEVEL **************************** */
+
+void initBevel(TransInfo *t) 
+{
+       t->mode = TFM_BEVEL;
+       t->flag |= T_NO_CONSTRAINT;
+       t->transform = Bevel;
+       t->handleEvent = handleEventBevel;
+       if (G.editBMesh->imval[0] == 0 && G.editBMesh->imval[1] == 0) {
+               /* save the initial mouse co */
+               G.editBMesh->imval[0] = t->imval[0];
+               G.editBMesh->imval[1] = t->imval[1];
+       }
+       else {
+               /* restore the mouse co from a previous call to initTransform() */
+               t->imval[0] = G.editBMesh->imval[0];
+               t->imval[1] = G.editBMesh->imval[1];
+       }
+}
+
+int handleEventBevel(TransInfo *t, unsigned short event, short val)
+{
+       if (val) {
+               switch (event) {
+               case MIDDLEMOUSE:
+                       G.editBMesh->options ^= BME_BEVEL_VERT;
+                       t->state = TRANS_CANCEL;
+                       return 1;
+               //case PADPLUSKEY:
+               //      G.editBMesh->options ^= BME_BEVEL_RES;
+               //      G.editBMesh->res += 1;
+               //      if (G.editBMesh->res > 4) {
+               //              G.editBMesh->res = 4;
+               //      }
+               //      t->state = TRANS_CANCEL;
+               //      return 1;
+               //case PADMINUS:
+               //      G.editBMesh->options ^= BME_BEVEL_RES;
+               //      G.editBMesh->res -= 1;
+               //      if (G.editBMesh->res < 0) {
+               //              G.editBMesh->res = 0;
+               //      }
+               //      t->state = TRANS_CANCEL;
+               //      return 1;
+               default:
+                       return 0;
+               }
+       }
+       return 0;
+}
+
+int Bevel(TransInfo *t, short mval[2])
+{
+       float distance,d;
+       int i;
+       char str[128];
+       char *mode;
+       TransData *td = t->data;
+
+       mode = (G.editBMesh->options & BME_BEVEL_VERT) ? "verts only" : "normal";
+       distance = InputHorizontalAbsolute(t, mval)/4; /* 4 just seemed a nice value to me, nothing special */
+
+       applyNumInput(&t->num, &distance);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               sprintf(str, "Bevel: %s", c);
+       }
+       else {
+               /* default header print */
+               sprintf(str, "Bevel - Dist: %.4f, Mode: %s (MMB to toggle))", distance, mode);
+       }
+       
+       if (distance < 0) distance = -distance;
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->axismtx[1][0] > 0 && distance > td->axismtx[1][0]) {
+                       d = td->axismtx[1][0];
+               }
+               else {
+                       d = distance;
+               }
+               VECADDFAC(td->loc,td->center,td->axismtx[0],(*td->val)*d);
+       }
+
+       recalcData(t);
+
+       headerprint(str);
+
+       viewRedrawForce(t);
+
+       return 1;
+}
+
+/* ************************** BEVEL WEIGHT *************************** */
+
+void initBevelWeight(TransInfo *t) 
+{
+       t->mode = TFM_BWEIGHT;
+       t->transform = BevelWeight;
+       
+       t->idx_max = 0;
+       t->num.idx_max = 0;
+       t->snap[0] = 0.0f;
+       t->snap[1] = 0.1f;
+       t->snap[2] = t->snap[1] * 0.1f;
+       
+       t->flag |= T_NO_CONSTRAINT;
+
+       t->fac = (float)sqrt(
+               (
+                       ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+               +
+                       ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+               ) );
+
+       if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
+}
+
+int BevelWeight(TransInfo *t, short mval[2]) 
+{
+       TransData *td = t->data;
+       float weight;
+       int i;
+       char str[50];
+
+               
+       if(t->flag & T_SHIFT_MOD) {
+               /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+               float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+               float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+               weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
+               
+               dx= (float)(t->center2d[0] - mval[0]);
+               dy= (float)(t->center2d[1] - mval[1]);
+               weight+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -weight);
+               
+       }
+       else {
+               float dx= (float)(t->center2d[0] - mval[0]);
+               float dy= (float)(t->center2d[1] - mval[1]);
+               weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
+       }
+
+       weight -= 1.0f;
+       if (weight > 1.0f) weight = 1.0f;
+
+       snapGrid(t, &weight);
+
+       applyNumInput(&t->num, &weight);
+
+       /* header print for NumInput */
+       if (hasNumInput(&t->num)) {
+               char c[20];
+
+               outputNumInput(&(t->num), c);
+
+               if (weight >= 0.0f)
+                       sprintf(str, "Bevel Weight: +%s %s", c, t->proptext);
+               else
+                       sprintf(str, "Bevel Weight: %s %s", c, t->proptext);
+       }
+       else {
+               /* default header print */
+               if (weight >= 0.0f)
+                       sprintf(str, "Bevel Weight: +%.3f %s", weight, t->proptext);
+               else
+                       sprintf(str, "Bevel Weight: %.3f %s", weight, t->proptext);
+       }
+       
+       for(i = 0 ; i < t->total; i++, td++) {
+               if (td->flag & TD_NOACTION)
+                       break;
+
+               if (td->val) {
+                       *td->val = td->ival + weight * td->factor;
+                       if (*td->val < 0.0f) *td->val = 0.0f;
+                       if (*td->val > 1.0f) *td->val = 1.0f;
+               }
+       }
+
+       recalcData(t);
+
+       headerprint(str);
+
+       viewRedrawForce(t);
+
+       helpline (t, t->center);
+
+       return 1;
+}
+
 /* ************************** CREASE *************************** */
 
 void initCrease(TransInfo *t)