remove files no longer used since bmesh merge.

This commit is contained in:
Campbell Barton
2012-02-19 19:27:06 +00:00
parent b2956ecd00
commit b1a3d3cea1
10 changed files with 0 additions and 5790 deletions

View File

@@ -58,12 +58,6 @@ set(INC_SYS
)
set(SRC
intern/BME_Customdata.c
intern/BME_conversions.c
intern/BME_eulers.c
intern/BME_mesh.c
intern/BME_structure.c
intern/BME_tools.c
intern/CCGSubSurf.c
intern/DerivedMesh.c
intern/action.c

View File

@@ -1,200 +0,0 @@
#if 0
/**
* BME_customdata.c jan 2007
*
* Custom Data functions for Bmesh
*
*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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, Brecht Van Lommel, Ben Batt
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_Customdata.c
* \ingroup bke
*/
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BKE_bmeshCustomData.h"
#include "bmesh_private.h"
/********************* Layer type information **********************/
typedef struct BME_LayerTypeInfo {
int size;
const char *defaultname;
void (*copy)(const void *source, void *dest, int count);
void (*free)(void *data, int count, int size);
void (*interp)(void **sources, float *weights, float *sub_weights, int count, void *dest);
void (*set_default)(void *data, int count);
} BME_LayerTypeInfo;
const BME_LayerTypeInfo BMELAYERTYPEINFO[BME_CD_NUMTYPES] = {
{sizeof(BME_facetex), "TexFace", NULL, NULL, NULL, NULL},
{sizeof(BME_looptex), "UV", NULL, NULL, NULL, NULL},
{sizeof(BME_loopcol), "VCol", NULL, NULL, NULL, NULL},
{sizeof(BME_DeformVert), "Group", NULL, NULL, NULL, NULL}
};
static const BME_LayerTypeInfo *BME_layerType_getInfo(int type)
{
if(type < 0 || type >= CD_NUMTYPES) return NULL;
return &BMELAYERTYPEINFO[type];
}
void BME_CD_Create(BME_CustomData *data, BME_CustomDataInit *init, int initalloc)
{
int i, j, offset=0;
const BME_LayerTypeInfo *info;
/*initialize data members*/
data->layers = NULL;
data->pool = NULL;
data->totlayer = 0;
data->totsize = 0;
/*first count how many layers to alloc*/
for(i=0; i < BME_CD_NUMTYPES; i++){
info = BME_layerType_getInfo(i);
data->totlayer += init->layout[i];
data->totsize += (init->layout[i] * info->size);
}
/*alloc our layers*/
if(data->totlayer){
/*alloc memory*/
data->layers = MEM_callocN(sizeof(BME_CustomDataLayer)*data->totlayer, "BMesh Custom Data Layers");
data->pool = BLI_mempool_create(data->totsize, initalloc, initalloc, TRUE);
/*initialize layer data*/
for(i=0; i < BME_CD_NUMTYPES; i++){
if(init->layout[i]){
info = BME_layerType_getInfo(i);
for(j=0; j < init->layout[i]; j++){
if(j==0) data->layers[j+i].active = init->active[i];
data->layers[j+i].type = i;
data->layers[j+i].offset = offset;
strcpy(data->layers[j+i].name, &(init->nametemplate[j+i]));
offset += info->size;
}
}
}
}
}
void BME_CD_Free(BME_CustomData *data)
{
if(data->pool) BLI_mempool_destroy(data->pool);
}
/*Block level ops*/
void BME_CD_free_block(BME_CustomData *data, void **block)
{
const BME_LayerTypeInfo *typeInfo;
int i;
if(!*block) return;
for(i = 0; i < data->totlayer; ++i) {
typeInfo = BME_layerType_getInfo(data->layers[i].type);
if(typeInfo->free) {
int offset = data->layers[i].offset;
typeInfo->free((char*)*block + offset, 1, typeInfo->size);
}
}
BLI_mempool_free(data->pool, *block);
*block = NULL;
}
static void BME_CD_alloc_block(BME_CustomData *data, void **block)
{
if (*block) BME_CD_free_block(data, block); //if we copy layers that have their own free functions like deformverts
if (data->totsize > 0)
*block = BLI_mempool_alloc(data->pool);
else
*block = NULL;
}
void BME_CD_copy_data(const BME_CustomData *source, BME_CustomData *dest,
void *src_block, void **dest_block)
{
const BME_LayerTypeInfo *typeInfo;
int dest_i, src_i;
if (!*dest_block) /*for addXXXlist functions!*/
BME_CD_alloc_block(dest, dest_block);
/* copies a layer at a time */
dest_i = 0;
for(src_i = 0; src_i < source->totlayer; ++src_i) {
/* find the first dest layer with type >= the source type
* (this should work because layers are ordered by type)
*/
while(dest_i < dest->totlayer
&& dest->layers[dest_i].type < source->layers[src_i].type)
++dest_i;
/* if there are no more dest layers, we're done */
if(dest_i >= dest->totlayer) return;
/* if we found a matching layer, copy the data */
if(dest->layers[dest_i].type == source->layers[src_i].type &&
strcmp(dest->layers[dest_i].name, source->layers[src_i].name) == 0) {
char *src_data = (char*)src_block + source->layers[src_i].offset;
char *dest_data = (char*)*dest_block + dest->layers[dest_i].offset;
typeInfo = BME_layerType_getInfo(source->layers[src_i].type);
if(typeInfo->copy)
typeInfo->copy(src_data, dest_data, 1);
else
memcpy(dest_data, src_data, typeInfo->size);
/* if there are multiple source & dest layers of the same type,
* we don't want to copy all source layers to the same dest, so
* increment dest_i
*/
++dest_i;
}
}
}
void BME_CD_set_default(BME_CustomData *data, void **block)
{
const BME_LayerTypeInfo *typeInfo;
int i;
if (!*block)
BME_CD_alloc_block(data, block); //for addXXXlist functions...
for(i = 0; i < data->totlayer; ++i) {
int offset = data->layers[i].offset;
typeInfo = BME_layerType_getInfo(data->layers[i].type);
if(typeInfo->set_default)
typeInfo->set_default((char*)*block + offset, 1);
}
}
#endif

View File

@@ -1,651 +0,0 @@
#if 0
/**
* BME_mesh.c jan 2007
*
* BMesh mesh level functions.
*
*
* ***** BEGIN GPL 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.
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_conversions.c
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_edgehash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_mesh.h"
#include "BKE_cdderivedmesh.h"
//XXX #include "BIF_editmesh.h"
//XXX #include "editmesh.h"
#include "bmesh_private.h"
//XXX #include "BSE_edit.h"
/* XXX IMPORTANT: editmesh stuff doesn't belong in kernel! (ton) */
/*merge these functions*/
static void BME_DMcorners_to_loops(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f, int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i< numTex; i++){
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texpoly->tpage = texface[index].tpage;
texpoly->flag = texface[index].flag;
texpoly->transp = texface[index].transp;
texpoly->mode = texface[index].mode;
texpoly->tile = texface[index].tile;
texpoly->unwrap = texface[index].unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
mloopuv->uv[0] = texface[index].uv[j][0];
mloopuv->uv[1] = texface[index].uv[j][1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_get_layer_n(facedata, CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mloopcol->r = mcol[(index*4)+j].r;
mloopcol->g = mcol[(index*4)+j].g;
mloopcol->b = mcol[(index*4)+j].b;
mloopcol->a = mcol[(index*4)+j].a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
static void BME_DMloops_to_corners(BME_Mesh *bm, CustomData *facedata, int index, BME_Poly *f,int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i < numTex; i++){
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texface[index].tpage = texpoly->tpage;
texface[index].flag = texpoly->flag;
texface[index].transp = texpoly->transp;
texface[index].mode = texpoly->mode;
texface[index].tile = texpoly->tile;
texface[index].unwrap = texpoly->unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
texface[index].uv[j][0] = mloopuv->uv[0];
texface[index].uv[j][1] = mloopuv->uv[1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_get_layer_n(facedata,CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mcol[(index*4) + j].r = mloopcol->r;
mcol[(index*4) + j].g = mloopcol->g;
mcol[(index*4) + j].b = mloopcol->b;
mcol[(index*4) + j].a = mloopcol->a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
static void BME_corners_to_loops(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i < numTex; i++){
texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texpoly->tpage = texface->tpage;
texpoly->flag = texface->flag;
texpoly->transp = texface->transp;
texpoly->mode = texface->mode;
texpoly->tile = texface->tile;
texpoly->unwrap = texface->unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
mloopuv->uv[0] = texface->uv[j][0];
mloopuv->uv[1] = texface->uv[j][1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mloopcol->r = mcol[j].r;
mloopcol->g = mcol[j].g;
mloopcol->b = mcol[j].b;
mloopcol->a = mcol[j].a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
static void BME_loops_to_corners(BME_Mesh *bm, CustomData *facedata, void *face_block, BME_Poly *f,int numCol, int numTex){
int i, j;
BME_Loop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i < numTex; i++){
texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texface->tpage = texpoly->tpage;
texface->flag = texpoly->flag;
texface->transp = texpoly->transp;
texface->mode = texpoly->mode;
texface->tile = texpoly->tile;
texface->unwrap = texpoly->unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
texface->uv[j][0] = mloopuv->uv[0];
texface->uv[j][1] = mloopuv->uv[1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mcol[j].r = mloopcol->r;
mcol[j].g = mloopcol->g;
mcol[j].b = mloopcol->b;
mcol[j].a = mloopcol->a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
/*move the EditMesh conversion functions to editmesh_tools.c*/
BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) {
BME_Mesh *bm;
int allocsize[4] = {512,512,2048,512}, numTex, numCol;
BME_Vert *v1, *v2;
BME_Edge *e, *edar[4];
BME_Poly *f;
EditVert *eve;
EditEdge *eed;
EditFace *efa;
int len;
bm = BME_make_mesh(allocsize);
/*copy custom data layout*/
CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
/*needed later*/
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
BME_model_begin(bm);
/*add verts*/
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;
/*Copy Custom Data*/
CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v1->data);
eve->tmp.v = (EditVert*)v1;
eve = eve->next;
}
/*add edges*/
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;
//XXX if(eed->h & EM_FGON) e->flag |= ME_FGON;
if(eed->h & 1) e->flag |= ME_HIDE;
eed->tmp.e = (EditEdge*)e;
CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->data);
eed = eed->next;
}
/*add faces.*/
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_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->data);
BME_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
efa = efa->next;
}
BME_model_end(bm);
return bm;
}
/* adds the geometry in the bmesh to editMesh (does not free editMesh)
* if td != NULL, the transdata will be mapped to the EditVert's co */
void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) {
BME_Vert *v1;
BME_Edge *e;
BME_Poly *f;
BME_TransData *vtd;
EditVert *eve1, /* *eve2, *eve3, *eve4, */ /* UNUSED */ **evlist;
EditEdge *eed;
EditFace *efa;
int totvert, len, i, numTex, numCol;
if (em == NULL) return;
CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0);
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
/* convert to EditMesh */
/* make editverts */
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 = NULL; //XXX 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 */
for (e=bm->edges.first;e;e=e->next) {
if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){
eed= NULL; //XXX 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;
//XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
if(e->flag & ME_HIDE) eed->h |= 1;
if(em->selectmode==SCE_SELECT_EDGE) {
; //XXX EM_select_edge(eed, eed->f & SELECT);
}
CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data);
}
}
/* make faces */
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]; */ /* UNUSED */
/* eve3= evlist[f->loopbase->next->next->v->tflag1]; */ /* UNUSED */
/* if (len == 4) {
eve4= evlist[f->loopbase->prev->v->tflag1];
}
else {
eve4= NULL;
} */ /* UNUSED */
efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL);
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;
// XXX flag depricated
// if((G.f & G_FACESELECT) && (efa->f & SELECT))
//XXX EM_select_face(efa, 1); /* flush down */
CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex);
}
}
MEM_freeN(evlist);
}
/* Adds the geometry found in dm to bm
*/
BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
{
BME_Mesh *bm;
int allocsize[4] = {512,512,2048,512};
MVert *mvert, *mv;
MEdge *medge, *me;
MFace *mface, *mf;
int totface,totedge,totvert,i,len, numTex, numCol;
BME_Vert *v1=NULL,*v2=NULL, **vert_array;
BME_Edge *e=NULL;
BME_Poly *f=NULL;
EdgeHash *edge_hash = BLI_edgehash_new();
bm = BME_make_mesh(allocsize);
/*copy custom data layout*/
CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata, 0, 0);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
/*needed later*/
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
totface = dm->getNumTessFaces(dm);
mvert = dm->getVertArray(dm);
medge = dm->getEdgeArray(dm);
mface = dm->getTessFaceArray(dm);
vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array");
BME_model_begin(bm);
/*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_bmesh_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_bmesh_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_bmesh_block(&dm->faceData,&bm->pdata,i,&f->data);
BME_DMcorners_to_loops(bm, &dm->faceData,i,f, numCol,numTex);
}
BME_model_end(bm);
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 *origindex;
int totface, totedge, totvert, i, /* bmeshok, */ /* UNUSED */ len, numTex, numCol;
BME_Vert *v1=NULL;
BME_Edge *e=NULL, *oe=NULL;
BME_Poly *f=NULL;
DerivedMesh *result;
EdgeHash *edge_hash = BLI_edgehash_new();
totvert = BLI_countlist(&(bm->verts));
totedge = 0;
/*we cannot have double edges in a derived mesh!*/
for(i=0, v1=bm->verts.first; v1; v1=v1->next, i++) v1->tflag1 = i;
for(e=bm->edges.first; e; e=e->next){
oe = BLI_edgehash_lookup(edge_hash,e->v1->tflag1, e->v2->tflag1);
if(!oe){
totedge++;
BLI_edgehash_insert(edge_hash,e->v1->tflag1,e->v2->tflag1,e);
e->tflag2 = 1;
}
else{
e->tflag2 = 0;
}
}
/*count quads and tris*/
totface = 0;
/* bmeshok = 1; */ /* UNUSED */
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*/
/*BMESH_TODO this should add in mloops and mpolys as well*/
result = CDDM_from_template(dm,totvert,totedge,totface, 0, 0);
CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
/*Make Verts*/
mvert = CDDM_get_verts(result);
origindex = result->getVertDataArray(result, CD_ORIGINDEX);
for(i=0,v1=bm->verts.first,mv=mvert;v1;v1=v1->next,i++,mv++){
VECCOPY(mv->co,v1->co);
mv->flag = (unsigned char)v1->flag;
mv->bweight = (char)(255.0*v1->bweight);
CustomData_from_bmesh_block(&bm->vdata, &result->vertData, &v1->data, i);
origindex[i] = ORIGINDEX_NONE;
}
medge = CDDM_get_edges(result);
origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
i=0;
for(e=bm->edges.first,me=medge;e;e=e->next){
if(e->tflag2){
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_bmesh_block(&bm->edata, &result->edgeData, &e->data, i);
origindex[i] = ORIGINDEX_NONE;
me++;
i++;
}
}
if(totface){
mface = CDDM_get_tessfaces(result);
origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
/*make faces*/
for(i=0,f=bm->polys.first;f;f=f->next){
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_bmesh_block(&bm->pdata, &result->faceData, &f->data, i);
BME_DMloops_to_corners(bm, &result->faceData, i, f,numCol,numTex);
origindex[i] = ORIGINDEX_NONE;
i++;
}
}
}
BLI_edgehash_free(edge_hash, NULL);
return result;
}
#endif

