Modified Files:
authorGeoffrey Bantle <hairbat@yahoo.com>
Mon, 13 Feb 2006 22:49:46 +0000 (22:49 +0000)
committerGeoffrey Bantle <hairbat@yahoo.com>
Mon, 13 Feb 2006 22:49:46 +0000 (22:49 +0000)
source/blender/blenlib/BLI_editVert.h
  source/blender/include/BIF_editmesh.h
  source/blender/src/edit.c source/blender/src/editmesh.c
  source/blender/src/editmesh_lib.c
  source/blender/src/editmesh_mods.c
  source/blender/src/editmesh_tools.c
  source/blender/src/header_view3d.c
Log:
Commit of the 'upgraded merge tools' (Patch #3345) and 'inclusive selection mode conversion' (Patch #3768).

source/blender/blenlib/BLI_editVert.h
source/blender/include/BIF_editmesh.h
source/blender/src/edit.c
source/blender/src/editmesh.c
source/blender/src/editmesh_lib.c
source/blender/src/editmesh_mods.c
source/blender/src/editmesh_tools.c
source/blender/src/header_view3d.c

index 315498bab4c7ea1062b41a8e22f2c4709e8ba731..57fe08e5305f1651712224f8470fae8f678640d8 100644 (file)
@@ -130,6 +130,9 @@ typedef struct EditMesh
        EditEdge *alledges, *curedge;
        EditFace *allfaces, *curface;
        
+       /*for improved merge code*/
+       EditVert *lastvert, *firstvert;
+       
                /* DerivedMesh caches... note that derived cage can be equivalent
                 * to derived final, care should be taken on release.
                 */
index b1620ec58a6d1b461963e9cf95b159cabb48beb1..8c5fa1660cef338ad874b913bb6364f8d2ce6850 100644 (file)
@@ -202,5 +202,9 @@ int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed);
 void shape_copy_select_from(void);
 void shape_propagate(void);
 
+int collapseEdges(void);
+int collapseFaces(void);
+int merge_firstlast(int first);
+
 #endif
 
index 355aee6e6c9f7569f0c72aefc1fa33a7cd3e9e88..6ee71832651d1e7b15e9e83768529dc6beeba64e 100644 (file)
@@ -66,6 +66,7 @@
 #include "BLI_blenlib.h"
 #include "BLI_arithb.h"
 #include "BLI_editVert.h"
+#include "BLI_linklist.h"
 
 #include "BKE_action.h"
 #include "BKE_armature.h"
@@ -600,6 +601,17 @@ void countall()
                                G.totface++;
                                if(efa->f & SELECT) G.totfacesel++;
                        }
