diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-09-26 02:45:14 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-09-26 02:55:17 +0300 |
commit | 34d98cfe61bd34aa742879a31ba0da01d32d7e3a (patch) | |
tree | 98cd59d03cfc53fd03d519dcd613a77cf701ad44 /source | |
parent | fcf3aa90daed0dde8c770857990f92c6601f8096 (diff) |
BMesh: spin option to merge first/last
For 360d revolutions this is almost always whats intended,
enable by default.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/bmesh/intern/bmesh_opdefines.c | 1 | ||||
-rw-r--r-- | source/blender/bmesh/operators/bmo_dupe.c | 70 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_extrude_spin.c | 21 |
3 files changed, 80 insertions, 12 deletions
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 891a15d4184..7abf05044dd 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1389,6 +1389,7 @@ static BMOpDefine bmo_spin_def = { {"angle", BMO_OP_SLOT_FLT}, /* total rotation angle (radians) */ {"space", BMO_OP_SLOT_MAT}, /* matrix to define the space (typically object matrix) */ {"steps", BMO_OP_SLOT_INT}, /* number of steps */ + {"use_merge", BMO_OP_SLOT_BOOL}, /* Merge first/last when the angle is a full revolution. */ {"use_normal_flip", BMO_OP_SLOT_BOOL}, /* Create faces with reversed direction. */ {"use_duplicate", BMO_OP_SLOT_BOOL}, /* duplicate or extrude? */ {{'\0'}}, diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index af1cd22ac8d..c50c7657deb 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -26,6 +26,8 @@ * Duplicate, Split, Split operators. */ +#include "MEM_guardedalloc.h" + #include "BLI_math.h" #include "BLI_alloca.h" @@ -486,10 +488,29 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op) steps = BMO_slot_int_get(op->slots_in, "steps"); phi = BMO_slot_float_get(op->slots_in, "angle") / steps; do_dupli = BMO_slot_bool_get(op->slots_in, "use_duplicate"); - const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); + const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip"); + /* Caller needs to perform other sanity checks (such as the spin being 360d). */ + const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge") && steps >= 3; axis_angle_normalized_to_mat3(rmat, axis, phi); + BMVert **vtable = NULL; + if (use_merge) { + vtable = MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__); + int i = 0; + BMIter iter; + BMVert *v; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + vtable[i] = v; + /* Evil! store original index in normal, + * this is duplicated into every other vertex. + * So we can read the original from the final. + * + * The normals must be recalculated anyway. */ + *((int *)&v->no[0]) = i; + } + } + BMO_slot_copy(op, slots_in, "geom", op, slots_out, "geom_last.out"); for (a = 0; a < steps; a++) { @@ -507,11 +528,44 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op) BMO_op_initf(bm, &extop, op->flag, "extrude_face_region geom=%S use_normal_flip=%b", op, "geom_last.out", use_normal_flip && (a == 0)); BMO_op_exec(bm, &extop); - BMO_op_callf(bm, op->flag, - "rotate cent=%v matrix=%m3 space=%s verts=%S", - cent, rmat, op, "space", &extop, "geom.out"); - BMO_slot_copy(&extop, slots_out, "geom.out", - op, slots_out, "geom_last.out"); + if ((use_merge && (a == steps - 1)) == false) { + BMO_op_callf(bm, op->flag, + "rotate cent=%v matrix=%m3 space=%s verts=%S", + cent, rmat, op, "space", &extop, "geom.out"); + BMO_slot_copy(&extop, slots_out, "geom.out", + op, slots_out, "geom_last.out"); + } + else { + /* Merge first/last vertices and edges (maintaining 'geom.out' state). */ + BMOpSlot *slot_geom_out = BMO_slot_get(extop.slots_out, "geom.out"); + BMElem **elem_array = (BMElem **)slot_geom_out->data.buf; + int elem_array_len = slot_geom_out->len; + for (int i = 0; i < elem_array_len; ) { + if (elem_array[i]->head.htype == BM_VERT) { + BMVert *v_src = (BMVert *)elem_array[i]; + BMVert *v_dst = vtable[*((const int *)&v_src->no[0])]; + BM_vert_splice(bm, v_dst, v_src); + elem_array_len--; + elem_array[i] = elem_array[elem_array_len]; + } + else { + i++; + } + } + for (int i = 0; i < elem_array_len; ) { + if (elem_array[i]->head.htype == BM_EDGE) { + BMEdge *e_src = (BMEdge *)elem_array[i]; + BMEdge *e_dst = BM_edge_find_double(e_src); + BM_edge_splice(bm, e_dst, e_src); + elem_array_len--; + elem_array[i] = elem_array[elem_array_len]; + } + else { + i++; + } + } + slot_geom_out->len = elem_array_len; + } BMO_op_finish(bm, &extop); } @@ -522,4 +576,8 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op) dvec, op, "space", op, "geom_last.out"); } } + + if (vtable) { + MEM_freeN(vtable); + } } diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 03176bae2f6..88407576ec0 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -65,9 +65,14 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) RNA_float_get_array(op->ptr, "center", cent); RNA_float_get_array(op->ptr, "axis", axis); const int steps = RNA_int_get(op->ptr, "steps"); - const float angle = -RNA_float_get(op->ptr, "angle"); - const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); + const float angle = RNA_float_get(op->ptr, "angle"); + const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip") ^ (angle < 0.0f); const bool dupli = RNA_boolean_get(op->ptr, "dupli"); + const bool use_auto_merge = ( + RNA_boolean_get(op->ptr, "use_auto_merge") && + (dupli == false) && + (steps >= 3) && + fabsf((fabsf(angle) - (M_PI * 2))) <= 1e-6f); if (is_zero_v3(axis)) { BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis"); @@ -78,14 +83,17 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) if (!EDBM_op_init( em, &spinop, op, "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 " - "use_normal_flip=%b use_duplicate=%b", - BM_ELEM_SELECT, cent, axis, d, steps, angle, obedit->obmat, use_normal_flip, dupli)) + "use_normal_flip=%b use_duplicate=%b use_merge=%b", + BM_ELEM_SELECT, cent, axis, d, steps, -angle, obedit->obmat, + use_normal_flip, dupli, use_auto_merge)) { return OPERATOR_CANCELLED; } BMO_op_exec(bm, &spinop); - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + if (use_auto_merge == false) { + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true); + } if (!EDBM_op_finish(em, &spinop, op, true)) { return OPERATOR_CANCELLED; } @@ -140,6 +148,7 @@ void MESH_OT_spin(wmOperatorType *ot) prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -1e12f, 1e12f, "Angle", "Rotation for each step", DEG2RADF(-360.0f), DEG2RADF(360.0f)); RNA_def_property_subtype(prop, PROP_ANGLE); + RNA_def_boolean(ot->srna, "use_auto_merge", true, "Auto Merge", "Merge first/last when the angle is a full revolution"); RNA_def_boolean(ot->srna, "use_normal_flip", 0, "Flip Normals", ""); RNA_def_float_vector(ot->srna, "center", 3, NULL, -1e12f, 1e12f, |