select more/less properly uses bmops now, and also made a little start on documenting the bmops.

This commit is contained in:
2009-08-06 05:06:55 +00:00
parent c73712675b
commit 88b43b52b1
7 changed files with 290 additions and 190 deletions

View File

@@ -344,18 +344,15 @@ BMVert *BM_Split_Edge(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percen
v2 = bmesh_edge_getothervert(e,v);
nv = bmesh_semv(bm,v,e,ne);
if (nv == NULL) return NULL;
VECSUB(nv->co,v2->co,v->co);
VECADDFAC(nv->co,v->co,nv->co,percent);
if (ne) {
if(bmesh_test_sysflag(&(e->head), BM_SELECT)) {
bmesh_set_sysflag((BMHeader*)*ne, BM_SELECT);
bmesh_set_sysflag((BMHeader*)nv, BM_SELECT);
}
if(bmesh_test_sysflag(&(e->head), BM_HIDDEN)) {
bmesh_set_sysflag((BMHeader*)*ne, BM_HIDDEN);
bmesh_set_sysflag((BMHeader*)nv, BM_HIDDEN);
}
(*ne)->head.flag = e->head.flag;
BM_Copy_Attributes(bm, bm, e, *ne);
}
/*v->nv->v2*/
BM_Data_Facevert_Edgeinterp(bm,v2, v, nv, e, percent);
BM_Data_Interp_From_Verts(bm, v2, v, nv, percent);

View File

@@ -2,11 +2,99 @@
#include "bmesh_private.h"
#include <stdio.h>
/*do not rename any operator or slot names! otherwise you must go
through the code and find all references to them!*/
/*
This file defines (and documents) all bmesh operators (bmops).
Do not rename any operator or slot names! otherwise you must go
through the code and find all references to them!
A word on slot names:
For geometry input slots, the following are valid names:
* verts
* edges
* faces
* edgefacein
* vertfacein
* vertedgein
* vertfacein
* geom
The basic rules are, for single-type geometry slots, use the plural of the
type name (e.g. edges). for double-type slots, use the two type names plus
"in" (e.g. edgefacein). for three-type slots, use geom.
for output slots, for single-type geometry slots, use the type name plus "out",
(e.g. vertout), for double-type slots, use the two type names plus "out",
(e.g. vertfaceout), for three-type slots, use geom. note that you can also
use more esohteric names (e.g. skirtout) do long as the comment next to the
slot definition tells you what types of elements are in it.
*/
/*
ok, I'm going to write a little docgen script. so all
bmop comments must conform to the following template/rules:
template (py quotes used because nested comments don't work
on all C compilers):
"""
Region Extend.
paragraph1, Extends bleh bleh bleh.
Bleh Bleh bleh.
Another paragraph.
Another paragraph.
"""
so the first line is the "title" of the bmop.
subsequent line blocks seperated by blank lines
are paragraphs. individual descriptions of slots
would be extracted from comments
next to them, e.g.
{BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //output slot, boundary region
the doc generator would automatically detect the presence of "output slot"
and flag the slot as an output. the same happens for "input slot". also
note that "edges", "faces", "verts", "loops", and "geometry" are valid
substitutions for "slot".
*/
/*
Region Extend
used to implement the select more/less tools.
this puts some geometry surrounding regions of
geometry in geom into geomout.
if usefaces is 0 then geomout spits out verts and edges,
otherwise it spits out faces.
*/
BMOpDefine def_regionextend = {
"regionextend",
{{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, //input geometry
{BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //output slot, computed boundary geometry.
{BMOP_OPSLOT_INT, "constrict"}, //find boundary inside the regions, not outside.
{BMOP_OPSLOT_INT, "usefaces"}, //extend from faces instead of edges
{0} /*null-terminating sentinel*/,
},
bmesh_regionextend_exec,
0
};
/*
Edge Rotate
Rotates edges topologically. Also known as "spin edge" to some people.
Simple example: [/] becomes [|] then [\].
*/
BMOpDefine def_edgerotate = {
"edgerotate",
{{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
{{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, //input edges
{BMOP_OPSLOT_ELEMENT_BUF, "edgeout"}, //newly spun edges
{BMOP_OPSLOT_INT, "ccw"}, //rotate edge counter-clockwise if true, othewise clockwise
{0} /*null-terminating sentinel*/,
@@ -15,38 +103,54 @@ BMOpDefine def_edgerotate = {
0
};
/*
Reverse Faces
Reverses the winding (vertex order) of faces. This has the effect of
flipping the normal.
*/
BMOpDefine def_reversefaces = {
"reversefaces",
{{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
{{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, //input faces
{0} /*null-terminating sentinel*/,
},
bmesh_reversefaces_exec,
0
};
/*
Edge Split
Splits input edges (but doesn't do anything else).
*/
BMOpDefine def_edgesplit = {
"edgesplit",
{{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
{BMOP_OPSLOT_INT, "numcuts"},
{BMOP_OPSLOT_ELEMENT_BUF, "outsplit"},
{{BMOP_OPSLOT_ELEMENT_BUF, "edges"}, //input edges
{BMOP_OPSLOT_INT, "numcuts"}, //number of cuts
{BMOP_OPSLOT_ELEMENT_BUF, "outsplit"}, //newly created vertices and edges
{0} /*null-terminating sentinel*/,
},
esplit_exec,
0
};
/*
Mirror
Mirrors geometry along an axis. The resulting geometry is welded on using
mergedist. Pairs of original/mirrored vertices are welded using the mergedist
parameter (which defines the minimum distance for welding to happen).
*/
BMOpDefine def_mirror = {
"mirror",
/*maps welded vertices to verts they should weld to.*/
{{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
//list of verts to keep
{{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, //input geometry
{BMOP_OPSLOT_MAT, "mat"}, //matrix defining the mirror transformation
{BMOP_OPSLOT_FLT, "mergedist"}, //does no merging if mergedist is 0
{BMOP_OPSLOT_ELEMENT_BUF, "newout"},
{BMOP_OPSLOT_INT, "axis"},
{BMOP_OPSLOT_INT, "mirror_u"},
{BMOP_OPSLOT_INT, "mirror_v"},
{BMOP_OPSLOT_FLT, "mergedist"}, //maximum distance for merging. does no merging if 0.
{BMOP_OPSLOT_ELEMENT_BUF, "newout"}, //output geometry, mirrored
{BMOP_OPSLOT_INT, "axis"}, //the axis to use, 0, 1, or 2 for x, y, z
{BMOP_OPSLOT_INT, "mirror_u"}, //mirror UVs across the u axis
{BMOP_OPSLOT_INT, "mirror_v"}, //mirror UVs across the v axis
{0, /*null-terminating sentinel*/}},
bmesh_mirror_exec,
0,
@@ -369,6 +473,7 @@ BMOpDefine *opdefines[] = {
&def_edgesplit,
&def_reversefaces,
&def_edgerotate,
&def_regionextend,
};
int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));

View File

@@ -38,5 +38,6 @@ void bmesh_mirror_exec(BMesh *bm, BMOperator *op);
void esplit_exec(BMesh *bm, BMOperator *op);
void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op);
void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op);
void bmesh_regionextend_exec(BMesh *bm, BMOperator *op);
#endif

View File

@@ -31,7 +31,8 @@
*
*/
void bmesh_makevert_exec(BMesh *bm, BMOperator *op) {
void bmesh_makevert_exec(BMesh *bm, BMOperator *op)
{
float vec[3];
BMO_Get_Vec(op, "co", vec);
@@ -40,7 +41,8 @@ void bmesh_makevert_exec(BMesh *bm, BMOperator *op) {
BMO_Flag_To_Slot(bm, op, "newvertout", 1, BM_VERT);
}
void bmesh_transform_exec(BMesh *bm, BMOperator *op) {
void bmesh_transform_exec(BMesh *bm, BMOperator *op)
{
BMOIter iter;
BMVert *v;
float mat[4][4];
@@ -56,7 +58,8 @@ void bmesh_transform_exec(BMesh *bm, BMOperator *op) {
is a little complex, but makes it easier to make
sure the transform op is working, since initially
only this one will be used.*/
void bmesh_translate_exec(BMesh *bm, BMOperator *op) {
void bmesh_translate_exec(BMesh *bm, BMOperator *op)
{
float mat[4][4], vec[3];
BMO_Get_Vec(op, "vec", vec);
@@ -67,7 +70,8 @@ void bmesh_translate_exec(BMesh *bm, BMOperator *op) {
BMO_CallOpf(bm, "transform mat=%m4 verts=%s", mat, op, "verts");
}
void bmesh_rotate_exec(BMesh *bm, BMOperator *op) {
void bmesh_rotate_exec(BMesh *bm, BMOperator *op)
{
float vec[3];
BMO_Get_Vec(op, "cent", vec);
@@ -84,7 +88,8 @@ void bmesh_rotate_exec(BMesh *bm, BMOperator *op) {
BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
}
void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op) {
void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
BMFace *f;
@@ -93,7 +98,8 @@ void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op) {
}
}
void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op) {
void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
BMEdge *e, *e2;
int ccw = BMO_Get_Int(op, "ccw");
@@ -109,3 +115,98 @@ void bmesh_edgerotate_exec(BMesh *bm, BMOperator *op) {
BMO_Flag_To_Slot(bm, op, "edgeout", 1, BM_EDGE);
}
#define SEL_FLAG 1
#define SEL_ORIG 2
static void bmesh_regionextend_extend(BMesh *bm, BMOperator *op, int usefaces)
{
BMVert *v;
BMEdge *e;
BMIter eiter;
BMOIter siter;
if (!usefaces) {
BMO_ITER(v, &siter, bm, op, "geom", BM_VERT) {
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
if (!BMO_TestFlag(bm, e, SEL_ORIG))
break;
}
if (e) {
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
BMO_SetFlag(bm, e, SEL_FLAG);
BMO_SetFlag(bm, BM_OtherEdgeVert(e, v), SEL_FLAG);
}
}
}
} else {
BMIter liter, fiter;
BMFace *f, *f2;
BMLoop *l;
BMO_ITER(f, &siter, bm, op, "geom", BM_FACE) {
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
if (!BMO_TestFlag(bm, f2, SEL_ORIG))
BMO_SetFlag(bm, f2, SEL_FLAG);
}
}
}
}
}
static void bmesh_regionextend_constrict(BMesh *bm, BMOperator *op, int usefaces)
{
BMVert *v;
BMEdge *e;
BMIter eiter;
BMOIter siter;
if (!usefaces) {
BMO_ITER(v, &siter, bm, op, "geom", BM_VERT) {
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
if (!BMO_TestFlag(bm, e, SEL_ORIG))
break;
}
if (e) {
BMO_SetFlag(bm, v, SEL_FLAG);
BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
BMO_SetFlag(bm, e, SEL_FLAG);
}
}
}
} else {
BMIter liter, fiter;
BMFace *f, *f2;
BMLoop *l;
BMO_ITER(f, &siter, bm, op, "geom", BM_FACE) {
BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
BM_ITER(f2, &fiter, bm, BM_FACES_OF_EDGE, l->e) {
if (!BMO_TestFlag(bm, f2, SEL_ORIG)) {
BMO_SetFlag(bm, f, SEL_FLAG);
break;
}
}
}
}
}
}
void bmesh_regionextend_exec(BMesh *bm, BMOperator *op)
{
int usefaces = BMO_Get_Int(op, "usefaces");
int constrict = BMO_Get_Int(op, "constrict");
BMO_Flag_Buffer(bm, op, "geom", SEL_ORIG);
if (constrict)
bmesh_regionextend_constrict(bm, op, usefaces);
else
bmesh_regionextend_extend(bm, op, usefaces);
BMO_Flag_To_Slot(bm, op, "geomout", SEL_FLAG, BM_ALL);
}

View File

@@ -1622,84 +1622,25 @@ void MESH_OT_select_linked(wmOperatorType *ot)
/* ******************** **************** */
void EDBM_select_more(BMEditMesh *em)
{
BMIter iter;
/*for now, bmops aren't supposed to mess with header flags
(might need to revisit that design decision later), so
this function is slightly unconventional to avoid the use
of the BMO_[Set/Clear]Flag functions. it accumulates lists
of elements to make selection changes to in pointer arrays.*/
if (em->selectmode <= SCE_SELECT_EDGE) {
BMVert *v;
BMEdge *e;
BMIter eiter;
BMVert **verts = NULL;
V_DECLARE(verts);
V_DECLARE(edges);
BMEdge **edges = NULL;
int vtot=0, etot=0, i;
BM_ITER_NOTSELECT(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
if (BM_TestHFlag(BM_OtherEdgeVert(e, v), BM_SELECT))
break;
}
if (e) {
V_GROW(verts);
verts[vtot++] = v;
}
}
for (i=0; i<vtot; i++) {
BM_Select(em->bm, verts[i], 1);
}
/*make sure we flush from vertices on up, not from edges*/
EDBM_select_flush(em, SCE_SELECT_VERTEX);
V_FREE(verts);
} else {
BMIter liter, fiter;
BMFace *f, *f2, **faces = NULL;
V_DECLARE(faces);
BMLoop *l;
int i, tot=0;
BM_ITER_SELECT(f, &iter, em->bm, BM_FACES_OF_MESH, NULL)
BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
BM_ITER(f2, &fiter, em->bm, BM_FACES_OF_EDGE, l->e) {
if (!BM_TestHFlag(f2, BM_SELECT)) {
V_GROW(faces);
faces[tot++] = f2;
}
}
}
}
for (i=0; i<tot; i++) {
BM_Select(em->bm, faces[i], 1);
}
V_FREE(faces);
}
EDBM_selectmode_flush(em);
}
static int select_more(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
BMOperator bmop;
int usefaces = em->selectmode > SCE_SELECT_EDGE;
EDBM_select_more(em);
EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d",
BM_SELECT, 0, usefaces);
BMO_Exec_Op(em->bm, &bmop);
BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT);
EDBM_selectmode_flush(em);
if (!EDBM_FinishOp(em, &bmop, op, 1))
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
return OPERATOR_FINISHED;
}
@@ -1717,92 +1658,23 @@ void MESH_OT_select_more(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
void EDBM_select_less(BMEditMesh *em)
{
BMIter iter;
/*for now, bmops aren't supposed to mess with header flags
(might need to revisit that design decision later), so
this function is slightly unconventional to avoid the use
of the BMO_[Set/Clear]Flag functions. it accumulates lists
of elements to make selection changes to in pointer arrays.*/
if (em->selectmode <= SCE_SELECT_EDGE) {
BMVert *v;
BMEdge *e;
BMIter eiter;
BMVert **verts = NULL;
V_DECLARE(verts);
V_DECLARE(edges);
BMEdge **edges = NULL;
int vtot=0, etot=0, i;
BM_ITER_SELECT(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
if (!BM_TestHFlag(e, BM_SELECT))
break;
}
if (e) {
V_GROW(verts);
verts[vtot++] = v;
BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
V_GROW(edges);
edges[etot++] = e;
}
}
}
for (i=0; i<vtot; i++) {
BM_Select(em->bm, verts[i], 0);
}
for (i=0; i<etot; i++) {
BM_Select(em->bm, edges[i], 0);
}
V_FREE(verts);
V_FREE(edges);
} else {
BMIter liter, fiter;
BMFace *f, *f2, **faces = NULL;
V_DECLARE(faces);
BMLoop *l;
int i, tot=0;
BM_ITER_SELECT(f, &iter, em->bm, BM_FACES_OF_MESH, NULL)
BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
BM_ITER(f2, &fiter, em->bm, BM_FACES_OF_EDGE, l->e) {
if (!BM_TestHFlag(f2, BM_SELECT))
break;
}
if (f2)
break;
}
if (l) {
V_GROW(faces);
faces[tot++] = f;
}
}
for (i=0; i<tot; i++) {
BM_Select(em->bm, faces[i], 0);
}
V_FREE(faces);
}
EDBM_selectmode_flush(em);
}
static int select_less(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
BMOperator bmop;
int usefaces = em->selectmode > SCE_SELECT_EDGE;
EDBM_select_less(em);
EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d",
BM_SELECT, 1, usefaces);
BMO_Exec_Op(em->bm, &bmop);
BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT);
EDBM_selectmode_flush(em);
if (!EDBM_FinishOp(em, &bmop, op, 1))
return OPERATOR_CANCELLED;
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
return OPERATOR_FINISHED;

View File

@@ -502,18 +502,11 @@ short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float
EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
/*deselect original verts*/
v = BMO_IterNew(&siter, em->bm, &bmop, "verts", BM_VERT);
for (; v; v=BMO_IterStep(&siter)) {
BM_Select(em->bm, v, 0);
}
BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT);
BMO_Exec_Op(em->bm, &bmop);
v = BMO_IterNew(&siter, em->bm, &bmop, "vertout", BM_VERT);
for (; v; v=BMO_IterStep(&siter)) {
BM_Select(em->bm, v, 1);
}
BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT);
if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
return 'g'; // g is grab

View File

@@ -399,6 +399,37 @@ void EDBM_selectmode_flush(BMEditMesh *em)
BM_SelectMode_Flush(em->bm);
}
/*EDBM_select_[more/less] are api functions, I think the uv editor
uses them? though the select more/less ops themselves do not.*/
void EDBM_select_more(BMEditMesh *em)
{
BMOperator bmop;
int usefaces = em->selectmode > SCE_SELECT_EDGE;
BMO_InitOpf(em->bm, &bmop,
"regionextend geom=%hvef constrict=%d usefaces=%d",
BM_SELECT, 0, usefaces);
BMO_Exec_Op(em->bm, &bmop);
BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT);
BMO_Finish_Op(em->bm, &bmop);
EDBM_selectmode_flush(em);
}
void EDBM_select_less(BMEditMesh *em)
{
BMOperator bmop;
int usefaces = em->selectmode > SCE_SELECT_EDGE;
BMO_InitOpf(em->bm, &bmop,
"regionextend geom=%hvef constrict=%d usefaces=%d",
BM_SELECT, 0, usefaces);
BMO_Exec_Op(em->bm, &bmop);
BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT);
BMO_Finish_Op(em->bm, &bmop);
EDBM_selectmode_flush(em);
}
int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese)
{