+                       
+                       /*for keeping track of last & first vertex selected*/
+                       /*lastvert and first must be cleared in two circumstances.....*/
+                       // 1: if last/first vert exists but is NOT selected, get rid of it.
+                       // 2: if totvertsel = 0, get rid of last/first vert
+                       
+                       if((G.editMesh->lastvert) && ( !(G.editMesh->lastvert->f&SELECT) )) G.editMesh->lastvert = NULL;
+                       else if(G.totvertsel == 0) G.editMesh->lastvert = NULL;
+                       
+                       if((G.editMesh->firstvert) && ( !(G.editMesh->firstvert->f&SELECT) )) G.editMesh->firstvert = NULL;
+                       else if(G.totvertsel == 0) G.editMesh->firstvert = NULL;
                }
                else if (G.obedit->type==OB_ARMATURE){
                        for (ebo=G.edbo.first;ebo;ebo=ebo->next){
@@ -1552,25 +1564,61 @@ void snapmenu()
 }
 
 
+#define MERGELIMIT 0.001
 void mergemenu(void)
-{
-       short event;
-
-       event = pupmenu("Merge %t|At Center%x1|At Cursor%x2");
-
-       if (event==-1) return; /* Return if the menu is closed without any choices */
-
-       if (event==1) 
-               snap_to_center(); /*Merge at Center*/
-       else
-               snap_sel_to_curs(); /*Merge at Cursor*/
+{      
 
-       notice("Removed %d Vertices", removedoublesflag(1, G.scene->toolsettings->doublimit));
+       short event;
+       int remCount;
+       if(G.scene->selectmode == SCE_SELECT_VERTEX)
+               if(G.editMesh->firstvert && G.editMesh->lastvert) event = pupmenu("Merge %t|At First %x6|At Last%x1|At Center%x3|At Cursor%x4");
+               else if (G.editMesh->firstvert) event = pupmenu("Merge %t|At First %x6|At Center%x3|At Cursor%x4");
+               else if (G.editMesh->lastvert) event = pupmenu("Merge %t|At Last %x1|At Center%x3|At Cursor%x4");
+               else event = pupmenu("Merge %t|At Center%x3|At Cursor%x4");
+               
+       else if(G.scene->selectmode == SCE_SELECT_EDGE)
+               event = pupmenu("Merge %t|Collapse Edges%x2|At Center%x3|At Cursor%x4");
+               
+       else if(G.scene->selectmode == SCE_SELECT_FACE)
+               event = pupmenu("Merge %t|Collapse Faces%x5|At Center%x3|At Cursor%x4");
+       else event = pupmenu("Merge %t|At Center%x3|At Cursor%x4");
+       switch (event)
+       {
+               case -1:
+                       return;
+               case 3:
+                       snap_to_center();
+                       remCount = removedoublesflag(1,MERGELIMIT);
+                       BIF_undo_push("Merge at center");
+                       break;
+               case 4:
+                       snap_sel_to_curs();
+                       remCount = removedoublesflag(1,MERGELIMIT);
+                       BIF_undo_push("Merge at cursor");
+                       break;
+               case 1:
+                       remCount = merge_firstlast(0);
+                       BIF_undo_push("Merge at last selected");
+                       break;
+               case 6:
+                       remCount = merge_firstlast(1);
+                       BIF_undo_push("Merge at first selected");
+                       break;
+               case 2:
+                       remCount = collapseEdges();
+                       BIF_undo_push("Collapse Edges");
+                       break;
+               case 5:
+                       remCount = collapseFaces();
+                       BIF_undo_push("Collapse Faces");
+                       break;
+       }
+       notice("Removed %d Vertices", remCount);
        allqueue(REDRAWVIEW3D, 0);
        countall();
-       BIF_undo_push("Merge"); /* push the mesh down the undo pipe */
-
 }
+#undef MERGELIMIT
+
 
 void delete_context_selected(void) 
 {
index e54bb0c156dfe21c8b8b0e667277abb9dd5a3d66..fefec0b460d66405d1f6b8f4c8609e5615c6aa56 100644 (file)
@@ -1575,6 +1575,8 @@ typedef struct UndoMesh {
        EditFaceC *faces;
        TFace *tfaces;
        int totvert, totedge, totface;
+       int lastvert, firstvert; /*index for last and first selected vert. -1 if no first/last vert exists (nasty)*/
+       short selectmode;
 } UndoMesh;
 
 
@@ -1609,9 +1611,30 @@ static void *editMesh_to_undoMesh(void)
        EditEdgeC *eedc=NULL;
        EditFaceC *efac=NULL;
        TFace *tface= NULL;
-       int a=0;
+       int i, a=0;
        
        um= MEM_callocN(sizeof(UndoMesh), "undomesh");
+       
+       um->selectmode = G.scene->selectmode;
+       um->lastvert = -1;
+       um->firstvert = -1;
+       
+       if(em->lastvert){
+               for (i=0,eve=G.editMesh->verts.first; eve; i++,eve=eve->next){
+                       if(eve == em->lastvert){
+                               um->lastvert = i;
+                               break;
+                       }
+               }
+       }
+       if(em->firstvert){
+               for (i=0,eve=G.editMesh->verts.first; eve; i++,eve=eve->next){
+                       if(eve == em->firstvert){
+                               um->firstvert = i;
+                               break;
+                       }
+               }
+       }
 
        for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
        for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
@@ -1678,7 +1701,7 @@ static void *editMesh_to_undoMesh(void)
 
 static void undoMesh_to_editMesh(void *umv)
 {
-       UndoMesh *um= umv;
+       UndoMesh *um= (UndoMesh*)umv;
        EditMesh *em= G.editMesh;
        EditVert *eve, **evar=NULL;
        EditEdge *eed;
@@ -1689,11 +1712,15 @@ static void undoMesh_to_editMesh(void *umv)
        TFace *tface;
        int a=0;
        
+       G.scene->selectmode = um->selectmode;
+       
        free_editMesh(G.editMesh);
        
        /* malloc blocks */
        memset(em, 0, sizeof(EditMesh));
 
+       
+               
        init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
 
        /* now copy vertices */
@@ -1743,6 +1770,22 @@ static void undoMesh_to_editMesh(void *umv)
        
        end_editmesh_fastmalloc();
        if(evar) MEM_freeN(evar);
+       
+       /*restore last and first selected vertex pointers*/
+       
+       G.totvert = um->totvert; 
+       if(um->lastvert != -1 || um-> firstvert != -1){ 
+
+               EM_init_index_arrays(1,0,0);
+               if(um->lastvert != -1) em->lastvert = EM_get_vert_for_index(um->lastvert);
+               else em->lastvert = NULL;
+               
+               if(um->firstvert != -1) em->firstvert = EM_get_vert_for_index(um->firstvert);
+               else em->firstvert = NULL;
+               
+               EM_free_index_arrays();
+       }
+
 }
 
 
index fecd6efeccea352c0fe4c80552227293368dd4a3..8c57120021b779fc6cb87a64b47f71e25a74b217 100644 (file)
@@ -392,6 +392,70 @@ void EM_selectmode_flush(void)
 
 }
 
+void EM_convertsel(short oldmode, short selectmode)
+{
+       EditMesh *em = G.editMesh;
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       /*clear flags*/
+       for(eve= em->verts.first; eve; eve= eve->next) eve->f1 = 0;
+       for(eed= em->edges.first; eed; eed= eed->next) eed->f1 = 0;
+       for(efa= em->faces.first; efa; efa= efa->next) efa->f1 = 0;
+       
+       /*have to find out what the selectionmode was previously*/
+       if(oldmode == SCE_SELECT_VERTEX) {
+               if(selectmode == SCE_SELECT_EDGE){
+                       /*select all edges associated with every selected vertex*/
+                       for(eed= em->edges.first; eed; eed= eed->next){
+                                       if(eed->v1->f&SELECT) eed->f1 = 1;
+                                       else if(eed->v2->f&SELECT) eed->f1 = 1;
+                               }
+               
+                       for(eed= em->edges.first; eed; eed= eed->next){
+                                       if(eed->f1 == 1) EM_select_edge(eed,1); 
+                               }
+                       }               
+               else if(selectmode == SCE_SELECT_FACE){
+                       /*select all faces associated with every selected vertex*/
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                                       if(efa->v1->f&SELECT) efa->f1 = 1;
+                                       else if(efa->v2->f&SELECT) efa->f1 = 1;
+                                       else if(efa->v3->f&SELECT) efa->f1 = 1;
+                                       else{ 
+                                               if(efa->v4){
+                                                       if(efa->v4->f&SELECT) efa->f1 =1;
+                                               }
+                                       }
+                                               
+                               }
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                               if(efa->f1 == 1) EM_select_face(efa,1);
+                               }
+                       check_fgons_selection();
+                       countall();
+               }
+       }
+       
+       if(oldmode == SCE_SELECT_EDGE){
+               if(selectmode == SCE_SELECT_FACE){
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                                       if(efa->e1->f&SELECT) efa->f1 = 1;
+                                       else if(efa->e2->f&SELECT) efa->f1 = 1;
+                                       else if(efa->e3->f&SELECT) efa->f1 = 1;
+                                       else if(efa->e4){
+                                               if(efa->e4->f&SELECT) efa->f1 = 1;
+                                       }
+                               }
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                                       if(efa->f1 == 1) EM_select_face(efa,1);
+                               }
+                       check_fgons_selection();
+                       countall();
+                       }
+       }
+}
+
 /* when switching select mode, makes sure selection is consistant for editing */
 /* also for paranoia checks to make sure edge or face mode works */
 void EM_selectmode_set(void)
