made subdivide's patterns more configurable, and also implemented all the quad corner types. still need to extend these options to the knife tool.

This commit is contained in:
Joseph Eagar
2009-08-11 11:33:23 +00:00
parent eb34e3ad7c
commit e4f0c65bf3
4 changed files with 152 additions and 255 deletions

View File

@@ -14,6 +14,14 @@ enum {
DEL_ONLYTAGGED,
};
/*quad innervert values*/
enum {
SUBD_INNERVERT,
SUBD_PATH,
SUBD_FAN,
SUBD_STRAIGHT_CUT,
};
extern BMOpDefine *opdefines[];
extern int bmesh_total_ops;
@@ -28,7 +36,8 @@ struct EditMesh;
void BMOP_DupeFromFlag(struct BMesh *bm, int etypeflag, int flag);
void BM_esubdivideflag(struct Object *obedit, BMesh *bm, int flag, float smooth,
float fractal, int beauty, int numcuts, int seltype);
float fractal, int beauty, int numcuts, int seltype,
int cornertype, int singleedge, int gridfill);
void BM_extrudefaceflag(BMesh *bm, int flag);
/*this next one return 1 if they did anything, or zero otherwise.

View File

@@ -552,6 +552,11 @@ BMOpDefine def_subdop = {
/*these next two can have multiple types of elements in them.*/
{BMOP_OPSLOT_ELEMENT_BUF, "outinner"},
{BMOP_OPSLOT_ELEMENT_BUF, "outsplit"},
{BMOP_OPSLOT_INT, "quadcornertype"}, //quad corner type, see bmesh_operators.h
{BMOP_OPSLOT_INT, "gridfill"}, //fill in fully-selected faces with a grid
{BMOP_OPSLOT_INT, "singleedge"}, //tesselate the case of one edge selected in a quad or triangle
{0} /*null-terminating sentinel*/,
},
esubdivide_exec,

View File