View File

@@ -1,975 +0,0 @@
#if 0
/**
* BME_eulers.c jan 2007
*
* BMesh Euler construction API.
*
*
* ***** BEGIN GPL 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.
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_eulers.c
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "bmesh_private.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 NULL;
#ifndef BME_FASTEULER
/*count valance of v1*/
if(v1->e){
d1 = BME_disk_getpointer(v1->e,v1);
if(d1) valance1 = BME_cycle_length(d1);
else BME_error();
}
if(v2->e){
d2 = BME_disk_getpointer(v2->e,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, **vlist;
int i, j, done, cont, edok;
if(len < 2) return NULL;
/*make sure that v1 and v2 are in elist[0]*/
if(BME_verts_in_edge(v1,v2,elist[0]) == 0) return 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]->l->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 NULL;
edok = BME_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
if(edok != 2) return NULL;
}
/*set start edge, start vert and target vert for our loop traversal*/
curedge = elist[0];
tv = v1;
curvert = v2;
if(bm->vtarlen < len){
MEM_freeN(bm->vtar);
bm->vtar = MEM_callocN(sizeof(BME_Vert *)* len, "BMesh Vert pointer array");
bm->vtarlen = len;
}
/*insert tv into vlist since its the first vertex in face*/
i=0;
vlist=bm->vtar;
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->lbase = l;
BME_cycle_append(f->lbase, 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->lbase);
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();
}
}
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->e == 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->l == 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->lbase);
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->lbase->next;
oldbase = bply->lbase;
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, edok, valance1=0, valance2=0;
if(BME_vert_in_edge(e,tv) == 0) return 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->e,ov);
edok = BME_cycle_validate(valance1, diskbase);
if(!edok) BME_error();
diskbase = BME_disk_getpointer(tv->e,tv);
edok = BME_cycle_validate(valance2, diskbase);
if(!edok) BME_error();
diskbase = BME_disk_getpointer(nv->e,nv);
edok = BME_cycle_validate(2, diskbase);
if(!edok) BME_error();
/*Split the radial cycle if present*/
if(e->l){
BME_Loop *nl,*l;
BME_CycleNode *radEBase=NULL, *radNEBase=NULL;
int radlen = BME_cycle_length(&(e->l->radial));
/*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
while(e->l){
l=e->l;
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->l = radEBase->data;
ne->l = radNEBase->data;
/*verify length of radial cycle*/
edok = BME_cycle_validate(radlen,&(e->l->radial));
if(!edok) BME_error();
edok = BME_cycle_validate(radlen,&(ne->l->radial));
if(!edok) BME_error();
/*verify loop->v and loop->next->v pointers for e*/
for(i=0,l=e->l; i < radlen; i++, l = l->radial_next){
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->lbase);
if(!edok) BME_error();
}
/*verify loop->v and loop->next->v pointers for ne*/
for(i=0,l=ne->l; i < radlen; i++, l = l->radial_next){
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->lbase);
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;
/*verify that v1 and v2 are in face.*/
len = BME_cycle_length(f->lbase);
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 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,v2loop);
f2loop = BME_create_loop(bm,v1,e,f2,v1loop);
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->lbase);
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->lbase);
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->e, 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->e, ov);
valance1 = BME_cycle_length(diskbase);
diskbase = BME_disk_getpointer(tv->e, 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->l){
/*first step, fix the neighboring loops of all loops in ke's radial cycle*/
radlen = BME_cycle_length(&(ke->l->radial));
for(i=0,killoop = ke->l; 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->lbase = killoop->next;
}
/*second step, remove all the hanging loops attached to ke*/
killoop = ke->l;
radlen = BME_cycle_length(&(ke->l->radial));
/*make sure we have enough room in bm->lpar*/
if(bm->lparlen < radlen){
MEM_freeN(bm->lpar);
bm->lpar = MEM_callocN(sizeof(BME_Loop *)* radlen, "BMesh Loop pointer array");
bm->lparlen = bm->lparlen * radlen;
}
/*this should be wrapped into a bme_free_radial function to be used by BME_KF as well...*/
i=0;
while(i<radlen){
bm->lpar[i] = killoop;
killoop = killoop->radial_next;
i++;
}
i=0;
while(i<radlen){
BME_free_loop(bm,bm->lpar[i]);
i++;
}
/*Validate radial cycle of oe*/
edok = BME_cycle_validate(radlen,&(oe->l->radial));
}
/*Validate disk cycles*/
diskbase = BME_disk_getpointer(ov->e,ov);
edok = BME_cycle_validate(valance1, diskbase);
if(!edok) BME_error();
diskbase = BME_disk_getpointer(tv->e,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->l; i<radlen; i++, nextl = BME_radial_nextloop(nextl)){
edok = BME_cycle_validate(nextl->f->len,nextl->f->lbase);
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;
int i, j, edok, len = 0;
len = BME_cycle_length(l);
if(bm->edarlen < len){
MEM_freeN(bm->edar);
bm->edar = MEM_callocN(sizeof(BME_Edge *)* len, "BMesh Edge pointer array");
bm->edarlen = len;
}
for(i=0, curloop = l; i< len; i++, curloop=curloop->next){
curloop->e->eflag1 = 0;
curloop->e->eflag2 = BME_cycle_length(&curloop->radial);
BME_radial_remove_loop(curloop, curloop->e);
/*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
curloop->radial.next = curloop->radial.prev = NULL;
bm->edar[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 = bm->edar[1];
l->next->e = bm->edar[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, bm->edar[j]);
if(edok){
curloop->e = bm->edar[j];
break;
}
}
}
}
/*rebuild radial*/
for(i=0, curloop = l; i < len; i++, curloop = curloop->next) BME_radial_append(curloop->e, curloop);
/*validate radial*/
for(i=0, curloop = l; i < len; i++, curloop = curloop->next){
edok = BME_cycle_validate(curloop->e->eflag2, &(curloop->radial));
if(!edok){
BME_error();
}
}
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, edok;
if(f1 == f2) return NULL; //can't join a face to itself
/*verify that e is in both f1 and f2*/
f1len = BME_cycle_length(f1->lbase);
f2len = BME_cycle_length(f2->lbase);
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 NULL;
/*validate that edge is 2-manifold edge*/
radlen = BME_cycle_length(&(f1loop->radial));
if(radlen != 2) return NULL;
/*validate direction of f2's loop cycle is compatible.*/
if(f1loop->v == f2loop->v) return 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 NULL;
if(BME_radial_find_face(f1loop->prev->e,f2)) return NULL;
if(BME_radial_find_face(f2loop->next->e,f1)) return NULL;
if(BME_radial_find_face(f2loop->prev->e,f1)) return 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->lbase = f1loop->next;
/*validate the new loop*/
loopok = BME_cycle_validate((f1len+f2len)-2, f1->lbase);
if(!loopok) BME_error();
/*make sure each loop points to the proper face*/
newlen = BME_cycle_length(f1->lbase);
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->lbase);
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;
}
#endif