@@ -424,6 +488,7 @@ void EM_selectmode_set(void)
                for(efa= em->faces.first; efa; efa= efa->next) 
                        if(efa->f & SELECT) EM_select_face(efa, 1);
        }
+       BIF_undo_push("Selectmode Set");
 }
 
 /* paranoia check, actually only for entering editmode. rule:
index aa3353046a8b39eabcf3f754536ba8bbd94f5005..7179543c69530d81a0114f890f48c39b9f814b3e 100644 (file)
@@ -1052,7 +1052,11 @@ void mouse_mesh(void)
                        }
                }
                else if(eve) {
-                       if((eve->f & SELECT)==0) eve->f |= SELECT;
+                       if((eve->f & SELECT)==0) {
+                               eve->f |= SELECT;
+                               if((G.qual & LR_SHIFTKEY)==0) G.editMesh->firstvert = eve;
+                               else G.editMesh->lastvert = eve;
+                       }
                        else if(G.qual & LR_SHIFTKEY) eve->f &= ~SELECT;
                }
                
@@ -1937,10 +1941,20 @@ void EM_selectmode_menu(void)
        else pupmenu_set_active(3);
        
        val= pupmenu("Select Mode%t|Vertices|Edges|Faces");
+       
+       
        if(val>0) {
                if(val==1) G.scene->selectmode= SCE_SELECT_VERTEX;
-               else if(val==2) G.scene->selectmode= SCE_SELECT_EDGE;
-               else G.scene->selectmode= SCE_SELECT_FACE;
+                       
+               else if(val==2){
+                       if((G.qual==LR_CTRLKEY)) EM_convertsel(G.scene->selectmode, SCE_SELECT_EDGE);
+                       G.scene->selectmode= SCE_SELECT_EDGE;
+               }
+               
+               else{
+                if((G.qual==LR_CTRLKEY)) EM_convertsel(G.scene->selectmode, SCE_SELECT_FACE);
+                G.scene->selectmode= SCE_SELECT_FACE;
+               }
        
                EM_selectmode_set(); // when mode changes
                allqueue(REDRAWVIEW3D, 1);
index c244f1d249cc692dc7da7a89d8456a71d83ba496..3bc528e7702742a8f4bc3ab901e5d067ea624c81 100644 (file)
@@ -5565,4 +5565,383 @@ void shape_copy_select_from()
        return;
 }
 
+/* Collection Routines|Currently used by the improved merge code*/
+/* both buildEdge_collection() and buildFace_collection() create a series of lists*/
+/* these lists are filled with edges or faces that are topologically connected.*/
+
+#define MERGELIMIT 0.001
+
+LinkNode *build_edgecollection(LinkNode *allCollections)
+{
+       EditEdge *eed;
+       
+       LinkNode *edgeCollection, *currEdge;
+       
+       edgeCollection = NULL;
+       currEdge = NULL;
+       allCollections = NULL;
+       
+       int currTag, lowtag;
+       
+       short ebalanced = 0;
+       short listfound;
+       
+       currTag = 1;
+       
+       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;
+       }
+       
+       /*build our list of lists - Needs to be in a seperate function, identical to build_facecollection()!*/
+       for(eed=G.editMesh->edges.first; eed; eed=eed->next)
+       {
+               if(eed->f&SELECT)
+               {
+                       if(allCollections) /*allCollections is NOT NULL*/
+                       {
+                               for(edgeCollection = allCollections; edgeCollection; edgeCollection=edgeCollection->next)
+                               {
+                                       currEdge = edgeCollection->link;
+                                       if(((EditEdge*)currEdge->link)->tmp.l == eed->tmp.l)
+                                       {
+                                               BLI_linklist_append(&currEdge,eed);     
+                                               listfound = 1;
+                                               break;
+                                       }
+                                       else listfound = 0;
+                               }
+                               
+                               if(!listfound) 
+                               {
+                                       /*add a new faceCollection to the Collections list*/
+                                       edgeCollection = NULL;
+                                       BLI_linklist_prepend(&edgeCollection, eed);
+                                       BLI_linklist_append(allCollections, edgeCollection);
+                               
+                               }
+                       }
+                       else /*allCollections is a 'zero length list'*/
+                       {
+                               edgeCollection = NULL;
+                               BLI_linklist_prepend(&edgeCollection, eed);
+                               BLI_linklist_prepend(&allCollections, edgeCollection); /*this actually looks like it is correct*/
+                       }
+                       }
+               }
+       return allCollections;
+       
+}
+
+LinkNode *build_facecollection(LinkNode *allCollections) /*Builds a collection of lists of connected faces from the currently selected set*/
+{
+       EditFace *efa;
+       
+       LinkNode *faceCollection, *currFace;
+       
+       faceCollection = NULL;
+       currFace = NULL;
+       allCollections = NULL;
+       
+       int currTag, lowtag;
+       short listfound,aCount;
+       int tagArray[3];        /*used to pull the tags out of faces vertices. an entry of -1 means no vertex exists....*/
+       currTag = 1;            /*don't start with zero since f1 is cleared to that in editvert and editface structs already*/
+
+       for (efa=G.editMesh->faces.first; efa; efa=efa->next){
+       
+               efa->tmp.l = 0;
+               efa->v1->tmp.l = 0;
+               efa->v2->tmp.l = 0;
+               efa->v3->tmp.l = 0;
+               if(efa->v4) efa->v4->tmp.l = 0; 
+
+       }
+       
+       /*1st pass*/
+       for (efa=G.editMesh->faces.first; efa; efa=efa->next)
+       {
+               
+               if(efa->f&SELECT)
+               {       /*face has no vertices that have been visited before since all the f1 tags are zero*/
+                       if((efa->v1->tmp.l + efa->v2->tmp.l + efa->v3->tmp.l + ((efa->v4) ? efa->v4->tmp.l : 0)) == 0)
+                       { 
+                               efa->v1->tmp.l = currTag;
+                               efa->v2->tmp.l = currTag;
+                               efa->v3->tmp.l = currTag;
+                               if(efa->v4) efa->v4->tmp.l = currTag; 
+                       }
+                       else
+                       {       /*the face has some vert tagged allready as a result of another face that it shares verts with being already visited*/
+                               lowtag = currTag+1; /* plus one? why? this makes little sense!*/
+                               
+                               /*test to find the lowest tag....*/
+                               if(efa->v1->tmp.l < lowtag && efa->v1->tmp.l != 0 && efa->v1->tmp.l != -1) lowtag = efa->v1->tmp.l;
+                               if(efa->v2->tmp.l < lowtag && efa->v2->tmp.l != 0 && efa->v2->tmp.l != -1) lowtag = efa->v2->tmp.l;
+                               if(efa->v3->tmp.l < lowtag && efa->v3->tmp.l != 0 && efa->v3->tmp.l != -1) lowtag = efa->v3->tmp.l;
+                               
+                               if(efa->v4){
+                               if(efa->v4->tmp.l < lowtag && efa->v4->tmp.l != 0 && efa->v4->tmp.l != -1) lowtag = efa->v4->tmp.l;
+                               }
+                               
+                       /*set all vertices to lowest tag*/
+                               efa->v1->tmp.l = lowtag;
+                               efa->v2->tmp.l = lowtag;
+                               efa->v3->tmp.l = lowtag;
+                               if(efa->v4) efa->v4->tmp.l = lowtag;                    
+                       }
+                       currTag += 1;
+               }
+       }
+       
+       /*2nd pass - Nessecary because of faces connected only by a single vertex*/
+       
+       for (efa=G.editMesh->faces.first; efa; efa=efa->next)
+       {
+               
+               lowtag = currTag+1; /*plus one? why? this makes little sense!*/
+               if(efa->f&SELECT)
+               {
+                       tagArray[0] =  efa->v1->tmp.l;
+                       tagArray[1] =  efa->v2->tmp.l;
+                       tagArray[2] =  efa->v3->tmp.l;
+                       tagArray[3] = (efa->v4) ? efa->v4->tmp.l : -1; /*could be a triangle, have to test*/
+                       
+                       if(efa->v1->tmp.l < lowtag && efa->v1->tmp.l != 0 && efa->v1->tmp.l != -1) lowtag = efa->v1->tmp.l;
+                       if(efa->v2->tmp.l < lowtag && efa->v2->tmp.l != 0 && efa->v2->tmp.l != -1) lowtag = efa->v2->tmp.l;
+                       if(efa->v3->tmp.l < lowtag && efa->v3->tmp.l != 0 && efa->v3->tmp.l != -1) lowtag = efa->v3->tmp.l;
+                               
+                       if(efa->v4){
+                       if(efa->v4->tmp.l < lowtag && efa->v4->tmp.l != 0 && efa->v4->tmp.l != -1) lowtag = efa->v4->tmp.l;
+                       }
+                       
+                                               
+                       efa->tmp.l = lowtag; /*actually tag the face now with lowtag*/
+               }
+       }
+
+       /*build our list of lists*/
+       for(efa=G.editMesh->faces.first; efa; efa=efa->next)
+       {
+               if(efa->f&SELECT)
+               {
+                       if(allCollections) /*allCollections is NOT NULL*/
+                       {
+                               for(faceCollection = allCollections; faceCollection; faceCollection=faceCollection->next)
+                               {
+                                       currFace = faceCollection->link;
+                                       if(((EditFace*)currFace->link)->tmp.l == efa->tmp.l) /*put efa into this list.........*/
+                                       {
+                                               BLI_linklist_append(&currFace,efa);     
+                                               listfound = 1;
+                                               break;
+                                       }
+                                       else listfound = 0;
+                               }
+                               
+                               if(!listfound) 
+                               {
+                                       /*add a new faceCollection to the Collections list*/
+                                       faceCollection = NULL;
+                                       BLI_linklist_prepend(&faceCollection, efa);
+                                       BLI_linklist_append(allCollections, faceCollection);
+                               
+                               }
+                       }
+                       else /*allCollections is a 'zero length list'*/
+                       {
+                               faceCollection = NULL;
+                               BLI_linklist_prepend(&faceCollection, efa);
+                               BLI_linklist_prepend(&allCollections, faceCollection); /*this actually looks like it is correct*/
+                       }
+                       }
+               }
+       return allCollections;
+       }
+
+void freeCollections(LinkNode *allCollections)
+{
+       LinkNode *Collection;
+       Collection = NULL;
+       
+       for(Collection = allCollections; Collection; Collection = Collection->next)
+       {
+               BLI_linklist_free((LinkNode*)Collection->link,NULL);
+       }
+       
+       BLI_linklist_free(allCollections,NULL);
+}
+
+int collapseEdges(void)
+{
+       LinkNode *allCollections, *edgeCollection, *currEdge;
+       
+       int totEdges, groupCount, mergecount,vCount;
+       float avgCount[3];
+       
+       mergecount = 0;
+       
+       allCollections = build_edgecollection(allCollections);
+       groupCount = BLI_linklist_length(allCollections);
+       
+       
+       for(edgeCollection = allCollections; edgeCollection; edgeCollection = edgeCollection->next)
+       {
+               totEdges = BLI_linklist_length(edgeCollection->link);
+               mergecount += totEdges;
+               avgCount[0] = 0; avgCount[1] = 0; avgCount[2] = 0;
+               vCount = 0;
+               
+               for(currEdge = edgeCollection->link; currEdge; currEdge = currEdge->next)
+               {
+                       avgCount[0] += ((EditEdge*)currEdge->link)->v1->co[0];
+                       avgCount[1] += ((EditEdge*)currEdge->link)->v1->co[1];
+                       avgCount[2] += ((EditEdge*)currEdge->link)->v1->co[2];
+                       
+                       avgCount[0] += ((EditEdge*)currEdge->link)->v2->co[0];
+                       avgCount[1] += ((EditEdge*)currEdge->link)->v2->co[1];
+                       avgCount[2] += ((EditEdge*)currEdge->link)->v2->co[2];
+                       
+                       vCount +=2;
+               }
+               
+               avgCount[0] /= vCount; avgCount[1] /=vCount; avgCount[2] /= vCount;
+               
+               for(currEdge = edgeCollection->link; currEdge; currEdge = currEdge->next)
+               {
+                       VECCOPY(((EditEdge*)currEdge->link)->v1->co,avgCount);
+                       VECCOPY(((EditEdge*)currEdge->link)->v2->co,avgCount);
+               }
+       }
+       freeCollections(allCollections);
+       removedoublesflag(1, MERGELIMIT);
+       /*get rid of this!*/
+       countall();
+       return mergecount;
+
+       
+}
+
+int collapseFaces(void)
+{
+       LinkNode *allCollections, *faceCollection, *currFace;
+       
+       int groupCount;
+       int vCount,totFaces,mergecount;
+       float avgCount[3];
+       
+       mergecount = 0;
+       allCollections = build_facecollection(allCollections);
+       groupCount = BLI_linklist_length(allCollections);
+
+       for(faceCollection = allCollections; faceCollection; faceCollection = faceCollection->next)
+       {
+               totFaces = BLI_linklist_length(faceCollection->link);
+               mergecount += totFaces;
+               avgCount[0] = 0; avgCount[1] = 0; avgCount[2] = 0;
+               vCount = 0;
+               for(currFace = faceCollection->link; currFace; currFace = currFace->next)
+               {
+                       avgCount[0] += ((EditFace*)currFace->link)->v1->co[0];
+                       avgCount[1] += ((EditFace*)currFace->link)->v1->co[1];
+                       avgCount[2] += ((EditFace*)currFace->link)->v1->co[2];
+                       
+                       avgCount[0] += ((EditFace*)currFace->link)->v2->co[0];
+                       avgCount[1] += ((EditFace*)currFace->link)->v2->co[1];
+                       avgCount[2] += ((EditFace*)currFace->link)->v2->co[2];
+                       
+                       avgCount[0] += ((EditFace*)currFace->link)->v3->co[0];
+                       avgCount[1] += ((EditFace*)currFace->link)->v3->co[1];
+                       avgCount[2] += ((EditFace*)currFace->link)->v3->co[2];
+                       
+                       vCount+= 3;
+                       
+                       if(((EditFace*)currFace->link)->v4)
+                       {
+                               avgCount[0] += ((EditFace*)currFace->link)->v3->co[0];
+                               avgCount[1] += ((EditFace*)currFace->link)->v3->co[1];
+                               avgCount[2] += ((EditFace*)currFace->link)->v3->co[2];
+                               vCount+=1;
+                       }
+                       
+               }
+               
+               avgCount[0] /= vCount; avgCount[1] /=vCount; avgCount[2] /= vCount;
+               
+               for(currFace = faceCollection->link; currFace; currFace = currFace->next)
+               {
+                       VECCOPY(((EditFace*)currFace->link)->v1->co,avgCount);
+                       VECCOPY(((EditFace*)currFace->link)->v2->co,avgCount);
+                       VECCOPY(((EditFace*)currFace->link)->v3->co,avgCount);
+                       if(((EditFace*)currFace->link)->v4) VECCOPY(((EditFace*)currFace->link)->v4->co, avgCount);
+               }
+       }
+       freeCollections(allCollections);
+       removedoublesflag(1, MERGELIMIT);
+       /*get rid of this!*/
+       countall();
+       return mergecount;
+}
+
+int merge_firstlast(int first)
+{
+       EditVert *ev,*mergevert;
+       
+       if(first == 0) mergevert=G.editMesh->lastvert;
+       else mergevert=G.editMesh->firstvert;
+       
+       if(mergevert->f&SELECT){
+       for (ev=G.editMesh->verts.first; ev; ev=ev->next)
+       {
+               if (ev->f&SELECT)
+                       VECCOPY(ev->co,mergevert->co);
+                       }
+       }
+       
+       countall();
+
+return removedoublesflag(1,MERGELIMIT);
+}
+#undef MERGELIMIT
+
+
 