@@ -19,6 +19,15 @@
#include <string.h>
#include <math.h>
/*subdivide future development notes:
each pattern should be able to be disabled
by the client code, and the client code
should be able to pass in custom patterns.
so you can configure it anywhere from a simple
edge connect tool, to what's in 2.49a.
*/
/*flags for all elements share a common bitfield space*/
#define SUBD_SPLIT 1
@@ -264,31 +273,30 @@ subdpattern q_1edge = {
/*
v4---v3---v2
| s |
v6--------v5
| |
| |
| s |
v5---v0---v1
| |v4s
| |v3s
| s s |
v7-v0--v1-v2
*/
static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **verts,
subdparams *params)
static void q_2edge_split_tess(BMesh *bm, BMFace *face, BMVert **verts,
subdparams *params)
{
BMFace *nf;
int i, numcuts = params->numcuts;
for (i=0; i<numcuts; i++) {
connect_smallest_face(bm, verts[i],verts[(numcuts-i-1)+numcuts+2],
connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)],
&nf);
}
connect_smallest_face(bm, verts[numcuts*2+3], verts[numcuts*2+1], &nf);
}
subdpattern q_2edge_op = {
{1, 0, 1, 0},
q_2edge_op_split,
subdpattern q_2edge_path = {
{1, 1, 0, 0},
q_2edge_split_tess,
4,
};
@@ -301,22 +309,63 @@ v6--------v5
v7-v0--v1-v2
*/
static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **verts,
static void q_2edge_split_innervert(BMesh *bm, BMFace *face, BMVert **verts,
subdparams *params)
{
BMFace *nf;
BMVert *v, *lastv;
BMEdge *e, *ne;
int i, numcuts = params->numcuts;
for (i=0; i<numcuts; i++) {
connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)],
lastv = verts[numcuts];
for (i=numcuts-1; i>=0; i--) {
e = connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)],
&nf);
v = BM_Split_Edge(bm, e->v1, e, &ne, 0.5f);
connect_smallest_face(bm, lastv, v, &nf);
lastv = v;
}
//experimentally disabled -> connect_smallest_face(bm, verts[numcuts*2+3], verts[numcuts*2+1], &nf);
connect_smallest_face(bm, lastv, verts[numcuts*2+2], &nf);
}
subdpattern q_2edge = {
subdpattern q_2edge_innervert = {
{1, 1, 0, 0},
q_2edge_split,
q_2edge_split_innervert,
4,
};
/*
v6--------v5
| |
| |v4s
| |v3s
| s s |
v7-v0--v1-v2
*/
static void q_2edge_split_fan(BMesh *bm, BMFace *face, BMVert **verts,
subdparams *params)
{
BMFace *nf;
BMVert *v, *lastv;
BMEdge *e, *ne;
int i, numcuts = params->numcuts;
lastv = verts[2];
for (i=0; i<numcuts; i++) {
connect_smallest_face(bm, verts[i], verts[numcuts*2+2], &nf);
connect_smallest_face(bm, verts[numcuts+(numcuts-i)],
verts[numcuts*2+2], &nf);
}
}
subdpattern q_2edge_fan = {
{1, 1, 0, 0},
q_2edge_split_fan,
4,
};
@@ -462,33 +511,6 @@ subdpattern t_1edge = {
3,
};
/* v5
/ \
/ \ v4 s
/ \
/ \ v3 s
/ \
v6--v0--v1--v2
s s
*/
static void t_2edge_split(BMesh *bm, BMFace *face, BMVert **verts,
subdparams *params)
{
BMFace *nf;
int i, numcuts = params->numcuts;
for (i=0; i<numcuts; i++) {
connect_smallest_face(bm, verts[i], verts[numcuts+numcuts-i], &nf);
}
}
subdpattern t_2edge = {
{1, 1, 0},
t_2edge_split,
3,
};
/* v5
/ \
s v6/---\ v4 s
@@ -593,14 +615,12 @@ subdpattern q_4edge = {
};
subdpattern *patterns[] = {
//&q_1edge,
//&q_2edge_op,
&q_4edge,
NULL, //quad single edge pattern is inserted here
NULL, //quad corner vert pattern is inserted here
NULL, //tri single edge pattern is inserted here
NULL,
&q_3edge,
//&q_2edge,
//&t_1edge,
&t_2edge,
&t_3edge,
NULL,
};
#define PLEN (sizeof(patterns) / sizeof(void*))
@@ -628,17 +648,48 @@ void esubdivide_exec(BMesh *bmesh, BMOperator *op)
V_DECLARE(splits);
V_DECLARE(loops);
float smooth, fractal;
int beauty;
int beauty, cornertype, singleedge, gridfill;
int i, j, matched, a, b, numcuts, totesel;
BMO_Flag_Buffer(bmesh, op, "edges", SUBD_SPLIT, BM_EDGE);
numcuts = BMO_GetSlot(op, "numcuts")->data.i;
smooth = BMO_GetSlot(op, "smooth")->data.f;
fractal = BMO_GetSlot(op, "fractal")->data.f;
beauty = BMO_GetSlot(op, "beauty")->data.i;
numcuts = BMO_Get_Int(op, "numcuts");
smooth = BMO_Get_Float(op, "smooth");
fractal = BMO_Get_Float(op, "fractal");
beauty = BMO_Get_Int(op, "beauty");
cornertype = BMO_Get_Int(op, "quadcornertype");
singleedge = BMO_Get_Int(op, "singleedge");
gridfill = BMO_Get_Int(op, "gridfill");
patterns[1] = NULL;
//straight cut is patterns[1] == NULL
switch (cornertype) {
case SUBD_PATH:
patterns[1] = &q_2edge_path;
break;
case SUBD_INNERVERT:
patterns[1] = &q_2edge_innervert;
break;
case SUBD_FAN:
patterns[1] = &q_2edge_fan;
break;
}
if (singleedge) {
patterns[0] = &q_1edge;
patterns[2] = &t_1edge;
} else {
patterns[0] = NULL;
patterns[2] = NULL;
}
einput = BMO_GetSlot(op, "edges");
if (gridfill) {
patterns[3] = &q_4edge;
patterns[5] = &t_3edge;
} else {
patterns[3] = NULL;
patterns[5] = NULL;
}
/*first go through and tag edges*/
BMO_Flag_To_Slot(bmesh, op, "edges",
@@ -735,6 +786,8 @@ void esubdivide_exec(BMesh *bmesh, BMOperator *op)
for (i=0; i<PLEN; i++) {
pat = patterns[i];
if (!pat) continue;
if (pat->len == face->len) {
for (a=0; a<pat->len; a++) {
matched = 1;
@@ -896,12 +949,16 @@ void esubdivide_exec(BMesh *bmesh, BMOperator *op)
/*editmesh-emulating function*/
void BM_esubdivideflag(Object *obedit, BMesh *bm, int flag, float smooth,
float fractal, int beauty, int numcuts, int seltype) {
float fractal, int beauty, int numcuts,
int seltype, int cornertype, int singleedge, int gridfill)
{
BMOperator op;
BMO_InitOpf(bm, &op, "esubd edges=%he smooth=%f fractal=%f "
"beauty=%d numcuts=%d", flag, smooth, fractal,
beauty, numcuts);
"beauty=%d numcuts=%d quadcornertype=%d singleedge=%d "
"gridfill=%d",
flag, smooth, fractal, beauty, numcuts,
cornertype, singleedge, gridfill);
BMO_Exec_Op(bm, &op);

View File

@@ -112,7 +112,12 @@ static int subdivide_exec(bContext *C, wmOperator *op)
if(fractal != 0.0f)
flag |= B_FRACTAL;
BM_esubdivideflag(obedit, em->bm, BM_SELECT, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0);
BM_esubdivideflag(obedit, em->bm, BM_SELECT,
smooth, fractal,
scene->toolsettings->editbutflag|flag,
cuts, 0, RNA_enum_get(op->ptr, "quadcorner"),
RNA_boolean_get(op->ptr, "tess_single_edge"),
RNA_boolean_get(op->ptr, "gridfill"));
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
@@ -120,6 +125,15 @@ static int subdivide_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
/* Note, these values must match delete_mesh() event values */
static EnumPropertyItem prop_mesh_cornervert_types[] = {
{SUBD_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
{SUBD_PATH, "PATH", 0, "Path", ""},
{SUBD_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
{SUBD_FAN, "FAN", 0, "Fan", ""},
{0, NULL, 0, NULL, NULL}
};
void MESH_OT_subdivide(wmOperatorType *ot)
{
/* identifiers */
@@ -137,200 +151,12 @@ void MESH_OT_subdivide(wmOperatorType *ot)
RNA_def_int(ot->srna, "number_cuts", 1, 1, 20, "Number of Cuts", "", 1, INT_MAX);
RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
}
#if 0
static int subdivide_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, 1, 0);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
void MESH_OT_subdivide(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Subdivide";
ot->idname= "MESH_OT_subdivide";
/* api callbacks */
ot->exec= subdivide_exec;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
static int subdivide_multi_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, RNA_int_get(op->ptr,"number_cuts"), 0);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
void MESH_OT_subdivide_multi(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Subdivide Multi";
ot->idname= "MESH_OT_subdivide_multi";
/* api callbacks */
ot->exec= subdivide_multi_exec;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* props */
RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
}
static int subdivide_multi_fractal_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
BM_esubdivideflag(obedit, em->bm, 1, -(RNA_float_get(op->ptr, "random_factor")/100), scene->toolsettings->editbutflag, RNA_int_get(op->ptr, "number_cuts"), 0);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
void MESH_OT_subdivide_multi_fractal(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Subdivide Multi Fractal";
ot->idname= "MESH_OT_subdivide_multi_fractal";
/* api callbacks */
ot->exec= subdivide_multi_fractal_exec;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
}
static int subdivide_smooth_exec(bContext *C, wmOperator *op)
{
Object *obedit= CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
BM_esubdivideflag(obedit, em->bm, 1, 0.292f*RNA_float_get(op->ptr, "smoothness"), scene->toolsettings->editbutflag | B_SMOOTH, 1, 0);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return OPERATOR_FINISHED;
}
void MESH_OT_subdivide_smooth(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Subdivide Smooth";
ot->idname= "MESH_OT_subdivide_smooth";
/* api callbacks */
ot->exec= subdivide_smooth_exec;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* props */
RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);
}
static int subdivs_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
uiPopupMenu *pup;
uiLayout *layout;
pup= uiPupMenuBegin(C, "Subdivision Type", 0);
layout= uiPupMenuLayout(pup);
uiItemsEnumO(layout, "MESH_OT_subdivs", "type");
uiPupMenuEnd(C, pup);
return OPERATOR_CANCELLED;
}
static int subdivs_exec(bContext *C, wmOperator *op)
{
switch(RNA_int_get(op->ptr, "type"))
{
case 0: // simple
subdivide_exec(C,op);
break;
case 1: // multi
subdivide_multi_exec(C,op);
break;
case 2: // fractal;
subdivide_multi_fractal_exec(C,op);
break;
case 3: //smooth
subdivide_smooth_exec(C,op);
break;
}
return OPERATOR_FINISHED;
}
void MESH_OT_subdivs(wmOperatorType *ot)
{
static EnumPropertyItem type_items[]= {
{0, "SIMPLE", 0, "Simple", ""},
{1, "MULTI", 0, "Multi", ""},
{2, "FRACTAL", 0, "Fractal", ""},
{3, "SMOOTH", 0, "Smooth", ""},
{0, NULL, NULL}};
/* identifiers */
ot->name= "subdivs";
ot->idname= "MESH_OT_subdivs";
/* api callbacks */
ot->invoke= subdivs_invoke;
ot->exec= subdivs_exec;
ot->poll= ED_operator_editmesh;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/*props */
RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
/* this is temp, the ops are different, but they are called from subdivs, so all the possible props should be here as well*/
RNA_def_int(ot->srna, "number_cuts", 4, 1, 10, "Number of Cuts", "", 1, INT_MAX);
RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);
RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_INNERVERT, "Quad Corner Type", "Method used for subdividing two adjacent edges in a quad");
RNA_def_boolean(ot->srna, "tess_single_edge", 1, "Tesselate Single Edge", "Adds triangles to single edges belonging to triangles or quads");
RNA_def_boolean(ot->srna, "gridfill", 1, "Grid Fill", "Fill Fully Selected Triangles and Quads With A Grid");
}
#endif
/* individual face extrude */
/* will use vertex normals for extrusion directions, so *nor is unaffected */