View File

@@ -1,287 +0,0 @@
#if 0
/**
* BME_mesh.c jan 2007
*
* BMesh mesh level functions.
*
*
* ***** BEGIN GPL 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.
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_mesh.c
* \ingroup bke
*/
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
#include "BKE_bmesh.h"
#include "bmesh_private.h"
/*
* BME MAKE MESH
*
* Allocates a new BME_Mesh structure.
* Returns -
* Pointer to a Bmesh
*
*/
BME_Mesh *BME_make_mesh(int allocsize[4])
{
/*allocate the structure*/
BME_Mesh *bm = MEM_callocN(sizeof(BME_Mesh),"BMesh");
/*allocate the memory pools for the mesh elements*/
bm->vpool = BLI_mempool_create(sizeof(BME_Vert), allocsize[0], allocsize[0], TRUE, FALSE);
bm->epool = BLI_mempool_create(sizeof(BME_Edge), allocsize[1], allocsize[1], TRUE, FALSE);
bm->lpool = BLI_mempool_create(sizeof(BME_Loop), allocsize[2], allocsize[2], TRUE, FALSE);
bm->ppool = BLI_mempool_create(sizeof(BME_Poly), allocsize[3], allocsize[3], TRUE, FALSE);
return bm;
}
/*
* BME FREE MESH
*
* Frees a BME_Mesh structure.
*/
void BME_free_mesh(BME_Mesh *bm)
{
BME_Vert *v;
BME_Edge *e;
BME_Loop *l;
BME_Poly *f;
for(v=bm->verts.first; v; v=v->next) CustomData_bmesh_free_block(&bm->vdata, &v->data);
for(e=bm->edges.first; e; e=e->next) CustomData_bmesh_free_block(&bm->edata, &e->data);
for(f=bm->polys.first; f; f=f->next){
CustomData_bmesh_free_block(&bm->pdata, &f->data);
l = f->loopbase;
do{
CustomData_bmesh_free_block(&bm->ldata, &l->data);
l = l->next;
}while(l!=f->lbase);
}
/*Free custom data pools, This should probably go in CustomData_free?*/
if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
/*free custom data*/
CustomData_free(&bm->vdata,0);
CustomData_free(&bm->edata,0);
CustomData_free(&bm->ldata,0);
CustomData_free(&bm->pdata,0);
/*destroy element pools*/
BLI_mempool_destroy(bm->vpool);
BLI_mempool_destroy(bm->epool);
BLI_mempool_destroy(bm->ppool);
BLI_mempool_destroy(bm->lpool);
MEM_freeN(bm);
}
/*
* 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.
*
* The purpose of these calls is allow for housekeeping tasks to be performed,
* such as allocating/freeing scratch arrays or performing debug validation of
* the mesh structure.
*
* Returns -
* Nothing
*
*/
int BME_model_begin(BME_Mesh *bm){
/*Initialize some scratch pointer arrays used by eulers*/
bm->vtar = MEM_callocN(sizeof(BME_Vert *) * 1024, "BMesh scratch vert array");
bm->edar = MEM_callocN(sizeof(BME_Edge *) * 1024, "BMesh scratch edge array");
bm->lpar = MEM_callocN(sizeof(BME_Loop *) * 1024, "BMesh scratch loop array");
bm->plar = MEM_callocN(sizeof(BME_Poly *) * 1024, "BMesh scratch poly array");
bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024;
return 1;
}
void BME_model_end(BME_Mesh *bm){
int meshok, totvert, totedge, totpoly;
totvert = BLI_countlist(&(bm->verts));
totedge = BLI_countlist(&(bm->edges));
totpoly = BLI_countlist(&(bm->polys));
if(bm->vtar) MEM_freeN(bm->vtar);
if(bm->edar) MEM_freeN(bm->edar);
if(bm->lpar) MEM_freeN(bm->lpar);
if(bm->plar) MEM_freeN(bm->plar);
bm->vtar = NULL;
bm->edar = NULL;
bm->lpar = NULL;
bm->plar = NULL;
bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0;
if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totpoly!=totpoly)
BME_error();
meshok = BME_validate_mesh(bm, 1);
if(!meshok){
BME_error();
}
}
/*
* 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
*
* -Make this only part of debug builds
*/
#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->l->e*/
if(e->l){
if(e->l->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->e pointer*/
if(v->tflag1){
if(v->e){
ok = BME_vert_in_edge(v->e,v);
if(!ok) VHALT(halt);
/*validate length of disk cycle*/
diskbase = BME_disk_getpointer(v->e, 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->e; 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->lbase);
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->l poitner*/
if(l->e->l == NULL) VHALT(halt);
/*validate l->f pointer*/
if(l->f != f) VHALT(halt);
/*see if l->e->l is actually in radial cycle*/
l->e->tflag2++;
}
}
/*validate length of radial cycle*/
for(e=bm->edges.first; e; e=e->next){
if(e->l){
ok = BME_cycle_validate(e->tflag2,&(e->l->radial));
if(!ok) VHALT(halt);
}
}
/*validate that EIDs are within range... if not indicates corrupted mem*/
/*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!");
}
#endif

View File

@@ -1,631 +0,0 @@
#if 0
/**
* BME_structure.c jan 2007
*
* Low level routines for manipulating the BMesh structure.
*
*
* ***** BEGIN GPL 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.
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
*/
#if 0
/** \file blender/blenkernel/intern/BME_structure.c
* \ingroup bke
*/
#include <limits.h>
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_bmesh.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 = BLI_mempool_alloc(bm->vpool);
v->next = v->prev = NULL;
v->EID = bm->nextv;
v->co[0] = v->co[1] = v->co[2] = 0.0f;
v->no[0] = v->no[1] = v->no[2] = 0.0f;
v->e = NULL;
v->data = NULL;
v->eflag1 = v->eflag2 = v->tflag1 = v->tflag2 = 0;
v->flag = v->h = 0;
v->bweight = 0.0f;
BLI_addtail(&(bm->verts), v);
bm->nextv++;
bm->totvert++;
if(example){
VECCOPY(v->co,example->co);
CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->data, &v->data);
}
else
CustomData_bmesh_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 = BLI_mempool_alloc(bm->epool);
e->next = e->prev = NULL;
e->EID = bm->nexte;
e->v1 = v1;
e->v2 = v2;
e->d1.next = e->d1.prev = e->d2.next = e->d2.prev = NULL;
e->d1.data = e;
e->d2.data = e;
e->l = NULL;
e->data = NULL;
e->eflag1 = e->eflag2 = e->tflag1 = e->tflag2 = 0;
e->flag = e->h = 0;
e->crease = e->bweight = 0.0f;
bm->nexte++;
bm->totedge++;
BLI_addtail(&(bm->edges), e);
if(example)
CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->data, &e->data);
else
CustomData_bmesh_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){
BME_Loop *l=NULL;
l = BLI_mempool_alloc(bm->lpool);
l->next = l->prev = NULL;
l->EID = bm->nextl;
l->radial.next = l->radial.prev = NULL;
l->radial.data = l;
l->v = v;
l->e = e;
l->f = f;
l->data = NULL;
l->eflag1 = l->eflag2 = l->tflag1 = l->tflag2 = 0;
l->flag = l->h = 0; //stupid waste!
bm->nextl++;
bm->totloop++;
if(example)
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, example->data, &l->data);
else
CustomData_bmesh_set_default(&bm->ldata, &l->data);
return l;
}
BME_Poly *BME_addpolylist(BME_Mesh *bm, BME_Poly *example){
BME_Poly *f = NULL;
f = BLI_mempool_alloc(bm->ppool);
f->next = f->prev = NULL;
f->EID = bm->nextp;
f->loopbase = NULL;
f->len = 0;
f->data = NULL;
f->eflag1 = f->eflag2 = f->tflag1 = f->tflag2 = 0;
f->flag = f->h = f->mat_nr;
BLI_addtail(&(bm->polys),f);
bm->nextp++;
bm->totpoly++;
if(example)
CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->data, &f->data);
else
CustomData_bmesh_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_bmesh_free_block(&bm->vdata, &v->data);
BLI_mempool_free(bm->vpool, v);
}
void BME_free_edge(BME_Mesh *bm, BME_Edge *e){
bm->totedge--;
CustomData_bmesh_free_block(&bm->edata, &e->data);
BLI_mempool_free(bm->epool, e);
}
void BME_free_poly(BME_Mesh *bm, BME_Poly *f){
bm->totpoly--;
CustomData_bmesh_free_block(&bm->pdata, &f->data);
BLI_mempool_free(bm->ppool, f);
}
void BME_free_loop(BME_Mesh *bm, BME_Loop *l){
bm->totloop--;
CustomData_bmesh_free_block(&bm->ldata, &l->data);
BLI_mempool_free(bm->lpool, 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->l->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->lbase.
*
* 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->e == NULL){
v->e = 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->e*/
base = BME_disk_getpointer(v->e, 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->e, v);
remnode = BME_disk_getpointer(e, v);
/*first deal with v->e pointer...*/
len = BME_cycle_length(base);
if(len == 1) newbase = NULL;
else if(v->e == e) newbase = base->next-> data;
else newbase = v->e;
/*remove and rebase*/
BME_cycle_remove(base, remnode);
v->e = 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; */ /* UNUSED */
BME_Edge *curedge;
int /* len, */ /* UNUSED */ ok;
if(eflag && tflag) return NULL;
ok = BME_vert_in_edge(e,v);
if(ok){
/* diskbase = BME_disk_getpointer(e, v); */ /* UNUSED */
/* len = BME_cycle_length(diskbase); */ /* UNUSED */
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->e){
if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/
diskbase = BME_disk_getpointer(v->e, v);
len = BME_cycle_length(diskbase);
for(i = 0, curedge=v->e; 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->e){
diskbase = BME_disk_getpointer(v->e,v);
len = BME_cycle_length(diskbase);
for(i = 0, curedge=v->e; 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);
}
void BME_radial_append(BME_Edge *e, BME_Loop *l){
if(e->l == NULL) e->l = l;
BME_cycle_append(&(e->l->radial), &(l->radial));
}
void BME_radial_remove_loop(BME_Loop *l, BME_Edge *e)
{
BME_Loop *newbase;
int len;
/*deal with edge->l pointer*/
len = BME_cycle_length(&(e->l->radial));
if(len == 1) newbase = NULL;
else if(e->l == l) newbase = e->l->radial_next;
else newbase = e->l;
/*remove and rebase*/
BME_cycle_remove(&(e->l->radial), &(l->radial));
e->l = newbase;
}
int BME_radial_find_face(BME_Edge *e,BME_Poly *f)
{
BME_Loop *curloop;
int i, len;
len = BME_cycle_length(&(e->l->radial));
for(i = 0, curloop = e->l; i < len; i++, curloop = curloop->radial_next){
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->lbase);
for (i = 0, l=f->loopbase; i < len; i++, l=l->next) {
if (l->v == v) return l;
}
return NULL;
}
#endif
#endif

View File

@@ -1,1345 +0,0 @@
#if 0
/**
* BME_tools.c jan 2007
*
* Functions for changing the topology of a mesh.
*
*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/BME_tools.c
* \ingroup bke
*/
#include <math.h>
#include "MEM_guardedalloc.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BKE_bmesh.h"
/*split this all into a seperate bevel.c file in src*/
/* ------- 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, "BME_init_transdata gh");
td->ma = BLI_memarena_new(bufsize, "BME_TransData arena");
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) {
copy_v3_v3(vtd->co, co);
}
if (org == NULL && is_new) {
copy_v3_v3(vtd->org, v->co); /* default */
}
else if (org != NULL) {
copy_v3_v3(vtd->org,org);
}
if (vec != NULL) {
copy_v3_v3(vtd->vec,vec);
normalize_v3(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));
}
static int BME_is_nonmanifold_vert(BME_Mesh *UNUSED(bm), BME_Vert *v) {
BME_Edge *e, *oe;
BME_Loop *l;
int len, count, flag;
if (v->e == NULL) {
/* loose vert */
return 1;
}
/* count edges while looking for non-manifold edges */
oe = v->e;
for (len=0,e=v->e; e != oe || (e == oe && len == 0); len++,e=BME_disk_nextedge(e,v)) {
if (e->l == NULL) {
/* loose edge */
return 1;
}
if (BME_cycle_length(&(e->l->radial)) > 2) {
/* edge shared by more than two faces */
return 1;
}
}
count = 1;
flag = 1;
e = NULL;
oe = v->e;
l = oe->l;
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 == l) {
/* we've hit the edge of an open mesh, reset once */
flag = 0;
count = 1;
oe = e;
e = NULL;
l = oe->l;
}
else if (l->radial_next == l) {
/* break the loop */
e = oe;
}
else {
l = l->radial_next;
}
}
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 */
static BME_Poly *BME_JFKE_safe(BME_Mesh *bm, BME_Poly *f1, BME_Poly *f2, BME_Edge *e) {
BME_Loop *l1, *l2;
l1 = e->l;
l2 = l1->radial_next;
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 */
static 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 && (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;
}
#if 0
static void BME_data_interp_from_verts(BME_Mesh *bm, BME_Vert *v1, BME_Vert *v2, BME_Vert *v, float fac)
{
void *src[2];
float w[2];
if (v1->data && v2->data) {
src[0]= v1->data;
src[1]= v2->data;
w[0] = 1.0f-fac;
w[1] = fac;
CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->data);
}
}
#endif
static void BME_data_facevert_edgesplit(BME_Mesh *bm, BME_Vert *v1, BME_Vert *UNUSED(v2), BME_Vert *v, BME_Edge *e1, float fac){
void *src[2];
float w[2];
BME_Loop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
w[0] = 1.0f - fac;
w[1] = fac;
if(!e1->l) return;
l = e1->l;
do{
if(l->v == v1){
v1loop = l;
vloop = v1loop->next;
v2loop = vloop->next;
}else if(l->v == v){
v1loop = l->next;
vloop = l;
v2loop = l->prev;
}
src[0] = v1loop->data;
src[1] = v2loop->data;
CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->data);
l = l->radial_next;
}while(l!=e1->l);
}
/* a wrapper for BME_SEMV that transfers element flags */ /*add custom data interpolation in here!*/
static 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 = len_v3(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;
}
/*v->nv->v2*/
BME_data_facevert_edgesplit(bm,v2, v, nv, e, 0.75);
return nv;
}
static void BME_collapse_vert(BME_Mesh *bm, BME_Edge *ke, BME_Vert *kv, float fac){
void *src[2];
float w[2];
BME_Loop *l=NULL, *kvloop=NULL, *tvloop=NULL;
BME_Vert *tv = BME_edge_getothervert(ke,kv);
w[0] = 1.0f - fac;
w[1] = fac;
if(ke->l){
l = ke->l;
do{
if(l->v == tv && l->next->v == kv){
tvloop = l;
kvloop = l->next;
src[0] = kvloop->data;
src[1] = tvloop->data;
CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, kvloop->data);
}
l=l->radial_next;
}while(l!=ke->l);
}
BME_JEKV(bm,ke,kv);
}
static 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 */
static 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 (compare_v3v3(vtd1->org,vtd2->org,0.000001f)) {
sub_v3_v3v3(vec, v2->co, v1->co);
if (len_v3(vec) < 0.000001f) {
zero_v3(vec);
}
return 0;
}
else {
sub_v3_v3v3(vec,vtd2->org,vtd1->org);
if (len_v3(vec) < 0.000001f) {
zero_v3(vec);
}
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 */
static float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *UNUSED(td))
{
float factor, vec3[3], tmp[3],c1,c2;
cross_v3_v3v3(tmp,vec1,vec2);
normalize_v3(tmp);
factor = dot_v3v3(up_vec,tmp);
if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) {
cross_v3_v3v3(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */
}
else {
cross_v3_v3v3(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */
}
normalize_v3(vec3);
c1 = dot_v3v3(vec3,vec1);
c2 = dot_v3v3(vec1,vec1);
if (fabsf(c1) < 0.000001f || fabsf(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. */
static BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, BME_Loop *l, float *up_vec, float value, BME_TransData_Head *td) {
BME_TransData *vtd, *vtd1 /* , *vtd2 */ /* UNUSED */;
BME_Vert *sv, *v2, *v3 /* , *ov */ /* UNUSED */;
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 */ /* UNUSED */;
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; */ /* UNUSED */
if (v->e == NULL) {
//printf("We can't split a loose vert's edge!\n");
return NULL;
}
e1 = v->e; /* we just use the first two edges */
e2 = BME_disk_nextedge(v->e, 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;
}
/* ov = BME_edge_getothervert(e1,v); */ /* UNUSED */
sv = BME_split_edge(bm,v,e1,&ne,0);
//BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
//BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
//BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
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);
cross_v3_v3v3(t_up_vec,vec1,vec2);
normalize_v3(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; */ /* UNUSED */
sv = v1;
if (forward) v1 = l->next->next->v;
else v1 = l->prev->v;
}
else {
/* is_split_vert = 0; */ /* UNUSED */
/* ov = BME_edge_getothervert(l->e,v); */ /* UNUSED */
sv = BME_split_edge(bm,v,l->e,&ne,0);
//BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
//BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
//BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
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 = len_v3(vec1);
normalize_v3(vec1);
vtd = BME_get_transdata(td, sv);
vtd1 = BME_get_transdata(td, v);
/* vtd2 = BME_get_transdata(td,v1); */ /* UNUSED */
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;
}
madd_v3_v3v3fl(sv->co, v->co, vec1, dis);
sub_v3_v3v3(vec1, sv->co, vtd1->org);
dis = len_v3(vec1);
normalize_v3(vec1);
BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max);
return sv;
}
static 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 {
copy_v3_v3(vec2, vtd1->vec);
mul_v3_fl(vec2, vtd1->factor);
if (dot_v3v3(vec1, vec1)) {
project_v3_v3v3(vec2, vec2,vec1);
fac1 = len_v3(vec2) / value;
}
else {
fac1 = 0;
}
}
if (vtd2->loc == NULL) {
fac2 = 0;
}
else {
copy_v3_v3(vec3, vtd2->vec);
mul_v3_fl(vec3, vtd2->factor);
if (dot_v3v3(vec1, vec1)) {
project_v3_v3v3(vec2, vec3, vec1);
fac2 = len_v3(vec2) / value;
}
else {
fac2 = 0;
}
}
if (fac1 || fac2) {
max = len_v3(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;
}
static BME_Vert *BME_bevel_wire(BME_Mesh *bm, BME_Vert *v, float value, int res, int UNUSED(options), BME_TransData_Head *td) {
BME_Vert *ov1, *ov2, *v1, *v2;
ov1 = BME_edge_getothervert(v->e, v);
ov2 = BME_edge_getothervert(BME_disk_nextedge(v->e, 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->e,v);
}
return v1;
}
static BME_Loop *BME_bevel_edge(BME_Mesh *bm, BME_Loop *l, float value, int UNUSED(options), float *up_vec, BME_TransData_Head *td) {
BME_Vert *v1, *v2, *kv;
BME_Loop *kl=NULL, *nl;
BME_Edge *e;
BME_Poly *f;
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;
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)->f,kl->f,kl->prev->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//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)->f,kl->f,kl->next->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//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;
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)->f,kl->f,kl->prev->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//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)->f,kl->f,kl->next->e);
BME_collapse_vert(bm, kl->e, kv, 1.0);
//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;
}
if (l->f != f){
//printf("Whoops! You got something out of order in BME_bevel_edge()!\n");
}
return l;
}
static BME_Loop *BME_bevel_vert(BME_Mesh *bm, BME_Loop *l, float value, int UNUSED(options), float *up_vec, BME_TransData_Head *td) {
BME_Vert *v1, *v2;
/* BME_Poly *f; */ /* UNUSED */
/* 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 = */ /* UNUSED */ 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.
*/
static 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);
cross_v3_v3v3(vec3, vec2, vec1);
add_v3_v3(up_vec, vec3);
i++;
}
mul_v3_fl(up_vec,1.0f/i);
normalize_v3(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 {
copy_v3_v3(vec2,vtd1->vec);
mul_v3_fl(vec2,vtd1->factor);
if (dot_v3v3(vec1, vec1)) {
project_v3_v3v3(vec2,vec2,vec1);
fac1 = len_v3(vec2)/value;
}
else {
fac1 = 0;
}
}
if (vtd2->loc == NULL) {
fac2 = 0;
}
else {
copy_v3_v3(vec3,vtd2->vec);
mul_v3_fl(vec3,vtd2->factor);
if (dot_v3v3(vec1, vec1)) {
project_v3_v3v3(vec2,vec3,vec1);
fac2 = len_v3(vec2)/value;
}
else {
fac2 = 0;
}
}
if (fac1 || fac2) {
max = len_v3(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;
}
static 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);
}
}
static float BME_bevel_get_angle(BME_Mesh *UNUSED(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->l;
l2 = e->l->radial_next;
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);
cross_v3_v3v3(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);
cross_v3_v3v3(vec4,vec2,vec1);
normalize_v3(vec3);
normalize_v3(vec4);
return dot_v3v3(vec3,vec4);
}
static int BME_face_sharededges(BME_Poly *f1, BME_Poly *f2){
BME_Loop *l;
int count = 0;
l = f1->loopbase;
do{
if(BME_radial_find_face(l->e,f2)) count++;
l = l->next;
}while(l != f1->lbase);
return count;
}
/**
* 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.
*/
static BME_Mesh *BME_bevel_initialize(BME_Mesh *bm, int options, int UNUSED(defgrp_index), float angle, BME_TransData_Head *td) {
BME_Vert *v;
BME_Edge *e;
BME_Poly *f;
/* BME_TransData *vtd; */ /* UNUSED */
/* MDeformVert *dvert; */ /* UNUSED */
/* MDeformWeight *dw; */ /* UNUSED */
int len;
float weight, threshold;
/* vert pass */
for (v=bm->verts.first; v; v=v->next) {
/* dvert = NULL; */ /* UNUSED */
/* dw = NULL; */ /* UNUSED */
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->e == NULL) {
len = 0;
}
else {
len = BME_cycle_length(BME_disk_getpointer(v->e,v));
/* we'll assign a default transform data to every vert (except the loose ones) */
/* vtd = */ /* UNUSED */ 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 = */ /* UNUSED */ 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 = */ /* UNUSED */ 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.001) * 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->l == NULL) {
len = 0;
e->v1->tflag1 |= BME_BEVEL_NONMAN;
e->v2->tflag1 |= BME_BEVEL_NONMAN;
}
else {
len = BME_cycle_length(&(e->l->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;
/*clean up edges with 2 faces that share more than one edge*/
for (e=bm->edges.first; e; e=e->next){
if(e->tflag1 & BME_BEVEL_BEVEL){
int count = 0;
count = BME_face_sharededges(e->l->f, ((BME_Loop*)e->l->radial_next)->f);
if(count > 1){
e->tflag1 &= ~BME_BEVEL_BEVEL;
}
}
}
return bm;
}
/* tags all elements as originals */
static 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.
*/
static void bmesh_dissolve_disk(BME_Mesh *bm, BME_Vert *v){
BME_Poly *f;
BME_Edge *e;
int done, len;
if(v->e){
done = 0;
while(!done){
done = 1;
e = v->e; /*loop the edge looking for a edge to dissolve*/
do{
f = NULL;
len = BME_cycle_length(&(e->l->radial));
if(len == 2){
f = BME_JFKE_safe(bm,e->l->f, ((BME_Loop*)(e->l->radial_next))->f, e);
}
if(f){
done = 0;
break;
}
e = BME_disk_nextedge(e,v);
}while(e != v->e);
}
BME_collapse_vert(bm, v->e, v, 1.0);
//BME_JEKV(bm,v->e,v);
}
}
static BME_Mesh *BME_bevel_mesh(BME_Mesh *bm, float value, int res, int options, int UNUSED(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))) {
int count = 0;
/* first, make sure we're not sitting on an edge to be removed */
oe = v->e;
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)) ) {
count++;
/* join the faces (we'll split them later) */
f = BME_JFKE_safe(bm,e->l->f,((BME_Loop*)e->l->radial_next)->f,e);
if (!f){
//printf("Non-manifold geometry not getting tagged right?\n");
}
}
/*need to do double check *before* you bevel to make sure that manifold edges are for two faces that share only *one* edge to make sure it doesnt hang here!*/
/* 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->e, v));
for (i=0,e=v->e; i < len; i++,e=BME_disk_nextedge(e,v)) {
l = e->l;
l2 = l->radial_next;
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;
}
}
}
bmesh_dissolve_disk(bm, v);
}
v = nv;
}
return bm;
}
static 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;
}
/*Main bevel function:
Should be only one exported
*/
/* 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_model_begin(bm);
BME_bevel_mesh(bm,d,res,options,defgrp_index,td);
BME_model_end(bm);
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;
}
madd_v3_v3v3fl(v->co,vtd->org,vtd->vec,vtd->factor*d);
}
v->tflag1 = 0;
}
BME_free_transdata(td);
return bm;
}
#endif

View File

@@ -94,7 +94,6 @@ set(SRC
intern/bmesh_polygon.c
intern/bmesh_queries.c
intern/bmesh_opdefines.c
intern/bmesh_eulers.c
intern/bmesh_operators.c
intern/bmesh_private.h
intern/bmesh_walkers.c

View File

@@ -1,1215 +0,0 @@
/*some of this may come back, such as split face or split edge, if necassary for speed*/
#if 0
/*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
*/
/** \file blender/bmesh/intern/bmesh_eulers.c
* \ingroup bmesh
*
* BM Euler construction API.
*/
#include "MEM_guardedalloc.h"
#include "DNA_listBase.h"
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "BKE_customdata.h"
#include "BKE_utildefines.h"
#include "bmesh.h"
#include "bmesh_private.h"
#include "BLI_blenlib.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 BM 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 bmesh_loop_reverse, which is its own inverse).
bmesh_MF/KF: Make Face and Kill Face
bmesh_ME/KE: Make Edge and Kill Edge
bmesh_MV/KV: Make Vert and Kill Vert
bmesh_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
bmesh_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
bmesh_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.
BMESH_TODO:
-Make seperate 'debug levels' of validation
-Add in the UnglueFaceRegionMakeVert and GlueFaceRegionKillVert eulers.
NOTE:
-The functions in this file are notoriously difficult to debug and even understand sometimes.
better code comments would be nice....
*/
/*MAKE Eulers*/
/**
* bmesh_MV
*
* MAKE VERT EULER:
*
* Makes a single loose vertex.
*
* Returns -
* A BMVert pointer.
*/
BMVert *bmesh_mv(BMesh *bm, const float vec[3])
{
BMVert *v = bmesh_addvertlist(bm, NULL);
copy_v3_v3(v->co,vec);
return v;
}
/**
* bmesh_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 BMEdge pointer.
*/
BMEdge *bmesh_me(BMesh *bm, BMVert *v1, BMVert *v2)
{
BMEdge *e=NULL;
BMNode *d1=NULL, *d2=NULL;
int valance1=0, valance2=0, edok;
/*edge must be between two distinct vertices...*/
if(v1 == v2) return NULL;
#ifndef bmesh_FASTEULER
/*count valance of v1*/
if(v1->e) {
d1 = bmesh_disk_getpointer(v1->e,v1);
if(d1) valance1 = bmesh_cycle_length(d1);
else bmesh_error();
}
if(v2->e) {
d2 = bmesh_disk_getpointer(v2->e,v2);
if(d2) valance2 = bmesh_cycle_length(d2);
else bmesh_error();
}
#endif
/*go ahead and add*/
e = bmesh_addedgelist(bm, v1, v2, NULL);
bmesh_disk_append_edge(e, e->v1);
bmesh_disk_append_edge(e, e->v2);
#ifndef bmesh_FASTEULER
/*verify disk cycle lengths*/
d1 = bmesh_disk_getpointer(e, e->v1);
edok = bmesh_cycle_validate(valance1+1, d1);
if(!edok) bmesh_error();
d2 = bmesh_disk_getpointer(e, e->v2);
edok = bmesh_cycle_validate(valance2+1, d2);
if(!edok) bmesh_error();
/*verify that edge actually made it into the cycle*/
edok = bmesh_disk_hasedge(v1, e);
if(!edok) bmesh_error();
edok = bmesh_disk_hasedge(v2, e);
if(!edok) bmesh_error();
#endif
return e;
}
/**
* bmesh_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 BMFace pointer
*/
#define MF_CANDIDATE 1
#define MF_VISITED 2
#define MF_TAKEN 4
BMFace *bmesh_mf(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **elist, int len)
{
BMFace *f = NULL;
BMEdge *curedge;
BMVert *curvert, *tv, **vlist;
int i, j, done, cont, edok;
if(len < 2) return NULL;
/*make sure that v1 and v2 are in elist[0]*/
//if(bmesh_verts_in_edge(v1,v2,elist[0]) == 0)
// return NULL;
/*clear euler flags*/
for(i=0;i<len;i++) {
BMNode *diskbase;
BMEdge *curedge;
BMVert *v1;
int j;
for (j=0; j<2; j++) {
int a, len=0;
v1 = j ? elist[i]->v2 : elist[i]->v1;
diskbase = bmesh_disk_getpointer(v1->e, v1);
len = bmesh_cycle_length(diskbase);
for(a=0,curedge=v1->e;a<len;a++,curedge = bmesh_disk_nextedge(curedge,v1)) {
curedge->head.eflag1 = curedge->head.eflag2 = 0;
}
}
}
for(i=0;i<len;i++) {
elist[i]->head.eflag1 |= MF_CANDIDATE;
/*if elist[i] has a loop, count its radial length*/
if(elist[i]->loop) elist[i]->head.eflag2 = bmesh_cycle_length(&(elist[i]->l->radial));
else elist[i]->head.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 = bmesh_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
// if(edok != 2) return NULL;
// edok = bmesh_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
// if(edok != 2) return NULL;
// }
/*set start edge, start vert and target vert for our loop traversal*/
curedge = elist[0];
tv = v1;
curvert = v2;
if(bm->vtarlen < len) {
if (bm->vtar) MEM_freeN(bm->vtar);
bm->vtar = MEM_callocN(sizeof(BMVert *)* len, "BM Vert pointer array");
bm->vtarlen = len;
}
/*insert tv into vlist since its the first vertex in face*/
i=0;
vlist=bm->vtar;
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->head.eflag1 |= MF_VISITED;
/*find next edge and vert*/
curedge = bmesh_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
curvert = bmesh_edge_getothervert(curedge, curvert);
if(curvert == tv) {
curedge->head.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]->head.eflag1 & MF_VISITED) == 0) cont = 0;
// }
/*if we get this far, its ok to allocate the face and add the loops*/
if(cont) {
BMLoop *l;
BMEdge *e;
f = bmesh_addpolylist(bm, NULL);
f->len = len;
for(i=0;i<len;i++) {
curvert = vlist[i];
l = bmesh_create_loop(bm,curvert,NULL,f,NULL);
if(!(f->loopbase)) f->lbase = l;
bmesh_cycle_append(f->lbase, 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 = bmesh_verts_in_edge(l->v, ((l->next))->v, elist[j]);
if(edok) {
e = elist[j];
break;
}
}
}
l->e = e; /*set pointer*/
bmesh_radial_append(e, l); /*append into radial*/
}
f->len = len;
/*Validation Loop cycle*/
edok = bmesh_cycle_validate(len, f->lbase);
if(!edok) bmesh_error();
for(i=0, l = f->loopbase; i<len; i++, l=((l->next))) {
/*validate loop vert pointers*/
edok = bmesh_verts_in_edge(l->v, ((l->next))->v, l->e);
if(!edok) bmesh_error();
/*validate the radial cycle of each edge*/
edok = bmesh_cycle_length(&(l->radial));
if(edok != (l->e->head.eflag2 + 1)) bmesh_error();
}
}
for(i=0;i<len;i++) elist[i]->head.eflag1=elist[i]->head.eflag2 = 0;
return f;
}
/* KILL Eulers */
/**
* bmesh_KV
*
* KILL VERT EULER:
*
* Kills a single loose vertex.
*
* Returns -
* 1 for success, 0 for failure.
*/
int bmesh_kv(BMesh *bm, BMVert *v)
{
if(v->e == NULL) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) bm->totvertsel--;
BLI_remlink(&(bm->verts), &(v->head));
bmesh_free_vert(bm,v);
return 1;
}
return 0;
}
/**
* bmesh_KE
*
* KILL EDGE EULER:
*
* Kills a wire edge.
*
* Returns -
* 1 for success, 0 for failure.
*/
int bmesh_ke(BMesh *bm, BMEdge *e)
{
int edok;
/*Make sure that no faces!*/
if(e->l == NULL) {
bmesh_disk_remove_edge(e, e->v1);
bmesh_disk_remove_edge(e, e->v2);
/*verify that edge out of disk*/
edok = bmesh_disk_hasedge(e->v1, e);
if(edok) bmesh_error();
edok = bmesh_disk_hasedge(e->v2, e);
if(edok) bmesh_error();
/*remove and deallocate*/
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel--;
BLI_remlink(&(bm->edges), &(e->head));
bmesh_free_edge(bm, e);
return 1;
}
return 0;
}
/**
* bmesh_KF
*
* KILL FACE EULER:
*
* The logical inverse of bmesh_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 bmesh_kf(BMesh *bm, BMFace *bply)
{
BMLoop *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 = bmesh_cycle_length(bply->lbase);
for(i=0, curloop=bply->loopbase; i < len; i++, curloop = ((curloop->next)))
bmesh_radial_remove_loop(curloop, curloop->e);
/*now deallocate the editloops*/
for(i=0; i < len; i++) {
newbase = ((bply->lbase->next));
oldbase = bply->lbase;
bmesh_cycle_remove(oldbase, oldbase);
bmesh_free_loop(bm, oldbase);
bply->loopbase = newbase;
}
if (BM_elem_flag_test(bply, BM_ELEM_SELECT)) bm->totfacesel--;
BLI_remlink(&(bm->polys), &(bply->head));
bmesh_free_poly(bm, bply);
return 1;
}
/*SPLIT Eulers*/
/**
* bmesh_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 -
* BMVert pointer.
*
*/
BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **re)
{
BMVert *nv, *ov;
BMNode *diskbase;
BMEdge *ne;
int i, edok, valance1=0, valance2=0;
if(bmesh_vert_in_edge(e,tv) == 0) return NULL;
ov = bmesh_edge_getothervert(e,tv);
//v2 = tv;
/*count valance of v1*/
diskbase = bmesh_disk_getpointer(e, ov);
valance1 = bmesh_cycle_length(diskbase);
/*count valance of v2*/
diskbase = bmesh_disk_getpointer(e, tv);
valance2 = bmesh_cycle_length(diskbase);
nv = bmesh_addvertlist(bm, tv);
ne = bmesh_addedgelist(bm, nv, tv, e);
//e->v2 = nv;
/*remove e from v2's disk cycle*/
bmesh_disk_remove_edge(e, tv);
/*swap out tv for nv in e*/
bmesh_edge_swapverts(e, tv, nv);
/*add e to nv's disk cycle*/
bmesh_disk_append_edge(e, nv);
/*add ne to nv's disk cycle*/
bmesh_disk_append_edge(ne, nv);
/*add ne to tv's disk cycle*/
bmesh_disk_append_edge(ne, tv);
/*verify disk cycles*/
diskbase = bmesh_disk_getpointer(ov->e,ov);
edok = bmesh_cycle_validate(valance1, diskbase);
if(!edok) bmesh_error();
diskbase = bmesh_disk_getpointer(tv->e,tv);
edok = bmesh_cycle_validate(valance2, diskbase);
if(!edok) bmesh_error();
diskbase = bmesh_disk_getpointer(nv->e,nv);
edok = bmesh_cycle_validate(2, diskbase);
if(!edok) bmesh_error();
/*Split the radial cycle if present*/
if(e->l) {
BMLoop *nl,*l;
BMNode *radEBase=NULL, *radNEBase=NULL;
int radlen = bmesh_cycle_length(&(e->l->radial));
/*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
while(e->l) {
l=e->l;
l->f->len++;
bmesh_radial_remove_loop(l,e);
nl = bmesh_create_loop(bm,NULL,NULL,l->f,l);
nl->prev = (BMHeader*)l;
nl->next = (BMHeader*)(l->next);
nl->prev->next = (BMHeader*)nl;
nl->next->prev = (BMHeader*)nl;
nl->v = nv;
/*assign the correct edge to the correct loop*/
if(bmesh_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;
}
bmesh_cycle_append(radEBase,&(nl->radial));
bmesh_cycle_append(radNEBase,&(l->radial));
}
else if(bmesh_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;
}
bmesh_cycle_append(radEBase,&(l->radial));
bmesh_cycle_append(radNEBase,&(nl->radial));
}
}
e->l = radEBase->data;
ne->l = radNEBase->data;
/*verify length of radial cycle*/
edok = bmesh_cycle_validate(radlen,&(e->l->radial));
if(!edok) bmesh_error();
edok = bmesh_cycle_validate(radlen,&(ne->l->radial));
if(!edok) bmesh_error();
/*verify loop->v and loop->next->v pointers for e*/
for(i=0,l=e->l; i < radlen; i++, l = l->radial_next) {
if(!(l->e == e)) bmesh_error();
if(!(l->radial.data == l)) bmesh_error();
if( ((l->prev))->e != ne && ((l->next))->e != ne) bmesh_error();
edok = bmesh_verts_in_edge(l->v, ((l->next))->v, e);
if(!edok) bmesh_error();
if(l->v == ((l->next))->v) bmesh_error();
if(l->e == ((l->next))->e) bmesh_error();
/*verify loop cycle for kloop->f*/
edok = bmesh_cycle_validate(l->f->len, l->f->lbase);
if(!edok) bmesh_error();
}
/*verify loop->v and loop->next->v pointers for ne*/
for(i=0,l=ne->l; i < radlen; i++, l = l->radial_next) {
if(!(l->e == ne)) bmesh_error();
if(!(l->radial.data == l)) bmesh_error();
if( ((l->prev))->e != e && ((l->next))->e != e) bmesh_error();
edok = bmesh_verts_in_edge(l->v, ((l->next))->v, ne);
if(!edok) bmesh_error();
if(l->v == ((l->next))->v) bmesh_error();
if(l->e == ((l->next))->e) bmesh_error();
/*verify loop cycle for kloop->f. Redundant*/
edok = bmesh_cycle_validate(l->f->len, l->f->lbase);
if(!edok) bmesh_error();
}
}
if(re) *re = ne;
return nv;
}
/**
* bmesh_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.
*
* Note that the tesselator abuses eflag2 while using this euler! (don't ever ever do this....)
*
* Returns -
* A BMFace pointer
*/
BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **rl)
{
BMFace *f2;
BMLoop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
BMEdge *e;
int i, len, f1len, f2len;
/*verify that v1 and v2 are in face.*/
len = bmesh_cycle_length(f->lbase);
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 NULL;
/*allocate new edge between v1 and v2*/
e = bmesh_addedgelist(bm, v1, v2,NULL);
bmesh_disk_append_edge(e, v1);
bmesh_disk_append_edge(e, v2);
f2 = bmesh_addpolylist(bm,f);
f1loop = bmesh_create_loop(bm,v2,e,f,v2loop);
f2loop = bmesh_create_loop(bm,v1,e,f2,v1loop);
f1loop->prev = v2loop->prev;
f2loop->prev = v1loop->prev;
v2loop->prev->next = (BMHeader*)f1loop;
v1loop->prev->next = (BMHeader*)f2loop;
f1loop->next = (BMHeader*)v1loop;
f2loop->next = (BMHeader*)v2loop;
v1loop->prev = (BMHeader*)f1loop;
v2loop->prev = (BMHeader*)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 = bmesh_cycle_length(f2->lbase);
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*/
bmesh_radial_append(e, f1loop);
bmesh_radial_append(e, f2loop);
f2->len = f2len;
f1len = bmesh_cycle_length(f->lbase);
f->len = f1len;
if(rl) *rl = f2loop;
return f2;
}
/**
* bmesh_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 bmesh_jekv(BMesh *bm, BMEdge *ke, BMVert *kv)
{
BMEdge *oe;
BMVert *ov, *tv;
BMNode *diskbase;
BMLoop *killoop,*nextl;
int len,radlen=0, halt = 0, i, valance1, valance2,edok;
if(bmesh_vert_in_edge(ke,kv) == 0) return 0;
diskbase = bmesh_disk_getpointer(kv->e, kv);
len = bmesh_cycle_length(diskbase);
if(len == 2) {
oe = bmesh_disk_nextedge(ke, kv);
tv = bmesh_edge_getothervert(ke, kv);
ov = bmesh_edge_getothervert(oe, kv);
halt = bmesh_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 = bmesh_disk_getpointer(ov->e, ov);
valance1 = bmesh_cycle_length(diskbase);
diskbase = bmesh_disk_getpointer(tv->e, tv);
valance2 = bmesh_cycle_length(diskbase);
/*remove oe from kv's disk cycle*/
bmesh_disk_remove_edge(oe,kv);
/*relink oe->kv to be oe->tv*/
bmesh_edge_swapverts(oe, kv, tv);
/*append oe to tv's disk cycle*/
bmesh_disk_append_edge(oe, tv);
/*remove ke from tv's disk cycle*/
bmesh_disk_remove_edge(ke, tv);
/*deal with radial cycle of ke*/
if(ke->l) {
/*first step, fix the neighboring loops of all loops in ke's radial cycle*/
radlen = bmesh_cycle_length(&(ke->l->radial));
for(i=0,killoop = ke->l; i<radlen; i++, killoop = bmesh_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->lbase = ((killoop->next));
}
/*second step, remove all the hanging loops attached to ke*/
killoop = ke->l;
radlen = bmesh_cycle_length(&(ke->l->radial));
/*make sure we have enough room in bm->lpar*/
if(bm->lparlen < radlen) {
MEM_freeN(bm->lpar);
bm->lpar = MEM_callocN(sizeof(BMLoop *)* radlen, "BM Loop pointer array");
bm->lparlen = bm->lparlen * radlen;
}
/*this should be wrapped into a bme_free_radial function to be used by bmesh_KF as well...*/
i=0;
while(i<radlen) {
bm->lpar[i] = killoop;
killoop = killoop->radial_next;
i++;
}
i=0;
while(i<radlen) {
bmesh_free_loop(bm,bm->lpar[i]);
i++;
}
/*Validate radial cycle of oe*/
edok = bmesh_cycle_validate(radlen,&(oe->l->radial));
}
/*Validate disk cycles*/
diskbase = bmesh_disk_getpointer(ov->e,ov);
edok = bmesh_cycle_validate(valance1, diskbase);
if(!edok) bmesh_error();
diskbase = bmesh_disk_getpointer(tv->e,tv);
edok = bmesh_cycle_validate(valance2, diskbase);
if(!edok) bmesh_error();
/*Validate loop cycle of all faces attached to oe*/
for(i=0,nextl = oe->l; i<radlen; i++, nextl = bmesh_radial_nextloop(nextl)) {
edok = bmesh_cycle_validate(nextl->f->len,nextl->f->lbase);
if(!edok) bmesh_error();
}
/*deallocate edge*/
BLI_remlink(&(bm->edges), &(ke->head));
bmesh_free_edge(bm, ke);
/*deallocate vertex*/
BLI_remlink(&(bm->verts), &(kv->head));
bmesh_free_vert(bm, kv);
return 1;
}
}
return 0;
}
/**
* bmesh_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.
*
* BMESH_TODO: reinsert validation code.
*
* Returns -
* 1 for success, 0 for failure.
*/
int bmesh_loop_reverse(BMesh *bm, BMFace *f)
{
BMLoop *l = f->loopbase, *curloop, *oldprev, *oldnext;
int i, j, edok, len = 0;
len = bmesh_cycle_length(l);
if(bm->edarlen < len) {
MEM_freeN(bm->edar);
bm->edar = MEM_callocN(sizeof(BMEdge *)* len, "BM Edge pointer array");
bm->edarlen = len;
}
for(i=0, curloop = l; i< len; i++, curloop= ((curloop->next)) ) {
curloop->e->head.eflag1 = 0;
curloop->e->head.eflag2 = bmesh_cycle_length(&curloop->radial);
bmesh_radial_remove_loop(curloop, curloop->e);
/*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
curloop->radial.next = curloop->radial.prev = NULL;
bm->edar[i] = curloop->e;
}
/*actually reverse the loop. This belongs in bmesh_cycle_reverse!*/
for(i=0, curloop = l; i < len; i++) {
oldnext = ((curloop->next));
oldprev = ((curloop->prev));
curloop->next = (BMHeader*)oldprev;
curloop->prev = (BMHeader*)oldnext;
curloop = oldnext;
}
if(len == 2) { //two edged face
//do some verification here!
l->e = bm->edar[1];
((l->next))->e = bm->edar[0];
}
else {
for(i=0, curloop = l; i < len; i++, curloop = ((curloop->next)) ) {
edok = 0;
for(j=0; j < len; j++) {
edok = bmesh_verts_in_edge(curloop->v, ((curloop->next))->v, bm->edar[j]);
if(edok) {
curloop->e = bm->edar[j];
break;
}
}
}
}
/*rebuild radial*/
for(i=0, curloop = l; i < len; i++, curloop = curloop->next ) bmesh_radial_append(curloop->e, curloop);
/*validate radial*/
for(i=0, curloop = l; i < len; i++, curloop = ((curloop->next)) ) {
edok = bmesh_cycle_validate(curloop->e->head.eflag2, &(curloop->radial));
if(!edok) {
bmesh_error();
}
}
return 1;
}
/**
* bmesh_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 bmesh_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 BMFace pointer
*/
//disregarding f1loop and f2loop, if a vertex appears in a joined face more than once, we cancel
BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
{
BMLoop *curloop, *f1loop=NULL, *f2loop=NULL;
int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok, shared;
if(f1 == f2) return NULL; //can't join a face to itself
/*verify that e is in both f1 and f2*/
f1len = bmesh_cycle_length(f1->lbase);
f2len = bmesh_cycle_length(f2->lbase);
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 NULL;
/*validate that edge is 2-manifold edge*/
radlen = bmesh_cycle_length(&(f1loop->radial));
if(radlen != 2) return NULL;
/*validate direction of f2's loop cycle is compatible.*/
if(f1loop->v == f2loop->v) return NULL;
/*
validate that for each face, each vertex has another edge in its disk cycle that is
not e, and not shared.
*/
if(bmesh_radial_find_face( ((f1loop->next))->e,f2)) return NULL;
if(bmesh_radial_find_face( ((f1loop->prev))->e,f2)) return NULL;
if(bmesh_radial_find_face( ((f2loop->next))->e,f1)) return NULL;
if(bmesh_radial_find_face( ((f2loop->prev))->e,f1)) return NULL;
/*validate only one shared edge*/
shared = BM_face_share_edges(f1,f2);
if(shared > 1) return NULL;
/*validate no internal joins*/
for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((curloop->next)) ) curloop->v->head.eflag1 = 0;
for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((curloop->next)) ) curloop->v->head.eflag1 = 0;
for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((curloop->next)) ) {
if(curloop != f1loop)
curloop->v->head.eflag1++;
}
for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((curloop->next)) ) {
if(curloop != f2loop)
curloop->v->head.eflag1++;
}
for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((curloop->next)) ) {
if(curloop->v->head.eflag1 > 1)
return NULL;
}
for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((curloop->next)) ) {
if(curloop->v->head.eflag1 > 1)
return 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->lbase = ((f1loop->next));
/*validate the new loop*/
loopok = bmesh_cycle_validate((f1len+f2len)-2, f1->lbase);
if(!loopok) bmesh_error();
/*make sure each loop points to the proper face*/
newlen = bmesh_cycle_length(f1->lbase);
for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = ((curloop->next)) ) curloop->f = f1;
f1->len = newlen;
edok = bmesh_cycle_validate(f1->len, f1->lbase);
if(!edok) bmesh_error();
/*remove edge from the disk cycle of its two vertices.*/
bmesh_disk_remove_edge(f1loop->e, f1loop->e->v1);
bmesh_disk_remove_edge(f1loop->e, f1loop->e->v2);
/*deallocate edge and its two loops as well as f2*/
BLI_remlink(&(bm->edges), &(f1loop->e->head));
BLI_remlink(&(bm->polys), &(f2->head));
bmesh_free_edge(bm, f1loop->e);
bmesh_free_loop(bm, f1loop);
bmesh_free_loop(bm, f2loop);
bmesh_free_poly(bm, f2);
return f1;
}
/**
* bmesh_URMV
*
* UNGLUE REGION MAKE VERT:
*
* Takes a locally manifold disk of face corners and 'unglues' it
* creating a new vertex
*
**/
#define URMV_VISIT 1
#define URMV_VISIT2 2
BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv)
{
BMVert *nv = NULL;
BMLoop *l = NULL, *sl = NULL;
BMEdge *curedge = NULL;
int numloops = 0, numedges = 0, i, maxedges, maxloops;
/*BMESH_TODO: Validation*/
/*validate radial cycle of all collected loops*/
/*validate the disk cycle of sv, and nv*/
/*validate the face length of all faces? overkill?*/
/*validate the l->e pointers of all affected faces, ie: l->v and l->next->v should be equivalent to l->e*/
/*verify that sv has edges*/
if(sv->e == NULL)
return NULL;
/*first verify no wire edges on sv*/
curedge = sv->e;
do {
if(curedge->l == NULL)
return NULL;
curedge = bmesh_disk_nextedge(curedge, sv);
} while(curedge != sv->e);
/*next verify that sv is in sf*/
l = sf->loopbase;
do {
if(l->v == sv) {
sl = l;
break;
}
l = (l->next);
} while(l != sf->lbase);
if(sl == NULL)
return NULL;
/*clear euler flags*/
sv->head.eflag1 = 0;
curedge = sv->e;
do {
curedge->head.eflag1 = 0;
l = curedge->l;
do {
l->head.eflag1 = 0;
l->f->head.eflag1 = 0;
l = bmesh_radial_nextloop(l);
} while(l != curedge->l);
curedge = bmesh_disk_nextedge(curedge, sv);
} while(curedge != sv->e);
/*search through face disk and flag elements as we go.*/
/*Note, test this to make sure that it works correct on
non-manifold faces!
*/
l = sl;
l->e->head.eflag1 |= URMV_VISIT;
l->f->head.eflag1 |= URMV_VISIT;
do {
if(l->v == sv)
l = bmesh_radial_nextloop((l->prev));
else
l = bmesh_radial_nextloop((l->next));
l->e->head.eflag1 |= URMV_VISIT;
l->f->head.eflag1 |= URMV_VISIT;
} while(l != sl && (bmesh_cycle_length(&(l->radial)) > 1) );
/*Verify that all visited edges are at least 1 or 2 manifold*/
curedge = sv->e;
do {
if(curedge->head.eflag1 && (bmesh_cycle_length(&(curedge->l->radial)) > 2) )
return NULL;
curedge = bmesh_disk_nextedge(curedge, sv);
} while(curedge != sv->e);
/*allocate temp storage - we overallocate here instead of trying to be clever*/
maxedges = 0;
maxloops = 0;
curedge = sv->e;
do {
if(curedge->l) {
l = curedge->l;
do {
maxloops += l->f->len;
l = bmesh_radial_nextloop(l);
} while(l != curedge->l);
}
maxedges+= 1;
curedge = bmesh_disk_nextedge(curedge,sv);
} while(curedge != sv->e);
if(bm->edarlen < maxedges) {
MEM_freeN(bm->edar);
bm->edar = MEM_callocN(sizeof(BMEdge *) * maxedges, "BM Edge pointer array");
bm->edarlen = maxedges;
}
if(bm->lparlen < maxloops) {
MEM_freeN(bm->lpar);
bm->lpar = MEM_callocN(sizeof(BMLoop *) * maxloops, "BM Loop pointer array");
bm->lparlen = maxloops;
}
/*first get loops by looping around edges and loops around that edges faces*/
curedge = sv->e;
do {
if(curedge->l) {
l = curedge->l;
do {
if( (l->head.eflag1 & URMV_VISIT) && (!(l->head.eflag1 & URMV_VISIT2)) ) {
bm->lpar[numloops] = l;
l->head.eflag1 |= URMV_VISIT2;
numloops++;
}
l = bmesh_radial_nextloop(l);
} while(l != curedge->l);
}
curedge = bmesh_disk_nextedge(curedge, sv);
} while(curedge != sv->e);
/*now collect edges by looping around edges and looking at visited flags*/
curedge = sv->e;
do {
if(curedge->head.eflag1 & URMV_VISIT) {
bm->edar[numedges] = curedge;
numedges++;
}
curedge = bmesh_disk_nextedge(curedge, sv);
} while(curedge != sv->e);
/*make new vertex*/
nv = bmesh_addvertlist(bm, sv);
/*go through and relink edges*/
for(i = 0; i < numedges; i++) {
curedge = bm->edar[i];
/*remove curedge from sv*/
bmesh_disk_remove_edge(curedge, sv);
/*swap out sv for nv in curedge*/
bmesh_edge_swapverts(curedge, sv, nv);
/*add curedge to nv's disk cycle*/
bmesh_disk_append_edge(curedge, nv);
}
/*go through and relink loops*/
for(i = 0; i < numloops; i ++) {
l = bm->lpar[i];
if(l->v == sv)
l->v = nv;
}
return nv;
}
#endif