index a1120e9ed5d8dec1a4eeadc13a5029cb4414ea06..03788e848f7b3bb7957087e575beaa92cbd00464 100644 (file)
@@ -4093,17 +4093,25 @@ void do_view3d_buttons(short event)
                allqueue(REDRAWVIEW3D, 1);
                break;
        case B_SEL_EDGE:
-               if( (G.qual & LR_SHIFTKEY)==0 || G.scene->selectmode==0)
-                       G.scene->selectmode= SCE_SELECT_EDGE;
+               if( (G.qual & LR_SHIFTKEY)==0 || G.scene->selectmode==0){
+                       if( (G.scene->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX){
+                               if(G.qual==LR_CTRLKEY) EM_convertsel(SCE_SELECT_VERTEX,SCE_SELECT_EDGE); 
+                               }
+                       G.scene->selectmode = SCE_SELECT_EDGE;
+               }
                EM_selectmode_set();
                allqueue(REDRAWVIEW3D, 1);
                break;
        case B_SEL_FACE:
-               if( (G.qual & LR_SHIFTKEY)==0 || G.scene->selectmode==0)
-                       G.scene->selectmode= SCE_SELECT_FACE;
+               if( (G.qual & LR_SHIFTKEY)==0 || G.scene->selectmode==0){
+                       if( ((G.scene->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((G.scene->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){
+                               if(G.qual==LR_CTRLKEY) EM_convertsel((G.scene->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE);
+                               }
+                       G.scene->selectmode = SCE_SELECT_FACE;
+               }
                EM_selectmode_set();
                allqueue(REDRAWVIEW3D, 1);
-               break;
+               break;  
        
        case B_MAN_TRANS:
                if( (G.qual & LR_SHIFTKEY)==0 || G.vd->twtype==0)