diff options
Diffstat (limited to 'source/blender/bmesh/tools/BME_extrude.c')
-rw-r--r-- | source/blender/bmesh/tools/BME_extrude.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/source/blender/bmesh/tools/BME_extrude.c b/source/blender/bmesh/tools/BME_extrude.c new file mode 100644 index 00000000000..b7b3a94893d --- /dev/null +++ b/source/blender/bmesh/tools/BME_extrude.c @@ -0,0 +1,216 @@ +/** + * BMESH EXTRUDE TOOL + * + * A rewrite of the old editmesh extrude code with the + * redundant parts broken into multiple functions + * in an effort to reduce code. This works with multiple + * selection modes, and is intended to build the + * extrusion in steps, depending on what elements are selected. + * Also decoupled the calculation of transform normal + * and put it in UI where it probably is more appropriate + * for the moment. + * + * TODO: + * -Fit this into the new 'easy' API. +*/ + +void BME_extrude_verts(BME_Mesh *bm, GHash *vhash){ + BMVert *v, *nv = NULL; + BMEdge *ne = NULL; + float vec[3]; + + //extrude the vertices + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(BME_SELECTED(v)){ + VECCOPY(vec,v->co); + nv = BME_MV(bm,vec); + nv->tflag2 =1; //mark for select + ne = BME_ME(bm,v,nv); + ne->tflag1 = 2; //mark as part of skirt 'ring' + BLI_ghash_insert(vhash,v,nv); + BME_VISIT(v); + } + } +} + +void BME_extrude_skirt(BME_Mesh *bm, GHash *ehash){ + + BMFace *nf=NULL; + BMEdge *e, *l=NULL, *r=NULL, *edar[4], *ne; + BMVert *v, *v1, *v2, *lv, *rv, *nv; + + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(BME_SELECTED(e)){ + /*find one face incident upon e and use it for winding of new face*/ + if(e->loop){ + v1 = e->loop->next->v; + v2 = e->loop->v; + } + else{ + v1 = e->v1; + v2 = e->v2; + } + + if(v1->edge->tflag1 == 2) l = v1->edge; + else l = BME_disk_next_edgeflag(v1->edge, v1, 0, 2); + if(v2->edge->tflag1 == 2) r = v2->edge; + else r = BME_disk_next_edgeflag(v2->edge, v2, 0, 2); + + lv = BME_edge_getothervert(l,v1); + rv = BME_edge_getothervert(r,v2); + + ne = BME_ME(bm,lv,rv); + ne->tflag2 = 1; //mark for select + BLI_ghash_insert(ehash,e,ne); + BME_VISIT(e); + + edar[0] = e; + edar[1] = l; + edar[2] = ne; + edar[3] = r; + BME_MF(bm,v1,v2,edar,4); + } + } +} + +void BME_cap_skirt(BME_Mesh *bm, GHash *vhash, GHash *ehash){ + BMVert *v, *nv, *v1, *v2; + BMEdge *e, **edar, *ne; + BME_Loop *l; + BMFace *f, *nf; + MemArena *edgearena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + float vec[3]; + int i, j, del_old =0; + + + //loop through faces, then loop through their verts. If the verts havnt been visited yet, duplicate these. + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(BME_SELECTED(f)){ + l = f->loopbase; + do{ + if(!(BME_ISVISITED(l->v))){ //interior vertex + //dupe vert + VECCOPY(vec,l->v->co); + nv = BME_MV(bm,vec); + BLI_ghash_insert(vhash,l->v,nv); + //mark for delete + l->v->tflag1 = 1; + BME_VISIT(l->v); //we dont want to dupe it again. + } + l=l->next; + }while(l!=f->loopbase); + } + } + + //find out if we delete old faces or not. This needs to be improved a lot..... + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(BME_SELECTED(e) && e->loop){ + i= BME_cycle_length(&(e->loop->radial)); + if(i > 2){ + del_old = 1; + break; + } + } + } + + + //build a new edge net, insert the new edges into the edge hash + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(BME_SELECTED(f)){ + l=f->loopbase; + do{ + if(!(BME_ISVISITED(l->e))){ //interior edge + //dupe edge + ne = BME_ME(bm,BLI_ghash_lookup(vhash,l->e->v1),BLI_ghash_lookup(vhash,l->e->v2)); + BLI_ghash_insert(ehash,l->e,ne); + //mark for delete + l->e->tflag1 = 1; + BME_VISIT(l->e); //we dont want to dupe it again. + } + l=l->next; + }while(l!=f->loopbase); + } + } + + //build new faces. grab edges from edge hash. + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(BME_SELECTED(f)){ + edar = MEM_callocN(sizeof(BMEdge*)*f->len,"Extrude array"); + v1 = BLI_ghash_lookup(vhash,f->loopbase->v); + v2 = BLI_ghash_lookup(vhash,f->loopbase->next->v); + for(i=0,l=f->loopbase; i < f->len; i++,l=l->next){ + ne = BLI_ghash_lookup(ehash,l->e); + edar[i] = ne; + } + nf=BME_MF(bm,v1,v2,edar,f->len); + nf->tflag2 = 1; // mark for select + if(del_old) f->tflag1 = 1; //mark for delete + MEM_freeN(edar); + } + } + BLI_memarena_free(edgearena); +} + +/*unified extrude code*/ +void BME_extrude_mesh(BME_Mesh *bm, int type){ + + BMVert *v; + BMEdge *e; + BMFace *f; + BME_Loop *l; + + struct GHash *vhash, *ehash; + /*Build a hash table of old pointers and new pointers.*/ + vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + BME_selectmode_flush(bm); //ensure consistent selection. contains hack to make sure faces get consistent select. + if(type & BME_EXTRUDE_FACES){ //Find selected edges with more than one incident face that is also selected. deselect them. + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + int totsel=0; + if(e->loop){ + l= e->loop; + do{ + if(BME_SELECTED(l->f)) totsel++; + l=BME_radial_nextloop(l); + }while(l!=e->loop); + } + if(totsel > 1) BME_select_edge(bm,e,0); + } + } + + /*another hack to ensure consistent selection.....*/ + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(BME_SELECTED(e)) BME_select_edge(bm,e,1); + } + + /*now we are ready to extrude*/ + if(type & BME_EXTRUDE_VERTS) BME_extrude_verts(bm,vhash); + if(type & BME_EXTRUDE_EDGES) BME_extrude_skirt(bm,ehash); + if(type & BME_EXTRUDE_FACES) BME_cap_skirt(bm,vhash,ehash); + + /*clear all selection flags*/ + BME_clear_flag_all(bm, SELECT|BME_VISITED); + /*go through and fix up selection flags. Anything with BME_NEW should be selected*/ + for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ + if(f->tflag2 == 1) BME_select_poly(bm,f,1); + if(f->tflag1 == 1) BME_VISIT(f); //mark for delete + } + for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ + if(e->tflag2 == 1) BME_select_edge(bm,e,1); + if(e->tflag1 == 1) BME_VISIT(e); // mark for delete + } + for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ + if(v->tflag2 == 1) BME_select_vert(bm,v,1); + if(v->tflag1 == 1) BME_VISIT(v); //mark for delete + } + /*go through and delete all of our old faces , edges and vertices.*/ + remove_tagged_polys(bm); + remove_tagged_edges(bm); + remove_tagged_verts(bm); + /*free our hash tables*/ + BLI_ghash_free(vhash,NULL, NULL); //check usage! + BLI_ghash_free(ehash,NULL, NULL); //check usage! + BME_selectmode_flush(bm); +} + |