View File

@@ -1,479 +0,0 @@
#if 0
/*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK *****
*/
#include "MEM_guardedalloc.h"
#include "BKE_customdata.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 "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 "bmesh_private.h"
/*
* BMESH DERIVED MESH CONVERSION FUNCTIONS
*
* The functions in this file provides
* methods for converting to and from
* a bmesh.
*
*/
/*
* DMCORNERS TO LOOPS
*
* Function to convert derived mesh per-face
* corner data (uvs, vertex colors), to n-gon
* per-loop data.
*
*/
static void DMcorners_to_loops(BMMesh *bm, CustomData *facedata, int index, BMFace *f, int numCol, int numTex)
{
int i, j;
BMLoop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i< numTex; i++){
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texpoly->tpage = texface[index].tpage;
texpoly->flag = texface[index].flag;
texpoly->transp = texface[index].transp;
texpoly->mode = texface[index].mode;
texpoly->tile = texface[index].tile;
texpoly->unwrap = texface[index].unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
mloopuv->uv[0] = texface[index].uv[j][0];
mloopuv->uv[1] = texface[index].uv[j][1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_get_layer_n(facedata, CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mloopcol->r = mcol[(index*4)+j].r;
mloopcol->g = mcol[(index*4)+j].g;
mloopcol->b = mcol[(index*4)+j].b;
mloopcol->a = mcol[(index*4)+j].a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
/*
* LOOPS TO DMCORNERS
*
* Function to convert n-gon per-loop data
* (uvs, vertex colors, ect)to derived mesh
* face corner data.
*
*/
static void loops_to_DMcorners(BMMesh *bm, CustomData *facedata, int index, BMFace *f,int numCol, int numTex)
{
int i, j;
BMLoop *l;
MTFace *texface;
MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
for(i=0; i < numTex; i++){
texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
texface[index].tpage = texpoly->tpage;
texface[index].flag = texpoly->flag;
texface[index].transp = texpoly->transp;
texface[index].mode = texpoly->mode;
texface[index].tile = texpoly->tile;
texface[index].unwrap = texpoly->unwrap;
j = 0;
l = f->loopbase;
do{
mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
texface[index].uv[j][0] = mloopuv->uv[0];
texface[index].uv[j][1] = mloopuv->uv[1];
j++;
l = l->next;
}while(l!=f->loopbase);
}
for(i=0; i < numCol; i++){
mcol = CustomData_get_layer_n(facedata,CD_MCOL, i);
j = 0;
l = f->loopbase;
do{
mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
mcol[(index*4) + j].r = mloopcol->r;
mcol[(index*4) + j].g = mloopcol->g;
mcol[(index*4) + j].b = mloopcol->b;
mcol[(index*4) + j].a = mloopcol->a;
j++;
l = l->next;
}while(l!=f->loopbase);
}
}
/*
* MVERT TO BMESHVERT
*
* Converts a MVert to a BMVert
*
*/
static BMVert *mvert_to_bmeshvert(BMMesh *bm, BMVert **vert_array, int index, MVert *mv, CustomData *data)
{
BMVert *v = NULL;
v = bmesh_make_vert(bm, mv->co, NULL);
vert_array[index] = v;
if(mv->flag & SELECT) bmesh_set_flag(v, BMESH_SELECT);
v->bweight = mv->bweight/255.0f;
CustomData_to_bmesh_block(data, &bm->vdata, index, &v->data);
return v;
}
/*
* MEDGE TO BMESHEDGE
*
* Converts a MEdge to a BMEdge
*
*/
static BMEdge *medge_to_bmeshedge(BMMesh *bm, BMVert **vert_array, int index, MEdge *me, CustomData *data, Edge_Hash *edge_hash)
{
BMVert *v1, *v2;
BMEdge *e = NULL;
v1 = vert_array[me->v1];
v2 = vert_array[me->v2];
e = bmesh_make_edge(bm, v1, v2, NULL, 0);
e->crease = me->crease/255.0f;
e->bweight = me->bweight/255.0f;
if(me->flag & 1) bmesh_set_flag(e, BMESH_SELECT);
if(me->flag & ME_SEAM) bmesh_set_flag(e, BMESH_SEAM);
BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
CustomData_to_bmesh_block(data, &bm->edata, index, &e->data);
return e;
}
/*
* MFACE TO BMESHFACE
*
* Converts a MFace to a BMFace.
* Note that this will fail on eekadoodle
* faces.
*
*/
static BMFace *mface_to_bmeshface(BMMesh *bm, BMVert **vert_array, int index, MFace *mf, CustomData *data, Edge_Hash *edge_hash)
{
BMVert *v1, *v2;
BMEdge *edar[4];
BMFace *f = NULL;
int len;
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 = bmesh_make_ngon(bm, v1, v2, edar, len, 0);
f->mat_nr = mf->mat_nr;
if(mf->flag & 1) bmesh_set_flag(f, BMESH_SELECT);
if(mf->flag & ME_HIDE) bmesh_set_flag(f, BMESH_HIDDEN);
CustomData_to_bmesh_block(data, &bm->pdata, index, &f->data);
return f;
}
/*
* DERIVEDMESH TO BMESH
*
* Converts a derived mesh to a bmesh.
*
*/
BMMesh *derivedmesh_to_bmesh(DerivedMesh *dm)
{
BMMesh *bm;
BMVert **vert_array;
BMFace *f=NULL;
MVert *mvert, *mv;
MEdge *medge, *me;
MFace *mface, *mf;
int totface,totedge,totvert,i,len, numTex, numCol;
int allocsize[4] = {512,512,2048,512};
EdgeHash *edge_hash = BLI_edgehash_new();
/*allocate a new bmesh*/
bm = bmesh_make_mesh(allocsize);
/*copy custom data layout*/
CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
/*needed later*/
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
totface = dm->getNumTessFaces(dm);
mvert = dm->getVertArray(dm);
medge = dm->getEdgeArray(dm);
mface = dm->getTessFaceArray(dm);
vert_array = MEM_mallocN(sizeof(BMVert *)* totvert,"derivedmesh to bmesh vertex pointer array");
bmesh_begin_edit(bm);
/*add verts*/
for(i=0, mv = mvert; i < totvert; i++, mv++)
mvert_to_bmeshvert(bm, vert_array, i, mv, &dm->vertData);
/*add edges*/
for(i=0, me = medge; i < totedge; i++, me++)
medge_to_bmeshedge(bm, vert_array, i, me, &dm->edgeData, edge_hash);
/*add faces.*/
for(i=0, mf = mface; i < totface; i++, mf++){
f = mface_to_bmeshface(bm, vert_array, mf, &dm->faceData, edge_hash);
if(f) DMcorners_to_loops(bm, &dm->faceData, i, f, numCol, numTex);
}
bmesh_end__edit(bm);
BLI_edgehash_free(edge_hash, NULL);
MEM_freeN(vert_array);
return bm;
}
static void bmeshvert_to_mvert(BMMesh *bm, BMVert *v, MVert *mv, int index, CustomData *data)
{
copy_v3_v3(mv->co, v->co);
if(bmesh_test_flag(v, BMESH_SELECT)) mv->flag |= 1;
if(bmesh_test_flag(v, BMESH_HIDDEN)) mv->flag |= ME_HIDE;
mv->bweight = (char)(255.0*v1->bweight);
CustomData_from_bmesh_block(&bm->vdata, data, &v1->data, index);
}
static int bmeshedge_to_medge(BMMesh *bm, BMEdge *e, MEdge *me, int index, CustomData *data)
{
if(e->head.eflag2){
if(e->v1->head.eflag1 < e->v2->head.eflag1){
me->v1 = e->v1->head.eflag1;
me->v2 = e->v2->head.eflag1;
}
else{
me->v1 = e->v2->head.eflag1;
me->v2 = e->v1->eflag1;
}
me->crease = (char)(255.0*e->crease);
me->bweight = (char)(255.0*e->bweight);
if(bmesh_test_flag(e, BMESH_SELECT)) me->flag |= 1;
if(bmesh_test_flag(e, BMESH_HIDDEN)) me->flag |= ME_HIDE;
CustomData_from_bmesh_block(&bm->edata, data, &e->data, index);
return 1;
}
return 0;
}
static int bmeshface_to_mface(BMMesh *bm, BMFace *f, MFace *mf, int index, CustomData *data)
{
if(f->len==3 || f->len==4){
mf->v1 = f->loopbase->v->head.eflag1;
mf->v2 = f->loopbase->next->v->head.eflag1;
mf->v3 = f->loopbase->next->next->v->head.eflag1;
if(len == 4){
mf->v4 = f->loopbase->prev->v->head.eflag1;
}
/* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
if(mf->v3 == 0 || (f->len == 4 && mf->v4 == 0)){
test_index_face(mf, NULL, index, f->len);
}
mf->mat_nr = (unsigned char)f->mat_nr;
if(bmesh_test_flag(f, BMESH_SELECT)) mf->flag |= 1;
if(bmesh_test_flag(f, BMESH_HIDDEN)) mf->flag |= ME_HIDE;
CustomData_from_bmesh_block(&bm->pdata, data, &f->data, index);
return TRUE;
}
return FALSE;
}
/*
* BMESH TO DERIVEDMESH
*
* Converts a bmesh to a derived mesh.
*
*/
DerivedMesh *bmesh_to_derivedmesh(BMMesh *bm, DerivedMesh *dm)
{
MFace *mface = NULL, *mf = NULL;
MEdge *medge = NULL, *me = NULL;
MVert *mvert = NULL, *mv = NULL;
DerivedMesh *result = NULL;
BMVert *v=NULL;
BMEdge *e=NULL, *oe=NULL;
BMFace *f=NULL;
BMIter verts;
BMIter edges;
BMIter faces;
int totface = 0,totedge = 0,totvert = 0,i = 0, numTex, numCol;
EdgeHash *edge_hash = BLI_edgehash_new();
/*get element counts*/
totvert = bmesh_count_element(bm, BMESH_VERT);
/*store element indices. Note that the abuse of eflag here should NOT be duplicated!*/
for(i=0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++)
v->head.eflag1 = i;
/*we cannot have double edges in a derived mesh!*/
for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
oe = BLI_edgehash_lookup(edge_hash,e->v1->head.eflag1, e->v2->head.eflag1);
if(!oe){
totedge++;
BLI_edgehash_insert(edge_hash,e->v1->head.eflag1,e->v2->head.eflag1,e);
e->head.eflag2 = 1;
}
else{
e->head.eflag2 = 0;
}
}
/*count quads and tris*/
for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
if(f->len == 3 || f->len == 4) totface++;
}
/*Allocate derivedmesh and copy custom data*/
result = CDDM_from_template(dm,totvert,totedge,totface);
CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
/*Make Verts*/
mvert = CDDM_get_verts(result);
for(i = 0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++, mv++){
bmeshvert_to_mvert(bm,v,mv,i,&result->vertData);
}
/*Make Edges*/
medge = CDDM_get_edges(result);
i=0;
for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
me = &medge[i];
if(bmeshedge_to_medge(bm, e, me, i, &result->edgeData){
me++;
i++;
}
}
/*Make Faces*/
if(totface){
mface = CDDM_get_faces(result);
i=0;
for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
mf = &mface[i];
if(bmeshface_to_mface(bm, f, mf, i, &result->faceData)){
loops_to_DMcorners(bm, &result->faceData, i, f, numCol, numTex);
i++;
}
}
}
BLI_edgehash_free(edge_hash, NULL);
return result;
}
#endif