-> Bevel tools and Bmesh kernel

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.
This commit is contained in:
Geoffrey Bantle
2008-02-23 22:11:16 +00:00
parent 40934ef6df
commit e03ab146ae
23 changed files with 4560 additions and 16 deletions

View File

@@ -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

View 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

View File

@@ -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;
}

View File

@@ -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
*/

View File

@@ -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!");
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View 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;

View 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;

View 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;

View 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);

View 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

View 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]);

View 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

View 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;

View 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 */

View 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);
}

View 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);
}

View 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;

View 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, "");

View 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) {

View 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)