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)
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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; i<me->totvert; i++, mvert++) {
|
||||
for (i=0, mvert = me->mvert; i<me->totvert; i++, mvert++) {
|
||||
v = BM_Make_Vert(bm, keyco&&set_key ? keyco[i] : mvert->co, NULL);
|
||||
normal_short_to_float_v3(v->no, mvert->no);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; i<max_iter; i++)
|
||||
{
|
||||
/* Get a seed vertex to start the walk */
|
||||
v_seed = NULL;
|
||||
BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
|
||||
v_seed = v;
|
||||
break;
|
||||
}
|
||||
|
||||
/* No vertices available, can't do anything */
|
||||
if (v_seed == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/*Select the seed explicitly, in case it has no edges*/
|
||||
BM_Select(bm, v_seed, 1);
|
||||
|
||||
/*Walk from the single vertex, selecting everything connected
|
||||
to it*/
|
||||
BMW_Init(&walker, bm, BMW_SHELL, 0, 0);
|
||||
e = BMW_Begin(&walker, v_seed);
|
||||
for (; e; e=BMW_Step(&walker)) {
|
||||
BM_Select(bm, e->v1, 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)
|
||||
|
||||
Reference in New Issue
Block a user