From e1315ef15a4aea5c7bfaffc84c769ada88d70847 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Sun, 28 Aug 2011 17:15:24 +0000 Subject: [PATCH] implement select nth, separate loose parts, and a few bug fixes This code is from Andrew Wiggen (ender79) and reviewed by me. His comments: Implements some tools that were marked TODO: - select nth - separate loose parts And also fixes a few bugs; - extrude and move on normals causes faces to disappear until the move starts - hiding verts/edges/faces does not deselect them - deleting a selection sometimes deletes too much (e.g. a solid cube and a wire cube build of only edges, join them on a single edge, select only the faces of the solid cube and delete, some of the deselected edges from the wire cube were also being deleted) --- source/blender/blenlib/intern/path_util.c | 3 +- source/blender/bmesh/intern/bmesh_marking.c | 5 + .../blender/bmesh/intern/bmesh_walkers_impl.c | 13 +- .../blender/bmesh/operators/bmesh_dupeops.c | 13 +- source/blender/bmesh/operators/mesh_conv.c | 3 +- source/blender/editors/mesh/bmesh_select.c | 547 ++++++++++-------- source/blender/editors/mesh/bmesh_tools.c | 112 +++- 7 files changed, 427 insertions(+), 269 deletions(-) diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index f89283178ec..a67f1c53bd8 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "MEM_guardedalloc.h" @@ -298,7 +299,7 @@ void BLI_uniquename(ListBase *list, void *vlink, const char defname[], char deli void BLI_cleanup_path(const char *relabase, char *dir) { - short a; + ptrdiff_t a; char *start, *eind; if (relabase) { BLI_path_abs(dir, relabase); diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index e0818105429..bb70b47fabd 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -648,6 +648,11 @@ void BM_Hide(BMesh *bm, void *element, int hide) { BMHeader *h = element; + /*Follow convention of always deselecting before + hiding an element*/ + if (hide) + BM_Select(bm, element, 0); + switch (h->type) { case BM_VERT: BM_Hide_Vert(bm, element, hide); diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c index dceaefd1242..90e658c380b 100644 --- a/source/blender/bmesh/intern/bmesh_walkers_impl.c +++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c @@ -231,7 +231,7 @@ static void *islandboundWalker_step(BMWalker *walker) l = bmesh_radial_nextloop(l); f = l->f; e = l->e; - if(!BMO_TestFlag(walker->bm, f, walker->restrictflag)){ + if(walker->restrictflag && !BMO_TestFlag(walker->bm, f, walker->restrictflag)){ l = l->radial_next; break; } @@ -301,7 +301,7 @@ static void *islandWalker_step(BMWalker *walker) for (; l; l=BMIter_Step(&liter)) { f = BMIter_New(&iter, walker->bm, BM_FACES_OF_EDGE, l->e); for (; f; f=BMIter_Step(&iter)) { - if (!BMO_TestFlag(walker->bm, f, walker->restrictflag)) + if (walker->restrictflag && !BMO_TestFlag(walker->bm, f, walker->restrictflag)) continue; if (BLI_ghash_haskey(walker->visithash, f)) continue; @@ -310,7 +310,6 @@ static void *islandWalker_step(BMWalker *walker) iwalk->cur = f; BLI_ghash_insert(walker->visithash, f, NULL); break; - } } @@ -318,13 +317,9 @@ static void *islandWalker_step(BMWalker *walker) } -/* Island Walker: +/* Edge Loop Walker: * - * Starts at a tool flagged-face and walks over the face region - * - * TODO: - * - * Add restriction flag/callback for wire edges. + * Starts at a tool-flagged edge and walks over the edge loop * */ diff --git a/source/blender/bmesh/operators/bmesh_dupeops.c b/source/blender/bmesh/operators/bmesh_dupeops.c index dca43507dc3..c7661269c3c 100644 --- a/source/blender/bmesh/operators/bmesh_dupeops.c +++ b/source/blender/bmesh/operators/bmesh_dupeops.c @@ -516,10 +516,19 @@ static void delete_context(BMesh *bm, int type){ /*now go through and mark all remaining faces all edges for keeping.*/ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){ if(!BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){ - for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e= BMIter_Step(&edges)) + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e= BMIter_Step(&edges)){ BMO_ClearFlag(bm, (BMHeader*)e, DEL_INPUT); - for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v= BMIter_Step(&verts)) + } + for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v= BMIter_Step(&verts)){ BMO_ClearFlag(bm, (BMHeader*)v, DEL_INPUT); + } + } + } + /*also mark all the vertices of remaining edges for keeping.*/ + for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){ + if(!BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)){ + BMO_ClearFlag(bm, (BMHeader*)e->v1, DEL_INPUT); + BMO_ClearFlag(bm, (BMHeader*)e->v2, DEL_INPUT); } } /*now delete marked faces*/ diff --git a/source/blender/bmesh/operators/mesh_conv.c b/source/blender/bmesh/operators/mesh_conv.c index 75d4cb58122..60b8b2770f2 100644 --- a/source/blender/bmesh/operators/mesh_conv.c +++ b/source/blender/bmesh/operators/mesh_conv.c @@ -63,7 +63,6 @@ void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { if (!me || !me->totvert) return; /*sanity check*/ - mvert = me->mvert; vt = MEM_mallocN(sizeof(void**)*me->totvert, "mesh to bmesh vtable"); CustomData_copy(&me->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0); @@ -125,7 +124,7 @@ void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) { CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]); CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]); - for (i=0; itotvert; i++, mvert++) { + for (i=0, mvert = me->mvert; itotvert; i++, mvert++) { v = BM_Make_Vert(bm, keyco&&set_key ? keyco[i] : mvert->co, NULL); normal_short_to_float_v3(v->no, mvert->no); diff --git a/source/blender/editors/mesh/bmesh_select.c b/source/blender/editors/mesh/bmesh_select.c index 8258f9f1a5b..d0e6714399a 100644 --- a/source/blender/editors/mesh/bmesh_select.c +++ b/source/blender/editors/mesh/bmesh_select.c @@ -1646,20 +1646,318 @@ void MESH_OT_select_less(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } +/* not that optimal!, should be nicer with bmesh */ +static void tag_face_edges(BMesh* bm, BMFace *f) +{ + BMLoop *l; + BMIter iter; + + BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) { + BM_SetIndex(l->e, 1); + } +} +static int tag_face_edges_test(BMesh* bm, BMFace *f) +{ + BMLoop *l; + BMIter iter; + + BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) { + if(BM_GetIndex(l->e) != 0) + return 1; + } + + return 0; +} + +static void em_deselect_nth_face(BMEditMesh *em, int nth, BMFace *f_act) +{ + BMFace *f; + BMEdge *e; + BMIter iter; + BMesh *bm = em->bm; + int index; + int ok= 1; + + if(f_act==NULL) { + return; + } + + /* to detect loose edges, we put f2 flag on 1 */ + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + BM_SetIndex(e, 0); + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + BM_SetIndex(f, 0); + } + + BM_SetIndex(f_act, 1); + + while(ok) { + ok = 0; + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + index= BM_GetIndex(f); + if(index==1) { /* initialize */ + tag_face_edges(bm, f); + } + + if (index) + BM_SetIndex(f, index+1); + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + if(BM_GetIndex(f)==0 && tag_face_edges_test(bm, f)) { + BM_SetIndex(f, 1); + ok= 1; /* keep looping */ + } + } + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + index= BM_GetIndex(f); + if(index > 0 && index % nth) { + BM_Select(bm, f, 0); + } + } + + EDBM_select_flush(em, SCE_SELECT_FACE); +} + +/* not that optimal!, should be nicer with bmesh */ +static void tag_edge_verts(BMesh *bm, BMEdge *e) +{ + BM_SetIndex(e->v1, 1); + BM_SetIndex(e->v2, 1); +} +static int tag_edge_verts_test(BMesh *bm, BMEdge *e) +{ + return (BM_GetIndex(e->v1) || BM_GetIndex(e->v2)) ? 1:0; +} + +static void em_deselect_nth_edge(BMEditMesh *em, int nth, BMEdge *e_act) +{ + BMEdge *e; + BMVert *v; + BMIter iter; + BMesh *bm = em->bm; + int index; + int ok= 1; + + if(e_act==NULL) { + return; + } + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, 0); + } + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + BM_SetIndex(e, 0); + } + + BM_SetIndex(e_act, 1); + + while(ok) { + ok = 0; + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + index= BM_GetIndex(e); + if (index==1) { /* initialize */ + tag_edge_verts(bm, e); + } + + if (index) + BM_SetIndex(e, index+1); + } + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (BM_GetIndex(e)==0 && tag_edge_verts_test(bm, e)) { + BM_SetIndex(e, 1); + ok = 1; /* keep looping */ + } + } + } + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + index= BM_GetIndex(e); + if (index > 0 && index % nth) + BM_Select(bm, e, 0); + } + + EDBM_select_flush(em, SCE_SELECT_EDGE); +} + +static void em_deselect_nth_vert(BMEditMesh *em, int nth, BMVert *v_act) +{ + BMEdge *e; + BMVert *v; + BMIter iter; + BMesh *bm = em->bm; + int ok= 1; + + if(v_act==NULL) { + return; + } + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, 0); + } + + BM_SetIndex(v_act, 1); + + while(ok) { + ok = 0; + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + int index = BM_GetIndex(v); + if (index != 0) + BM_SetIndex(v, index+1); + } + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + int indexv1= BM_GetIndex(e->v1); + int indexv2= BM_GetIndex(e->v2); + if (indexv1 == 2 && indexv2 == 0) { + BM_SetIndex(e->v2, 1); + ok = 1; /* keep looping */ + } + else if (indexv2 == 2 && indexv1 == 0) { + BM_SetIndex(e->v1, 1); + ok = 1; /* keep looping */ + } + } + } + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + int index= BM_GetIndex(v); + if(index && index % nth) { + BM_Select(bm, v, 0); + } + } + + EDBM_select_flush(em, SCE_SELECT_VERTEX); +} + +BMFace *EM_get_actFace(BMEditMesh *em, int sloppy) +{ + if (em->bm->act_face) { + return em->bm->act_face; + } else if (sloppy) { + BMIter iter; + BMFace *f= NULL; + BMEditSelection *ese; + + /* Find the latest non-hidden face from the BMEditSelection */ + ese = em->bm->selected.last; + for (; ese; ese=ese->prev){ + if(ese->type == BM_FACE) { + f = (BMFace *)ese->data; + + if (BM_TestHFlag(f, BM_HIDDEN)) f= NULL; + else break; + } + } + /* Last attempt: try to find any selected face */ + if (f==NULL) { + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_TestHFlag(f, BM_SELECT)) + break; + } + } + return f; /* can still be null */ + } + return NULL; +} + +static void deselect_nth_active(BMEditMesh *em, BMVert **v_p, BMEdge **e_p, BMFace **f_p) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + BMIter iter; + BMEditSelection *ese; + + *v_p= NULL; + *e_p= NULL; + *f_p= NULL; + + EDBM_selectmode_flush(em); + ese= (BMEditSelection*)em->bm->selected.last; + + if(ese) { + switch(ese->type) { + case BM_VERT: + *v_p= (BMVert *)ese->data; + return; + case BM_EDGE: + *e_p= (BMEdge *)ese->data; + return; + case BM_FACE: + *f_p= (BMFace *)ese->data; + return; + } + } + + if(em->selectmode & SCE_SELECT_VERTEX) { + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v, BM_SELECT)) { + *v_p = v; + return; + } + } + } + else if(em->selectmode & SCE_SELECT_EDGE) { + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_SELECT)) { + *e_p = e; + return; + } + } + } + else if(em->selectmode & SCE_SELECT_FACE) { + f= EM_get_actFace(em, 1); + if(f) { + *f_p= f; + return; + } + } +} + +static int EM_deselect_nth(BMEditMesh *em, int nth) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + deselect_nth_active(em, &v, &e, &f); + + if(v) { + em_deselect_nth_vert(em, nth, v); + return 1; + } + else if(e) { + em_deselect_nth_edge(em, nth, e); + return 1; + } + else if(f) { + em_deselect_nth_face(em, nth, f); + return 1; + } + + return 0; +} + static int mesh_select_nth_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); -// BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; -// int nth = RNA_int_get(op->ptr, "nth"); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + int nth= RNA_int_get(op->ptr, "nth"); -#if 0 //BMESH_TODO if(EM_deselect_nth(em, nth) == 0) { BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face."); return OPERATOR_CANCELLED; } -#else - BKE_report(op->reports, RPT_ERROR, "Unimplemented"); -#endif DAG_id_tag_update(obedit->data, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); @@ -1685,243 +1983,6 @@ void MESH_OT_select_nth(wmOperatorType *ot) RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX); } -#if 0 //BMESH_TODO, select nth tool -/* not that optimal!, should be nicer with bmesh */ -static void tag_face_edges(EditFace *efa) -{ - if(efa->v4) - efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1; - else - efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1; -} -static int tag_face_edges_test(EditFace *efa) -{ - if(efa->v4) - return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l || efa->e4->tmp.l) ? 1:0; - else - return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l) ? 1:0; -} - -void em_deselect_nth_face(EditMesh *em, int nth, EditFace *efa_act) -{ - EditFace *efa; - EditEdge *eed; - int ok= 1; - - if(efa_act==NULL) { - return; - } - - /* to detect loose edges, we put f2 flag on 1 */ - for(eed= em->edges.first; eed; eed= eed->next) { - eed->tmp.l= 0; - } - - for (efa= em->faces.first; efa; efa= efa->next) { - efa->tmp.l = 0; - } - - efa_act->tmp.l = 1; - - while(ok) { - ok = 0; - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->tmp.l==1) { /* initialize */ - tag_face_edges(efa); - } - - if(efa->tmp.l) - efa->tmp.l++; - } - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->tmp.l==0 && tag_face_edges_test(efa)) { - efa->tmp.l= 1; - ok = 1; /* keep looping */ - } - } - } - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->tmp.l > 0 && efa->tmp.l % nth) { - EM_select_face(efa, 0); - } - } - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - EM_select_face(efa, 1); - } - } - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -/* not that optimal!, should be nicer with bmesh */ -static void tag_edge_verts(EditEdge *eed) -{ - eed->v1->tmp.l= eed->v2->tmp.l= 1; -} -static int tag_edge_verts_test(EditEdge *eed) -{ - return (eed->v1->tmp.l || eed->v2->tmp.l) ? 1:0; -} - -void em_deselect_nth_edge(EditMesh *em, int nth, EditEdge *eed_act) -{ - EditEdge *eed; - EditVert *eve; - int ok= 1; - - if(eed_act==NULL) { - return; - } - - for(eve= em->verts.first; eve; eve= eve->next) { - eve->tmp.l= 0; - } - - for (eed= em->edges.first; eed; eed= eed->next) { - eed->tmp.l = 0; - } - - eed_act->tmp.l = 1; - - while(ok) { - ok = 0; - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->tmp.l==1) { /* initialize */ - tag_edge_verts(eed); - } - - if(eed->tmp.l) - eed->tmp.l++; - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->tmp.l==0 && tag_edge_verts_test(eed)) { - eed->tmp.l= 1; - ok = 1; /* keep looping */ - } - } - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->tmp.l > 0 && eed->tmp.l % nth) { - EM_select_edge(eed, 0); - } - } - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - EM_select_edge(eed, 1); - } - } - - { - /* grr, should be a function */ - EditFace *efa; - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4) { - if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT ); - else efa->f &= ~SELECT; - } - else { - if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT ); - else efa->f &= ~SELECT; - } - } - } - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -void em_deselect_nth_vert(EditMesh *em, int nth, EditVert *eve_act) -{ - EditVert *eve; - EditEdge *eed; - int ok= 1; - - if(eve_act==NULL) { - return; - } - - for (eve= em->verts.first; eve; eve= eve->next) { - eve->tmp.l = 0; - } - - eve_act->tmp.l = 1; - - while(ok) { - ok = 0; - - for (eve= em->verts.first; eve; eve= eve->next) { - if(eve->tmp.l) - eve->tmp.l++; - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->tmp.l==2 && eed->v2->tmp.l==0) { /* initialize */ - eed->v2->tmp.l= 1; - ok = 1; /* keep looping */ - } - else if(eed->v2->tmp.l==2 && eed->v1->tmp.l==0) { /* initialize */ - eed->v1->tmp.l= 1; - ok = 1; /* keep looping */ - } - } - } - - for (eve= em->verts.first; eve; eve= eve->next) { - if(eve->tmp.l > 0 && eve->tmp.l % nth) { - eve->f &= ~SELECT; - } - } - - EM_deselect_flush(em); - - EM_nvertices_selected(em); - // EM_nedges_selected(em); // flush does these - // EM_nfaces_selected(em); // flush does these -} -#endif - -static int EM_deselect_nth(BMEditMesh *em, int nth) -{ -#if 1 /*BMESH_TODO*/ - (void)em; - (void)nth; -#else - EditSelection *ese; - ese = ((EditSelection*)em->selected.last); - if(ese) { - if(ese->type == EDITVERT) { - em_deselect_nth_vert(em, nth, (EditVert*)ese->data); - return 1; - } - - if(ese->type == EDITEDGE) { - em_deselect_nth_edge(em, nth, (EditEdge*)ese->data); - return 1; - } - } - else { - EditFace *efa_act = EM_get_actFace(em, 0); - if(efa_act) { - em_deselect_nth_face(em, nth, efa_act); - return 1; - } - } - - return 0; -#endif - return 1; -} - void em_setup_viewcontext(bContext *C, ViewContext *vc) { view3d_set_viewcontext(C, vc); diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c index 743467905fc..278ca0c5b1a 100644 --- a/source/blender/editors/mesh/bmesh_tools.c +++ b/source/blender/editors/mesh/bmesh_tools.c @@ -692,7 +692,13 @@ static int mesh_extrude_region_exec(bContext *C, wmOperator *op) BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; EDBM_Extrude_Mesh(scene, obedit, em, op, NULL); - + + /*This normally happens when pushing undo but modal operators + like this one don't push undo data until after modal mode is + done.*/ + EDBM_RecalcNormals(em); + BMEdit_RecalcTesselation(em); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); return OPERATOR_FINISHED; @@ -1100,14 +1106,15 @@ static int delete_mesh_exec(bContext *C, wmOperator *op) int type = RNA_enum_get(op->ptr, "type"); if (type != 12) { - delete_mesh(C, obedit, op, type, scene); + if (delete_mesh(C, obedit, op, type, scene) == OPERATOR_CANCELLED) + return OPERATOR_CANCELLED; + EDBM_clear_flag_all(em, BM_SELECT); } else { if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT)) return OPERATOR_CANCELLED; DAG_id_tag_update(obedit->data, OB_RECALC_DATA); } - - + WM_event_add_notifier(C, NC_GEOM|ND_DATA|ND_SELECT, obedit); return OPERATOR_FINISHED; @@ -1594,6 +1601,8 @@ void EDBM_hide_mesh(BMEditMesh *em, int swap) BM_Hide(em->bm, h, 1); } + EDBM_selectmode_flush(em); + /*original hide flushing comment (OUTDATED): hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */ /* - vertex hidden, always means edge is hidden too @@ -1643,7 +1652,12 @@ void EDBM_reveal_mesh(BMEditMesh *em) int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH}; int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE))}; - for (i=0; i<3; i++) { + /*Reveal all hidden elements. Handle the reveal in order of faces, + edges, and finally vertices. This is important because revealing + edges may reveal faces, and revealing verts may reveal edges and + faces. Revealing edges or faces in an earlier pass would keep them + from getting selected in the later passes.*/ + for (i=2; i>=0; i--) { BM_ITER(ele, &iter, em->bm, types[i], NULL) { if (BM_TestHFlag(ele, BM_HIDDEN)) { BM_Hide(em->bm, ele, 0); @@ -3047,7 +3061,7 @@ static int select_axis_exec(bContext *C, wmOperator *op) Object *obedit= CTX_data_edit_object(C); BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; BMEditSelection *ese = em->bm->selected.last; - int axis= RNA_int_get(op->ptr, "axis"); + int axis= RNA_enum_get(op->ptr, "axis"); int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/ if(ese==NULL) @@ -3098,6 +3112,12 @@ void MESH_OT_select_axis(wmOperatorType *ot) {-1, "ALIGNED", 0, "Aligned Axis", ""}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem axis_items_xyz[] = { + {0, "X_AXIS", 0, "X Axis", ""}, + {1, "Y_AXIS", 0, "Y Axis", ""}, + {2, "Z_AXIS", 0, "Z Axis", ""}, + {0, NULL, 0, NULL, NULL}}; + /* identifiers */ ot->name= "Select Axis"; ot->description= "Select all data in the mesh on a single axis."; @@ -3112,7 +3132,7 @@ void MESH_OT_select_axis(wmOperatorType *ot) /* properties */ RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting"); - RNA_def_int(ot->srna, "axis", 0, 0, 2, "Axis", "Select the axis to compare each vertex on", 0, 2); + RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on"); } static int solidify_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) @@ -3515,7 +3535,7 @@ static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmO EDBM_CallOpf(em, wmop, "dupe geom=%hvef dest=%p", BM_SELECT, bmnew); EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_FACES); - + /*clean up any loose edges*/ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { if (BM_TestHFlag(e, BM_HIDDEN)) @@ -3534,7 +3554,7 @@ static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmO if (BM_Vert_EdgeCount(v) != 0) BM_Select(em->bm, v, 0); /*deselect*/ } - + EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_VERTS); BM_Compute_Normals(bmnew); @@ -3552,10 +3572,78 @@ static int mesh_separate_material(Main *UNUSED(bmain), Scene *UNUSED(scene), Bas return 0; } -//BMESH_TODO -static int mesh_separate_loose(Main *UNUSED(bmain), Scene *UNUSED(scene), Base *UNUSED(editbase), wmOperator *UNUSED(wmop)) +static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop) { - return 0; + int i; + BMVert *v; + BMEdge *e; + BMVert *v_seed; + BMWalker walker; + BMIter iter; + int result = 0; + Object *obedit = editbase->object; + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_btmesh; + BMesh *bm = em->bm; + int max_iter = bm->totvert; + + /*Clear all selected vertices*/ + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BM_Select(bm, v, 0); + } + + /*Flush the selection to clear edge/face selections to match + selected vertices*/ + EDBM_select_flush(em, SCE_SELECT_VERTEX); + + /*A "while(true)" loop should work here as each iteration should + select and remove at least one vertex and when all vertices + are selected the loop will break out. But guard against bad + behavior by limiting iterations to the number of vertices in the + original mesh.*/ + for(i=0; iv1, 1); + BM_Select(bm, e->v2, 1); + } + BMW_End(&walker); + + /*Flush the selection to get edge/face selections matching + the vertex selection*/ + EDBM_select_flush(em, SCE_SELECT_VERTEX); + + if (bm->totvert == bm->totvertsel) + { + /*Every vertex selected, nothing to separate, work is done*/ + break; + } + + /*Move selection into a separate object*/ + result |= mesh_separate_selected(bmain, scene, editbase, wmop); + } + + return result; } static int mesh_separate_exec(bContext *C, wmOperator *op)