Modified Files:

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).
This commit is contained in:
2006-02-13 22:49:46 +00:00
parent 9104862f48
commit 1f21e2eea7
8 changed files with 588 additions and 24 deletions

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

View 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

View 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;
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");
event = pupmenu("Merge %t|At Center%x1|At Cursor%x2");
else if(G.scene->selectmode == SCE_SELECT_EDGE)
event = pupmenu("Merge %t|Collapse Edges%x2|At Center%x3|At Cursor%x4");
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));
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)
{

View 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,10 +1611,31 @@ 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++;
for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
@@ -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();
}
}

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

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

View 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

View File

@@ -4093,14 +4093,22 @@ 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;