diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 463237c39a8..48f653f4759 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -80,28 +80,29 @@ set(SRC operators/bmo_triangulate.c operators/bmo_utils.c - intern/bmesh_newcore.c + intern/bmesh_construct.c + intern/bmesh_inline.c intern/bmesh_interp.c intern/bmesh_iterators.c intern/bmesh_iterators_inline.c intern/bmesh_marking.c intern/bmesh_mesh.c intern/bmesh_mods.c - intern/bmesh_structure.h - intern/bmesh_construct.c - intern/bmesh_operators_private.h - intern/bmesh_structure.c - intern/bmesh_polygon.c - intern/bmesh_queries.c + intern/bmesh_newcore.c intern/bmesh_opdefines.c intern/bmesh_operators.c + intern/bmesh_operators_private.h + intern/bmesh_polygon.c intern/bmesh_private.h + intern/bmesh_queries.c + intern/bmesh_structure.c + intern/bmesh_structure.h intern/bmesh_walkers.c intern/bmesh_walkers_impl.c intern/bmesh_walkers_private.h - intern/bmesh_inline.c tools/BME_bevel.c + bmesh.h bmesh_class.h bmesh_error.h diff --git a/source/blender/bmesh/editmesh_tools.c b/source/blender/bmesh/editmesh_tools.c deleted file mode 100644 index 93be1ac5422..00000000000 --- a/source/blender/bmesh/editmesh_tools.c +++ /dev/null @@ -1,6384 +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) 2004 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Johnny Matthews, Geoffrey Bantle. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/* - -editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c - -*/ - -#include -#include -#include - -#include "MEM_guardedalloc.h" - -#include "BMF_Api.h" -#include "DNA_mesh_types.h" -#include "DNA_material_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_view3d_types.h" -#include "DNA_key_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_editVert.h" -#include "BLI_rand.h" -#include "BLI_ghash.h" -#include "BLI_linklist.h" -#include "BLI_heap.h" - -#include "BKE_depsgraph.h" -#include "BKE_customdata.h" -#include "BKE_global.h" -#include "BKE_library.h" -#include "BKE_mesh.h" -#include "BKE_object.h" -#include "BKE_utildefines.h" -#include "BKE_bmesh.h" - -#ifdef WITH_VERSE -#include "BKE_verse.h" -#endif - -#include "BIF_cursors.h" -#include "BIF_editmesh.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" -#include "BIF_graphics.h" -#include "BIF_interface.h" -#include "BIF_mywindow.h" -#include "BIF_screen.h" -#include "BIF_space.h" -#include "BIF_resources.h" -#include "BIF_toolbox.h" -#include "BIF_transform.h" -#include "transform.h" - -#ifdef WITH_VERSE -#include "BIF_verse.h" -#endif - -#include "BDR_drawobject.h" -#include "BDR_editobject.h" - -#include "BSE_view.h" -#include "BSE_edit.h" - -#include "blendef.h" -#include "multires.h" -#include "mydevice.h" - -#include "editmesh.h" - -#include "MTC_vectorops.h" - -#include "PIL_time.h" - -#include "BLO_sys_types.h" // for intptr_t support - -/* local prototypes ---------------*/ -void bevel_menu(void); -static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa); - -/********* qsort routines *********/ - - -typedef struct xvertsort { - float x; - EditVert *v1; -} xvertsort; - -static int vergxco(const void *v1, const void *v2) -{ - const xvertsort *x1=v1, *x2=v2; - - if( x1->x > x2->x ) return 1; - else if( x1->x < x2->x) return -1; - return 0; -} - -struct facesort { - uintptr_t x; - struct EditFace *efa; -}; - - -static int vergface(const void *v1, const void *v2) -{ - const struct facesort *x1=v1, *x2=v2; - - if( x1->x > x2->x ) return 1; - else if( x1->x < x2->x) return -1; - return 0; -} - - -/* *********************************** */ - -void convert_to_triface(int direction) -{ - EditMesh *em = G.editMesh; - EditFace *efa, *efan, *next; - float fac; - - if(multires_test()) return; - - efa= em->faces.last; - while(efa) { - next= efa->prev; - if(efa->v4) { - if(efa->f & SELECT) { - /* choose shortest diagonal for split */ - fac= len_v3v3(efa->v1->co, efa->v3->co) - len_v3v3(efa->v2->co, efa->v4->co); - /* this makes sure exact squares get split different in both cases */ - if( (direction==0 && fac0.0f) ) { - efan= EM_face_from_faces(efa, NULL, 0, 1, 2, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - efan= EM_face_from_faces(efa, NULL, 0, 2, 3, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - } - else { - efan= EM_face_from_faces(efa, NULL, 0, 1, 3, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - efan= EM_face_from_faces(efa, NULL, 1, 2, 3, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - } - - BLI_remlink(&em->faces, efa); - free_editface(efa); - } - } - efa= next; - } - - EM_fgon_flags(); // redo flags and indices for fgons - -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - BIF_undo_push("Convert Quads to Triangles"); - -} - -int removedoublesflag(short flag, short automerge, float limit) /* return amount */ -{ - /* - flag - Test with vert->flags - automerge - Alternative operation, merge unselected into selected. - Used for "Auto Weld" mode. warning. - limit - Quick manhattan distance between verts. - */ - - EditMesh *em = G.editMesh; - /* all verts with (flag & 'flag') are being evaluated */ - EditVert *eve, *v1, *nextve; - EditEdge *eed, *e1, *nexted; - EditFace *efa, *nextvl; - xvertsort *sortblock, *sb, *sb1; - struct facesort *vlsortblock, *vsb, *vsb1; - int a, b, test, amount; - - if(multires_test()) return 0; - - - /* flag 128 is cleared, count */ - - /* Normal non weld operation */ - eve= em->verts.first; - amount= 0; - while(eve) { - eve->f &= ~128; - if(eve->h==0 && (automerge || (eve->f & flag))) amount++; - eve= eve->next; - } - if(amount==0) return 0; - - /* allocate memory and qsort */ - sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub"); - eve= em->verts.first; - while(eve) { - if(eve->h==0 && (automerge || (eve->f & flag))) { - sb->x= eve->co[0]+eve->co[1]+eve->co[2]; - sb->v1= eve; - sb++; - } - eve= eve->next; - } - qsort(sortblock, amount, sizeof(xvertsort), vergxco); - - - /* test for doubles */ - sb= sortblock; - if (automerge) { - for(a=0; av1; - if( (eve->f & 128)==0 ) { - sb1= sb+1; - for(b=a+1; bf & 128)==0; b++, sb1++) { - if(sb1->x - sb->x > limit) break; - - /* when automarge, only allow unselected->selected */ - v1= sb1->v1; - if( (v1->f & 128)==0 ) { - if ((eve->f & flag)==0 && (v1->f & flag)==1) { - if( (float)fabs(v1->co[0]-eve->co[0])<=limit && - (float)fabs(v1->co[1]-eve->co[1])<=limit && - (float)fabs(v1->co[2]-eve->co[2])<=limit) - { /* unique bit */ - eve->f|= 128; - eve->tmp.v = v1; - } - } else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) { - if( (float)fabs(v1->co[0]-eve->co[0])<=limit && - (float)fabs(v1->co[1]-eve->co[1])<=limit && - (float)fabs(v1->co[2]-eve->co[2])<=limit) - { /* unique bit */ - v1->f|= 128; - v1->tmp.v = eve; - } - } - } - } - } - } - } else { - for(a=0; av1; - if( (eve->f & 128)==0 ) { - sb1= sb+1; - for(b=a+1; bx - sb->x > limit) break; - v1= sb1->v1; - - /* second test: is vertex allowed */ - if( (v1->f & 128)==0 ) { - if( (float)fabs(v1->co[0]-eve->co[0])<=limit && - (float)fabs(v1->co[1]-eve->co[1])<=limit && - (float)fabs(v1->co[2]-eve->co[2])<=limit) - { - v1->f|= 128; - v1->tmp.v = eve; - } - } - } - } - } - } - MEM_freeN(sortblock); - - if (!automerge) - for(eve = em->verts.first; eve; eve=eve->next) - if((eve->f & flag) && (eve->f & 128)) - EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f); - - /* test edges and insert again */ - eed= em->edges.first; - while(eed) { - eed->f2= 0; - eed= eed->next; - } - eed= em->edges.last; - while(eed) { - nexted= eed->prev; - - if(eed->f2==0) { - if( (eed->v1->f & 128) || (eed->v2->f & 128) ) { - remedge(eed); - - if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v; - if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v; - e1= addedgelist(eed->v1, eed->v2, eed); - - if(e1) { - e1->f2= 1; - if(eed->f & SELECT) - e1->f |= SELECT; - } - if(e1!=eed) free_editedge(eed); - } - } - eed= nexted; - } - - /* first count amount of test faces */ - efa= (struct EditFace *)em->faces.first; - amount= 0; - while(efa) { - efa->f1= 0; - if(efa->v1->f & 128) efa->f1= 1; - else if(efa->v2->f & 128) efa->f1= 1; - else if(efa->v3->f & 128) efa->f1= 1; - else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1; - - if(efa->f1==1) amount++; - efa= efa->next; - } - - /* test faces for double vertices, and if needed remove them */ - efa= (struct EditFace *)em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f1==1) { - - if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v; - if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v; - if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v; - if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v; - - test= 0; - if(efa->v1==efa->v2) test+=1; - if(efa->v2==efa->v3) test+=2; - if(efa->v3==efa->v1) test+=4; - if(efa->v4==efa->v1) test+=8; - if(efa->v3==efa->v4) test+=16; - if(efa->v2==efa->v4) test+=32; - - if(test) { - if(efa->v4) { - if(test==1 || test==2) { - efa->v2= efa->v3; - efa->v3= efa->v4; - efa->v4= 0; - - EM_data_interp_from_faces(efa, NULL, efa, 0, 2, 3, 3); - - test= 0; - } - else if(test==8 || test==16) { - efa->v4= 0; - test= 0; - } - else { - BLI_remlink(&em->faces, efa); - free_editface(efa); - amount--; - } - } - else { - BLI_remlink(&em->faces, efa); - free_editface(efa); - amount--; - } - } - - if(test==0) { - /* set edge pointers */ - efa->e1= findedgelist(efa->v1, efa->v2); - efa->e2= findedgelist(efa->v2, efa->v3); - if(efa->v4==0) { - efa->e3= findedgelist(efa->v3, efa->v1); - efa->e4= 0; - } - else { - efa->e3= findedgelist(efa->v3, efa->v4); - efa->e4= findedgelist(efa->v4, efa->v1); - } - } - } - efa= nextvl; - } - - /* double faces: sort block */ - /* count again, now all selected faces */ - amount= 0; - efa= em->faces.first; - while(efa) { - efa->f1= 0; - if(faceselectedOR(efa, 1)) { - efa->f1= 1; - amount++; - } - efa= efa->next; - } - - if(amount) { - /* double faces: sort block */ - vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub"); - efa= em->faces.first; - while(efa) { - if(efa->f1 & 1) { - if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4); - else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3); - - vsb->efa= efa; - vsb++; - } - efa= efa->next; - } - - qsort(vlsortblock, amount, sizeof(struct facesort), vergface); - - vsb= vlsortblock; - for(a=0; aefa; - if( (efa->f1 & 128)==0 ) { - vsb1= vsb+1; - - for(b=a+1; bx != vsb1->x) break; - - /* second test: is test permitted? */ - efa= vsb1->efa; - if( (efa->f1 & 128)==0 ) { - if( compareface(efa, vsb->efa)) efa->f1 |= 128; - - } - vsb1++; - } - } - vsb++; - } - - MEM_freeN(vlsortblock); - - /* remove double faces */ - efa= (struct EditFace *)em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f1 & 128) { - BLI_remlink(&em->faces, efa); - free_editface(efa); - } - efa= nextvl; - } - } - - /* remove double vertices */ - a= 0; - eve= (struct EditVert *)em->verts.first; - while(eve) { - nextve= eve->next; - if(automerge || eve->f & flag) { - if(eve->f & 128) { - a++; - BLI_remlink(&em->verts, eve); - free_editvert(eve); - } - } - eve= nextve; - } - -#ifdef WITH_VERSE - if((a>0) && (G.editMesh->vnode)) { - sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); - } -#endif - - return a; /* amount */ -} - -/* called from buttons */ -static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y, int index) -{ - xvertsort *sortblock = userData; - - sortblock[index].x = x; -} -void xsortvert_flag(int flag) -{ - EditMesh *em = G.editMesh; - /* all verts with (flag & 'flag') are sorted */ - EditVert *eve; - xvertsort *sortblock; - ListBase tbase; - int i, amount = BLI_countlist(&em->verts); - - if(multires_test()) return; - - sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort"); - for (i=0,eve=em->verts.first; eve; i++,eve=eve->next) - if(eve->f & flag) - sortblock[i].v1 = eve; - mesh_foreachScreenVert(xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF); - qsort(sortblock, amount, sizeof(xvertsort), vergxco); - - /* make temporal listbase */ - tbase.first= tbase.last= 0; - for (i=0; iverts, eve); - BLI_addtail(&tbase, eve); - } - } - - addlisttolist(&em->verts, &tbase); - - MEM_freeN(sortblock); - -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - - BIF_undo_push("Xsort"); - -} - -/* called from buttons */ -void hashvert_flag(int flag) -{ - /* switch vertex order using hash table */ - EditMesh *em = G.editMesh; - EditVert *eve; - struct xvertsort *sortblock, *sb, onth, *newsort; - ListBase tbase; - int amount, a, b; - - if(multires_test()) return; - - /* count */ - eve= em->verts.first; - amount= 0; - while(eve) { - if(eve->f & flag) amount++; - eve= eve->next; - } - if(amount==0) return; - - /* allocate memory */ - sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub"); - eve= em->verts.first; - while(eve) { - if(eve->f & flag) { - sb->v1= eve; - sb++; - } - eve= eve->next; - } - - BLI_srand(1); - - sb= sortblock; - for(a=0; a=0 && bv1; - BLI_remlink(&em->verts, eve); - BLI_addtail(&tbase, eve); - sb++; - } - - addlisttolist(&em->verts, &tbase); - - MEM_freeN(sortblock); -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - BIF_undo_push("Hash"); - -} - -/* generic extern called extruder */ -void extrude_mesh(void) -{ - float nor[3]= {0.0, 0.0, 0.0}; - short nr, transmode= 0; - - TEST_EDITMESH - if(multires_test()) return; - - if(G.scene->selectmode & SCE_SELECT_VERTEX) { - if(G.totvertsel==0) nr= 0; - else if(G.totvertsel==1) nr= 4; - else if(G.totedgesel==0) nr= 4; - else if(G.totfacesel==0) - nr= pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4"); - else if(G.totfacesel==1) - nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4"); - else - nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4"); - } - else if(G.scene->selectmode & SCE_SELECT_EDGE) { - if (G.totedgesel==0) nr = 0; - else if (G.totedgesel==1) nr = 3; - else if(G.totfacesel==0) nr = 3; - else if(G.totfacesel==1) - nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3"); - else - nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3"); - } - else { - if (G.totfacesel == 0) nr = 0; - else if (G.totfacesel == 1) nr = 1; - else - nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2"); - } - - if(nr<1) return; - - if(nr==1) transmode= extrudeflag(SELECT, nor); - else if(nr==4) transmode= extrudeflag_verts_indiv(SELECT, nor); - else if(nr==3) transmode= extrudeflag_edges_indiv(SELECT, nor); - else transmode= extrudeflag_face_indiv(SELECT, nor); - - if(transmode==0) { - error("No valid selection"); - } - else { - EM_fgon_flags(); - countall(); - - /* We need to force immediate calculation here because - * transform may use derived objects (which are now stale). - * - * This shouldn't be necessary, derived queries should be - * automatically building this data if invalid. Or something. - */ - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - object_handle_update(G.obedit); - - /* individual faces? */ - BIF_TransformSetUndo("Extrude"); - if(nr==2) { - initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR); - Transform(); - } - else { - initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR); - if(transmode=='n') { - mul_m4_v3(G.obedit->obmat, nor); - sub_v3_v3v3(nor, nor, G.obedit->obmat[3]); - BIF_setSingleAxisConstraint(nor, "along normal"); - } - Transform(); - } - } - -} - -void split_mesh(void) -{ - - TEST_EDITMESH - if(multires_test()) return; - - if(okee(" Split ")==0) return; - - waitcursor(1); - - /* make duplicate first */ - adduplicateflag(SELECT); - /* old faces have flag 128 set, delete them */ - delfaceflag(128); - recalc_editnormals(); - - waitcursor(0); - - countall(); - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - - BIF_undo_push("Split"); - -} - -void extrude_repeat_mesh(int steps, float offs) -{ - float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0}; - short a; - - TEST_EDITMESH - if(multires_test()) return; - - /* dvec */ - dvec[0]= G.vd->persinv[2][0]; - dvec[1]= G.vd->persinv[2][1]; - dvec[2]= G.vd->persinv[2][2]; - normalize_v3(dvec); - dvec[0]*= offs; - dvec[1]*= offs; - dvec[2]*= offs; - - /* base correction */ - copy_m3_m4(bmat, G.obedit->obmat); - invert_m3_m3(tmat, bmat); - mul_m3_v3(tmat, dvec); - - for(a=0; aobmat); - invert_m3_m3(imat,bmat); - - curs= give_cursor(); - copy_v3_v3(cent, curs); - cent[0]-= G.obedit->obmat[3][0]; - cent[1]-= G.obedit->obmat[3][1]; - cent[2]-= G.obedit->obmat[3][2]; - mul_m3_v3(imat, cent); - - phi= degr*M_PI/360.0; - phi/= steps; - if(G.scene->toolsettings->editbutflag & B_CLOCKWISE) phi= -phi; - - if(dvec) { - n[0]= G.vd->viewinv[1][0]; - n[1]= G.vd->viewinv[1][1]; - n[2]= G.vd->viewinv[1][2]; - } else { - n[0]= G.vd->viewinv[2][0]; - n[1]= G.vd->viewinv[2][1]; - n[2]= G.vd->viewinv[2][2]; - } - normalize_v3(n); - - q[0]= (float)cos(phi); - si= (float)sin(phi); - q[1]= n[0]*si; - q[2]= n[1]*si; - q[3]= n[2]*si; - quat_to_mat3( cmat,q); - - mul_m3_m3m3(tmat,cmat,bmat); - mul_m3_m3m3(bmat,imat,tmat); - - if(mode==0) if(G.scene->toolsettings->editbutflag & B_KEEPORIG) adduplicateflag(1); - ok= 1; - - for(a=0;averts.first; - while(eve) { - nextve= eve->next; - if(eve->f & SELECT) { - BLI_remlink(&em->verts,eve); - free_editvert(eve); - } - eve= nextve; - } - } - recalc_editnormals(); - - EM_fgon_flags(); - countall(); - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - - - if(dvec==NULL) BIF_undo_push("Spin"); -} - -void screw_mesh(int steps, int turns) -{ - EditMesh *em = G.editMesh; - EditVert *eve,*v1=0,*v2=0; - EditEdge *eed; - float dvec[3], nor[3]; - - TEST_EDITMESH - if(multires_test()) return; - - /* clear flags */ - eve= em->verts.first; - while(eve) { - eve->f1= 0; - eve= eve->next; - } - /* edges set flags in verts */ - eed= em->edges.first; - while(eed) { - if(eed->v1->f & SELECT) { - if(eed->v2->f & SELECT) { - /* watch: f1 is a byte */ - if(eed->v1->f1<2) eed->v1->f1++; - if(eed->v2->f1<2) eed->v2->f1++; - } - } - eed= eed->next; - } - /* find two vertices with eve->f1==1, more or less is wrong */ - eve= em->verts.first; - while(eve) { - if(eve->f1==1) { - if(v1==0) v1= eve; - else if(v2==0) v2= eve; - else { - v1=0; - break; - } - } - eve= eve->next; - } - if(v1==0 || v2==0) { - error("You have to select a string of connected vertices too"); - return; - } - - /* calculate dvec */ - dvec[0]= ( (v1->co[0]- v2->co[0]) )/(steps); - dvec[1]= ( (v1->co[1]- v2->co[1]) )/(steps); - dvec[2]= ( (v1->co[2]- v2->co[2]) )/(steps); - - copy_v3_v3(nor, G.obedit->obmat[2]); - - if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) { - dvec[0]= -dvec[0]; - dvec[1]= -dvec[1]; - dvec[2]= -dvec[2]; - } - - spin_mesh(turns*steps, turns*360, dvec, 0); - - BIF_undo_push("Spin"); -} - - -static void erase_edges(ListBase *l) -{ - EditEdge *ed, *nexted; - - ed = (EditEdge *) l->first; - while(ed) { - nexted= ed->next; - if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) { - remedge(ed); - free_editedge(ed); - } - ed= nexted; - } -} - -static void erase_faces(ListBase *l) -{ - EditFace *f, *nextf; - - f = (EditFace *) l->first; - - while(f) { - nextf= f->next; - if( faceselectedOR(f, SELECT) ) { - BLI_remlink(l, f); - free_editface(f); - } - f = nextf; - } -} - -static void erase_vertices(ListBase *l) -{ - EditVert *v, *nextv; - - v = (EditVert *) l->first; - while(v) { - nextv= v->next; - if(v->f & 1) { - BLI_remlink(l, v); - free_editvert(v); - } - v = nextv; - } -} - -void delete_mesh(void) -{ - EditMesh *em = G.editMesh; - EditFace *efa, *nextvl; - EditVert *eve,*nextve; - EditEdge *eed,*nexted; - short event; - int count; - char *str="Erase"; - - TEST_EDITMESH - if(multires_test()) return; - - event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5|Edge Loop%x6"); - if(event<1) return; - - if(event==10 ) { - str= "Erase Vertices"; - erase_edges(&em->edges); - erase_faces(&em->faces); - erase_vertices(&em->verts); - } - else if(event==6) { - if(!EdgeLoopDelete()) - return; - - str= "Erase Edge Loop"; - } - else if(event==4) { - str= "Erase Edges & Faces"; - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - /* delete only faces with 1 or more edges selected */ - count= 0; - if(efa->e1->f & SELECT) count++; - if(efa->e2->f & SELECT) count++; - if(efa->e3->f & SELECT) count++; - if(efa->e4 && (efa->e4->f & SELECT)) count++; - if(count) { - BLI_remlink(&em->faces, efa); - free_editface(efa); - } - efa= nextvl; - } - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f & SELECT) { - remedge(eed); - free_editedge(eed); - } - eed= nexted; - } - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - event=0; - if( efa->v1->f & SELECT) event++; - if( efa->v2->f & SELECT) event++; - if( efa->v3->f & SELECT) event++; - if(efa->v4 && (efa->v4->f & SELECT)) event++; - - if(event>1) { - BLI_remlink(&em->faces, efa); - free_editface(efa); - } - efa= nextvl; - } - } - else if(event==1) { - str= "Erase Edges"; - // faces first - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - event=0; - if( efa->e1->f & SELECT) event++; - if( efa->e2->f & SELECT) event++; - if( efa->e3->f & SELECT) event++; - if(efa->e4 && (efa->e4->f & SELECT)) event++; - - if(event) { - BLI_remlink(&em->faces, efa); - free_editface(efa); - } - efa= nextvl; - } - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f & SELECT) { - remedge(eed); - free_editedge(eed); - } - eed= nexted; - } - /* to remove loose vertices: */ - eed= em->edges.first; - while(eed) { - if( eed->v1->f & SELECT) eed->v1->f-=SELECT; - if( eed->v2->f & SELECT) eed->v2->f-=SELECT; - eed= eed->next; - } - eve= em->verts.first; - while(eve) { - nextve= eve->next; - if(eve->f & SELECT) { - BLI_remlink(&em->verts,eve); - free_editvert(eve); - } - eve= nextve; - } - - } - else if(event==2) { - str="Erase Faces"; - delfaceflag(SELECT); - } - else if(event==3) { - str= "Erase All"; - if(em->verts.first) free_vertlist(&em->verts); - if(em->edges.first) free_edgelist(&em->edges); - if(em->faces.first) free_facelist(&em->faces); - if(em->selected.first) BLI_freelistN(&(em->selected)); - } - else if(event==5) { - str= "Erase Only Faces"; - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f & SELECT) { - BLI_remlink(&em->faces, efa); - free_editface(efa); - } - efa= nextvl; - } - } - - EM_fgon_flags(); // redo flags and indices for fgons - - countall(); - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - BIF_undo_push(str); -} - - -/* Got this from scanfill.c. You will need to juggle around the - * callbacks for the scanfill.c code a bit for this to work. */ -void fill_mesh(void) -{ - EditMesh *em = G.editMesh; - EditVert *eve,*v1; - EditEdge *eed,*e1,*nexted; - EditFace *efa,*nextvl, *efan; - short ok; - - if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return; - if(multires_test()) return; - - waitcursor(1); - - /* copy all selected vertices */ - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { - v1= BLI_addfillvert(eve->co); - eve->tmp.v= v1; - v1->tmp.v= eve; - v1->xs= 0; // used for counting edges - } - eve= eve->next; - } - /* copy all selected edges */ - eed= em->edges.first; - while(eed) { - if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) { - e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v); - e1->v1->xs++; - e1->v2->xs++; - } - eed= eed->next; - } - /* from all selected faces: remove vertices and edges to prevent doubles */ - /* all edges add values, faces subtract, - then remove edges with vertices ->xs<2 */ - efa= em->faces.first; - ok= 0; - while(efa) { - nextvl= efa->next; - if( faceselectedAND(efa, 1) ) { - efa->v1->tmp.v->xs--; - efa->v2->tmp.v->xs--; - efa->v3->tmp.v->xs--; - if(efa->v4) efa->v4->tmp.v->xs--; - ok= 1; - - } - efa= nextvl; - } - if(ok) { /* there are faces selected */ - eed= filledgebase.first; - while(eed) { - nexted= eed->next; - if(eed->v1->xs<2 || eed->v2->xs<2) { - BLI_remlink(&filledgebase,eed); - } - eed= nexted; - } - } - - if(BLI_edgefill(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) { - efa= fillfacebase.first; - while(efa) { - /* normals default pointing up */ - efan= addfacelist(efa->v3->tmp.v, efa->v2->tmp.v, - efa->v1->tmp.v, 0, NULL, NULL); - if(efan) EM_select_face(efan, 1); - efa= efa->next; - } - } - - BLI_end_edgefill(); - - waitcursor(0); - EM_select_flush(); - countall(); - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - - BIF_undo_push("Fill"); -} -/*GB*/ -/*-------------------------------------------------------------------------------*/ -/*--------------------------- Edge Based Subdivide ------------------------------*/ - -#define EDGENEW 2 -#define FACENEW 2 -#define EDGEINNER 4 -#define EDGEOLD 8 - -/*used by faceloop cut to select only edges valid for edge slide*/ -#define DOUBLEOPFILL 16 - -/* calculates offset for co, based on fractal, sphere or smooth settings */ -static void alter_co(float *co, EditEdge *edge, float rad, int beauty, float perc) -{ - float vec1[3], fac; - - if(beauty & B_SMOOTH) { - /* we calculate an offset vector vec1[], to be added to *co */ - float len, fac, nor[3], nor1[3], nor2[3]; - - sub_v3_v3v3(nor, edge->v1->co, edge->v2->co); - len= 0.5f*normalize_v3(nor); - - copy_v3_v3(nor1, edge->v1->no); - copy_v3_v3(nor2, edge->v2->no); - - /* cosine angle */ - fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ; - - vec1[0]= fac*nor1[0]; - vec1[1]= fac*nor1[1]; - vec1[2]= fac*nor1[2]; - - /* cosine angle */ - fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ; - - vec1[0]+= fac*nor2[0]; - vec1[1]+= fac*nor2[1]; - vec1[2]+= fac*nor2[2]; - - vec1[0]*= rad*len; - vec1[1]*= rad*len; - vec1[2]*= rad*len; - - co[0] += vec1[0]; - co[1] += vec1[1]; - co[2] += vec1[2]; - } - else { - if(rad > 0.0) { /* subdivide sphere */ - normalize_v3(co); - co[0]*= rad; - co[1]*= rad; - co[2]*= rad; - } - else if(rad< 0.0) { /* fractal subdivide */ - fac= rad* len_v3v3(edge->v1->co, edge->v2->co); - vec1[0]= fac*(float)(0.5-BLI_drand()); - vec1[1]= fac*(float)(0.5-BLI_drand()); - vec1[2]= fac*(float)(0.5-BLI_drand()); - add_v3_v3v3(co, co, vec1); - } - - } -} - -/* assumes in the edge is the correct interpolated vertices already */ -/* percent defines the interpolation, rad and beauty are for special options */ -/* results in new vertex with correct coordinate, vertex normal and weight group info */ -static EditVert *subdivide_edge_addvert(EditEdge *edge, float rad, int beauty, float percent) -{ - EditVert *ev; - float co[3]; - - co[0] = (edge->v2->co[0]-edge->v1->co[0])*percent + edge->v1->co[0]; - co[1] = (edge->v2->co[1]-edge->v1->co[1])*percent + edge->v1->co[1]; - co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2]; - - /* offset for smooth or sphere or fractal */ - alter_co(co, edge, rad, beauty, percent); - - /* clip if needed by mirror modifier */ - if (edge->v1->f2) { - if ( edge->v1->f2 & edge->v2->f2 & 1) { - co[0]= 0.0f; - } - if ( edge->v1->f2 & edge->v2->f2 & 2) { - co[1]= 0.0f; - } - if ( edge->v1->f2 & edge->v2->f2 & 4) { - co[2]= 0.0f; - } - } - - ev = addvertlist(co, NULL); - - /* vert data (vgroups, ..) */ - EM_data_interp_from_verts(edge->v1, edge->v2, ev, percent); - - /* normal */ - ev->no[0] = (edge->v2->no[0]-edge->v1->no[0])*percent + edge->v1->no[0]; - ev->no[1] = (edge->v2->no[1]-edge->v1->no[1])*percent + edge->v1->no[1]; - ev->no[2] = (edge->v2->no[2]-edge->v1->no[2])*percent + edge->v1->no[2]; - normalize_v3(ev->no); - - return ev; -} - -static void flipvertarray(EditVert** arr, short size) -{ - EditVert *hold; - int i; - - for(i=0; iv1->co, *v2 = source->v2->co, *v3 = source->v3->co; - float *v4 = source->v4? source->v4->co: NULL; - float w[4][4]; - - CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data); - - target->mat_nr = source->mat_nr; - target->flag = source->flag; - target->h = source->h; - - interp_weights_face_v3( w[0],v1, v2, v3, v4, target->v1->co); - interp_weights_face_v3( w[1],v1, v2, v3, v4, target->v2->co); - interp_weights_face_v3( w[2],v1, v2, v3, v4, target->v3->co); - if (target->v4) - interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co); - - CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data); -} - -static void fill_quad_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype) -{ - EditEdge *cedge=NULL; - EditVert *v[4], **verts; - EditFace *hold; - short start=0, end, left, right, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} - else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} - else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} - else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} - - // Point verts to the array of new verts for cedge - verts = BLI_ghash_lookup(gh, cedge); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} - end = (start+1)%4; - left = (start+2)%4; - right = (start+3)%4; - - /* - We should have something like this now - - end start - 3 2 1 0 - |---*---*---| - | | - | | - | | - ------------- - left right - - where start,end,left, right are indexes of EditFace->v1, etc (stored in v) - and 0,1,2... are the indexes of the new verts stored in verts - - We will fill this case like this or this depending on even or odd cuts - - |---*---*---| |---*---| - | / \ | | / \ | - | / \ | | / \ | - |/ \| |/ \| - ------------- --------- - */ - - // Make center face - if(vertsize % 2 == 0) { - hold = addfacelist(verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL); - hold->e2->f2 |= EDGEINNER; - hold->e4->f2 |= EDGEINNER; - }else{ - hold = addfacelist(verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL); - hold->e1->f2 |= EDGEINNER; - hold->e3->f2 |= EDGEINNER; - } - facecopy(efa,hold); - - // Make side faces - for(i=0;i<(vertsize-1)/2;i++) { - hold = addfacelist(verts[i],verts[i+1],v[right],NULL,NULL,NULL); - facecopy(efa,hold); - if(i+1 != (vertsize-1)/2) { - if(seltype == SUBDIV_SELECT_INNER) { - hold->e2->f2 |= EDGEINNER; - } - } - hold = addfacelist(verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL); - facecopy(efa,hold); - if(i+1 != (vertsize-1)/2) { - if(seltype == SUBDIV_SELECT_INNER) { - hold->e3->f2 |= EDGEINNER; - } - } - } -} - -static void fill_tri_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype) -{ - EditEdge *cedge=NULL; - EditVert *v[3], **verts; - EditFace *hold; - short start=0, end, op, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - - if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} - else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} - else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} - - // Point verts to the array of new verts for cedge - verts = BLI_ghash_lookup(gh, cedge); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} - end = (start+1)%3; - op = (start+2)%3; - - /* - We should have something like this now - - end start - 3 2 1 0 - |---*---*---| - \ | - \ | - \ | - \ | - \ | - \ | - |op - - where start,end,op are indexes of EditFace->v1, etc (stored in v) - and 0,1,2... are the indexes of the new verts stored in verts - - We will fill this case like this or this depending on even or odd cuts - - 3 2 1 0 - |---*---*---| - \ \ \ | - \ \ \ | - \ \ \ | - \ \ \| - \ \\| - \ | - |op - */ - - // Make side faces - for(i=0;i<(vertsize-1);i++) { - hold = addfacelist(verts[i],verts[i+1],v[op],NULL,NULL,NULL); - if(i+1 != vertsize-1) { - if(seltype == SUBDIV_SELECT_INNER) { - hold->e2->f2 |= EDGEINNER; - } - } - facecopy(efa,hold); - } -} - -static void fill_quad_double_op(EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], **verts[2]; - EditFace *hold; - short start=0, end, left, right, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT) { cedge[0] = efa->e1; cedge[1] = efa->e3; start = 0;} - else if(efa->e2->f & SELECT) { cedge[0] = efa->e2; cedge[1] = efa->e4; start = 1;} - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - end = (start+1)%4; - left = (start+2)%4; - right = (start+3)%4; - if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - |---*---*---| - | | - | | - | | - |---*---*---| - 0 1 2 3 - left right - - We will fill this case like this or this depending on even or odd cuts - - |---*---*---| - | | | | - | | | | - | | | | - |---*---*---| - */ - - // Make side faces - for(i=0;ie2->f2 |= EDGEINNER; - hold->e2->f2 |= DOUBLEOPFILL; - } - facecopy(efa,hold); - } -} - -static void fill_quad_double_adj_path(EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], **verts[2]; - EditFace *hold; - short start=0, start2=0, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} - if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3;} - if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0;} - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | | - 1* | - | | - 2* | - | | - end2 3|-----------| - - We will fill this case like this or this depending on even or odd cuts - |---*---*---| - | / / / | - * / / | - | / / | - * / | - | / | - |-----------| - */ - - // Make outside tris - hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); - /* when ctrl is depressed, only want verts on the cutline selected */ - if (G.qual != LR_CTRLKEY) - hold->e3->f2 |= EDGEINNER; - facecopy(efa,hold); - hold = addfacelist(verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL); - /* when ctrl is depressed, only want verts on the cutline selected */ - if (G.qual != LR_CTRLKEY) - hold->e1->f2 |= EDGEINNER; - facecopy(efa,hold); - //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e1->h |= EM_FGON; - //} - // Make side faces - - for(i=0;ie2->f2 |= EDGEINNER; - facecopy(efa,hold); - } - //EM_fgon_flags(); - -} - -static void fill_quad_double_adj_fan(EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], *op=NULL, **verts[2]; - EditFace *hold; - short start=0, start2=0, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} - if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} - if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} - - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | | - 1* | - | | - 2* | - | | - end2 3|-----------|op - - We will fill this case like this or this (warning horrible ascii art follows) - |---*---*---| - | \ \ \ | - *---\ \ \ | - | \ \ \ \| - *---- \ \ \ | - | --- \\\| - |-----------| - */ - - for(i=0;i<=numcuts;i++) { - hold = addfacelist(op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL); - hold->e1->f2 |= EDGEINNER; - facecopy(efa,hold); - - hold = addfacelist(op,verts[0][i],verts[0][i+1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(efa,hold); - } -} - -static void fill_quad_double_adj_inner(EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], *op=NULL, **verts[2],**inner; - EditFace *hold; - short start=0, start2=0, vertsize,i; - float co[3]; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} - if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} - if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} - - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | | - 1* | - | | - 2* | - | | - end2 3|-----------|op - - We will fill this case like this or this (warning horrible ascii art follows) - |---*-----*---| - | * / | - * \ / | - | * | - | / \ | - * \ | - | \ | - |-------------| - */ - - // Add Inner Vert(s) - inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts"); - - for(i=0;ico[0] + verts[1][i+1]->co[0] ) / 2 ; - co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ; - co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ; - inner[i] = addvertlist(co, NULL); - inner[i]->f2 |= EDGEINNER; - - EM_data_interp_from_verts(verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f); - } - - // Add Corner Quad - hold = addfacelist(verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - hold->e3->f2 |= EDGEINNER; - facecopy(efa,hold); - // Add Bottom Quads - hold = addfacelist(verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(efa,hold); - - hold = addfacelist(op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(efa,hold); - - //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e1->h |= EM_FGON; - //} - // Add Fill Quads (if # cuts > 1) - - for(i=0;ie1->f2 |= EDGEINNER; - hold->e3->f2 |= EDGEINNER; - facecopy(efa,hold); - - hold = addfacelist(inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - hold->e4->f2 |= EDGEINNER; - facecopy(efa,hold); - - //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e1->h |= EM_FGON; - //} - } - - //EM_fgon_flags(); - - MEM_freeN(inner); -} - -static void fill_tri_double(EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[3], **verts[2]; - EditFace *hold; - short start=0, start2=0, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} - if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e1; start = 2; start2 = 0;} - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | / - 1* / - | / - 2* / - | / - end2 3| - - We will fill this case like this or this depending on even or odd cuts - |---*---*---| - | / / / - * / / - | / / - * / - | / - | - */ - - // Make outside tri - hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(efa,hold); - // Make side faces - - for(i=0;ie2->f2 |= EDGEINNER; - facecopy(efa,hold); - } -} - -static void fill_quad_triple(EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[3]={0}; - EditVert *v[4], **verts[3]; - EditFace *hold; - short start=0, start2=0, start3=0, vertsize, i, repeats; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(!(efa->e1->f & SELECT)) { - cedge[0] = efa->e2; - cedge[1] = efa->e3; - cedge[2] = efa->e4; - start = 1;start2 = 2;start3 = 3; - } - if(!(efa->e2->f & SELECT)) { - cedge[0] = efa->e3; - cedge[1] = efa->e4; - cedge[2] = efa->e1; - start = 2;start2 = 3;start3 = 0; - } - if(!(efa->e3->f & SELECT)) { - cedge[0] = efa->e4; - cedge[1] = efa->e1; - cedge[2] = efa->e2; - start = 3;start2 = 0;start3 = 1; - } - if(!(efa->e4->f & SELECT)) { - cedge[0] = efa->e1; - cedge[1] = efa->e2; - cedge[2] = efa->e3; - start = 0;start2 = 1;start3 = 2; - } - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - verts[2] = BLI_ghash_lookup(gh, cedge[2]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);} - /* - We should have something like this now - - start2 - 3 2 1 0 - start3 0|---*---*---|3 - | | - 1* *2 - | | - 2* *1 - | | - 3|-----------|0 start - - We will fill this case like this or this depending on even or odd cuts - there are a couple of differences. For odd cuts, there is a tri in the - middle as well as 1 quad at the bottom (not including the extra quads - for odd cuts > 1 - - For even cuts, there is a quad in the middle and 2 quads on the bottom - - they are numbered here for clarity - - 1 outer tris and bottom quads - 2 inner tri or quad - 3 repeating quads - - |---*---*---*---| - |1/ / \ \ 1| - |/ 3 / \ 3 \| - * / 2 \ * - | / \ | - |/ \ | - *---------------* - | 3 | - | | - *---------------* - | | - | 1 | - | | - |---------------| - - |---*---*---*---*---| - | 1/ / \ \ 1| - | / / \ \ | - |/ 3 / \ 3 \| - * / \ * - | / \ | - | / 2 \ | - |/ \| - *-------------------* - | | - | 3 | - | | - *-------------------* - | | - | 1 | - | | - *-------------------* - | | - | 1 | - | | - |-------------------| - - */ - - // Make outside tris - hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(efa,hold); - hold = addfacelist(verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(efa,hold); - // Make bottom quad - hold = addfacelist(verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(efa,hold); - //If it is even cuts, add the 2nd lower quad - if(numcuts % 2 == 0) { - hold = addfacelist(verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(efa,hold); - // Also Make inner quad - hold = addfacelist(verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL); - hold->e3->f2 |= EDGEINNER; - //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e3->h |= EM_FGON; - //} - facecopy(efa,hold); - repeats = (numcuts / 2) -1; - } else { - // Make inner tri - hold = addfacelist(verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL); - hold->e2->f2 |= EDGEINNER; - //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e2->h |= EM_FGON; - //} - facecopy(efa,hold); - repeats = ((numcuts+1) / 2)-1; - } - - // cuts for 1 and 2 do not have the repeating quads - if(numcuts < 3) {repeats = 0;} - for(i=0;ie2->f2 |= EDGEINNER; - facecopy(efa,hold); - hold = addfacelist(verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL); - hold->e4->f2 |= EDGEINNER; - facecopy(efa,hold); - } - // Do repeating bottom quads - for(i=0;ie2->f2 |= EDGEINNER; - facecopy(efa,hold); - } - //EM_fgon_flags(); -} - -static void fill_quad_quadruple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty) -{ - EditVert **verts[4], ***innerverts; - EditFace *hold; - EditEdge temp; - short vertsize, i, j; - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, efa->e1); - verts[1] = BLI_ghash_lookup(gh, efa->e2); - verts[2] = BLI_ghash_lookup(gh, efa->e3); - verts[3] = BLI_ghash_lookup(gh, efa->e4); - - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} - if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);} - if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);} - /* - We should have something like this now - 1 - - 3 2 1 0 - 0|---*---*---|0 - | | - 1* *1 - 2 | | 4 - 2* *2 - | | - 3|---*---*---|3 - 3 2 1 0 - - 3 - // we will fill a 2 dim array of editvert*s to make filling easier - // the innervert order is shown - - 0 0---1---2---3 - | | | | - 1 0---1---2---3 - | | | | - 2 0---1---2---3 - | | | | - 3 0---1---2---3 - - */ - innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array"); - for(i=0;ie1->f2 = EDGENEW; - hold->e2->f2 = EDGENEW; - hold->e3->f2 = EDGENEW; - hold->e4->f2 = EDGENEW; - - if(i != 0) { hold->e1->f2 |= EDGEINNER; } - if(j != 0) { hold->e2->f2 |= EDGEINNER; } - if(i != numcuts) { hold->e3->f2 |= EDGEINNER; } - if(j != numcuts) { hold->e4->f2 |= EDGEINNER; } - - facecopy(efa,hold); - } - } - // Clean up our dynamic multi-dim array - for(i=0;ie1); - verts[1] = BLI_ghash_lookup(gh, efa->e2); - verts[2] = BLI_ghash_lookup(gh, efa->e3); - - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} - if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);} - /* - We should have something like this now - 3 - - 3 2 1 0 - 0|---*---*---|3 - | / - 1 1* *2 - | / - 2* *1 2 - | / - 3|/ - 0 - - we will fill a 2 dim array of editvert*s to make filling easier - - 3 - - 0 0---1---2---3---4 - | / | / |/ | / - 1 0---1----2---3 - 1 | / | / | / - 2 0----1---2 2 - | / | / - |/ |/ - 3 0---1 - | / - |/ - 4 0 - - */ - - innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array"); - for(i=0;ie1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - if(i != 0) { hold->e1->f2 |= EDGEINNER; } - if(j != 0) { hold->e2->f2 |= EDGEINNER; } - if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;} - - facecopy(efa,hold); - //if there are more to come, we do the 2nd - if(j+1 <= numcuts-i) { - hold = addfacelist(innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL); - facecopy(efa,hold); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - } - } - } - - // Clean up our dynamic multi-dim array - for(i=0;iv1, efa->v2, efa->v3, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e3->f2 |= EDGEINNER; - facecopy(efa, hold); - - hold= addfacelist(efa->v1, efa->v3, efa->v4, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e1->f2 |= EDGEINNER; - facecopy(efa, hold); - } - else{ - hold= addfacelist(efa->v1, efa->v2, efa->v4, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e2->f2 |= EDGEINNER; - facecopy(efa, hold); - - hold= addfacelist(efa->v2, efa->v3, efa->v4, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e3->f2 |= EDGEINNER; - facecopy(efa, hold); - } -} - -static void fill_quad_singlevert(EditFace *efa, struct GHash *gh) -{ - EditEdge *cedge=NULL; - EditVert *v[4], **verts; - EditFace *hold; - short start=0, end, left, right, vertsize; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} - else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} - else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} - else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} - - // Point verts to the array of new verts for cedge - verts = BLI_ghash_lookup(gh, cedge); - //This is the index size of the verts array - vertsize = 3; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0] != v[start]) {flipvertarray(verts,3);} - end = (start+1)%4; - left = (start+2)%4; - right = (start+3)%4; - -/* - We should have something like this now - - end start - 2 1 0 - |-----*-----| - | | - | | - | | - ------------- - left right - - where start,end,left, right are indexes of EditFace->v1, etc (stored in v) - and 0,1,2 are the indexes of the new verts stored in verts. We fill like - this, depending on whether its vertex 'left' or vertex 'right' thats - been knifed through... - - |---*---| |---*---| - | / | | \ | - | / | | \ | - |/ | | \| - X-------- --------X -*/ - - if(v[left]->f1) { - //triangle is composed of cutvert, end and left - hold = addfacelist(verts[1],v[end],v[left],NULL, NULL,NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e3->f2 |= EDGEINNER; - facecopy(efa, hold); - - //quad is composed of cutvert, left, right and start - hold = addfacelist(verts[1],v[left],v[right],v[start], NULL, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e4->f2 |= EDGENEW; - hold->e1->f2 |= EDGEINNER; - facecopy(efa, hold); - } - else if(v[right]->f1) { - //triangle is composed of cutvert, right and start - hold = addfacelist(verts[1],v[right],v[start], NULL, NULL, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e1->f2 |= EDGEINNER; - facecopy(efa, hold); - //quad is composed of cutvert, end, left, right - hold = addfacelist(verts[1],v[end], v[left], v[right], NULL, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e4->f2 |= EDGENEW; - hold->e4->f2 |= EDGEINNER; - facecopy(efa, hold); - } - -} - -// This function takes an example edge, the current point to create and -// the total # of points to create, then creates the point and return the -// editvert pointer to it. -static EditVert *subdivideedgenum(EditEdge *edge, int curpoint, int totpoint, float rad, int beauty) -{ - EditVert *ev; - float percent; - - if (beauty & (B_PERCENTSUBD) && totpoint == 1) - //percent=(float)(edge->tmp.l)/32768.0f; - percent= edge->tmp.fp; - else - percent= (float)curpoint/(float)(totpoint+1); - - ev= subdivide_edge_addvert(edge, rad, beauty, percent); - ev->f = edge->v1->f; - - return ev; -} - -void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype) -{ - EditMesh *em = G.editMesh; - EditFace *ef; - EditEdge *eed, *cedge, *sort[4]; - EditVert *eve, **templist; - struct GHash *gh; - float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3]; - int i, j, edgecount, touchcount, facetype,hold; - ModifierData *md= G.obedit->modifiers.first; - - if(multires_test()) return; - - //Set faces f1 to 0 cause we need it later - for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0; - for(eve=em->verts.first; eve; eve=eve->next) { - if(!(beauty & B_KNIFE)) /* knife sets this flag for vertex cuts */ - eve->f1 = 0; - eve->f2 = 0; - } - - for (; md; md=md->next) { - if ((md->type==eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData*) md; - - if(mmd->flag & MOD_MIR_CLIPPING) { - for (eve= em->verts.first; eve; eve= eve->next) { - eve->f2= 0; - switch(mmd->axis) { - case 0: - if (fabs(eve->co[0]) < mmd->tolerance) - eve->f2 |= 1; - break; - case 1: - if (fabs(eve->co[1]) < mmd->tolerance) - eve->f2 |= 2; - break; - case 2: - if (fabs(eve->co[2]) < mmd->tolerance) - eve->f2 |= 4; - break; - } - } - } - } - } - - //Flush vertex flags upward to the edges - for(eed = em->edges.first;eed;eed = eed->next) { - //if(eed->f & flag && eed->v1->f == eed->v2->f) { - // eed->f |= eed->v1->f; - // } - eed->f2 = 0; - if(eed->f & flag) { - eed->f2 |= EDGEOLD; - } - } - - // We store an array of verts for each edge that is subdivided, - // we put this array as a value in a ghash which is keyed by the EditEdge* - - // Now for beauty subdivide deselect edges based on length - if(beauty & B_BEAUTY) { - for(ef = em->faces.first;ef;ef = ef->next) { - if(!ef->v4) { - continue; - } - if(ef->f & SELECT) { - copy_v3_v3(v1mat, ef->v1->co); - copy_v3_v3(v2mat, ef->v2->co); - copy_v3_v3(v3mat, ef->v3->co); - copy_v3_v3(v4mat, ef->v4->co); - mul_mat3_m4_v3(G.obedit->obmat, v1mat); - mul_mat3_m4_v3(G.obedit->obmat, v2mat); - mul_mat3_m4_v3(G.obedit->obmat, v3mat); - mul_mat3_m4_v3(G.obedit->obmat, v4mat); - - length[0] = len_v3v3(v1mat, v2mat); - length[1] = len_v3v3(v2mat, v3mat); - length[2] = len_v3v3(v3mat, v4mat); - length[3] = len_v3v3(v4mat, v1mat); - sort[0] = ef->e1; - sort[1] = ef->e2; - sort[2] = ef->e3; - sort[3] = ef->e4; - - - // Beauty Short Edges - if(beauty & B_BEAUTY_SHORT) { - for(j=0;j<2;j++) { - hold = -1; - for(i=0;i<4;i++) { - if(length[i] < 0) { - continue; - } else if(hold == -1) { - hold = i; - } else { - if(length[hold] < length[i]) { - hold = i; - } - } - } - sort[hold]->f &= ~SELECT; - sort[hold]->f2 |= EDGENEW; - length[hold] = -1; - } - } - - // Beauty Long Edges - else { - for(j=0;j<2;j++) { - hold = -1; - for(i=0;i<4;i++) { - if(length[i] < 0) { - continue; - } else if(hold == -1) { - hold = i; - } else { - if(length[hold] > length[i]) { - hold = i; - } - } - } - sort[hold]->f &= ~SELECT; - sort[hold]->f2 |= EDGENEW; - length[hold] = -1; - } - } - } - } - } - - gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - - // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut - if(beauty & B_KNIFE) { - for(eed= em->edges.first;eed;eed=eed->next) { - if( eed->tmp.fp == 0 ) { - EM_select_edge(eed,0); - } - } - } - // So for each edge, if it is selected, we allocate an array of size cuts+2 - // so we can have a place for the v1, the new verts and v2 - for(eed=em->edges.first;eed;eed = eed->next) { - if(eed->f & flag) { - templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist"); - templist[0] = eed->v1; - for(i=0;if2 = EDGENEW; - } - templist[i+1] = eed->v2; - //Do the last edge too - cedge = addedgelist(templist[i],templist[i+1],eed); - cedge->f2 = EDGENEW; - // Now that the edge is subdivided, we can put its verts in the ghash - BLI_ghash_insert(gh, eed, templist); - } - } - - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - // Now for each face in the mesh we need to figure out How many edges were cut - // and which filling method to use for that face - for(ef = em->faces.first;ef;ef = ef->next) { - edgecount = 0; - facetype = 3; - if(ef->e1->f & flag) {edgecount++;} - if(ef->e2->f & flag) {edgecount++;} - if(ef->e3->f & flag) {edgecount++;} - if(ef->v4) { - facetype = 4; - if(ef->e4->f & flag) {edgecount++;} - } - if(facetype == 4) { - switch(edgecount) { - case 0: - if(beauty & B_KNIFE && numcuts == 1){ - /*Test for when knifing through two opposite verts but no edges*/ - touchcount = 0; - if(ef->v1->f1) touchcount++; - if(ef->v2->f1) touchcount++; - if(ef->v3->f1) touchcount++; - if(ef->v4->f1) touchcount++; - if(touchcount == 2){ - if(ef->v1->f1 && ef->v3->f1){ - ef->f1 = SELECT; - fill_quad_doublevert(ef, 1, 3); - } - else if(ef->v2->f1 && ef->v4->f1){ - ef->f1 = SELECT; - fill_quad_doublevert(ef, 2, 4); - } - } - } - break; - - case 1: - if(beauty & B_KNIFE && numcuts == 1){ - /*Test for when knifing through an edge and one vert*/ - touchcount = 0; - if(ef->v1->f1) touchcount++; - if(ef->v2->f1) touchcount++; - if(ef->v3->f1) touchcount++; - if(ef->v4->f1) touchcount++; - - if(touchcount == 1){ - if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) || - (ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) || - (ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) || - (ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){ - - ef->f1 = SELECT; - fill_quad_singlevert(ef, gh); - } - else{ - ef->f1 = SELECT; - fill_quad_single(ef, gh, numcuts, seltype); - } - } - else{ - ef->f1 = SELECT; - fill_quad_single(ef, gh, numcuts, seltype); - } - } - else{ - ef->f1 = SELECT; - fill_quad_single(ef, gh, numcuts, seltype); - } - break; - case 2: ef->f1 = SELECT; - // if there are 2, we check if edge 1 and 3 are either both on or off that way - // we can tell if the selected pair is Adjacent or Opposite of each other - if((ef->e1->f & flag && ef->e3->f & flag) || - (ef->e2->f & flag && ef->e4->f & flag)) { - fill_quad_double_op(ef, gh, numcuts); - }else{ - switch(G.scene->toolsettings->cornertype) { - case 0: fill_quad_double_adj_path(ef, gh, numcuts); break; - case 1: fill_quad_double_adj_inner(ef, gh, numcuts); break; - case 2: fill_quad_double_adj_fan(ef, gh, numcuts); break; - } - - } - break; - case 3: ef->f1 = SELECT; - fill_quad_triple(ef, gh, numcuts); - break; - case 4: ef->f1 = SELECT; - fill_quad_quadruple(ef, gh, numcuts, rad, beauty); - break; - } - } else { - switch(edgecount) { - case 0: break; - case 1: ef->f1 = SELECT; - fill_tri_single(ef, gh, numcuts, seltype); - break; - case 2: ef->f1 = SELECT; - fill_tri_double(ef, gh, numcuts); - break; - case 3: ef->f1 = SELECT; - fill_tri_triple(ef, gh, numcuts, rad, beauty); - break; - } - } - } - - // Delete Old Edges and Faces - for(eed = em->edges.first;eed;eed = eed->next) { - if(BLI_ghash_haskey(gh,eed)) { - eed->f1 = SELECT; - } else { - eed->f1 = 0; - } - } - free_tagged_edges_faces(em->edges.first, em->faces.first); - - if(seltype == SUBDIV_SELECT_ORIG && G.qual != LR_CTRLKEY) { - /* bugfix: vertex could get flagged as "not-selected" - // solution: clear flags before, not at the same time as setting SELECT flag -dg - */ - for(eed = em->edges.first;eed;eed = eed->next) { - if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) { - eed->f &= !flag; - EM_select_edge(eed,0); - } - } - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) { - eed->f |= flag; - EM_select_edge(eed,1); - } - } - } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| G.qual == LR_CTRLKEY) { - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f2 & EDGEINNER) { - eed->f |= flag; - EM_select_edge(eed,1); - if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT; - if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT; - }else{ - eed->f &= !flag; - EM_select_edge(eed,0); - } - } - } else if(seltype == SUBDIV_SELECT_LOOPCUT){ - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f2 & DOUBLEOPFILL){ - eed->f |= flag; - EM_select_edge(eed,1); - }else{ - eed->f &= !flag; - EM_select_edge(eed,0); - } - } - } - if(G.scene->selectmode & SCE_SELECT_VERTEX) { - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f & SELECT) { - eed->v1->f |= SELECT; - eed->v2->f |= SELECT; - } - } - } - - //fix hide flags for edges. First pass, hide edges of hidden faces - for(ef=em->faces.first; ef; ef=ef->next){ - if(ef->h){ - ef->e1->h |= 1; - ef->e2->h |= 1; - ef->e3->h |= 1; - if(ef->e4) ef->e4->h |= 1; - } - } - //second pass: unhide edges of visible faces adjacent to hidden faces - for(ef=em->faces.first; ef; ef=ef->next){ - if(ef->h == 0){ - ef->e1->h &= ~1; - ef->e2->h &= ~1; - ef->e3->h &= ~1; - if(ef->e4) ef->e4->h &= ~1; - } - } - - // Free the ghash and call MEM_freeN on all the value entries to return - // that memory - BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); - - EM_selectmode_flush(); - for(ef=em->faces.first;ef;ef = ef->next) { - if(ef->e4) { - if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && - (ef->e3->f & SELECT && ef->e4->f & SELECT) ) { - ef->f |= SELECT; - } - } else { - if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) { - ef->f |= SELECT; - } - } - } - - recalc_editnormals(); - countall(); - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); -} - -static int count_selected_edges(EditEdge *ed) -{ - int totedge = 0; - while(ed) { - ed->tmp.p = 0; - if( ed->f & SELECT ) totedge++; - ed= ed->next; - } - return totedge; -} - -/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */ -typedef EditFace *EVPtr; -typedef EVPtr EVPTuple[2]; - -/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces) - sharing one edge. - arguments: selected edge list, face list. - Edges will also be tagged accordingly (see eed->f2) */ - -static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa) -{ - EditEdge *e1, *e2, *e3; - EVPtr *evp; - int i = 0; - - /* run through edges, if selected, set pointer edge-> facearray */ - while(eed) { - eed->f2= 0; - eed->f1= 0; - if( eed->f & SELECT ) { - eed->tmp.p = (EditVert *) (&efaa[i]); - i++; - } - else eed->tmp.p = NULL; - - eed= eed->next; - } - - - /* find edges pointing to 2 faces by procedure: - - - run through faces and their edges, increase - face counter e->f1 for each face - */ - - while(efa) { - efa->f1= 0; - if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */ - e1= efa->e1; - e2= efa->e2; - e3= efa->e3; - if(e1->f2<3 && e1->tmp.p) { - if(e1->f2<2) { - evp= (EVPtr *) e1->tmp.p; - evp[(int)e1->f2] = efa; - } - e1->f2+= 1; - } - if(e2->f2<3 && e2->tmp.p) { - if(e2->f2<2) { - evp= (EVPtr *) e2->tmp.p; - evp[(int)e2->f2]= efa; - } - e2->f2+= 1; - } - if(e3->f2<3 && e3->tmp.p) { - if(e3->f2<2) { - evp= (EVPtr *) e3->tmp.p; - evp[(int)e3->f2]= efa; - } - e3->f2+= 1; - } - } - else { - /* set to 3 to make sure these are not flipped or joined */ - efa->e1->f2= 3; - efa->e2->f2= 3; - efa->e3->f2= 3; - if (efa->e4) efa->e4->f2= 3; - } - - efa= efa->next; - } - return i; -} - - -/* returns vertices of two adjacent triangles forming a quad - - can be righthand or lefthand - - 4-----3 - |\ | - | \ 2 | <- efa1 - | \ | - efa-> | 1 \ | - | \| - 1-----2 - -*/ -#define VTEST(face, num, other) \ - (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3) - -static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex) -{ - if VTEST(efa, 1, efa1) { - *v1= efa->v1; - *v2= efa->v2; - vindex[0]= 0; - vindex[1]= 1; - } - else if VTEST(efa, 2, efa1) { - *v1= efa->v2; - *v2= efa->v3; - vindex[0]= 1; - vindex[1]= 2; - } - else if VTEST(efa, 3, efa1) { - *v1= efa->v3; - *v2= efa->v1; - vindex[0]= 2; - vindex[1]= 0; - } - - if VTEST(efa1, 1, efa) { - *v3= efa1->v1; - *v4= efa1->v2; - vindex[2]= 0; - vindex[3]= 1; - } - else if VTEST(efa1, 2, efa) { - *v3= efa1->v2; - *v4= efa1->v3; - vindex[2]= 1; - vindex[3]= 2; - } - else if VTEST(efa1, 3, efa) { - *v3= efa1->v3; - *v4= efa1->v1; - vindex[2]= 2; - vindex[3]= 0; - } - else - *v3= *v4= NULL; -} - -/* Helper functions for edge/quad edit features*/ -static void untag_edges(EditFace *f) -{ - f->e1->f1 = 0; - f->e2->f1 = 0; - f->e3->f1 = 0; - if (f->e4) f->e4->f1 = 0; -} - -/** remove and free list of tagged edges and faces */ -static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa) -{ - EditMesh *em= G.editMesh; - EditEdge *nexted; - EditFace *nextvl; - - while(efa) { - nextvl= efa->next; - if(efa->f1) { - BLI_remlink(&em->faces, efa); - free_editface(efa); - } - else - /* avoid deleting edges that are still in use */ - untag_edges(efa); - efa= nextvl; - } - - while(eed) { - nexted= eed->next; - if(eed->f1) { - remedge(eed); - free_editedge(eed); - } - eed= nexted; - } -} - -/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the - edge/face flags, with very mixed results.... */ -void beauty_fill(void) -{ - EditMesh *em = G.editMesh; - EditVert *v1, *v2, *v3, *v4; - EditEdge *eed, *nexted; - EditEdge dia1, dia2; - EditFace *efa, *w; - // void **efaar, **efaa; - EVPTuple *efaar; - EVPtr *efaa; - float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2; - int totedge, ok, notbeauty=8, onedone, vindex[4]; - - if(multires_test()) return; - - /* - all selected edges with two faces - * - find the faces: store them in edges (using datablock) - * - per edge: - test convex - * - test edge: flip? - * - if true: remedge, addedge, all edges at the edge get new face pointers - */ - - EM_selectmode_set(); // makes sure in selectmode 'face' the edges of selected faces are selected too - - totedge = count_selected_edges(em->edges.first); - if(totedge==0) return; - - /* temp block with face pointers */ - efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill"); - - while (notbeauty) { - notbeauty--; - - ok = collect_quadedges(efaar, em->edges.first, em->faces.first); - - /* there we go */ - onedone= 0; - - eed= em->edges.first; - while(eed) { - nexted= eed->next; - - /* f2 is set in collect_quadedges() */ - if(eed->f2==2 && eed->h==0) { - - efaa = (EVPtr *) eed->tmp.p; - - /* none of the faces should be treated before, nor be part of fgon */ - ok= 1; - efa= efaa[0]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - if(efa->fgonf) ok= 0; - efa= efaa[1]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - if(efa->fgonf) ok= 0; - - if(ok) { - /* test convex */ - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - if(v1 && v2 && v3 && v4) { - if( convex(v1->co, v2->co, v3->co, v4->co) ) { - - /* test edges */ - if( (v1) > (v3) ) { - dia1.v1= v3; - dia1.v2= v1; - } - else { - dia1.v1= v1; - dia1.v2= v3; - } - - if( (v2) > (v4) ) { - dia2.v1= v4; - dia2.v2= v2; - } - else { - dia2.v1= v2; - dia2.v2= v4; - } - - /* testing rule: - * the area divided by the total edge lengths - */ - - len1= len_v3v3(v1->co, v2->co); - len2= len_v3v3(v2->co, v3->co); - len3= len_v3v3(v3->co, v4->co); - len4= len_v3v3(v4->co, v1->co); - len5= len_v3v3(v1->co, v3->co); - len6= len_v3v3(v2->co, v4->co); - - opp1= area_tri_v3(v1->co, v2->co, v3->co); - opp2= area_tri_v3(v1->co, v3->co, v4->co); - - fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5); - - opp1= area_tri_v3(v2->co, v3->co, v4->co); - opp2= area_tri_v3(v2->co, v4->co, v1->co); - - fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6); - - ok= 0; - if(fac1 > fac2) { - if(dia2.v1==eed->v1 && dia2.v2==eed->v2) { - eed->f1= 1; - efa= efaa[0]; - efa->f1= 1; - efa= efaa[1]; - efa->f1= 1; - - w= EM_face_from_faces(efaa[0], efaa[1], - vindex[0], vindex[1], 4+vindex[2], -1); - w->f |= SELECT; - - - w= EM_face_from_faces(efaa[0], efaa[1], - vindex[0], 4+vindex[2], 4+vindex[3], -1); - w->f |= SELECT; - - onedone= 1; - } - } - else if(fac1 < fac2) { - if(dia1.v1==eed->v1 && dia1.v2==eed->v2) { - eed->f1= 1; - efa= efaa[0]; - efa->f1= 1; - efa= efaa[1]; - efa->f1= 1; - - - w= EM_face_from_faces(efaa[0], efaa[1], - vindex[1], 4+vindex[2], 4+vindex[3], -1); - w->f |= SELECT; - - - w= EM_face_from_faces(efaa[0], efaa[1], - vindex[0], 4+vindex[1], 4+vindex[3], -1); - w->f |= SELECT; - - onedone= 1; - } - } - } - } - } - - } - eed= nexted; - } - - free_tagged_edges_faces(em->edges.first, em->faces.first); - - if(onedone==0) break; - - EM_selectmode_set(); // new edges/faces were added - } - - MEM_freeN(efaar); - - EM_select_flush(); - - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - BIF_undo_push("Beauty Fill"); -} - - -/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */ -static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit) -{ - - /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/ - /*Note: this is more complicated than it needs to be and should be cleaned up...*/ - float measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff, - edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff, - minarea, maxarea, areaA, areaB; - - /*First Test: Normal difference*/ - normal_tri_v3( noA1,v1->co, v2->co, v3->co); - normal_tri_v3( noA2,v1->co, v3->co, v4->co); - - if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0; - else normalADiff = angle_v2v2(noA1, noA2); - //if(!normalADiff) normalADiff = 179; - normal_tri_v3( noB1,v2->co, v3->co, v4->co); - normal_tri_v3( noB2,v4->co, v1->co, v2->co); - - if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0; - else normalBDiff = angle_v2v2(noB1, noB2); - //if(!normalBDiff) normalBDiff = 179; - - measure += (normalADiff/360) + (normalBDiff/360); - if(measure > limit) return measure; - - /*Second test: Colinearity*/ - sub_v3_v3v3(edgeVec1, v1->co, v2->co); - sub_v3_v3v3(edgeVec2, v2->co, v3->co); - sub_v3_v3v3(edgeVec3, v3->co, v4->co); - sub_v3_v3v3(edgeVec4, v4->co, v1->co); - - diff = 0.0; - - diff = ( - fabs(angle_v2v2(edgeVec1, edgeVec2) - 90) + - fabs(angle_v2v2(edgeVec2, edgeVec3) - 90) + - fabs(angle_v2v2(edgeVec3, edgeVec4) - 90) + - fabs(angle_v2v2(edgeVec4, edgeVec1) - 90)) / 360; - if(!diff) return 0.0; - - measure += diff; - if(measure > limit) return measure; - - /*Third test: Concavity*/ - areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co); - areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co); - - if(areaA <= areaB) minarea = areaA; - else minarea = areaB; - - if(areaA >= areaB) maxarea = areaA; - else maxarea = areaB; - - if(!maxarea) measure += 1; - else measure += (1 - (minarea / maxarea)); - - return measure; -} - -#define T2QUV_LIMIT 0.005 -#define T2QCOL_LIMIT 3 -static int compareFaceAttribs(EditFace *f1, EditFace *f2, EditEdge *eed) -{ - /*Test to see if the per-face attributes for the joining edge match within limit*/ - MTFace *tf1, *tf2; - unsigned int *col1, *col2; - short i,attrok=0, flag = G.scene->toolsettings->editbutflag, fe1[2], fe2[2]; - - tf1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MTFACE); - tf2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MTFACE); - - col1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MCOL); - col2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MCOL); - - /*store indices for faceedges*/ - f1->v1->f1 = 0; - f1->v2->f1 = 1; - f1->v3->f1 = 2; - - fe1[0] = eed->v1->f1; - fe1[1] = eed->v2->f1; - - f2->v1->f1 = 0; - f2->v2->f1 = 1; - f2->v3->f1 = 2; - - fe2[0] = eed->v1->f1; - fe2[1] = eed->v2->f1; - - /*compare faceedges for each face attribute. Additional per face attributes can be added later*/ - /*do UVs*/ - if(flag & B_JOINTRIA_UV){ - - if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV; - else if(tf1->tpage != tf2->tpage); /*do nothing*/ - else{ - for(i = 0; i < 2; i++){ - if(tf1->uv[fe1[i]][0] + T2QUV_LIMIT > tf2->uv[fe2[i]][0] && tf1->uv[fe1[i]][0] - T2QUV_LIMIT < tf2->uv[fe2[i]][0] && - tf1->uv[fe1[i]][1] + T2QUV_LIMIT > tf2->uv[fe2[i]][1] && tf1->uv[fe1[i]][1] - T2QUV_LIMIT < tf2->uv[fe2[i]][1]) attrok |= B_JOINTRIA_UV; - } - } - } - - /*do VCOLs*/ - if(flag & B_JOINTRIA_VCOL){ - if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL; - else{ - char *f1vcol, *f2vcol; - for(i = 0; i < 2; i++){ - f1vcol = (char *)&(col1[fe1[i]]); - f2vcol = (char *)&(col2[fe2[i]]); - - /*compare f1vcol with f2vcol*/ - if( f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] && - f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] && - f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL; - } - } - } - - if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1; - return 0; -} - -static int fplcmp(const void *v1, const void *v2) -{ - const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2); - - if( e1->crease > e2->crease) return 1; - else if( e1->crease < e2->crease) return -1; - - return 0; -} - -/*Bitflags for edges.*/ -#define T2QDELETE 1 -#define T2QCOMPLEX 2 -#define T2QJOIN 4 -void join_triangles(void) -{ - EditMesh *em=G.editMesh; - EditVert *v1, *v2, *v3, *v4, *eve; - EditEdge *eed, **edsortblock = NULL, **edb = NULL; - EditFace *efa; - EVPTuple *efaar = NULL; - EVPtr *efaa = NULL; - float *creases = NULL; - float measure; /*Used to set tolerance*/ - float limit = G.scene->toolsettings->jointrilimit; - int i, ok, totedge=0, totseledge=0, complexedges, vindex[4]; - - /*test for multi-resolution data*/ - if(multires_test()) return; - - /*if we take a long time on very dense meshes we want waitcursor to display*/ - waitcursor(1); - - totseledge = count_selected_edges(em->edges.first); - if(totseledge==0) return; - - /*abusing crease value to store weights for edge pairs. Nasty*/ - for(eed=em->edges.first; eed; eed=eed->next) totedge++; - if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array"); - for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){ - creases[i] = eed->crease; - eed->crease = 0.0; - } - - /*clear temp flags*/ - for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0; - for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0; - for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0; - - /*For every selected 2 manifold edge, create pointers to its two faces.*/ - efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad"); - ok = collect_quadedges(efaar, em->edges.first, em->faces.first); - complexedges = 0; - - if(ok){ - - - /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/ - for(eed=em->edges.first; eed; eed=eed->next){ - /* eed->f2 is 2 only if this edge is part of exactly two - triangles, and both are selected, and it has EVPTuple assigned */ - if(eed->f2 == 2){ - efaa= (EVPtr *) eed->tmp.p; - efaa[0]->tmp.l++; - efaa[1]->tmp.l++; - } - } - - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f2 == 2){ - efaa= (EVPtr *) eed->tmp.p; - v1 = v2 = v3 = v4 = NULL; - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - if(v1 && v2 && v3 && v4){ - /*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/ - if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){ - if( convex(v1->co, v2->co, v3->co, v4->co) ){ - eed->f1 |= T2QJOIN; - efaa[0]->f1 = 1; //mark for join - efaa[1]->f1 = 1; //mark for join - } - } - else{ - - /* The face pair is part of a 'complex' island, so the rules for dealing with it are more involved. - Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria: - - 1: the two faces do not share the same material - 2: the edge joining the two faces is marked as sharp. - 3: the two faces UV's do not make a good match - 4: the two faces Vertex colors do not make a good match - - If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function. - This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user - the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the - same faces in the current pair later. - - This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of - the python scripts bundled with Blender releases. - */ - - if(G.scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/ - else if(G.scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/ - else if(((G.scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (G.scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) && - compareFaceAttribs(efaa[0], efaa[1], eed) == 0); /*do nothing*/ - else{ - measure = measure_facepair(v1, v2, v3, v4, limit); - if(measure < limit){ - complexedges++; - eed->f1 |= T2QCOMPLEX; - eed->crease = measure; /*we dont mark edges for join yet*/ - } - } - } - } - } - } - - /*Quicksort the complex edges according to their weighting*/ - if(complexedges){ - edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array"); - for(eed = em->edges.first; eed; eed=eed->next){ - if(eed->f1 & T2QCOMPLEX){ - *edb = eed; - edb++; - } - } - qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp); - /*now go through and mark the edges who get the highest weighting*/ - for(edb=edsortblock, i=0; i < complexedges; edb++, i++){ - efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/ - if( !efaa[0]->f1 && !efaa[1]->f1){ - efaa[0]->f1 = 1; //mark for join - efaa[1]->f1 = 1; //mark for join - (*edb)->f1 |= T2QJOIN; - } - } - } - - /*finally go through all edges marked for join (simple and complex) and create new faces*/ - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f1 & T2QJOIN){ - efaa= (EVPtr *)eed->tmp.p; - v1 = v2 = v3 = v4 = NULL; - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - if((v1 && v2 && v3 && v4) && (exist_face(v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be adressed.*/ - /*flag for delete*/ - eed->f1 |= T2QDELETE; - /*create new quad and select*/ - efa = EM_face_from_faces(efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]); - EM_select_face(efa,1); - } - else{ - efaa[0]->f1 = 0; - efaa[1]->f1 = 0; - } - } - } - } - - /*free data and cleanup*/ - if(creases){ - for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i]; - MEM_freeN(creases); - } - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f1 & T2QDELETE) eed->f1 = 1; - else eed->f1 = 0; - } - free_tagged_edges_faces(em->edges.first, em->faces.first); - if(efaar) MEM_freeN(efaar); - if(edsortblock) MEM_freeN(edsortblock); - - EM_selectmode_flush(); - countall(); - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - #ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); - #endif - waitcursor(0); - BIF_undo_push("Convert Triangles to Quads"); -} -/* ******************** END TRIANGLE TO QUAD ************************************* */ - -#define FACE_MARKCLEAR(f) (f->f1 = 1) - -/* quick hack, basically a copy of beauty_fill */ -void edge_flip(void) -{ - EditMesh *em = G.editMesh; - EditVert *v1, *v2, *v3, *v4; - EditEdge *eed, *nexted; - EditFace *efa, *w; - //void **efaar, **efaa; - EVPTuple *efaar; - EVPtr *efaa; - int totedge, ok, vindex[4]; - - /* - all selected edges with two faces - * - find the faces: store them in edges (using datablock) - * - per edge: - test convex - * - test edge: flip? - - if true: remedge, addedge, all edges at the edge get new face pointers - */ - - EM_selectmode_flush(); // makes sure in selectmode 'face' the edges of selected faces are selected too - - totedge = count_selected_edges(em->edges.first); - if(totedge==0) return; - - /* temporary array for : edge -> face[1], face[2] */ - efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip"); - - ok = collect_quadedges(efaar, em->edges.first, em->faces.first); - - eed= em->edges.first; - while(eed) { - nexted= eed->next; - - if(eed->f2==2) { /* points to 2 faces */ - - efaa= (EVPtr *) eed->tmp.p; - - /* don't do it if flagged */ - - ok= 1; - efa= efaa[0]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - efa= efaa[1]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - - if(ok) { - /* test convex */ - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - -/* - 4-----3 4-----3 - |\ | | /| - | \ 1 | | 1 / | - | \ | -> | / | - | 0 \ | | / 0 | - | \| |/ | - 1-----2 1-----2 -*/ - /* make new faces */ - if (v1 && v2 && v3) { - if( convex(v1->co, v2->co, v3->co, v4->co) ) { - if(exist_face(v1, v2, v3, v4)==0) { - /* outch this may break seams */ - w= EM_face_from_faces(efaa[0], efaa[1], vindex[0], - vindex[1], 4+vindex[2], -1); - - EM_select_face(w, 1); - - /* outch this may break seams */ - w= EM_face_from_faces(efaa[0], efaa[1], vindex[0], - 4+vindex[2], 4+vindex[3], -1); - - EM_select_face(w, 1); - } - /* tag as to-be-removed */ - FACE_MARKCLEAR(efaa[1]); - FACE_MARKCLEAR(efaa[0]); - eed->f1 = 1; - - } /* endif test convex */ - } - } - } - eed= nexted; - } - - /* clear tagged edges and faces: */ - free_tagged_edges_faces(em->edges.first, em->faces.first); - - MEM_freeN(efaar); - - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - BIF_undo_push("Flip Triangle Edges"); - -} - -static void edge_rotate(EditEdge *eed,int dir) -{ - EditMesh *em = G.editMesh; - EditVert **verts[2]; - EditFace *face[2], *efa, *newFace[2]; - EditEdge **edges[2], **hiddenedges, *srchedge; - int facecount, p1, p2, p3, p4, fac1, fac2, i, j; - int numhidden, numshared, p[2][4]; - - /* check to make sure that the edge is only part of 2 faces */ - facecount = 0; - for(efa = em->faces.first;efa;efa = efa->next) { - if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) { - if(facecount >= 2) { - /* more than two faces with this edge */ - return; - } - else { - face[facecount] = efa; - facecount++; - } - } - } - - if(facecount < 2) - return; - - /* how many edges does each face have */ - if(face[0]->e4) fac1= 4; - else fac1= 3; - - if(face[1]->e4) fac2= 4; - else fac2= 3; - - /* make a handy array for verts and edges */ - verts[0]= &face[0]->v1; - edges[0]= &face[0]->e1; - verts[1]= &face[1]->v1; - edges[1]= &face[1]->e1; - - /* we don't want to rotate edges between faces that share more than one edge */ - numshared= 0; - for(i=0; i 1) - return; - - /* coplaner faces only please */ - if(dot_v3v3(face[0]->n,face[1]->n) <= 0.000001) - return; - - /* we want to construct an array of vertex indicis in both faces, starting at - the last vertex of the edge being rotated. - - first we find the two vertices that lie on the rotating edge - - then we make sure they are ordered according to the face vertex order - - and then we construct the array */ - p1= p2= p3= p4= 0; - - for(i=0; i<4; i++) { - if(eed->v1 == verts[0][i]) p1 = i; - if(eed->v2 == verts[0][i]) p2 = i; - if(eed->v1 == verts[1][i]) p3 = i; - if(eed->v2 == verts[1][i]) p4 = i; - } - - if((p1+1)%fac1 == p2) - SWAP(int, p1, p2); - if((p3+1)%fac2 == p4) - SWAP(int, p3, p4); - - for (i = 0; i < 4; i++) { - p[0][i]= (p1 + i)%fac1; - p[1][i]= (p3 + i)%fac2; - } - - /* create an Array of the Edges who have h set prior to rotate */ - numhidden = 0; - for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next) - if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT))) - numhidden++; - - hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts"); - if(!hiddenedges) { - error("Malloc Was not happy!"); - return; - } - - numhidden = 0; - for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) - if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT)) - hiddenedges[numhidden++] = srchedge; - - /* create the 2 new faces */ - if(fac1 == 3 && fac2 == 3) { - /* no need of reverse setup */ - - newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); - newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); - } - else if(fac1 == 4 && fac2 == 3) { - if(dir == 1) { - newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); - newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); - } else if (dir == 2) { - newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]); - newFace[1]= EM_face_from_faces(face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1); - - verts[0][p[0][2]]->f |= SELECT; - verts[1][p[1][1]]->f |= SELECT; - } - } - else if(fac1 == 3 && fac2 == 4) { - if(dir == 1) { - newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); - newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); - } else if (dir == 2) { - newFace[0]= EM_face_from_faces(face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1); - newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]); - - verts[0][p[0][1]]->f |= SELECT; - verts[1][p[1][2]]->f |= SELECT; - } - - } - else if(fac1 == 4 && fac2 == 4) { - if(dir == 1) { - newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); - newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); - } else if (dir == 2) { - newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]); - newFace[1]= EM_face_from_faces(face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]); - - verts[0][p[0][2]]->f |= SELECT; - verts[1][p[1][2]]->f |= SELECT; - } - } - else - return; /* This should never happen */ - - if(dir == 1 || (fac1 == 3 && fac2 == 3)) { - verts[0][p[0][1]]->f |= SELECT; - verts[1][p[1][1]]->f |= SELECT; - } - - /* copy old edge's flags to new center edge*/ - for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) { - if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) { - srchedge->f = eed->f; - srchedge->h = eed->h; - srchedge->dir = eed->dir; - srchedge->seam = eed->seam; - srchedge->crease = eed->crease; - srchedge->bweight = eed->bweight; - } - } - - /* resetting hidden flag */ - for(numhidden--; numhidden>=0; numhidden--) - hiddenedges[numhidden]->h= 1; - - /* check for orhphan edges */ - for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) - srchedge->f1= -1; - - /* cleanup */ - MEM_freeN(hiddenedges); - - /* get rid of the old edge and faces*/ - remedge(eed); - free_editedge(eed); - BLI_remlink(&em->faces, face[0]); - free_editface(face[0]); - BLI_remlink(&em->faces, face[1]); - free_editface(face[1]); -} - -/* only accepts 1 selected edge, or 2 selected faces */ -void edge_rotate_selected(int dir) -{ - EditEdge *eed; - EditFace *efa; - short edgeCount = 0; - - /*clear new flag for new edges, count selected edges */ - for(eed= G.editMesh->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2 &= ~2; - if(eed->f & SELECT) edgeCount++; - } - - if(edgeCount>1) { - /* more selected edges, check faces */ - for(efa= G.editMesh->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - edgeCount= 0; - for(eed= G.editMesh->edges.first; eed; eed= eed->next) { - if(eed->f1==2) edgeCount++; - } - if(edgeCount==1) { - for(eed= G.editMesh->edges.first; eed; eed= eed->next) { - if(eed->f1==2) { - edge_rotate(eed,dir); - break; - } - } - } - else error("Select one edge or two adjacent faces"); - } - else if(edgeCount==1) { - for(eed= G.editMesh->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - EM_select_edge(eed, 0); - edge_rotate(eed,dir); - break; - } - } - } - else error("Select one edge or two adjacent faces"); - - - /* flush selected vertices (again) to edges/faces */ - EM_select_flush(); - - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - -#ifdef WITH_VERSE - if(G.editMesh->vnode) - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); -#endif - - BIF_undo_push("Rotate Edge"); -} - -/******************* BEVEL CODE STARTS HERE ********************/ - -static void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3]) -{ - float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac; - - sub_v3_v3v3(a, v1, v2); - sub_v3_v3v3(c, v3, v2); - - cross_v3_v3v3(n_a, a, no); - normalize_v3(n_a); - cross_v3_v3v3(n_c, no, c); - normalize_v3(n_c); - - normalize_v3(a); - normalize_v3(c); - ac = dot_v3v3(a, c); - - if (ac == 1 || ac == -1) { - midvec[0] = midvec[1] = midvec[2] = 0; - return; - } - ac2 = ac * ac; - fac = (float)sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1); - add_v3_v3v3(mid, n_c, n_a); - normalize_v3(mid); - mul_v3_fl(mid, d * fac); - add_v3_v3v3(mid, mid, v2); - copy_v3_v3(midvec, mid); -} - -/* Finds the new point using the sinus law to extrapolate a triangle - Lots of sqrts which would not be good for a real time algo - Using the mid point of the extrapolation of both sides - Useless for coplanar quads, but that doesn't happen too often */ -static void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3]) -{ - float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3]; - - sub_v3_v3v3(a, v3, v2); - l_a = normalize_v3(a); - sub_v3_v3v3(b, v4, v3); - normalize_v3(b); - sub_v3_v3v3(c, v1, v2); - normalize_v3(c); - - s_b = dot_v3v3(a, c); - s_b = (float)sqrt(1 - (s_b * s_b)); - s_a = dot_v3v3(b, c); - s_a = (float)sqrt(1 - (s_a * s_a)); - mul_v3_fl(a, -1); - s_c = dot_v3v3(a, b); - s_c = (float)sqrt(1 - (s_c * s_c)); - - l_b = s_b * l_a / s_a; - l_c = s_c * l_a / s_a; - - mul_v3_fl(b, l_b); - mul_v3_fl(c, l_c); - - add_v3_v3v3(Pos1, v2, c); - add_v3_v3v3(Pos2, v3, b); - - add_v3_v3v3(Dir, Pos1, Pos2); - mul_v3_fl(Dir, 0.5); - - bevel_displace_vec(midvec, v3, Dir, v2, d, no); - -} - - -static char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no) -{ - float o_a[3], a[3], o_c[3], c[3]; - - sub_v3_v3v3(o_a, o_v1, o_v2); - sub_v3_v3v3(a, v1, v2); - - cross_v3_v3v3(o_c, o_a, no); - cross_v3_v3v3(c, a, no); - - if (dot_v3v3(c, o_c) <= 0) - return 1; - else - return 0; -} - -// Detects and fix a quad wrapping after the resize -// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal -static void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no) -{ - float vec[3]; - char wrap[4]; - - // Quads can wrap partially. Watch out - wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2 - wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3 - wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4 - wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1 - - // Edge 1 inverted - if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) { - fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no); - copy_v3_v3(v1, vec); - copy_v3_v3(v2, vec); - } - // Edge 2 inverted - else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) { - fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no); - copy_v3_v3(v2, vec); - copy_v3_v3(v3, vec); - } - // Edge 3 inverted - else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) { - fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no); - copy_v3_v3(v3, vec); - copy_v3_v3(v4, vec); - } - // Edge 4 inverted - else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) { - fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no); - copy_v3_v3(v4, vec); - copy_v3_v3(v1, vec); - } - // Edge 2 and 4 inverted - else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) { - add_v3_v3v3(vec, v2, v3); - mul_v3_fl(vec, 0.5); - copy_v3_v3(v2, vec); - copy_v3_v3(v3, vec); - add_v3_v3v3(vec, v1, v4); - mul_v3_fl(vec, 0.5); - copy_v3_v3(v1, vec); - copy_v3_v3(v4, vec); - } - // Edge 1 and 3 inverted - else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) { - add_v3_v3v3(vec, v1, v2); - mul_v3_fl(vec, 0.5); - copy_v3_v3(v1, vec); - copy_v3_v3(v2, vec); - add_v3_v3v3(vec, v3, v4); - mul_v3_fl(vec, 0.5); - copy_v3_v3(v3, vec); - copy_v3_v3(v4, vec); - } - // Totally inverted - else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) { - add_v3_v3v3(vec, v1, v2); - add_v3_v3v3(vec, vec, v3); - add_v3_v3v3(vec, vec, v4); - mul_v3_fl(vec, 0.25); - copy_v3_v3(v1, vec); - copy_v3_v3(v2, vec); - copy_v3_v3(v3, vec); - copy_v3_v3(v4, vec); - } - -} - -// Detects and fix a tri wrapping after the resize -// Arguments are the orginal verts followed by the final verts and the normal -// Triangles cannot wrap partially (not in this situation -static void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no) -{ - if (detect_wrap(o_v1, o_v2, v1, v2, no)) { - float vec[3]; - add_v3_v3v3(vec, o_v1, o_v2); - add_v3_v3v3(vec, vec, o_v3); - mul_v3_fl(vec, 1.0f/3.0f); - copy_v3_v3(v1, vec); - copy_v3_v3(v2, vec); - copy_v3_v3(v3, vec); - } -} - -static void bevel_shrink_faces(float d, int flag) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - float vec[3], no[3], v1[3], v2[3], v3[3], v4[3]; - - /* move edges of all faces with efa->f1 & flag closer towards their centers */ - efa= em->faces.first; - while (efa) { - if (efa->f1 & flag) { - copy_v3_v3(v1, efa->v1->co); - copy_v3_v3(v2, efa->v2->co); - copy_v3_v3(v3, efa->v3->co); - copy_v3_v3(no, efa->n); - if (efa->v4 == NULL) { - bevel_displace_vec(vec, v1, v2, v3, d, no); - copy_v3_v3(efa->v2->co, vec); - bevel_displace_vec(vec, v2, v3, v1, d, no); - copy_v3_v3(efa->v3->co, vec); - bevel_displace_vec(vec, v3, v1, v2, d, no); - copy_v3_v3(efa->v1->co, vec); - - fix_bevel_tri_wrap(v1, v2, v3, efa->v1->co, efa->v2->co, efa->v3->co, no); - } else { - copy_v3_v3(v4, efa->v4->co); - bevel_displace_vec(vec, v1, v2, v3, d, no); - copy_v3_v3(efa->v2->co, vec); - bevel_displace_vec(vec, v2, v3, v4, d, no); - copy_v3_v3(efa->v3->co, vec); - bevel_displace_vec(vec, v3, v4, v1, d, no); - copy_v3_v3(efa->v4->co, vec); - bevel_displace_vec(vec, v4, v1, v2, d, no); - copy_v3_v3(efa->v1->co, vec); - - fix_bevel_quad_wrap(v1, v2, v3, v4, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, d, no); - } - } - efa= efa->next; - } -} - -static void bevel_shrink_draw(float d, int flag) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3]; - - /* move edges of all faces with efa->f1 & flag closer towards their centers */ - efa= em->faces.first; - while (efa) { - copy_v3_v3(v1, efa->v1->co); - copy_v3_v3(v2, efa->v2->co); - copy_v3_v3(v3, efa->v3->co); - copy_v3_v3(no, efa->n); - if (efa->v4 == NULL) { - bevel_displace_vec(vec, v1, v2, v3, d, no); - copy_v3_v3(fv2, vec); - bevel_displace_vec(vec, v2, v3, v1, d, no); - copy_v3_v3(fv3, vec); - bevel_displace_vec(vec, v3, v1, v2, d, no); - copy_v3_v3(fv1, vec); - - fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no); - - glBegin(GL_LINES); - glVertex3fv(fv1); - glVertex3fv(fv2); - glEnd(); - glBegin(GL_LINES); - glVertex3fv(fv2); - glVertex3fv(fv3); - glEnd(); - glBegin(GL_LINES); - glVertex3fv(fv1); - glVertex3fv(fv3); - glEnd(); - } else { - copy_v3_v3(v4, efa->v4->co); - bevel_displace_vec(vec, v4, v1, v2, d, no); - copy_v3_v3(fv1, vec); - bevel_displace_vec(vec, v1, v2, v3, d, no); - copy_v3_v3(fv2, vec); - bevel_displace_vec(vec, v2, v3, v4, d, no); - copy_v3_v3(fv3, vec); - bevel_displace_vec(vec, v3, v4, v1, d, no); - copy_v3_v3(fv4, vec); - - fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no); - - glBegin(GL_LINES); - glVertex3fv(fv1); - glVertex3fv(fv2); - glEnd(); - glBegin(GL_LINES); - glVertex3fv(fv2); - glVertex3fv(fv3); - glEnd(); - glBegin(GL_LINES); - glVertex3fv(fv3); - glVertex3fv(fv4); - glEnd(); - glBegin(GL_LINES); - glVertex3fv(fv1); - glVertex3fv(fv4); - glEnd(); - } - efa= efa->next; - } -} - -static void bevel_mesh(float bsize, int allfaces) -{ - EditMesh *em = G.editMesh; -//#define BEV_DEBUG -/* Enables debug printfs and assigns material indices: */ -/* 2 = edge quad */ -/* 3 = fill polygon (vertex clusters) */ - - EditFace *efa, *example; //, *nextvl; - EditEdge *eed, *eed2; - EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4; - //short found4, search; - //float f1, f2, f3, f4; - float cent[3], min[3], max[3]; - int a, b, c; - float limit= 0.001f; - - if(multires_test()) return; - - waitcursor(1); - - removedoublesflag(1, 0, limit); - - /* tag all original faces */ - efa= em->faces.first; - while (efa) { - efa->f1= 0; - if (faceselectedAND(efa, 1)||allfaces) { - efa->f1= 1; - efa->v1->f |= 128; - efa->v2->f |= 128; - efa->v3->f |= 128; - if (efa->v4) efa->v4->f |= 128; - } - efa->v1->f &= ~64; - efa->v2->f &= ~64; - efa->v3->f &= ~64; - if (efa->v4) efa->v4->f &= ~64; - - efa= efa->next; - } - -#ifdef BEV_DEBUG - fprintf(stderr,"bevel_mesh: split\n"); -#endif - - efa= em->faces.first; - while (efa) { - if (efa->f1 & 1) { - efa->f1-= 1; - v1= addvertlist(efa->v1->co, efa->v1); - v1->f= efa->v1->f & ~128; - efa->v1->tmp.v = v1; - - v1= addvertlist(efa->v2->co, efa->v2); - v1->f= efa->v2->f & ~128; - efa->v2->tmp.v = v1; - - v1= addvertlist(efa->v3->co, efa->v3); - v1->f= efa->v3->f & ~128; - efa->v3->tmp.v = v1; - - if (efa->v4) { - v1= addvertlist(efa->v4->co, efa->v4); - v1->f= efa->v4->f & ~128; - efa->v4->tmp.v = v1; - } - - /* Needs better adaption of creases? */ - addedgelist(efa->e1->v1->tmp.v, - efa->e1->v2->tmp.v, - efa->e1); - addedgelist(efa->e2->v1->tmp.v, - efa->e2->v2->tmp.v, - efa->e2); - addedgelist(efa->e3->v1->tmp.v, - efa->e3->v2->tmp.v, - efa->e3); - if (efa->e4) addedgelist(efa->e4->v1->tmp.v, - efa->e4->v2->tmp.v, - efa->e4); - - if(efa->v4) { - v1 = efa->v1->tmp.v; - v2 = efa->v2->tmp.v; - v3 = efa->v3->tmp.v; - v4 = efa->v4->tmp.v; - addfacelist(v1, v2, v3, v4, efa,NULL); - } else { - v1= efa->v1->tmp.v; - v2= efa->v2->tmp.v; - v3= efa->v3->tmp.v; - addfacelist(v1, v2, v3, 0, efa,NULL); - } - - efa= efa-> next; - } else { - efa= efa->next; - } - } - - for(efa= em->faces.first; efa; efa= efa->next) { - if( (efa->v1->f & 128) && (efa->v2->f & 128) && (efa->v3->f & 128) ) { - if(efa->v4==NULL || (efa->v4->f & 128)) efa->f |= 128; - } - } - - delfaceflag(128); // works with face flag now - - /* tag all faces for shrink*/ - efa= em->faces.first; - while (efa) { - if (faceselectedAND(efa, 1)||allfaces) { - efa->f1= 2; - } - efa= efa->next; - } - -#ifdef BEV_DEBUG - fprintf(stderr,"bevel_mesh: make edge quads\n"); -#endif - - /* find edges that are on each other and make quads between them */ - - eed= em->edges.first; - while(eed) { - eed->f2= eed->f1= 0; - if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces) - eed->f1 |= 4; /* original edges */ - eed->tmp.v = 0; - eed= eed->next; - } - - eed= em->edges.first; - while (eed) { - if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) { - eed2= em->edges.first; - while (eed2) { - if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) { - if ( - (eed->v1 != eed2->v1) && - (eed->v1 != eed2->v2) && - (eed->v2 != eed2->v1) && - (eed->v2 != eed2->v2) && ( - ( compare_v3v3(eed->v1->co, eed2->v1->co, limit) && - compare_v3v3(eed->v2->co, eed2->v2->co, limit) ) || - ( compare_v3v3(eed->v1->co, eed2->v2->co, limit) && - compare_v3v3(eed->v2->co, eed2->v1->co, limit) ) ) ) - { - -#ifdef BEV_DEBUG - fprintf(stderr, "bevel_mesh: edge quad\n"); -#endif - - eed->f1 |= 2; /* these edges are finished */ - eed2->f1 |= 2; - - example= NULL; - efa= em->faces.first; /* search example face (for mat_nr, ME_SMOOTH, ...) */ - while (efa) { - if ( (efa->e1 == eed) || - (efa->e2 == eed) || - (efa->e3 == eed) || - (efa->e4 && (efa->e4 == eed)) ) { - example= efa; - efa= NULL; - } - if (efa) efa= efa->next; - } - - neweve[0]= eed->v1; neweve[1]= eed->v2; - neweve[2]= eed2->v1; neweve[3]= eed2->v2; - - if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) { - efa= NULL; - - if (compare_v3v3(eed->v1->co, eed2->v2->co, limit)) { - efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example,NULL); - } else { - efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example,NULL); - } - - if(efa) { - float inp; - normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co); - inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2]; - if(inp < 0.0) flipface(efa); -#ifdef BEV_DEBUG - efa->mat_nr= 1; -#endif - } else fprintf(stderr,"bevel_mesh: error creating face\n"); - } - eed2= NULL; - } - } - if (eed2) eed2= eed2->next; - } - } - eed= eed->next; - } - - eed= em->edges.first; - while(eed) { - eed->f2= eed->f1= 0; - eed->f1= 0; - eed->v1->f1 &= ~1; - eed->v2->f1 &= ~1; - eed->tmp.v = 0; - eed= eed->next; - } - -#ifdef BEV_DEBUG - fprintf(stderr,"bevel_mesh: find clusters\n"); -#endif - - /* Look for vertex clusters */ - - eve= em->verts.first; - while (eve) { - eve->f &= ~(64|128); - eve->tmp.v = NULL; - eve= eve->next; - } - - /* eve->f: 128: first vertex in a list (->tmp.v) */ - /* 64: vertex is in a list */ - - eve= em->verts.first; - while (eve) { - eve2= em->verts.first; - eve3= NULL; - while (eve2) { - if ((eve2 != eve) && ((eve2->f & (64|128))==0)) { - if (compare_v3v3(eve->co, eve2->co, limit)) { - if ((eve->f & (128|64)) == 0) { - /* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */ - eve->f |= 128; - eve->tmp.v = eve2; - eve3= eve2; - } else if ((eve->f & 64) == 0) { - /* fprintf(stderr," *\n"); */ - if (eve3) eve3->tmp.v = eve2; - eve2->f |= 64; - eve3= eve2; - } - } - } - eve2= eve2->next; - if (!eve2) { - if (eve3) eve3->tmp.v = NULL; - } - } - eve= eve->next; - } - -#ifdef BEV_DEBUG - fprintf(stderr,"bevel_mesh: shrink faces\n"); -#endif - - bevel_shrink_faces(bsize, 2); - -#ifdef BEV_DEBUG - fprintf(stderr,"bevel_mesh: fill clusters\n"); -#endif - - /* Make former vertex clusters faces */ - - eve= em->verts.first; - while (eve) { - eve->f &= ~64; - eve= eve->next; - } - - eve= em->verts.first; - while (eve) { - if (eve->f & 128) { - eve->f &= ~128; - a= 0; - neweve[a]= eve; - eve2 = eve->tmp.v; - while (eve2) { - a++; - neweve[a]= eve2; - eve2 = eve2->tmp.v; - } - a++; - efa= NULL; - if (a>=3) { - example= NULL; - efa= em->faces.first; /* search example face */ - while (efa) { - if ( (efa->v1 == neweve[0]) || - (efa->v2 == neweve[0]) || - (efa->v3 == neweve[0]) || - (efa->v4 && (efa->v4 == neweve[0])) ) { - example= efa; - efa= NULL; - } - if (efa) efa= efa->next; - } -#ifdef BEV_DEBUG - fprintf(stderr,"bevel_mesh: Making %d-gon\n", a); -#endif - if (a>4) { - cent[0]= cent[1]= cent[2]= 0.0; - INIT_MINMAX(min, max); - for (b=0; bco); - DO_MINMAX(neweve[b]->co, min, max); - } - cent[0]= (min[0]+max[0])/2; - cent[1]= (min[1]+max[1])/2; - cent[2]= (min[2]+max[2])/2; - eve2= addvertlist(cent, NULL); - eve2->f |= 1; - eed= em->edges.first; - while (eed) { - c= 0; - for (b=0; bv1) || (neweve[b]==eed->v2)) c++; - if (c==2) { - if(exist_face(eed->v1, eed->v2, eve2, 0)==0) { - efa= addfacelist(eed->v1, eed->v2, eve2, 0, example,NULL); -#ifdef BEV_DEBUG - efa->mat_nr= 2; -#endif - } - } - eed= eed->next; - } - } else if (a==4) { - if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) { - /* the order of vertices can be anything, three cases to check */ - if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) { - efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL); - } - else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) { - efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL); - } - else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) { - efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL); - } - } - } - else if (a==3) { - if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0) - efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, example, NULL); - } - if(efa) { - float inp; - normal_tri_v3( efa->n,neweve[0]->co, neweve[1]->co, neweve[2]->co); - inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2]; - if(inp < 0.0) flipface(efa); -#ifdef BEV_DEBUG - efa->mat_nr= 2; -#endif - } - } - } - eve= eve->next; - } - - eve= em->verts.first; - while (eve) { - eve->f1= 0; - eve->f &= ~(128|64); - eve->tmp.v= NULL; - eve= eve->next; - } - - recalc_editnormals(); - waitcursor(0); - countall(); - allqueue(REDRAWVIEW3D, 0); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - - removedoublesflag(1, 0, limit); - - /* flush selected vertices to edges/faces */ - EM_select_flush(); - -#undef BEV_DEBUG -} - -static void bevel_mesh_recurs(float bsize, short recurs, int allfaces) -{ - float d; - short nr; - - d= bsize; - for (nr=0; nroptions = BME_BEVEL_RUNNING | BME_BEVEL_SELECT; - G.editBMesh->res = 1; - - while(G.editBMesh->options & BME_BEVEL_RUNNING) { - options = G.editBMesh->options; - res = G.editBMesh->res; - bm = BME_editmesh_to_bmesh(G.editMesh); - BIF_undo_push("Pre-Bevel"); - free_editMesh(G.editMesh); - BME_bevel(bm,0.1f,res,options,0,0,&td); - BME_bmesh_to_editmesh(bm, td); - EM_selectmode_flush(); - G.editBMesh->bm = bm; - G.editBMesh->td = td; - initTransform(TFM_BEVEL,CTX_BMESH); - Transform(); - BME_free_transdata(td); - BME_free_mesh(bm); - if (t->state != TRANS_CONFIRM) { - BIF_undo(); - } - if (options == G.editBMesh->options) { - G.editBMesh->options &= ~BME_BEVEL_RUNNING; - } - } - - if (gbm_free) { - MEM_freeN(G.editBMesh); - G.editBMesh = NULL; - } -} - - -void bevel_menu_old() -{ - char Finished = 0, Canceled = 0, str[100], Recalc = 0; - short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr; - float vec[3], d, drawd=0.0, center[3], fac = 1; - - getmouseco_areawin(mval); - oval[0] = mval[0]; oval[1] = mval[1]; - - // Silly hackish code to initialise the variable (warning if not done) - // while still drawing in the first iteration (and without using another variable) - curval[0] = mval[0] + 1; curval[1] = mval[1] + 1; - - // Init grabz for window to vec conversions - initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]); - window_to_3d(center, mval[0], mval[1]); - - if(button(&recurs, 1, 4, "Recursion:")==0) return; - - for (nr=0; nrobmat); - - glColor3ub(255, 255, 0); - - // PREVIEW CODE GOES HERE - bevel_shrink_draw(drawd, 2); - - /* restore matrix transform */ - glPopMatrix(); - - sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd); - headerprint(str); - - /* this also verifies other area/windows for clean swap */ - screen_swapbuffers(); - - persp(PERSP_WIN); - - glDrawBuffer(GL_FRONT); - - BIF_ThemeColor(TH_WIRE); - - setlinestyle(3); - glBegin(GL_LINE_STRIP); - glVertex2sv(mval); - glVertex2sv(oval); - glEnd(); - setlinestyle(0); - - persp(PERSP_VIEW); - bglFlush(); // flush display for frontbuffer - glDrawBuffer(GL_BACK); - } - while(qtest()) { - short val=0; - event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle - - /* val==0 on key-release event */ - if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)) { - if (event==RIGHTMOUSE || event==ESCKEY) - Canceled = 1; - Finished = 1; - } - else if (val && event==SPACEKEY) { - if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) { - drawd = d * fac; - Finished = 1; - } - } - else if (val) { - /* On any other keyboard event, recalc */ - Recalc = 1; - } - - } - } - if (Canceled==0) { - SetBlenderCursor(BC_WAITCURSOR); - bevel_mesh_recurs(drawd/fac, recurs, 1); - righthandfaces(1); - SetBlenderCursor(SYSCURSOR); - BIF_undo_push("Bevel"); - } -} - -/* -------------------- More tools ------------------ */ - -void mesh_set_face_flags(short mode) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - MTFace *tface; - short m_tex=0, m_tiles=0, m_shared=0, - m_light=0, m_invis=0, m_collision=0, - m_twoside=0, m_obcolor=0, m_halo=0, - m_billboard=0, m_shadow=0, m_text=0, - m_sort=0; - short flag = 0, change = 0; - - if (!EM_texFaceCheck()) { - error("not a mesh with uv/image layers"); - return; - } - - add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL); - add_numbut(1, TOG|SHO, "Tiles", 0, 0, &m_tiles, NULL); - add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL); - add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL); - add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL); - add_numbut(5, TOG|SHO, "Shared", 0, 0, &m_shared, NULL); - add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL); - add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL); - add_numbut(8, TOG|SHO, "Halo", 0, 0, &m_halo, NULL); - add_numbut(9, TOG|SHO, "Billboard", 0, 0, &m_billboard, NULL); - add_numbut(10, TOG|SHO, "Shadow", 0, 0, &m_shadow, NULL); - add_numbut(11, TOG|SHO, "Text", 0, 0, &m_text, NULL); - add_numbut(12, TOG|SHO, "Sort", 0, 0, &m_sort, NULL); - - if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW)) - return; - - /* these 2 cant both be on */ - if (mode) /* are we seeting*/ - if (m_halo) - m_billboard = 0; - - if (m_tex) flag |= TF_TEX; - if (m_tiles) flag |= TF_TILES; - if (m_shared) flag |= TF_SHAREDCOL; - if (m_light) flag |= TF_LIGHT; - if (m_invis) flag |= TF_INVISIBLE; - if (m_collision) flag |= TF_DYNAMIC; - if (m_twoside) flag |= TF_TWOSIDE; - if (m_obcolor) flag |= TF_OBCOL; - if (m_halo) flag |= TF_BILLBOARD; - if (m_billboard) flag |= TF_BILLBOARD2; - if (m_shadow) flag |= TF_SHADOW; - if (m_text) flag |= TF_BMFONT; - if (m_sort) flag |= TF_ALPHASORT; - - if (flag==0) - return; - - efa= em->faces.first; - while(efa) { - if(efa->f & SELECT) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (mode) tface->mode |= flag; - else tface->mode &= ~flag; - change = 1; - } - efa= efa->next; - } - - if (change) { - BIF_undo_push((mode ? "Set Flags" : "Clear Flags")); - - allqueue(REDRAWIMAGE, 0); - allqueue(REDRAWVIEW3D, 0); - } -} - -void mesh_set_smooth_faces(short event) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - - if(G.obedit==0) return; - - if(G.obedit->type != OB_MESH) return; - - efa= em->faces.first; - while(efa) { - if(efa->f & SELECT) { - if(event==1) efa->flag |= ME_SMOOTH; - else if(event==0) efa->flag &= ~ME_SMOOTH; - } - efa= efa->next; - } - - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - - if(event==1) BIF_undo_push("Set Smooth"); - else if(event==0) BIF_undo_push("Set Solid"); -} - -/* helper to find edge for edge_rip */ -static float mesh_rip_edgedist(float mat[][4], float *co1, float *co2, short *mval) -{ - float vec1[3], vec2[3], mvalf[2]; - - view3d_project_float(curarea, co1, vec1, mat); - view3d_project_float(curarea, co2, vec2, mat); - mvalf[0]= (float)mval[0]; - mvalf[1]= (float)mval[1]; - - return dist_to_line_segment_v2(mvalf, vec1, vec2); -} - -/* helper for below */ -static void mesh_rip_setface(EditFace *sefa) -{ - /* put new vertices & edges in best face */ - if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v; - if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v; - if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v; - if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v; - - sefa->e1= addedgelist(sefa->v1, sefa->v2, sefa->e1); - sefa->e2= addedgelist(sefa->v2, sefa->v3, sefa->e2); - if(sefa->v4) { - sefa->e3= addedgelist(sefa->v3, sefa->v4, sefa->e3); - sefa->e4= addedgelist(sefa->v4, sefa->v1, sefa->e4); - } - else - sefa->e3= addedgelist(sefa->v3, sefa->v1, sefa->e3); - -} - -/* based on mouse cursor position, it defines how is being ripped */ -void mesh_rip(void) -{ - extern void faceloop_select(EditEdge *startedge, int select); - EditMesh *em = G.editMesh; - EditVert *eve, *nextve; - EditEdge *eed, *seed= NULL; - EditFace *efa, *sefa= NULL; - float projectMat[4][4], viewMat[4][4], vec[3], dist, mindist; - short doit= 1, mval[2],propmode,prop; - - propmode = G.scene->prop_mode; - G.scene->prop_mode = 0; - prop = G.scene->proportional; - G.scene->proportional = 0; - - /* select flush... vertices are important */ - EM_selectmode_set(); - - getmouseco_areawin(mval); - view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat); - - /* find best face, exclude triangles and break on face select or faces with 2 edges select */ - mindist= 1000000.0f; - for(efa= em->faces.first; efa; efa=efa->next) { - if( efa->f & 1) - break; - if(efa->v4 && faceselectedOR(efa, SELECT) ) { - int totsel=0; - - if(efa->e1->f & SELECT) totsel++; - if(efa->e2->f & SELECT) totsel++; - if(efa->e3->f & SELECT) totsel++; - if(efa->e4->f & SELECT) totsel++; - - if(totsel>1) - break; - view3d_project_float(curarea, efa->cent, vec, projectMat); - dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) ); - if(distverts.last; eve; eve= eve->prev) { - eve->tmp.v = NULL; - if(eve->f & SELECT) { - eve->tmp.v = addvertlist(eve->co, eve); - eve->f &= ~SELECT; - eve->tmp.v->f |= SELECT; - } - } - - /* find the best candidate edge */ - /* or one of sefa edges is selected... */ - if(sefa->e1->f & SELECT) seed= sefa->e2; - if(sefa->e2->f & SELECT) seed= sefa->e1; - if(sefa->e3->f & SELECT) seed= sefa->e2; - if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3; - - /* or we do the distance trick */ - if(seed==NULL) { - mindist= 1000000.0f; - if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) { - dist = mesh_rip_edgedist(projectMat, - sefa->e1->v1->co, - sefa->e1->v2->co, mval); - if(diste1; - mindist= dist; - } - } - if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) { - dist = mesh_rip_edgedist(projectMat, - sefa->e2->v1->co, - sefa->e2->v2->co, mval); - if(diste2; - mindist= dist; - } - } - if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) { - dist= mesh_rip_edgedist(projectMat, - sefa->e3->v1->co, - sefa->e3->v2->co, mval); - if(diste3; - mindist= dist; - } - } - if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) { - dist= mesh_rip_edgedist(projectMat, - sefa->e4->v1->co, - sefa->e4->v2->co, mval); - if(diste4; - mindist= dist; - } - } - } - - if(seed==NULL) { // never happens? - error("No proper edge found to start"); - return; - } - - faceloop_select(seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1 - - /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */ - for(eed = em->edges.last; eed; eed= eed->prev) { - eed->tmp.v = NULL; - if((eed->v1->tmp.v) || (eed->v2->tmp.v)) { - EditEdge *newed; - - newed= addedgelist(eed->v1->tmp.v?eed->v1->tmp.v:eed->v1, - eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed); - if(eed->f & SELECT) { - eed->f &= ~SELECT; - newed->f |= SELECT; - } - eed->tmp.v = (EditVert *)newed; - } - } - - /* first clear edges to help finding neighbours */ - for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; - - /* put new vertices & edges && flag in best face */ - mesh_rip_setface(sefa); - - /* starting with neighbours of best face, we loop over the seam */ - sefa->f1= 2; - doit= 1; - while(doit) { - doit= 0; - - for(efa= em->faces.first; efa; efa=efa->next) { - /* new vert in face */ - if (efa->v1->tmp.v || efa->v2->tmp.v || - efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) { - /* face is tagged with loop */ - if(efa->f1==1) { - mesh_rip_setface(efa); - efa->f1= 2; - doit= 1; - } - } - } - } - - /* remove loose edges, that were part of a ripped face */ - for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; - for(efa= em->faces.first; efa; efa=efa->next) { - efa->e1->f1= 1; - efa->e2->f1= 1; - efa->e3->f1= 1; - if(efa->e4) efa->e4->f1= 1; - } - - for(eed = em->edges.last; eed; eed= seed) { - seed= eed->prev; - if(eed->f1==0) { - if(eed->v1->tmp.v || eed->v2->tmp.v || - (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) { - remedge(eed); - free_editedge(eed); - eed= NULL; - } - } - if(eed) { - eed->v1->f1= 1; - eed->v2->f1= 1; - } - } - - /* and remove loose selected vertices, that got duplicated accidentally */ - for(eve = em->verts.first; eve; eve= nextve) { - nextve= eve->next; - if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) { - BLI_remlink(&em->verts,eve); - free_editvert(eve); - } - } - - countall(); // apparently always needed when adding stuff, derived mesh - -#ifdef WITH_VERSE - if(G.editMesh->vnode) { - sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode); - sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode); - } -#endif - - BIF_TransformSetUndo("Rip"); - initTransform(TFM_TRANSLATION, 0); - Transform(); - - G.scene->prop_mode = propmode; - G.scene->proportional = prop; -} - -void shape_propagate(void) -{ - EditMesh *em = G.editMesh; - EditVert *ev = NULL; - Mesh* me = (Mesh*)G.obedit->data; - Key* ky = NULL; - KeyBlock* kb = NULL; - Base* base=NULL; - - - if(me->key){ - ky = me->key; - } else { - error("Object Has No Key"); - return; - } - - if(ky->block.first){ - for(ev = em->verts.first; ev ; ev = ev->next){ - if(ev->f & SELECT){ - for(kb=ky->block.first;kb;kb = kb->next){ - float *data; - data = kb->data; - copy_v3_v3(data+(ev->keyindex*3),ev->co); - } - } - } - } else { - error("Object Has No Blendshapes"); - return; - } - - //TAG Mesh Objects that share this data - for(base = G.scene->base.first; base; base = base->next){ - if(base->object && base->object->data == me){ - base->object->recalc = OB_RECALC_DATA; - } - } - - BIF_undo_push("Propagate Blendshape Verts"); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - return; -} - -void shape_copy_from_lerp(KeyBlock* thisBlock, KeyBlock* fromBlock) -{ - EditMesh *em = G.editMesh; - EditVert *ev = NULL; - short mval[2], curval[2], event = 0, finished = 0, canceled = 0, fullcopy=0 ; - float perc = 0; - char str[64]; - float *data, *odata; - - data = fromBlock->data; - odata = thisBlock->data; - - getmouseco_areawin(mval); - curval[0] = mval[0] + 1; curval[1] = mval[1] + 1; - - while (finished == 0) - { - getmouseco_areawin(mval); - if (mval[0] != curval[0] || mval[1] != curval[1]) - { - - if(mval[0] > curval[0]) - perc += 0.1; - else if(mval[0] < curval[0]) - perc -= 0.1; - - if(perc < 0) perc = 0; - if(perc > 1) perc = 1; - - curval[0] = mval[0]; - curval[1] = mval[1]; - - if(fullcopy == 1){ - perc = 1; - } - - for(ev = em->verts.first; ev ; ev = ev->next){ - if(ev->f & SELECT){ - interp_v3_v3v3(ev->co,odata+(ev->keyindex*3),data+(ev->keyindex*3),perc); - } - } - sprintf(str,"Blending at %d%c MMB to Copy at 100%c",(int)(perc*100),'%','%'); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - headerprint(str); - force_draw(0); - - if(fullcopy == 1){ - break; - } - - } else { - PIL_sleep_ms(10); - } - - while(qtest()) { - short val=0; - event= extern_qread(&val); - if(val){ - if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)){ - finished = 1; - } - else if (event == MIDDLEMOUSE){ - fullcopy = 1; - } - else if (ELEM3(event,ESCKEY,RIGHTMOUSE,RIGHTMOUSE)){ - canceled = 1; - finished = 1; - } - } - } - } - if(!canceled) - BIF_undo_push("Copy Blendshape Verts"); - else - for(ev = em->verts.first; ev ; ev = ev->next){ - if(ev->f & SELECT){ - copy_v3_v3(ev->co, odata+(ev->keyindex*3)); - } - } - return; -} - - - -void shape_copy_select_from() -{ - Mesh* me = (Mesh*)G.obedit->data; - EditMesh *em = G.editMesh; - EditVert *ev = NULL; - int totverts = 0,curshape = G.obedit->shapenr; - - Key* ky = NULL; - KeyBlock *kb = NULL,*thisBlock = NULL; - int maxlen=32, nr=0, a=0; - char *menu; - - if(me->key){ - ky = me->key; - } else { - error("Object Has No Key"); - return; - } - - if(ky->block.first){ - for(kb=ky->block.first;kb;kb = kb->next){ - maxlen += 40; // Size of a block name - if(a == curshape-1){ - thisBlock = kb; - } - - a++; - } - a=0; - menu = MEM_callocN(maxlen, "Copy Shape Menu Text"); - strcpy(menu, "Copy Vert Positions from Shape %t|"); - for(kb=ky->block.first;kb;kb = kb->next){ - if(a != curshape-1){ - sprintf(menu,"%s %s %cx%d|",menu,kb->name,'%',a); - } - a++; - } - nr = pupmenu_col(menu, 20); - MEM_freeN(menu); - } else { - error("Object Has No Blendshapes"); - return; - } - - a = 0; - - for(kb=ky->block.first;kb;kb = kb->next){ - if(a == nr){ - - for(ev = em->verts.first;ev;ev = ev->next){ - totverts++; - } - - if(me->totvert != totverts){ - error("Shape Has had Verts Added/Removed, please cycle editmode before copying"); - return; - } - shape_copy_from_lerp(thisBlock,kb); - - return; - } - a++; - } - return; -} - -/* Collection Routines|Currently used by the improved merge code*/ -/* buildEdge_collection() creates a list of lists*/ -/* these lists are filled with edges that are topologically connected.*/ -/* This whole tool needs to be redone, its rather poorly implemented...*/ - -typedef struct Collection{ - struct Collection *next, *prev; - int index; - ListBase collectionbase; -} Collection; - -typedef struct CollectedEdge{ - struct CollectedEdge *next, *prev; - EditEdge *eed; -} CollectedEdge; - -#define MERGELIMIT 0.000001 - -static void build_edgecollection(ListBase *allcollections) -{ - EditEdge *eed; - Collection *edgecollection, *newcollection; - CollectedEdge *newedge; - - int currtag = 1; - short ebalanced = 0; - short collectionfound = 0; - - for (eed=G.editMesh->edges.first; eed; eed = eed->next){ - eed->tmp.l = 0; - eed->v1->tmp.l = 0; - eed->v2->tmp.l = 0; - } - - /*1st pass*/ - for(eed=G.editMesh->edges.first; eed; eed=eed->next){ - if(eed->f&SELECT){ - eed->v1->tmp.l = currtag; - eed->v2->tmp.l = currtag; - currtag +=1; - } - } - - /*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */ - while(ebalanced == 0){ - ebalanced = 1; - for(eed=G.editMesh->edges.first; eed; eed = eed->next){ - if(eed->f&SELECT){ - if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{ - if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l; - else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l; - ebalanced = 0; - } - } - } - } - - /*3rd pass, set all the edge flags (unnessecary?)*/ - for(eed=G.editMesh->edges.first; eed; eed = eed->next){ - if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l; - } - - for(eed=G.editMesh->edges.first; eed; eed=eed->next){ - if(eed->f&SELECT){ - if(allcollections->first){ - for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){ - if(edgecollection->index == eed->tmp.l){ - newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); - newedge->eed = eed; - BLI_addtail(&(edgecollection->collectionbase), newedge); - collectionfound = 1; - break; - } - else collectionfound = 0; - } - } - if(allcollections->first == NULL || collectionfound == 0){ - newcollection = MEM_mallocN(sizeof(Collection), "element collection"); - newcollection->index = eed->tmp.l; - newcollection->collectionbase.first = 0; - newcollection->collectionbase.last = 0; - - newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); - newedge->eed = eed; - - BLI_addtail(&(newcollection->collectionbase), newedge); - BLI_addtail(allcollections, newcollection); - } - } - - } -} - -static void freecollections(ListBase *allcollections) -{ - struct Collection *curcollection; - - for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next) - BLI_freelistN(&(curcollection->collectionbase)); - BLI_freelistN(allcollections); -} - -/*Begin UV Edge Collapse Code - Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail - in areas such as the boundries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it. - The welded UV edges can then be sorted and collapsed. -*/ -typedef struct wUV{ - struct wUV *next, *prev; - ListBase nodes; - float u, v; /*cached copy of UV coordinates pointed to by nodes*/ - EditVert *eve; - int f; -} wUV; - -typedef struct wUVNode{ - struct wUVNode *next, *prev; - float *u; /*pointer to original tface data*/ - float *v; /*pointer to original tface data*/ -} wUVNode; - -typedef struct wUVEdge{ - struct wUVEdge *next, *prev; - float v1uv[2], v2uv[2]; /*nasty.*/ - struct wUV *v1, *v2; /*oriented same as editedge*/ - EditEdge *eed; - int f; -} wUVEdge; - -typedef struct wUVEdgeCollect{ /*used for grouping*/ - struct wUVEdgeCollect *next, *prev; - wUVEdge *uved; - int id; -} wUVEdgeCollect; - -static void append_weldedUV(EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts) -{ - wUV *curwvert, *newwvert; - wUVNode *newnode; - int found; - MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); - - found = 0; - - for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ - if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){ - newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); - newnode->u = &(tf->uv[tfindex][0]); - newnode->v = &(tf->uv[tfindex][1]); - BLI_addtail(&(curwvert->nodes), newnode); - found = 1; - break; - } - } - - if(!found){ - newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); - newnode->u = &(tf->uv[tfindex][0]); - newnode->v = &(tf->uv[tfindex][1]); - - newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert"); - newwvert->u = *(newnode->u); - newwvert->v = *(newnode->v); - newwvert->eve = eve; - - BLI_addtail(&(newwvert->nodes), newnode); - BLI_addtail(uvverts, newwvert); - - } -} - -static void build_weldedUVs(ListBase *uvverts) -{ - EditFace *efa; - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - if(efa->v1->f1) append_weldedUV(efa, efa->v1, 0, uvverts); - if(efa->v2->f1) append_weldedUV(efa, efa->v2, 1, uvverts); - if(efa->v3->f1) append_weldedUV(efa, efa->v3, 2, uvverts); - if(efa->v4 && efa->v4->f1) append_weldedUV(efa, efa->v4, 3, uvverts); - } -} - -static void append_weldedUVEdge(EditFace *efa, EditEdge *eed, ListBase *uvedges) -{ - wUVEdge *curwedge, *newwedge; - int v1tfindex, v2tfindex, found; - MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); - - found = 0; - - if(eed->v1 == efa->v1) v1tfindex = 0; - else if(eed->v1 == efa->v2) v1tfindex = 1; - else if(eed->v1 == efa->v3) v1tfindex = 2; - else /* if(eed->v1 == efa->v4) */ v1tfindex = 3; - - if(eed->v2 == efa->v1) v2tfindex = 0; - else if(eed->v2 == efa->v2) v2tfindex = 1; - else if(eed->v2 == efa->v3) v2tfindex = 2; - else /* if(eed->v2 == efa->v4) */ v2tfindex = 3; - - for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ - if(curwedge->eed == eed && curwedge->v1uv[0] == tf->uv[v1tfindex][0] && curwedge->v1uv[1] == tf->uv[v1tfindex][1] && curwedge->v2uv[0] == tf->uv[v2tfindex][0] && curwedge->v2uv[1] == tf->uv[v2tfindex][1]){ - found = 1; - break; //do nothing, we don't need another welded uv edge - } - } - - if(!found){ - newwedge = MEM_callocN(sizeof(wUVEdge), "Welded UV Edge"); - newwedge->v1uv[0] = tf->uv[v1tfindex][0]; - newwedge->v1uv[1] = tf->uv[v1tfindex][1]; - newwedge->v2uv[0] = tf->uv[v2tfindex][0]; - newwedge->v2uv[1] = tf->uv[v2tfindex][1]; - newwedge->eed = eed; - - BLI_addtail(uvedges, newwedge); - } -} - -static void build_weldedUVEdges(ListBase *uvedges, ListBase *uvverts) -{ - wUV *curwvert; - wUVEdge *curwedge; - EditFace *efa; - - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - if(efa->e1->f1) append_weldedUVEdge(efa, efa->e1, uvedges); - if(efa->e2->f1) append_weldedUVEdge(efa, efa->e2, uvedges); - if(efa->e3->f1) append_weldedUVEdge(efa, efa->e3, uvedges); - if(efa->e4 && efa->e4->f1) append_weldedUVEdge(efa, efa->e4, uvedges); - } - - - //link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers - for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ - for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ - if(curwedge->eed->v1 == curwvert->eve && curwedge->v1uv[0] == curwvert->u && curwedge->v1uv[1] == curwvert->v){ - curwedge->v1 = curwvert; - break; - } - } - for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ - if(curwedge->eed->v2 == curwvert->eve && curwedge->v2uv[0] == curwvert->u && curwedge->v2uv[1] == curwvert->v){ - curwedge->v2 = curwvert; - break; - } - } - } -} - -static void free_weldedUVs(ListBase *uvverts) -{ - wUV *curwvert; - for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes)); - BLI_freelistN(uvverts); -} - -static void collapse_edgeuvs(void) -{ - ListBase uvedges, uvverts, allcollections; - wUVEdge *curwedge; - wUVNode *curwnode; - wUVEdgeCollect *collectedwuve, *newcollectedwuve; - Collection *wuvecollection, *newcollection; - int curtag, balanced, collectionfound= 0, vcount; - float avg[2]; - - if (!EM_texFaceCheck()) - return; - - uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL; - - build_weldedUVs(&uvverts); - build_weldedUVEdges(&uvedges, &uvverts); - - curtag = 0; - - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ - curwedge->v1->f = curtag; - curwedge->v2->f = curtag; - curtag +=1; - } - - balanced = 0; - while(!balanced){ - balanced = 1; - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ - if(curwedge->v1->f != curwedge->v2->f){ - if(curwedge->v1->f > curwedge->v2->f) curwedge->v1->f = curwedge->v2->f; - else curwedge->v2->f = curwedge->v1->f; - balanced = 0; - } - } - } - - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f; - - - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ - if(allcollections.first){ - for(wuvecollection = allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ - if(wuvecollection->index == curwedge->f){ - newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); - newcollectedwuve->uved = curwedge; - BLI_addtail(&(wuvecollection->collectionbase), newcollectedwuve); - collectionfound = 1; - break; - } - - else collectionfound = 0; - } - } - if(allcollections.first == NULL || collectionfound == 0){ - newcollection = MEM_callocN(sizeof(Collection), "element collection"); - newcollection->index = curwedge->f; - newcollection->collectionbase.first = 0; - newcollection->collectionbase.last = 0; - - newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); - newcollectedwuve->uved = curwedge; - - BLI_addtail(&(newcollection->collectionbase), newcollectedwuve); - BLI_addtail(&allcollections, newcollection); - } - } - - for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ - - vcount = avg[0] = avg[1] = 0; - - for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ - avg[0] += collectedwuve->uved->v1uv[0]; - avg[1] += collectedwuve->uved->v1uv[1]; - - avg[0] += collectedwuve->uved->v2uv[0]; - avg[1] += collectedwuve->uved->v2uv[1]; - - vcount +=2; - - } - - avg[0] /= vcount; avg[1] /= vcount; - - for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ - for(curwnode=collectedwuve->uved->v1->nodes.first; curwnode; curwnode=curwnode->next){ - *(curwnode->u) = avg[0]; - *(curwnode->v) = avg[1]; - } - for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){ - *(curwnode->u) = avg[0]; - *(curwnode->v) = avg[1]; - } - } - } - - free_weldedUVs(&uvverts); - BLI_freelistN(&uvedges); - freecollections(&allcollections); -} - -/*End UV Edge collapse code*/ - -static void collapseuvs(EditVert *mergevert) -{ - EditFace *efa; - MTFace *tf; - int uvcount; - float uvav[2]; - - if (!EM_texFaceCheck()) - return; - - uvcount = 0; - uvav[0] = 0; - uvav[1] = 0; - - for(efa = G.editMesh->faces.first; efa; efa=efa->next){ - tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); - - if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) { - uvav[0] += tf->uv[0][0]; - uvav[1] += tf->uv[0][1]; - uvcount += 1; - } - if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){ - uvav[0] += tf->uv[1][0]; - uvav[1] += tf->uv[1][1]; - uvcount += 1; - } - if(efa->v3->f1 && ELEM(mergevert, NULL, efa->v3)){ - uvav[0] += tf->uv[2][0]; - uvav[1] += tf->uv[2][1]; - uvcount += 1; - } - if(efa->v4 && efa->v4->f1 && ELEM(mergevert, NULL, efa->v4)){ - uvav[0] += tf->uv[3][0]; - uvav[1] += tf->uv[3][1]; - uvcount += 1; - } - } - - if(uvcount > 0) { - uvav[0] /= uvcount; - uvav[1] /= uvcount; - - for(efa = G.editMesh->faces.first; efa; efa=efa->next){ - tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE); - - if(efa->v1->f1){ - tf->uv[0][0] = uvav[0]; - tf->uv[0][1] = uvav[1]; - } - if(efa->v2->f1){ - tf->uv[1][0] = uvav[0]; - tf->uv[1][1] = uvav[1]; - } - if(efa->v3->f1){ - tf->uv[2][0] = uvav[0]; - tf->uv[2][1] = uvav[1]; - } - if(efa->v4 && efa->v4->f1){ - tf->uv[3][0] = uvav[0]; - tf->uv[3][1] = uvav[1]; - } - } - } -} - -int collapseEdges(void) -{ - EditVert *eve; - EditEdge *eed; - - ListBase allcollections; - CollectedEdge *curredge; - Collection *edgecollection; - - int totedges, groupcount, mergecount,vcount; - float avgcount[3]; - - allcollections.first = 0; - allcollections.last = 0; - - mergecount = 0; - - if(multires_test()) return 0; - - build_edgecollection(&allcollections); - groupcount = BLI_countlist(&allcollections); - - - for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){ - totedges = BLI_countlist(&(edgecollection->collectionbase)); - mergecount += totedges; - avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0; - - vcount = 0; - - for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ - avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0]; - avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1]; - avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2]; - - avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0]; - avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1]; - avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2]; - - vcount +=2; - } - - avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount; - - for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ - copy_v3_v3(((EditEdge*)curredge->eed)->v1->co,avgcount); - copy_v3_v3(((EditEdge*)curredge->eed)->v2->co,avgcount); - } - - if (EM_texFaceCheck()) { - /*uv collapse*/ - for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0; - for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0; - for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ - curredge->eed->v1->f1 = 1; - curredge->eed->v2->f1 = 1; - curredge->eed->f1 = 1; - } - collapse_edgeuvs(); - } - - } - freecollections(&allcollections); - removedoublesflag(1, 0, MERGELIMIT); - /*get rid of this!*/ - countall(); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - if (EM_texFaceCheck()) - allqueue(REDRAWIMAGE, 0); - return mergecount; -} - -int merge_firstlast(int first, int uvmerge) -{ - EditVert *eve,*mergevert; - EditSelection *ese; - - if(multires_test()) return 0; - - /* do sanity check in mergemenu in edit.c ?*/ - if(first == 0){ - ese = G.editMesh->selected.last; - mergevert= (EditVert*)ese->data; - } - else{ - ese = G.editMesh->selected.first; - mergevert = (EditVert*)ese->data; - } - - if(mergevert->f&SELECT){ - for (eve=G.editMesh->verts.first; eve; eve=eve->next){ - if (eve->f&SELECT) - copy_v3_v3(eve->co,mergevert->co); - } - } - - if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){ - - for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0; - for(eve=G.editMesh->verts.first; eve; eve=eve->next){ - if(eve->f&SELECT) eve->f1 = 1; - } - collapseuvs(mergevert); - } - - countall(); - return removedoublesflag(1, 0, MERGELIMIT); -} - -int merge_target(int target, int uvmerge) -{ - EditVert *eve; - - if(multires_test()) return 0; - - if(target) snap_sel_to_curs(); - else snap_to_center(); - - if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){ - for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0; - for(eve=G.editMesh->verts.first; eve; eve=eve->next){ - if(eve->f&SELECT) eve->f1 = 1; - } - collapseuvs(NULL); - } - - countall(); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - return removedoublesflag(1, 0, MERGELIMIT); - -} -#undef MERGELIMIT - -typedef struct PathNode{ - int u; - int visited; - ListBase edges; -} PathNode; - -typedef struct PathEdge{ - struct PathEdge *next, *prev; - int v; - float w; -} PathEdge; - -void pathselect(void) -{ - EditVert *eve, *s, *t; - EditEdge *eed; - EditSelection *ese; - PathEdge *newpe, *currpe; - PathNode *currpn; - PathNode *Q; - int v, *previous, pathvert, pnindex; /*pnindex redundant?*/ - int unbalanced, totnodes; - short physical; - float *cost; - Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/ - - s = t = NULL; - - countall(); /*paranoid?*/ - - ese = ((EditSelection*)G.editMesh->selected.last); - if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){ - physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0"); - - t = (EditVert*)ese->data; - s = (EditVert*)ese->prev->data; - - /*need to find out if t is actually reachable by s....*/ - for(eve=G.editMesh->verts.first; eve; eve=eve->next){ - eve->f1 = 0; - } - - s->f1 = 1; - - unbalanced = 1; - totnodes = 1; - while(unbalanced){ - unbalanced = 0; - for(eed=G.editMesh->edges.first; eed; eed=eed->next){ - if(!eed->h){ - if(eed->v1->f1 && !eed->v2->f1){ - eed->v2->f1 = 1; - totnodes++; - unbalanced = 1; - } - else if(eed->v2->f1 && !eed->v1->f1){ - eed->v1->f1 = 1; - totnodes++; - unbalanced = 1; - } - } - } - } - - - - if(s->f1 && t->f1){ /*t can be reached by s*/ - Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes"); - totnodes = 0; - for(eve=G.editMesh->verts.first; eve; eve=eve->next){ - if(eve->f1){ - Q[totnodes].u = totnodes; - Q[totnodes].edges.first = 0; - Q[totnodes].edges.last = 0; - Q[totnodes].visited = 0; - eve->tmp.p = &(Q[totnodes]); - totnodes++; - } - else eve->tmp.p = NULL; - } - - for(eed=G.editMesh->edges.first; eed; eed=eed->next){ - if(!eed->h){ - if(eed->v1->f1){ - currpn = ((PathNode*)eed->v1->tmp.p); - - newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); - newpe->v = ((PathNode*)eed->v2->tmp.p)->u; - if(physical){ - newpe->w = len_v3v3(eed->v1->co, eed->v2->co); - } - else newpe->w = 1; - newpe->next = 0; - newpe->prev = 0; - BLI_addtail(&(currpn->edges), newpe); - } - if(eed->v2->f1){ - currpn = ((PathNode*)eed->v2->tmp.p); - newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); - newpe->v = ((PathNode*)eed->v1->tmp.p)->u; - if(physical){ - newpe->w = len_v3v3(eed->v1->co, eed->v2->co); - } - else newpe->w = 1; - newpe->next = 0; - newpe->prev = 0; - BLI_addtail(&(currpn->edges), newpe); - } - } - } - - heap = BLI_heap_new(); - cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs"); - previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices"); - - for(v=0; v < totnodes; v++){ - cost[v] = 1000000; - previous[v] = -1; /*array of indices*/ - } - - pnindex = ((PathNode*)s->tmp.p)->u; - cost[pnindex] = 0; - BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex)); - - while( !BLI_heap_empty(heap) ){ - - pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); - currpn = &(Q[pnindex]); - - if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/ - break; - - for(currpe=currpn->edges.first; currpe; currpe=currpe->next){ - if(!Q[currpe->v].visited){ - if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){ - cost[currpe->v] = cost[currpn->u] + currpe->w; - previous[currpe->v] = currpn->u; - Q[currpe->v].visited = 1; - BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v)); - } - } - } - } - - pathvert = ((PathNode*)t->tmp.p)->u; - while(pathvert != -1){ - for(eve=G.editMesh->verts.first; eve; eve=eve->next){ - if(eve->f1){ - if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT; - } - } - pathvert = previous[pathvert]; - } - - for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges)); - MEM_freeN(Q); - MEM_freeN(cost); - MEM_freeN(previous); - BLI_heap_free(heap, NULL); - EM_select_flush(); - countall(); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - if (EM_texFaceCheck()) - allqueue(REDRAWIMAGE, 0); - } - } - else{ - error("Path Selection requires that exactly two vertices be selected"); - return; - } -} - -void region_to_loop(void) -{ - EditEdge *eed; - EditFace *efa; - - if(G.totfacesel){ - for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0; - - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - if(efa->f&SELECT){ - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) - efa->e4->f1++; - } - } - - EM_clear_flag_all(SELECT); - - for(eed=G.editMesh->edges.first; eed; eed=eed->next){ - if(eed->f1 == 1) EM_select_edge(eed, 1); - } - - G.scene->selectmode = SCE_SELECT_EDGE; - EM_selectmode_set(); - countall(); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - if (EM_texFaceCheck()) - allqueue(REDRAWIMAGE, 0); - BIF_undo_push("Face Region to Edge Loop"); - - } -} - -static int validate_loop(Collection *edgecollection) -{ - EditEdge *eed; - EditFace *efa; - CollectedEdge *curredge; - - /*1st test*/ - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - curredge->eed->v1->f1 = 0; - curredge->eed->v2->f1 = 0; - } - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - curredge->eed->v1->f1++; - curredge->eed->v2->f1++; - } - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - if(curredge->eed->v1->f1 > 2) return(0); else - if(curredge->eed->v2->f1 > 2) return(0); - } - - /*2nd test*/ - for(eed = G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0; - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - if(curredge->eed->f1 > 2) return(0); - } - return(1); -} - -static int loop_bisect(Collection *edgecollection) -{ - - EditFace *efa, *sf1, *sf2; - EditEdge *eed, *sed; - CollectedEdge *curredge; - int totsf1, totsf2, unbalanced,balancededges; - - for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0; - for(efa=G.editMesh->faces.first; efa; efa=efa->next) efa->f1 = 0; - - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1; - - sf1 = sf2 = NULL; - sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed; - - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - if(sf2) break; - else if(sf1){ - if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa; - } - else{ - if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa; - } - } - - if(sf1==NULL || sf2==NULL) - return(-1); - - if(!(sf1->e1->f1)) sf1->e1->f2 = 1; - if(!(sf1->e2->f1)) sf1->e2->f2 = 1; - if(!(sf1->e3->f1)) sf1->e3->f2 = 1; - if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1; - sf1->f1 = 1; - totsf1 = 1; - - if(!(sf2->e1->f1)) sf2->e1->f2 = 2; - if(!(sf2->e2->f1)) sf2->e2->f2 = 2; - if(!(sf2->e3->f1)) sf2->e3->f2 = 2; - if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2; - sf2->f1 = 2; - totsf2 = 1; - - /*do sf1*/ - unbalanced = 1; - while(unbalanced){ - unbalanced = 0; - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - balancededges = 0; - if(efa->f1 == 0){ - if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){ - balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1; - balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1; - balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1; - if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1; - if(balancededges){ - unbalanced = 1; - efa->f1 = 1; - totsf1++; - } - } - } - } - } - - /*do sf2*/ - unbalanced = 1; - while(unbalanced){ - unbalanced = 0; - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - balancededges = 0; - if(efa->f1 == 0){ - if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){ - balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2; - balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2; - balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2; - if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2; - if(balancededges){ - unbalanced = 1; - efa->f1 = 2; - totsf2++; - } - } - } - } - } - - if(totsf1 < totsf2) return(1); - else return(2); -} - -void loop_to_region(void) -{ - EditFace *efa; - ListBase allcollections={NULL,NULL}; - Collection *edgecollection; - int testflag; - - build_edgecollection(&allcollections); - - for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){ - if(validate_loop(edgecollection)){ - testflag = loop_bisect(edgecollection); - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ - if(efa->f1 == testflag){ - if(efa->f&SELECT) EM_select_face(efa, 0); - else EM_select_face(efa,1); - } - } - } - } - - for(efa=G.editMesh->faces.first; efa; efa=efa->next){ /*fix this*/ - if(efa->f&SELECT) EM_select_face(efa,1); - } - - countall(); - freecollections(&allcollections); - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - if (EM_texFaceCheck()) - allqueue(REDRAWIMAGE, 0); - BIF_undo_push("Edge Loop to Face Region"); -} - - -/* texface and vertex color editmode tools for the face menu */ - -void mesh_rotate_uvs(void) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - short change = 0, ccw; - MTFace *tf; - float u1, v1; - - if (!EM_texFaceCheck()) { - error("mesh has no uv/image layers"); - return; - } - - ccw = (G.qual == LR_SHIFTKEY); - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - u1= tf->uv[0][0]; - v1= tf->uv[0][1]; - - if (ccw) { - if(efa->v4) { - tf->uv[0][0]= tf->uv[3][0]; - tf->uv[0][1]= tf->uv[3][1]; - - tf->uv[3][0]= tf->uv[2][0]; - tf->uv[3][1]= tf->uv[2][1]; - } else { - tf->uv[0][0]= tf->uv[2][0]; - tf->uv[0][1]= tf->uv[2][1]; - } - - tf->uv[2][0]= tf->uv[1][0]; - tf->uv[2][1]= tf->uv[1][1]; - - tf->uv[1][0]= u1; - tf->uv[1][1]= v1; - } else { - tf->uv[0][0]= tf->uv[1][0]; - tf->uv[0][1]= tf->uv[1][1]; - - tf->uv[1][0]= tf->uv[2][0]; - tf->uv[1][1]= tf->uv[2][1]; - - if(efa->v4) { - tf->uv[2][0]= tf->uv[3][0]; - tf->uv[2][1]= tf->uv[3][1]; - - tf->uv[3][0]= u1; - tf->uv[3][1]= v1; - } - else { - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - } - } - change = 1; - } - } - - if (change) { - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - BIF_undo_push("Rotate UV face"); - } -} - -void mesh_mirror_uvs(void) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - short change = 0, altaxis; - MTFace *tf; - float u1, v1; - - if (!EM_texFaceCheck()) { - error("mesh has no uv/image layers"); - return; - } - - altaxis = (G.qual == LR_SHIFTKEY); - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (altaxis) { - u1= tf->uv[1][0]; - v1= tf->uv[1][1]; - if(efa->v4) { - - tf->uv[1][0]= tf->uv[2][0]; - tf->uv[1][1]= tf->uv[2][1]; - - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - - u1= tf->uv[3][0]; - v1= tf->uv[3][1]; - - tf->uv[3][0]= tf->uv[0][0]; - tf->uv[3][1]= tf->uv[0][1]; - - tf->uv[0][0]= u1; - tf->uv[0][1]= v1; - } - else { - tf->uv[1][0]= tf->uv[2][0]; - tf->uv[1][1]= tf->uv[2][1]; - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - } - - } else { - u1= tf->uv[0][0]; - v1= tf->uv[0][1]; - if(efa->v4) { - - tf->uv[0][0]= tf->uv[1][0]; - tf->uv[0][1]= tf->uv[1][1]; - - tf->uv[1][0]= u1; - tf->uv[1][1]= v1; - - u1= tf->uv[3][0]; - v1= tf->uv[3][1]; - - tf->uv[3][0]= tf->uv[2][0]; - tf->uv[3][1]= tf->uv[2][1]; - - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - } - else { - tf->uv[0][0]= tf->uv[1][0]; - tf->uv[0][1]= tf->uv[1][1]; - tf->uv[1][0]= u1; - tf->uv[1][1]= v1; - } - } - change = 1; - } - } - - if (change) { - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - BIF_undo_push("Mirror UV face"); - } -} - -void mesh_rotate_colors(void) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - short change = 0, ccw; - MCol tmpcol, *mcol; - if (!EM_vertColorCheck()) { - error("mesh has no color layers"); - return; - } - - ccw = (G.qual == LR_SHIFTKEY); - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - tmpcol= mcol[0]; - - if (ccw) { - if(efa->v4) { - mcol[0]= mcol[3]; - mcol[3]= mcol[2]; - } else { - mcol[0]= mcol[2]; - } - mcol[2]= mcol[1]; - mcol[1]= tmpcol; - } else { - mcol[0]= mcol[1]; - mcol[1]= mcol[2]; - - if(efa->v4) { - mcol[2]= mcol[3]; - mcol[3]= tmpcol; - } - else - mcol[2]= tmpcol; - } - change = 1; - } - } - - if (change) { - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - BIF_undo_push("Rotate Color face"); - } -} - -void mesh_mirror_colors(void) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - short change = 0, altaxis; - MCol tmpcol, *mcol; - if (!EM_vertColorCheck()) { - error("mesh has no color layers"); - return; - } - - altaxis = (G.qual == LR_SHIFTKEY); - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - if (altaxis) { - tmpcol= mcol[1]; - mcol[1]= mcol[2]; - mcol[2]= tmpcol; - - if(efa->v4) { - tmpcol= mcol[0]; - mcol[0]= mcol[3]; - mcol[3]= tmpcol; - } - } else { - tmpcol= mcol[0]; - mcol[0]= mcol[1]; - mcol[1]= tmpcol; - - if(efa->v4) { - tmpcol= mcol[2]; - mcol[2]= mcol[3]; - mcol[3]= tmpcol; - } - } - change = 1; - } - } - - if (change) { - DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); - allqueue(REDRAWVIEW3D, 0); - BIF_undo_push("Mirror Color face"); - } -} - -#endif diff --git a/source/blender/bmesh/tools/BME_dupe_ops.c b/source/blender/bmesh/tools/BME_dupe_ops.c deleted file mode 100644 index fb357390ecc..00000000000 --- a/source/blender/bmesh/tools/BME_dupe_ops.c +++ /dev/null @@ -1,322 +0,0 @@ -#if 0 - -/* - * BME_DUPLICATE.C - * - * This file contains functions for duplicating, copying, and splitting - * elements from a bmesh. - * - */ - -/* - * COPY VERTEX - * - * Copy an existing vertex from one bmesh to another. - * -*/ - -static BMVert *copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash) -{ - BMVert *target_vertex = NULL; - - /*create a new vertex*/ - target_vertex = BM_vert_create(target, source_vertex->co, NULL); - - /*insert new vertex into the vert hash*/ - BLI_ghash_insert(vhash, source_vertex, target_vertex); - - /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ - CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data); - - /*Copy Markings*/ - if(BM_Is_Selected((BMHeader*)source_vertex)) BM_vert_select_set(target_mesh, target_vertex, TRUE); - if(BM_Is_Hidden((BMHeader*)source_vertex)) BM_Mark_Hidden((BMHeader*)target_vertex, 1); - - BMO_elem_flag_enable(target_mesh, (BMHeader*)target_vertex, DUPE_NEW); - - return target_vertex; -} - -/* - * COPY EDGE - * - * Copy an existing edge from one bmesh to another. - * -*/ - -static BMEdge *copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash) -{ - BMEdge *target_edge = NULL; - BMVert *target_vert1, *target_vert2; - - /*lookup v1 and v2*/ - target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1); - target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2); - - /*create a new edge*/ - target_edge = BM_edge_create(target_mesh, target_vert1, target_vert2, NULL, FALSE); - - /*insert new edge into the edge hash*/ - BLI_ghash_insert(ehash, source_edge, target_edge); - - /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ - CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data); - - /*copy flags*/ - if(BM_Is_Selected((BMHeader*) source_edge)) BM_edge_select_set(target_mesh, target_edge, TRUE); - if(BM_Is_Hidden((BMHeader*) source_edge)) BM_Mark_Hidden(target_mesh, target_edge, 1); - if(BM_Is_Sharp((BMHeader*) source_edge)) BM_Mark_Sharp(target_edge, 1); - if(BM_Is_Seam((BMHeader*) source_edge)) BM_Mark_Seam(target_edge, 1); - if(BM_Is_Fgon((BMHeader*) source_edge)) BM_Mark_Fgon(target_edge, 1); - - BMO_elem_flag_enable(target_mesh, (BMHeader*)target_edge, DUPE_NEW); - - return target_edge; -} - -/* - * COPY FACE - * - * Copy an existing face from one bmesh to another. - * -*/ - -static BMFace *copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash) -{ - BMEdge *target_edge; - BMVert *target_vert1, *target_vert2; - BMLoop *source_loop, *target_loop; - BMFace *target_face = NULL; - int i; - - /*lookup the first and second verts*/ - target_vert1 = BLI_ghash_lookup(vhash, source_face->lbase->v); - target_vert2 = BLI_ghash_lookup(vhash, source_face->lbase->next->v); - - /*lookup edges*/ - i = 0; - source_loop = source_face->lbase; - do{ - edar[i] = BLI_ghash_lookup(ehash, source_loop->e); - i++; - source_loop = source_loop->next; - }while(source_loop != source_face->lbase); - - /*create new face*/ - target_face = BM_face_create_ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0); - - /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/ - CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data); - - /*copy flags*/ - if(BM_Is_Selected((BMHeader*)source_face)) BM_Select_face(target, target_face, TRUE); - if(BM_Is_Hidden((BMHeader*)source_face)) BM_Mark_Hidden((BMHeader*)target_face, 1); - - /*mark the face for output*/ - BMO_elem_flag_enable(target_mesh, (BMHeader*)target_face, DUPE_NEW); - - /*copy per-loop custom data*/ - source_loop = source_face->lbase; - target_loop = target_face->lbase; - do{ - CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data); - source_loop = source_loop->next; - target_loop = target_loop->next; - }while(source_loop != source_face->lbase); - - return target_face; -} - -/* - * COPY MESH - * - * Internal Copy function. -*/ - -/*local flag defines*/ - -#define DUPE_INPUT 1 /*input from operator*/ -#define DUPE_NEW 2 -#define DUPE_DONE 3 - -static void copy_mesh(BMMesh *source, BMMesh *target) -{ - - BMVert *v = NULL; - BMEdge *e = NULL, **edar = NULL; - BMLoop *l = NULL; - BMFace *f = NULL; - - BMIter verts; - BMIter edges; - BMIter faces; - BMIter loops; - - GHash *vhash; - GHash *ehash; - - int maxlength = 0, flag; - - /*initialize pointer hashes*/ - vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp); - - /*initialize edge pointer array*/ - for(f = BM_iter_new(&faces, source, BM_FACES, source, 0, NULL); f; f = BM_iter_step(&faces)){ - if(f->len > maxlength) maxlength = f->len; - } - edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array"); - - - /*first we dupe all flagged faces and their elements from source*/ - for(f = BM_iter_new(&faces, source, BM_FACES, source, 0, NULL); f; f= BM_iter_step(&faces)){ - if(BMO_elem_flag_test(source, (BMHeader*)f, DUPE_INPUT)){ - /*vertex pass*/ - for(v = BM_iter_new(&verts, source, BM_VERT_OF_FACE, f, 0, NULL); v; v = BM_iter_step(&verts)){ - if(!BMO_elem_flag_test(source, (BMHeader*)v, DUPE_DONE)){ - copy_vertex(source,v, target, vhash); - BMO_elem_flag_enable(source, (BMHeader*)v, DUPE_DONE); - } - } - - /*edge pass*/ - for(e = BM_iter_new(&edges, source, BM_EDGE_OF_FACE, f, 0, NULL); e; e = BMeshIter_step(&edges)){ - if(!BMO_elem_flag_test(source, (BMHeader*)e, DUPE_DONE)){ - copy_edge(source, e, target, vhash, ehash); - BMO_elem_flag_enable(source, (BMHeader*)e, DUPE_DONE); - } - } - copy_face(source, f, target, edar, vhash, ehash); - BMO_elem_flag_enable(source, (BMHeader*)f, DUPE_DONE); - } - } - - /*now we dupe all the edges*/ - for(e = BM_iter_new(&edges, source, BM_EDGES, source, 0, NULL); e; e = BM_iter_step(&edges)){ - if(BMO_elem_flag_test(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_elem_flag_test(source, (BMHeader*)e, DUPE_DONE))){ - /*make sure that verts are copied*/ - if(!BMO_elem_flag_test(source, (BMHeader*)e->v1, DUPE_DONE){ - copy_vertex(source, e->v1, target, vhash); - BMO_elem_flag_enable(source, (BMHeader*)e->v1, DUPE_DONE); - } - if(!BMO_elem_flag_test(source, (BMHeader*)e->v2, DUPE_DONE){ - copy_vertex(source, e->v2, target, vhash); - BMO_elem_flag_enable(source, (BMHeader*)e->v2, DUPE_DONE); - } - /*now copy the actual edge*/ - copy_edge(source, e, target, vhash, ehash); - BMO_elem_flag_enable(source, (BMHeader*)e, DUPE_DONE); - } - } - - /*finally dupe all loose vertices*/ - for(v = BM_iter_new(&verts, source, BM_VERTS, source, 0, NULL); v; v = BM_iter_step(&verts)){ - if(BMO_elem_flag_test(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_elem_flag_test(source, (BMHeader*)v, DUPE_DONE))){ - copy_vertex(source, v, target, vhash); - BMO_elem_flag_enable(source, (BMHeader*)v, DUPE_DONE); - } - } - - /*free pointer hashes*/ - BLI_ghash_free(vhash, NULL, NULL); - BLI_ghash_free(ehash, NULL, NULL); - - /*free edge pointer array*/ - if(edar) - MEM_freeN(edar); -} -/* -BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4]) -{ - BMMesh *target = NULL; - target = bmesh_make_mesh(allocsize); - - - CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0); - - - CustomData_bmesh_init_pool(&target->vdata, allocsize[0]); - CustomData_bmesh_init_pool(&target->edata, allocsize[1]); - CustomData_bmesh_init_pool(&target->ldata, allocsize[2]); - CustomData_bmesh_init_pool(&target->pdata, allocsize[3]); - - bmesh_begin_edit(bm); - bmesh_begin_edit(target); - - bmesh_copy_mesh(bm, target, 0); - - bmesh_end_edit(bm); - bmesh_end_edit(target); - - return target; - -} -*/ - -void dupeop_exec(BMMesh *bm, BMOperator *op) -{ - BMOperator *dupeop = op; - BMOpSlot *vinput, *einput, *finput, *vnew, *enew, *fnew; - int i; - - vinput = BMO_Get_Slot(dupeop, BMOP_DUPE_VINPUT); - einput = BMO_Get_Slot(dupeop, BMOP_DUPE_EINPUT); - finput = BMO_Get_Slot(dupeop, BMOP_DUPE_FINPUT); - - /*go through vinput, einput, and finput and flag elements with private flags*/ - BMO_slot_buffer_flag_enable(bm, dupeop, BMOP_DUPE_VINPUT, DUPE_INPUT); - BMO_slot_buffer_flag_enable(bm, dupeop, BMOP_DUPE_EINPUT, DUPE_INPUT); - BMO_slot_buffer_flag_enable(bm, dupeop, BMOP_DUPE_FINPUT, DUPE_INPUT); - - /*use the internal copy function*/ - copy_mesh(bm, bm); - - /*Output*/ - /*First copy the input buffers to output buffers - original data*/ - BMO_Copy_Opslot_Buffer_Alloc(dupeop, vinput, BMO_Get_Slot(dupeop, BMOP_DUPE_VORIGINAL)); - BMO_Copy_Opslot_Buffer_Alloc(dupeop, einput, BMO_Get_Slot(dupeop, BMOP_DUPE_EORIGINAL)); - BMO_Copy_Opslot_Buffer_Alloc(dupeop, finput, BMO_Get_Slot(dupeop, BMOP_DUPE_FORIGINAL)); - - /*Now alloc the new output buffers*/ - BMO_slot_from_flag(bm, dupeop, BMOP_DUPE_VNEW, DUPE_NEW, BMESH_VERT); - BMO_slot_from_flag(bm, dupeop, BMOP_DUPE_ENEW, DUPE_NEW, BMESH_EDGE); - BMO_slot_from_flag(bm, dupeop, BMOP_DUPE_FNEW, DUPE_NEW, BMESH_FACE); -} - -void splitop_exec(BMMesh *bm, BMOperator *op) -{ - BMOperator *splitop = op; - BMOperator dupeop; - BMOperator delop; - - /*initialize our sub-operators*/ - BMO_op_init(&dupeop, BMOP_DUPE); - BMO_op_init(&delop, BMOP_DEL); - - BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_VINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_VINPUT)); - BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_EINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_EINPUT)); - BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_FINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_FINPUT)); - - BMO_op_exec(&dupeop); - - /*connect outputs of dupe to delete*/ - BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_VORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_VINPUT)); - BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_EORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_EINPUT)); - BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_FORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_FINPUT)); - - BMO_op_exec(&delop); - - /*now we make our outputs by copying the dupe outputs*/ - BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_VNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_VOUTPUT)); - BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_ENEW), BMO_Get_Slot(splitop, BMOP_SPLIT_EOUTPUT)); - BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_FNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_FOUTPUT)); - - /*cleanup*/ - BMO_op_finish(&dupeop); - BMO_op_finish(&delop); -} - -#endif diff --git a/source/blender/bmesh/tools/BME_duplicate.c b/source/blender/bmesh/tools/BME_duplicate.c deleted file mode 100644 index 11151de9ed7..00000000000 --- a/source/blender/bmesh/tools/BME_duplicate.c +++ /dev/null @@ -1,310 +0,0 @@ -#if 0 - -/* - * BME_DUPLICATE.C - * - * This file contains functions for duplicating, copying, and splitting - * elements from a bmesh. - * - */ - -/* - * BMESH COPY VERTEX - * - * Copy an existing vertex from one bmesh to another. - * -*/ - -static BMVert *bmesh_copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash) -{ - BMVert *target_vertex = NULL; - - /*create a new vertex*/ - target_vertex = bmesh_make_vert(target, source_vertex->co, NULL); - - /*insert new vertex into the vert hash*/ - BLI_ghash_insert(vhash, source_vertex, target_vertex); - - /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ - CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data); - - /*copy flags*/ - if(bmesh_test_flag(source_vertex, BMESH_SELECT)) bmesh_set_flag(target_vertex, BMESH_SELECT); - if(bmesh_test_flag(source_vertex, BMESH_HIDDEN)) bmesh_set_flag(target_vertex, BMESH_HIDDEN); - - return target_vertex; -} - -/* - * BMESH COPY EDGE - * - * Copy an existing edge from one bmesh to another. - * -*/ - -static BMEdge *bmesh_copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash) -{ - BMEdge *target_edge = NULL; - BMVert *target_vert1, *target_vert2; - - /*lookup v1 and v2*/ - target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1); - target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2); - - /*create a new edge*/ - target_edge = bmesh_make_edge(target_mesh, target_vert1, target_vert2, NULL, 0); - - /*insert new edge into the edge hash*/ - BLI_ghash_insert(ehash, source_edge, target_edge); - - /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/ - CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data); - - /*copy flags*/ - if(bmesh_test_flag(source_edge, BMESH_SELECT)) bmesh_set_flag(target_edge, BMESH_SELECT); - if(bmesh_test_flag(source_edge, BMESH_HIDDEN)) bmesh_set_flag(target_edge, BMESH_SELECT); - if(bmesh_test_flag(source_edge, BMESH_SHARP)) bmesh_set_flag(target_edge, BMESH_SHARP); - if(bmesh_test_flag(source_edge, BMESH_SEAM)) bmesh_set_flag(target_edge, BMESH_SEAM); - if(bmesh_test_flag(source_edge, BMESH_FGON)) bmesh_set_flag(target_edge, BMESH_FGON); - - return target_edge; -} - -/* - * BMESH COPY FACE - * - * Copy an existing face from one bmesh to another. - * -*/ - -static BMFace *bmesh_copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash) -{ - BMEdge *target_edge; - BMVert *target_vert1, *target_vert2; - BMLoop *source_loop, *target_loop; - BMFace *target_face = NULL; - int i; - - - /*lookup the first and second verts*/ - target_vert1 = BLI_ghash_lookup(vhash, source_face->lbase->v); - target_vert2 = BLI_ghash_lookup(vhash, source_face->lbase->next->v); - - /*lookup edges*/ - i = 0; - source_loop = source_face->lbase; - do{ - edar[i] = BLI_ghash_lookup(ehash, source_loop->e); - i++; - source_loop = source_loop->next; - }while(source_loop != source_face->lbase); - - /*create new face*/ - target_face = bmesh_make_ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0); - - /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/ - CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data); - - /*copy flags*/ - if(bmesh_test_flag(source_face, BMESH_SELECT)) bmesh_set_flag(target_face, BMESH_SELECT); - if(bmesh_test_flag(source_face, BMESH_HIDDEN)) bmesh_set_flag(target_face, BMESH_HIDDEN); - - /*mark the face as dirty for normal and tesselation calcs*/ - bmesh_set_flag(target_face, BMESH_DIRTY); - - /*copy per-loop custom data*/ - source_loop = source_face->lbase; - target_loop = target_face->lbase; - do{ - CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data); - source_loop = source_loop->next; - target_loop = target_loop->next; - }while(source_loop != source_face->lbase); - - return target_face; -} - -/* - * BMESH COPY MESH - * - * Internal Copy function. copies flagged elements from - * source to target, which may in fact be the same mesh. - * Note that if __flag is 0, all elements will be copied. - * -*/ - -static void bmesh_copy_mesh(BMMesh *source, BMMesh *target, int __flag) -{ - - BMVert *v; - BMEdge *e, **edar; - BMLoop *l; - BMFace *f; - - BMIter verts; - BMIter edges; - BMIter faces; - BMIter loops; - - GHash *vhash; - GHash *ehash; - - int maxlength = 0, flag; - - /*initialize pointer hashes*/ - vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp); - - /*initialize edge pointer array*/ - for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)){ - if(f->len > maxlength) maxlength = f->len; - } - edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array"); - - /*begin modelling loop for target*/ - bmesh_begin_edit(target); - - /*we make special exception for __flag == 0... we copy all*/ - if(!__flag){ - flag = BMESH_DUPE; - for(v = BMeshIter_init(verts, BM_VERTS, source, 0); v; v = BMeshIter_step(verts)) bmesh_set_flag(v, BMESH_DUPE); - for(e = BMeshIter_init(verts, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)) bmesh_set_flag(e, BMESH_DUPE); - for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)) bmesh_set_flag(f, BMESH_DUPE); - } else{ - flag = __flag; - } - - /*first we dupe all flagged faces and their elements from source*/ - for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f= BMeshIter_step(faces)){ - if(bmesh_test_flag(f, flag)){ - /*vertex pass*/ - for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){ - if(!bmesh_test_flag(l->v, BMESH_DUPED)){ - bmesh_copy_vertex(source,l->v, target, vhash); - bmesh_set_flag(l->v, BMESH_DUPED); - } - } - - /*edge pass*/ - for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){ - if(!bmesh_test_flag(l->e, BMESH_DUPED)){ - bmesh_copy_edge(source, l->e, target, vhash, ehash); - bmesh_set_flag(l->e, BMESH_DUPED); - } - } - bmesh_copy_face(source, f, target, edar, vhash, ehash); - bmesh_set_flag(f, BMESH_DUPED); - } - } - - /*now we dupe all the edges*/ - for(e = BMeshIter_init(edges, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)){ - if(bmesh_test_flag(e, flag) && (!bmesh_test_flag(e, BMESH_DUPED))){ - /*make sure that verts are copied*/ - if(!bmesh_test_flag(e->v1, BMESH_DUPED)){ - bmesh_copy_vertex(source, e->v1, target, vhash); - bmesh_set_flag(e->v1, BMESH_DUPED); - } - if(!bmesh_test_flag(e->v2, BMESH_DUPED)){ - bmesh_copy_vertex(source, e->v2, target, vhash); - bmesh_set_flag(e->v2, BMESH_DUPED); - } - /*now copy the actual edge*/ - bmesh_copy_edge(source, e, target, vhash, ehash); - bmesh_set_flag(e, BMESH_DUPED); - } - } - - /*finally dupe all loose vertices*/ - for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){ - if(bmesh_test_flag(v, flag) && (!bmesh_test_flag(v, BMESH_DUPED))){ - bmesh_copy_vertex(source, v, target, vhash); - bmesh_set_flag(v, BMESH_DUPED); - } - } - - /*finish*/ - bmesh_end_edit(target, BMESH_CALC_NORM | BMESH_CALC_TESS); - - /*free pointer hashes*/ - BLI_ghash_free(vhash, NULL, NULL); - BLI_ghash_free(ehash, NULL, NULL); - - /*free edge pointer array*/ - MEM_freeN(edar); -} - -/* - * BMESH MAKE MESH FROM MESH - * - * Creates a new mesh by duplicating an existing one. - * -*/ - -BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4]) -{ - BMMesh *target = NULL; - target = bmesh_make_mesh(allocsize); - - /*copy custom data layout*/ - CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0); - CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0); - - /*initialize memory pools*/ - CustomData_bmesh_init_pool(&target->vdata, allocsize[0]); - CustomData_bmesh_init_pool(&target->edata, allocsize[1]); - CustomData_bmesh_init_pool(&target->ldata, allocsize[2]); - CustomData_bmesh_init_pool(&target->pdata, allocsize[3]); - - bmesh_begin_edit(bm); - bmesh_begin_edit(target); - - bmesh_copy_mesh(bm, target, 0); /* copy all elements */ - - bmesh_end_edit(bm); - bmesh_end_edit(target); - - return target; - -} - -/* - * BMESH SPLIT MESH - * - * Copies flagged elements then deletes them. - * -*/ - -void bmesh_split_mesh(BMMesh *bm, int flag) -{ - BMVert *v; - BMEdge *e; - BMFace *f; - - BMIter verts; - BMIter edges; - BMIter faces; - - bmesh_begin_edit(bm); - bmesh_copy_mesh(bm, bm, flag); - - /*mark verts for deletion*/ - for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){ - if(bmesh_test_flag(v, flag)) bmesh_delete_vert(bm, v); - } - /*mark edges for deletion*/ - for(e = BMeshIter_init(edges, BM_EDGES, bm, 0); e; e = BMeshIter_step(edges)){ - if(bmesh_test_flag(e, flag)) bmesh_delete_edge(bm, e); - - } - /*mark faces for deletion*/ - for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f; f= BMeshIter_step(faces)){ - if(bmesh_tes t_flag(f, flag)) bmesh_delete_face(bm, f); - - } - bmesh_end_edit(bm); -} - -#endif diff --git a/source/blender/bmesh/tools/BME_weld.c b/source/blender/bmesh/tools/BME_weld.c deleted file mode 100644 index fe1a340d94a..00000000000 --- a/source/blender/bmesh/tools/BME_weld.c +++ /dev/null @@ -1,341 +0,0 @@ -#if - -/* - * BME_WELD.C - * - * This file contains functions for welding - * elements in a mesh togather (remove doubles, - * collapse, ect). - * - * TODO: - * -Rewrite this to fit into the new API - * -Seperate out find doubles code and put it in - * BME_queries.c - * -*/ - - -/********* qsort routines *********/ - - -typedef struct xvertsort { - float x; - BMVert *v1; -} xvertsort; - -static int vergxco(const void *v1, const void *v2) -{ - const xvertsort *x1=v1, *x2=v2; - - if( x1->x > x2->x ) return 1; - else if( x1->x < x2->x) return -1; - return 0; -} - -struct facesort { - unsigned long x; - struct BMFace *f; -}; - - -static int vergface(const void *v1, const void *v2) -{ - const struct facesort *x1=v1, *x2=v2; - - if( x1->x > x2->x ) return 1; - else if( x1->x < x2->x) return -1; - return 0; -} - - - -/*break this into two functions.... 'find doubles' and 'remove doubles'?*/ - -static void BME_remove_doubles__splitface(BME_Mesh *bm,BMFace *f,GHash *vhash) -{ - BMVert *doub=NULL, *target=NULL; - BME_Loop *l; - BMFace *f2=NULL; - int split=0; - - l=f->loopbase; - do{ - if(l->v->tflag1 == 2){ - target = BLI_ghash_lookup(vhash,l->v); - if((BME_vert_in_face(target,f)) && (target != l->next->v) && (target != l->prev->v)){ - doub = l->v; - split = 1; - break; - } - } - - l= l->next; - }while(l!= f->loopbase); - - if(split){ - f2 = BME_SFME(bm,f,doub,target,NULL); - BME_remove_doubles__splitface(bm,f,vhash); - BME_remove_doubles__splitface(bm,f2,vhash); - } -} - -int BME_remove_doubles(BME_Mesh *bm, float limit) -{ - - /* all verts with (flag & 'flag') are being evaluated */ - BMVert *v, *v2, *target; - BMEdge *e, **edar, *ne; - BME_Loop *l; - BMFace *f, *nf; - xvertsort *sortblock, *sb, *sb1; - struct GHash *vhash; - struct facesort *fsortblock, *vsb, *vsb1; - int a, b, test, amount=0, found; - float dist; - - /*Build a hash table of doubles to thier target vert/edge.*/ - vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - - /*count amount of selected vertices*/ - for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ - if(BME_SELECTED(v))amount++; - } - - /*qsort vertices based upon average of coordinate. We test this way first.*/ - sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub"); - - for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ - if(BME_SELECTED(v)){ - sb->x = v->co[0]+v->co[1]+v->co[2]; - sb->v1 = v; - sb++; - } - } - qsort(sortblock, amount, sizeof(xvertsort), vergxco); - - /* test for doubles */ - sb= sortblock; - for(a=0; av1; - if(!(v->tflag1)) { //have we tested yet? - sb1= sb+1; - for(b=a+1; bx - sb->x; - if(dist > limit) break; - - /* second test: have we already done this vertex? - (eh this should be swapped, simple equality test should be cheaper than math above... small savings - though) */ - v2= sb1->v1; - if(!(v2->tflag1)) { - dist= fabsf(v2->co[0]-v->co[0]); - if(dist<=limit) { - dist= fabsf(v2->co[1]-v->co[1]); - if(dist<=limit) { - dist= fabsf(v2->co[2]-v->co[2]); - if(dist<=limit) { - /*v2 is a double of v. We want to throw out v1 and relink everything to v*/ - BLI_ghash_insert(vhash,v2, v); - v->tflag1 = 1; //mark this vertex as a target - v->tflag2++; //increase user count for this vert. - v2->tflag1 = 2; //mark this vertex as a double. - BME_VISIT(v2); //mark for delete - } - } - } - } - sb1++; - } - } - sb++; - } - MEM_freeN(sortblock); - - - /*todo... figure out what this is for... - for(eve = em->verts.first; eve; eve=eve->next) - if((eve->f & flag) && (eve->f & 128)) - EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f); - */ - - /*We cannot collapse a vertex onto another vertex if they share a face and are not connected via a collapsable edge. - so to deal with this we simply find these offending vertices and split the faces. Note that this is not optimal, but works. - */ - - - for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ - if(!(BME_NEWELEM(f))){ - BME_remove_doubles__splitface(bm,f,vhash); - } - } - - for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){ - /*If either vertices of this edge are a double, we must mark it for removal and we create a new one.*/ - if(e->v1->tflag1 == 2 || e->v2->tflag1 == 2){ - v = v2 = NULL; - /*For each vertex in the edge, test to find out what it should equal now.*/ - if(e->v1->tflag1 == 2) v= BLI_ghash_lookup(vhash,e->v1); - else v = e->v1; - if(e->v2->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,e->v2); - else v2 = e->v2; - - /*small optimization, test to see if the edge needs to be rebuilt at all*/ - if((e->v1 != v) || (e->v2 != v2)){ /*will this always be true of collapsed edges?*/ - if(v == v2) e->tflag1 = 2; /*mark as a collapsed edge*/ - else if(!BME_disk_existedge(v,v2)) ne = BME_ME(bm,v,v2); - BME_VISIT(e); /*mark for delete*/ - } - } - } - - - /* need to remove double edges as well. To do this we decide on one edge to keep, - * and if its inserted into hash then we need to remove all other - * edges incident upon and relink.*/ - /* - * REBUILD FACES - * - * Loop through double faces and if they have vertices that have been flagged, they need to be rebuilt. - * We do this by looking up the face rebuild faces. - * loop through original face, for each loop, if the edge it is attached to is marked for delete and has no - * other edge in the hash edge, then we know to skip that loop on face recreation. Simple. - */ - - /*1st loop through, just marking elements*/ - for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ //insert bit here about double edges, mark with a flag (e->tflag2) so that we can nuke it later. - l = f->loopbase; - do{ - if(l->v->tflag1 == 2) f->tflag1 = 1; //double, mark for rebuild - if(l->e->tflag1 != 2) f->tflag2++; //count number of edges in the new face. - l=l->next; - }while(l!=f->loopbase); - } - - /*now go through and create new faces*/ - for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ - if(f->tflag1 && f->tflag2 < 3) BME_VISIT(f); //mark for delete - else if (f->tflag1 == 1){ /*is the face marked for rebuild*/ - edar = MEM_callocN(sizeof(BMEdge *)*f->tflag2,"Remove doubles face creation array."); - a=0; - l = f->loopbase; - do{ - v = l->v; - v2 = l->next->v; - if(l->v->tflag1 == 2) v = BLI_ghash_lookup(vhash,l->v); - if(l->next->v->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,l->next->v); - ne = BME_disk_existedge(v,v2); //use BME_disk_next_edgeflag here or something to find the edge that is marked as 'target'. - //add in call here to edge doubles hash array... then bobs your uncle. - if(ne){ - edar[a] = ne; - a++; - } - l=l->next; - }while(l!=f->loopbase); - - if(BME_vert_in_edge(edar[1],edar[0]->v2)){ - v = edar[0]->v1; - v2 = edar[0]->v2; - } - else{ - v = edar[0]->v2; - v2 = edar[0]->v1; - } - - nf = BME_MF(bm,v,v2,edar,f->tflag2); - - /*copy per loop data here*/ - if(nf){ - BME_VISIT(f); //mark for delete - } - MEM_freeN(edar); - } - } - - /*count amount of removed vert doubles*/ - a = 0; - for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ - if(v->tflag1 == 2) a++; - } - - /*free memory and return amount removed*/ - remove_tagged_polys(bm); - remove_tagged_edges(bm); - remove_tagged_verts(bm); - BLI_ghash_free(vhash,NULL, NULL); - BME_selectmode_flush(bm); - return a; -} - -static void BME_MeshWalk__collapsefunc(void *userData, BMEdge *applyedge) -{ - int index; - GHash *collected = userData; - index = BLI_ghash_size(collected); - if(!BLI_ghash_lookup(collected,applyedge->v1)){ - BLI_ghash_insert(collected,index,applyedge->v1); - index++; - } - if(!BLI_ghash_lookup(collected,applyedge->v2)){ - BLI_ghash_insert(collected,index,applyedge->v2); - } -} - -void BME_collapse_edges(BME_Mesh *bm) -{ - - BMVert *v, *cvert; - GHash *collected; - float min[3], max[3], cent[3]; - int size, i=0, j, num=0; - - for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){ - if(!(BME_ISVISITED(v)) && v->edge){ - /*initiate hash table*/ - collected = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); - /*do the walking.*/ - BME_MeshWalk(bm,v,BME_MeshWalk__collapsefunc,collected,BME_RESTRICTSELECT); - /*now loop through the hash table twice, once to calculate bounding box, second time to do the actual collapse*/ - size = BLI_ghash_size(collected); - /*initial values*/ - copy_v3_v3(min,v->co); - copy_v3_v3(max,v->co); - cent[0] = cent[1] = cent[2]=0; - for(i=0; ico[0]; - cent[1] = cent[1] + cvert->co[1]; - cent[2] = cent[2] + cvert->co[2]; - } - - cent[0] = cent[0] / size; - cent[1] = cent[1] / size; - cent[2] = cent[2] / size; - - for(i=0; ico,cent); - num++; - } - /*free the hash table*/ - BLI_ghash_free(collected,NULL, NULL); - } - } - /*if any collapsed, call remove doubles*/ - if(num){ - //need to change selection mode here, OR do something else? Or does tool change selection mode? - //selectgrep - //first clear flags - BMEdge *e; - BMFace *f; - BME_clear_flag_all(bm,BME_VISITED); - for(v=BME_first(bm,BME_VERT); v; v=BME_next(bm,BME_VERT,v)) v->tflag1 = v->tflag2 = 0; - for(e=BME_first(bm,BME_EDGE); e; e=BME_next(bm,BME_EDGE,e)) e->tflag1 = e->tflag2 = 0; - for(f=BME_first(bm,BME_POLY); f; f=BME_next(bm,BME_POLY,f)) f->tflag1 = f->tflag2 = 0; - /*now call remove doubles*/ - BME_remove_doubles(bm,0.0000001); - } - BME_selectmode_flush(bm); -} - -#endif diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 9fa69970acd..9d2229b52f4 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -38,18 +38,18 @@ set(INC_SYS ) set(SRC - meshtools.c - loopcut.c - mesh_ops.c - editmesh_bvh.c - editmesh_add.c - bmesh_selecthistory.c bmesh_select.c - bmesh_utils.c - mesh_data.c + bmesh_selecthistory.c bmesh_tools.c - knifetool.c + bmesh_utils.c editface.c + editmesh_add.c + editmesh_bvh.c + knifetool.c + loopcut.c + mesh_data.c + mesh_ops.c + meshtools.c editmesh_bvh.h mesh_intern.h