diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h index 0ff57f8cde7..e47d82043b7 100644 --- a/source/blender/blenlib/BLI_editVert.h +++ b/source/blender/blenlib/BLI_editVert.h @@ -66,7 +66,8 @@ typedef struct EditEdge short f1, f2; /* short, f1 is (ab)used in subdiv */ unsigned char f, h, dir, seam; float crease; - int fast; /* only 0 or 1, for editmesh_fastmalloc */ + short fast; /* only 0 or 1, for editmesh_fastmalloc */ + short fgoni; /* index for fgon, for search */ HashEdge hash; } EditEdge; @@ -80,7 +81,8 @@ typedef struct EditFace struct TFace tf; /* a copy of original tface. */ unsigned char mat_nr, flag; unsigned char f, f1, h, puno; - short fast; /* only 0 or 1, for editmesh_fastmalloc */ + unsigned char fast; /* only 0 or 1, for editmesh_fastmalloc */ + unsigned char fgonf; /* flag for fgon options */ } EditFace; typedef struct EditMesh diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h index fe11e0b684e..632283f9a53 100644 --- a/source/blender/include/BIF_editmesh.h +++ b/source/blender/include/BIF_editmesh.h @@ -43,6 +43,12 @@ struct Mesh; struct bDeformGroup; struct View3D; +// edge and face flag both +#define EM_FGON 2 +// face flag +#define EM_FGON_DRAW 1 + + /* ******************* editmesh.c */ extern void make_editMesh(void); extern void load_editMesh(void); diff --git a/source/blender/include/editmesh.h b/source/blender/include/editmesh.h index bb69b033cb7..927c8d40156 100644 --- a/source/blender/include/editmesh.h +++ b/source/blender/include/editmesh.h @@ -41,6 +41,7 @@ #define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float)); + /* ******************* editmesh.c */ extern void free_editvert(EditVert *eve); extern void free_editedge(EditEdge *eed); @@ -82,6 +83,7 @@ extern float convex(float *v1, float *v2, float *v3, float *v4); /* ******************* editmesh_mods.c */ extern EditEdge *findnearestedge(short *dist); +extern void make_fgon(void); /* ******************* editmesh_tools.c */ diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 426c06366ca..0a186765cae 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -80,6 +80,8 @@ typedef struct MSticky { /* medge->flag (1=SELECT)*/ #define ME_EDGEDRAW 2 #define ME_SEAM 4 +#define ME_FGON 8 + // reserve 16 for ME_HIDE /* puno = vertexnormal (mface) */ #define ME_FLIPV1 1 diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c index bba7864a6cd..ddfef9c6cb0 100644 --- a/source/blender/src/drawobject.c +++ b/source/blender/src/drawobject.c @@ -1153,7 +1153,8 @@ static void draw_vertices(short sel) bglBegin(GL_POINTS); for(efa= em->faces.first; efa; efa= efa->next) { if(efa->h==0) { - if(sel == (efa->f & SELECT)) { + if(efa->fgonf==EM_FGON); + else if(sel == (efa->f & SELECT)) { bglVertex3fv(efa->cent); } } @@ -1183,7 +1184,8 @@ static void draw_vertices(short sel) bglBegin(GL_POINTS); for(efa= em->faces.first; efa; efa= efa->next) { if(efa->h==0) { - if(sel == (efa->f & SELECT)) { + if(efa->fgonf==EM_FGON); + else if(sel == (efa->f & SELECT)) { bglVertex3fv(efa->cent); } } @@ -2521,27 +2523,50 @@ static void drawmeshwire(Object *ob) else if(G.scene->selectmode == SCE_SELECT_FACE) { /* draw faces twice, to have selected ones on top */ BIF_ThemeColor(TH_WIRE); + glBegin(GL_LINES); for(efa= em->faces.first; efa; efa= efa->next) { if(efa->h==0 && (efa->f & SELECT)==0) { - glBegin(GL_LINE_LOOP); - glVertex3fv(efa->v1->co); - glVertex3fv(efa->v2->co); - glVertex3fv(efa->v3->co); - if(efa->v4) glVertex3fv(efa->v4->co); - glEnd(); + if(efa->e1->h==0) { + glVertex3fv(efa->v1->co); + glVertex3fv(efa->v2->co); + } + if(efa->e2->h==0) { + glVertex3fv(efa->v2->co); + glVertex3fv(efa->v3->co); + } + if(efa->e3->h==0) { + glVertex3fv(efa->e3->v1->co); + glVertex3fv(efa->e3->v2->co); + } + if(efa->e4 && efa->e4->h==0) { + glVertex3fv(efa->e4->v1->co); + glVertex3fv(efa->e4->v2->co); + } } } + BIF_ThemeColor(TH_EDGE_SELECT); for(efa= em->faces.first; efa; efa= efa->next) { if(efa->h==0 && (efa->f & SELECT)) { - glBegin(GL_LINE_LOOP); - glVertex3fv(efa->v1->co); - glVertex3fv(efa->v2->co); - glVertex3fv(efa->v3->co); - if(efa->v4) glVertex3fv(efa->v4->co); - glEnd(); + if(efa->e1->h==0) { + glVertex3fv(efa->v1->co); + glVertex3fv(efa->v2->co); + } + if(efa->e2->h==0) { + glVertex3fv(efa->v2->co); + glVertex3fv(efa->v3->co); + } + if(efa->e3->h==0) { + glVertex3fv(efa->e3->v1->co); + glVertex3fv(efa->e3->v2->co); + } + if(efa->e4 && efa->e4->h==0) { + glVertex3fv(efa->e4->v1->co); + glVertex3fv(efa->e4->v2->co); + } } } + glEnd(); } else if( (G.f & G_DRAWEDGES) || (G.scene->selectmode & SCE_SELECT_EDGE) ) { /* Use edge highlighting */ diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c index 18f815ff15e..cc1f675a4bd 100644 --- a/source/blender/src/editmesh.c +++ b/source/blender/src/editmesh.c @@ -246,18 +246,20 @@ EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example) eed= findedgelist(v1, v2); if(eed==NULL) { - + eed= (EditEdge *)callocedge(sizeof(EditEdge), 1); eed->v1= v1; eed->v2= v2; BLI_addtail(&em->edges, eed); eed->dir= swap; insert_hashedge(eed); + /* copy edge data: rule is to do this with addedgelist call, before addfacelist */ if(example) { eed->crease= example->crease; eed->seam = example->seam; + eed->h |= (example->h & EM_FGON); } } @@ -330,12 +332,21 @@ EditFace *addfacelist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, Ed EditEdge *e1, *e2=0, *e3=0, *e4=0; /* add face to list and do the edges */ - e1= addedgelist(v1, v2, NULL); - e2= addedgelist(v2, v3, NULL); - if(v4) e3= addedgelist(v3, v4, NULL); - else e3= addedgelist(v3, v1, NULL); - if(v4) e4= addedgelist(v4, v1, NULL); - + if(example) { + e1= addedgelist(v1, v2, example->e1); + e2= addedgelist(v2, v3, example->e2); + if(v4) e3= addedgelist(v3, v4, example->e3); + else e3= addedgelist(v3, v1, example->e3); + if(v4) e4= addedgelist(v4, v1, example->e4); + } + else { + e1= addedgelist(v1, v2, NULL); + e2= addedgelist(v2, v3, NULL); + if(v4) e3= addedgelist(v3, v4, NULL); + else e3= addedgelist(v3, v1, NULL); + if(v4) e4= addedgelist(v4, v1, NULL); + } + if(v1==v2 || v2==v3 || v1==v3) return NULL; if(e2==0) return NULL; @@ -704,6 +715,8 @@ void make_editMesh() if(medge->flag & ME_SEAM) eed->seam= 1; if(medge->flag & SELECT) eed->f |= SELECT; + if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! + if(medge->flag & ME_HIDE) eed->h |= 1; } } @@ -743,6 +756,7 @@ void make_editMesh() efa->f |= SELECT; if(me->medge==NULL) EM_select_face(efa, 1); } + if(mface->flag & ME_HIDE) efa->h= 1; } if(me->tface) tface++; @@ -750,15 +764,12 @@ void make_editMesh() } } - /* flush hide flags */ - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->h || eed->v2->h) eed->h= 1; - else eed->h= 0; - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e1->h || efa->e2->h || efa->e3->h) efa->h= 1; - else if(efa->e4 && efa->e4->h) efa->h= 1; + /* flush hide flags when no medge */ + if(me->medge==NULL) { + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->v1->h || eed->v2->h) eed->h |= 1; + else eed->h &= ~1; + } } MEM_freeN(evlist); @@ -1009,6 +1020,8 @@ void load_editMesh(void) medge->flag= eed->f & SELECT; if(eed->f2<2) medge->flag |= ME_EDGEDRAW; if(eed->seam) medge->flag |= ME_SEAM; + if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes + if(eed->h & 1) medge->flag |= ME_HIDE; medge->crease= (char)(255.0*eed->crease); @@ -1030,10 +1043,12 @@ void load_editMesh(void) mface->mat_nr= efa->mat_nr; mface->puno= efa->puno; + mface->flag= efa->flag; /* bit 0 of flag is already taken for smooth... */ if(efa->f & 1) mface->flag |= ME_FACE_SEL; else mface->flag &= ~ME_FACE_SEL; + if(efa->h) mface->flag |= ME_HIDE; /* mat_nr in vertex */ if(me->totcol>1) { diff --git a/source/blender/src/editmesh_add.c b/source/blender/src/editmesh_add.c index 2186735ecd3..8421228fb2a 100644 --- a/source/blender/src/editmesh_add.c +++ b/source/blender/src/editmesh_add.c @@ -190,7 +190,11 @@ void addedgeface_mesh(void) makeDispList(G.obedit); return; } - if(amount<2 || amount>4) { + else if(amount > 4) { + //make_fgon(); + return; + } + else if(amount<2) { error("Incorrect number of vertices to make edge/face"); return; } diff --git a/source/blender/src/editmesh_lib.c b/source/blender/src/editmesh_lib.c index 263f860a7b2..3ea520cf571 100644 --- a/source/blender/src/editmesh_lib.c +++ b/source/blender/src/editmesh_lib.c @@ -704,6 +704,8 @@ short extrudeflag_vert(short flag) } eve= nextve; } + // since its vertex select mode now, it also deselects higher order + EM_selectmode_flush(); return 1; } diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c index bcfa7c303c4..7cd35e1421d 100644 --- a/source/blender/src/editmesh_mods.c +++ b/source/blender/src/editmesh_mods.c @@ -396,6 +396,33 @@ static int unified_findnearest(EditVert **eve, EditEdge **eed, EditFace **efa) return (*eve || *eed || *efa); } +void EM_select_face_fgon(EditFace *efa, int val) +{ + EditMesh *em = G.editMesh; + short index=0; + + if(efa->fgonf==0) EM_select_face(efa, val); + else { + if(efa->e1->fgoni) index= efa->e1->fgoni; + if(efa->e2->fgoni) index= efa->e2->fgoni; + if(efa->e3->fgoni) index= efa->e3->fgoni; + if(efa->v4 && efa->e4->fgoni) index= efa->e4->fgoni; + + if(index==0) printf("wrong fgon select\n"); + + // select all ngon faces with index + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->fgonf) { + if(efa->e1->fgoni==index || efa->e2->fgoni==index || + efa->e3->fgoni==index || (efa->e4 && efa->e4->fgoni==index) ) { + EM_select_face(efa, val); + } + } + } + } +} + + /* here actual select happens */ void mouse_mesh(void) { @@ -409,10 +436,10 @@ void mouse_mesh(void) if(efa) { if( (efa->f & SELECT)==0 ) { - EM_select_face(efa, 1); + EM_select_face_fgon(efa, 1); } else if(G.qual & LR_SHIFTKEY) { - EM_select_face(efa, 0); + EM_select_face_fgon(efa, 0); } } else if(eed) { @@ -566,6 +593,204 @@ void selectconnected_mesh(int qual) } +/* results in: + - faces having ->fgonf flag set (also for draw) + - edges having ->fgoni index set (for select) +*/ + +static float editface_area(EditFace *efa) +{ + if(efa->v4) return AreaQ3Dfl(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); + else return AreaT3Dfl(efa->v1->co, efa->v2->co, efa->v3->co); +} + +void fgon_flags() +{ + EditMesh *em = G.editMesh; + EditFace *efa, *efan, *efamax; + EditEdge *eed; + ListBase listb={NULL, NULL}; + float size, maxsize; + short done, curindex= 1; + + // for each face with fgon edge AND not fgon flag set + for(eed= em->edges.first; eed; eed= eed->next) eed->fgoni= 0; // index + for(efa= em->faces.first; efa; efa= efa->next) efa->fgonf= 0; // flag + + // for speed & simplicity, put fgon face candidates in new listbase + efa= em->faces.first; + while(efa) { + efan= efa->next; + if( (efa->e1->h & EM_FGON) || (efa->e2->h & EM_FGON) || + (efa->e3->h & EM_FGON) || (efa->e4 && (efa->e4->h & EM_FGON)) ) { + BLI_remlink(&em->faces, efa); + BLI_addtail(&listb, efa); + } + efa= efan; + } + + // find an undone face with fgon edge + for(efa= listb.first; efa; efa= efa->next) { + if(efa->fgonf==0) { + + // init this face + efa->fgonf= EM_FGON; + if(efa->e1->h & EM_FGON) efa->e1->fgoni= curindex; + if(efa->e2->h & EM_FGON) efa->e2->fgoni= curindex; + if(efa->e3->h & EM_FGON) efa->e3->fgoni= curindex; + if(efa->e4 && (efa->e4->h & EM_FGON)) efa->e4->fgoni= curindex; + + // we search for largest face, to give facedot drawing rights + maxsize= editface_area(efa); + efamax= efa; + + // now flush curendex over edges and set faceflags + done= 1; + while(done==1) { + done= 0; + + for(efan= listb.first; efan; efan= efan->next) { + if(efan->fgonf==0) { + // if one if its edges has index set, do other too + if( (efan->e1->fgoni==curindex) || (efan->e2->fgoni==curindex) || + (efan->e3->fgoni==curindex) || (efan->e4 && (efan->e4->fgoni==curindex)) ) { + + efan->fgonf= EM_FGON; + if(efan->e1->h & EM_FGON) efan->e1->fgoni= curindex; + if(efan->e2->h & EM_FGON) efan->e2->fgoni= curindex; + if(efan->e3->h & EM_FGON) efan->e3->fgoni= curindex; + if(efan->e4 && (efan->e4->h & EM_FGON)) efan->e4->fgoni= curindex; + + size= editface_area(efan); + if(size>maxsize) { + efamax= efan; + maxsize= size; + } + done= 1; + } + } + } + } + + efamax->fgonf |= EM_FGON_DRAW; + curindex++; + + } + } + + // put fgon face candidates back in listbase + efa= listb.first; + while(efa) { + efan= efa->next; + BLI_remlink(&listb, efa); + BLI_addtail(&em->faces, efa); + efa= efan; + } +} + + +/* selected faces get hidden edges */ +void make_fgon(void) +{ + EditMesh *em = G.editMesh; + EditFace *efa; + EditEdge *eed; + EditVert *eve; + float *nor=NULL, dot; // reference + int done=0; + + /* tagging edges. rule is: + - edge used by exactly 2 selected faces + - no vertices allowed with only tagged edges (return) + - face normals should not differ too much + + */ + for(eed= em->edges.first; eed; eed= eed->next) { + eed->f1= 0; // amount of selected + eed->f2= 0; // amount of unselected + } + + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->f & SELECT) { + if(nor==NULL) nor= efa->n; + if(efa->e1->f1 < 3) efa->e1->f1++; + if(efa->e2->f1 < 3) efa->e2->f1++; + if(efa->e3->f1 < 3) efa->e3->f1++; + if(efa->e4 && efa->e4->f1 < 3) efa->e4->f1++; + } + else { + if(efa->e1->f2 < 3) efa->e1->f2++; + if(efa->e2->f2 < 3) efa->e2->f2++; + if(efa->e3->f2 < 3) efa->e3->f2++; + if(efa->e4 && efa->e4->f2 < 3) efa->e4->f2++; + } + } + // now eed->f1 becomes tagged edge + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f1==2 && eed->f2==0) eed->f1= 1; + else eed->f1= 0; + } + + // no vertices allowed with only tagged edges + for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f1) { + eed->v1->f1 |= 1; + eed->v2->f1 |= 1; + } + else { + eed->v1->f1 |= 2; + eed->v2->f1 |= 2; + } + } + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->f1==1) break; + } + if(eve) { + error("Cannot make polygon with interior vertices"); + return; + } + + // check co-planar + if(nor==NULL) { + error("No faces selected to make FGon"); + return; + } + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->f & SELECT) { + dot= nor[0]*efa->n[0]+nor[1]*efa->n[1]+nor[2]*efa->n[2]; + if(dot<0.9 && dot > -0.9) break; + } + } + if(efa) { + error("Not a set of co-planar faces to make FGon"); + return; + } + + // and there we go + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f1) { + eed->h |= EM_FGON; + done= 1; + } + } + + if(done==0) { + error("Didn't find FGon to create"); + } + else { + Mesh *me= G.obedit->data; + // signal to save edges with ngon flags + if(!me->medge) + me->medge= MEM_callocN(sizeof(MEdge), "fake mesh edge"); + + fgon_flags(); // redo flags and indices for fgons + + allqueue(REDRAWVIEW3D, 0); + makeDispList(G.obedit); + BIF_undo_push("Make FGon"); + } +} /* swap is 0 or 1, if 1 it hides not selected */ @@ -591,7 +816,7 @@ void hide_mesh(int swap) for(eed= em->edges.first; eed; eed= eed->next) { if(eed->v1->h || eed->v2->h) { - eed->h= 1; + eed->h |= 1; eed->f &= ~SELECT; } else eed->h= 0; @@ -609,9 +834,7 @@ void hide_mesh(int swap) for(eed= em->edges.first; eed; eed= eed->next) { if((eed->f & SELECT)!=swap) { - eed->h= 1; - eed->v1->h= 1; - eed->v2->h= 1; + eed->h |= 1; EM_select_edge(eed, 0); } } @@ -629,11 +852,6 @@ void hide_mesh(int swap) for(efa= em->faces.first; efa; efa= efa->next) { if((efa->f & SELECT)!=swap) { efa->h= 1; - efa->e1->h= efa->e2->h= efa->e3->h= 1; - if(efa->e4) efa->e4->h= 1; - efa->v1->h= efa->v2->h= efa->v3->h= 1; - if(efa->v4) efa->v4->h= 1; - EM_select_face(efa, 0); } } @@ -663,7 +881,7 @@ void reveal_mesh(void) for(eed= em->edges.first; eed; eed= eed->next) { if(eed->h) { - eed->h= 0; + eed->h &= ~1; eed->f |= SELECT; } } diff --git a/source/blender/src/space.c b/source/blender/src/space.c index aa13f4e9394..e3ffb6483f4 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -637,9 +637,7 @@ void BIF_undo_push(char *str) } void BIF_undo(void) -{ - extern void undo_curve_step(int step); // editcurve.c - +{ if(G.obedit) { if(G.obedit->type==OB_MESH) undo_editmode_step(1); @@ -662,8 +660,6 @@ void BIF_undo(void) void BIF_redo(void) { - extern void undo_curve_step(int step); // editcurve.c - if(G.obedit) { if(G.obedit->type==OB_MESH) undo_editmode_step(-1);