Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/mesh/editmesh_tools.c')
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c1002
1 files changed, 782 insertions, 220 deletions
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 3f1023b7fb4..d3937188358 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -55,7 +55,7 @@
#include "BKE_main.h"
#include "BKE_editmesh.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -90,13 +90,13 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
if (RNA_boolean_get(op->ptr, "quadtri") &&
- RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
+ RNA_enum_get(op->ptr, "quadcorner") == SUBD_CORNER_STRAIGHT_CUT)
{
- RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
+ RNA_enum_set(op->ptr, "quadcorner", SUBD_CORNER_INNERVERT);
}
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
- smooth, SUBD_FALLOFF_ROOT, false,
+ smooth, SUBD_FALLOFF_INVSQUARE, false,
fractal, along_normal,
cuts,
SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
@@ -110,10 +110,10 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
/* 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", ""},
+ {SUBD_CORNER_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
+ {SUBD_CORNER_PATH, "PATH", 0, "Path", ""},
+ {SUBD_CORNER_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
+ {SUBD_CORNER_FAN, "FAN", 0, "Fan", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -134,19 +134,20 @@ void MESH_OT_subdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 100, "Number of Cuts", "", 1, 10);
/* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1e3f, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
- RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT,
+ RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_CORNER_STRAIGHT_CUT,
"Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)");
- RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f, "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
- RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
+ RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, 1e6f, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "fractal_along_normal", 0.0f, 0.0f, 1.0f,
+ "Along Normal", "Apply fractal displacement along normal only", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Random Seed", "Seed for the random number generator", 0, 255);
}
/* -------------------------------------------------------------------- */
@@ -176,24 +177,24 @@ static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_defa
PropertyRNA *prop;
- prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, INT_MAX, "Number of Cuts", "", 0, 64);
+ prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, 1000, "Number of Cuts", "", 0, 64);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH,
"Interpolation", "Interpolation method");
- RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, FLT_MAX,
+ RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1e3f,
"Smoothness", "Smoothness factor", 0.0f, 2.0f);
/* profile-shape */
- RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -FLT_MAX, FLT_MAX,
- "Profile Factor", "", -2.0f, 2.0f);
+ RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -1e3f, 1e3f,
+ "Profile Factor", "How much intermediary new edges are shrunk/expanded", -2.0f, 2.0f);
prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
RNA_def_property_enum_default(prop, PROP_SMOOTH);
RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
- RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
}
static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSubdProps *op_props)
@@ -289,7 +290,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_int(ot->srna, "iterations", 2, 1, INT_MAX, "Iterations", "Number of times to unsubdivide", 1, 100);
+ RNA_def_int(ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100);
}
void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
@@ -313,6 +314,16 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
}
}
+
+/* Note, these values must match delete_mesh() event values */
+enum {
+ MESH_DELETE_VERT = 0,
+ MESH_DELETE_EDGE = 1,
+ MESH_DELETE_FACE = 2,
+ MESH_DELETE_EDGE_FACE = 3,
+ MESH_DELETE_ONLY_FACE = 4,
+};
+
static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int totelem[3])
{
BKE_reportf(reports, RPT_INFO,
@@ -320,45 +331,38 @@ static void edbm_report_delete_info(ReportList *reports, BMesh *bm, const int to
totelem[0] - bm->totvert, totelem[1] - bm->totedge, totelem[2] - bm->totface);
}
-/* Note, these values must match delete_mesh() event values */
-static EnumPropertyItem prop_mesh_delete_types[] = {
- {0, "VERT", 0, "Vertices", ""},
- {1, "EDGE", 0, "Edges", ""},
- {2, "FACE", 0, "Faces", ""},
- {3, "EDGE_FACE", 0, "Only Edges & Faces", ""},
- {4, "ONLY_FACE", 0, "Only Faces", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
static int edbm_delete_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int type = RNA_enum_get(op->ptr, "type");
- if (type == 0) {
- if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
- return OPERATOR_CANCELLED;
- }
- else if (type == 1) {
- if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
- return OPERATOR_CANCELLED;
- }
- else if (type == 2) {
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
- return OPERATOR_CANCELLED;
- }
- else if (type == 3) {
- if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) /* Edges and Faces */
- return OPERATOR_CANCELLED;
- }
- else if (type == 4) {
- //"Erase Only Faces";
- if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i",
- BM_ELEM_SELECT, DEL_ONLYFACES))
- {
- return OPERATOR_CANCELLED;
- }
+ switch (type) {
+ case MESH_DELETE_VERT:
+ if (!EDBM_op_callf(em, op, "delete geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_EDGE:
+ if (!EDBM_op_callf(em, op, "delete geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_FACE:
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_EDGE_FACE:
+ /* Edges and Faces */
+ if (!EDBM_op_callf(em, op, "delete geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES))
+ return OPERATOR_CANCELLED;
+ break;
+ case MESH_DELETE_ONLY_FACE:
+ /* Only faces. */
+ if (!EDBM_op_callf(em, op, "delete geom=%hf context=%i", BM_ELEM_SELECT, DEL_ONLYFACES))
+ return OPERATOR_CANCELLED;
+ break;
+ default:
+ BLI_assert(0);
+ break;
}
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -370,6 +374,15 @@ static int edbm_delete_exec(bContext *C, wmOperator *op)
void MESH_OT_delete(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_mesh_delete_types[] = {
+ {MESH_DELETE_VERT, "VERT", 0, "Vertices", ""},
+ {MESH_DELETE_EDGE, "EDGE", 0, "Edges", ""},
+ {MESH_DELETE_FACE, "FACE", 0, "Faces", ""},
+ {MESH_DELETE_EDGE_FACE, "EDGE_FACE", 0, "Only Edges & Faces", ""},
+ {MESH_DELETE_ONLY_FACE, "ONLY_FACE", 0, "Only Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Delete";
ot->description = "Delete selected vertices, edges or faces";
@@ -385,7 +398,8 @@ void MESH_OT_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 0, "Type", "Method used for deleting mesh data");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, MESH_DELETE_VERT,
+ "Type", "Method used for deleting mesh data");
}
@@ -492,7 +506,7 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
+ if (!EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, true))
return OPERATOR_CANCELLED;
EDBM_update_generic(em, true, true);
@@ -877,23 +891,49 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMOperator bmop;
- const bool is_pair = (bm->totvertsel == 2);
- int len;
-
+ bool is_pair = (bm->totvertsel == 2);
+ int len = 0;
+ bool check_degenerate = true;
+ const int verts_len = bm->totvertsel;
+ BMVert **verts;
+
+ verts = MEM_mallocN(sizeof(*verts) * verts_len, __func__);
+ {
+ BMIter iter;
+ BMVert *v;
+ int i = 0;
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ verts[i++] = v;
+ }
+ }
+
+ if (is_pair) {
+ if (BM_vert_pair_share_face_check_cb(
+ verts[0], verts[1],
+ BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN)))
+ {
+ check_degenerate = false;
+ is_pair = false;
+ }
+ }
+ }
+
if (is_pair) {
if (!EDBM_op_init(em, &bmop, op,
- "connect_vert_pair verts=%hv verts_exclude=%hv faces_exclude=%hf",
- BM_ELEM_SELECT, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
+ "connect_vert_pair verts=%eb verts_exclude=%hv faces_exclude=%hf",
+ verts, verts_len, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
{
- return OPERATOR_CANCELLED;
+ goto finally;
}
}
else {
if (!EDBM_op_init(em, &bmop, op,
- "connect_verts verts=%hv faces_exclude=%hf check_degenerate=%b",
- BM_ELEM_SELECT, BM_ELEM_HIDDEN, true))
+ "connect_verts verts=%eb faces_exclude=%hf check_degenerate=%b",
+ verts, verts_len, BM_ELEM_HIDDEN, check_degenerate))
{
- return OPERATOR_CANCELLED;
+ goto finally;
}
}
@@ -908,15 +948,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
}
if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ len = 0;
}
else {
EDBM_selectmode_flush(em); /* so newly created edges get the selection state from the vertex */
EDBM_update_generic(em, true, true);
-
- return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+
+
+finally:
+ MEM_freeN(verts);
+ return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void MESH_OT_vert_connect(wmOperatorType *ot)
@@ -924,7 +967,7 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
/* identifiers */
ot->name = "Vertex Connect";
ot->idname = "MESH_OT_vert_connect";
- ot->description = "Connect 2 vertices of a face by an edge, splitting the face in two";
+ ot->description = "Connect selected vertices of faces, splitting the face";
/* api callbacks */
ot->exec = edbm_vert_connect_exec;
@@ -935,6 +978,308 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
}
+/**
+ * check that endpoints are verts and only have a single selected edge connected.
+ */
+static bool bm_vert_is_select_history_open(BMesh *bm)
+{
+ BMEditSelection *ele_a = bm->selected.first;
+ BMEditSelection *ele_b = bm->selected.last;
+ if ((ele_a->htype == BM_VERT) &&
+ (ele_b->htype == BM_VERT))
+ {
+ if ((BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_a->ele, BM_ELEM_SELECT, true) == 1) &&
+ (BM_iter_elem_count_flag(BM_EDGES_OF_VERT, (BMVert *)ele_b->ele, BM_ELEM_SELECT, true) == 1))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool bm_vert_connect_pair(BMesh *bm, BMVert *v_a, BMVert *v_b)
+{
+ BMOperator bmop;
+ BMVert **verts;
+ const int totedge_orig = bm->totedge;
+
+ BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, "connect_vert_pair");
+
+ verts = BMO_slot_buffer_alloc(&bmop, bmop.slots_in, "verts", 2);
+ verts[0] = v_a;
+ verts[1] = v_b;
+
+ BM_vert_normal_update(verts[0]);
+ BM_vert_normal_update(verts[1]);
+
+ BMO_op_exec(bm, &bmop);
+ BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+ BMO_op_finish(bm, &bmop);
+ return (bm->totedge != totedge_orig);
+}
+
+static bool bm_vert_connect_select_history(BMesh *bm)
+{
+ /* Logic is as follows:
+ *
+ * - If there are any isolated/wire verts - connect as edges.
+ * - Otherwise connect faces.
+ * - If all edges have been created already, closed the loop.
+ */
+ if (BLI_listbase_count_ex(&bm->selected, 2) == 2 && (bm->totvertsel > 2)) {
+ BMEditSelection *ese;
+ int tot = 0;
+ bool changed = false;
+ bool has_wire = false;
+ // bool all_verts;
+
+ /* ensure all verts have history */
+ for (ese = bm->selected.first; ese; ese = ese->next, tot++) {
+ BMVert *v;
+ if (ese->htype != BM_VERT) {
+ break;
+ }
+ v = (BMVert *)ese->ele;
+ if ((has_wire == false) && ((v->e == NULL) || BM_vert_is_wire(v))) {
+ has_wire = true;
+ }
+ }
+ // all_verts = (ese == NULL);
+
+ if (has_wire == false) {
+ /* all verts have faces , connect verts via faces! */
+ if (tot == bm->totvertsel) {
+ BMEditSelection *ese_last;
+ ese_last = bm->selected.first;
+ ese = ese_last->next;
+
+ do {
+
+ if (BM_edge_exists((BMVert *)ese_last->ele, (BMVert *)ese->ele)) {
+ /* pass, edge exists (and will be selected) */
+ }
+ else {
+ changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele);
+ }
+ } while ((ese_last = ese),
+ (ese = ese->next));
+
+ if (changed) {
+ return true;
+ }
+ }
+
+ if (changed == false) {
+ /* existing loops: close the selection */
+ if (bm_vert_is_select_history_open(bm)) {
+ changed |= bm_vert_connect_pair(
+ bm,
+ (BMVert *)((BMEditSelection *)bm->selected.first)->ele,
+ (BMVert *)((BMEditSelection *)bm->selected.last)->ele);
+
+ if (changed) {
+ return true;
+ }
+ }
+ }
+ }
+
+ else {
+ /* no faces, simply connect the verts by edges */
+ BMEditSelection *ese_prev;
+ ese_prev = bm->selected.first;
+ ese = ese_prev->next;
+
+
+ do {
+ if (BM_edge_exists((BMVert *)ese_prev->ele, (BMVert *)ese->ele)) {
+ /* pass, edge exists (and will be selected) */
+ }
+ else {
+ BMEdge *e;
+ e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
+ BM_edge_select_set(bm, e, true);
+ changed = true;
+ }
+ } while ((ese_prev = ese),
+ (ese = ese->next));
+
+ if (changed == false) {
+ /* existing loops: close the selection */
+ if (bm_vert_is_select_history_open(bm)) {
+ BMEdge *e;
+ ese_prev = bm->selected.first;
+ ese = bm->selected.last;
+ e = BM_edge_create(bm, (BMVert *)ese_prev->ele, (BMVert *)ese->ele, NULL, 0);
+ BM_edge_select_set(bm, e, true);
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Convert an edge selection to a temp vertex selection
+ * (which must be cleared after use as a path to connect).
+ */
+static bool bm_vert_connect_select_history_edge_to_vert_path(BMesh *bm, ListBase *r_selected)
+{
+ ListBase selected_orig = {NULL, NULL};
+ BMEditSelection *ese;
+ int edges_len = 0;
+ bool side = false;
+
+ /* first check all edges are OK */
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ if (ese->htype == BM_EDGE) {
+ edges_len += 1;
+ }
+ else {
+ return false;
+ }
+ }
+ /* if this is a mixed selection, bail out! */
+ if (bm->totedgesel != edges_len) {
+ return false;
+ }
+
+ SWAP(ListBase, bm->selected, selected_orig);
+
+ /* convert edge selection into 2 ordered loops (where the first edge ends up in the middle) */
+ for (ese = selected_orig.first; ese; ese = ese->next) {
+ BMEdge *e_curr = (BMEdge *)ese->ele;
+ BMEdge *e_prev = ese->prev ? (BMEdge *)ese->prev->ele : NULL;
+ BMLoop *l_curr;
+ BMLoop *l_prev;
+ BMVert *v;
+
+ if (e_prev) {
+ BMFace *f = BM_edge_pair_share_face_by_len(e_curr, e_prev, &l_curr, &l_prev, true);
+ if (f) {
+ if ((e_curr->v1 != l_curr->v) == (e_prev->v1 != l_prev->v)) {
+ side = !side;
+ }
+ }
+ else if (is_quad_flip_v3(e_curr->v1->co, e_curr->v2->co, e_prev->v2->co, e_prev->v1->co)) {
+ side = !side;
+ }
+ }
+
+ v = (&e_curr->v1)[side];
+ if (!bm->selected.last || (BMVert *)((BMEditSelection *)bm->selected.last)->ele != v) {
+ BM_select_history_store_notest(bm, v);
+ }
+
+ v = (&e_curr->v1)[!side];
+ if (!bm->selected.first || (BMVert *)((BMEditSelection *)bm->selected.first)->ele != v) {
+ BM_select_history_store_head_notest(bm, v);
+ }
+
+ e_prev = e_curr;
+ }
+
+ *r_selected = bm->selected;
+ bm->selected = selected_orig;
+
+ return true;
+}
+
+static int edbm_vert_connect_path_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ bool is_pair = (em->bm->totvertsel == 2);
+ ListBase selected_orig = {NULL, NULL};
+ int retval;
+
+ /* when there is only 2 vertices, we can ignore selection order */
+ if (is_pair) {
+ return edbm_vert_connect_exec(C, op);
+ }
+
+ if (bm->selected.first) {
+ BMEditSelection *ese = bm->selected.first;
+ if (ese->htype == BM_EDGE) {
+ if (bm_vert_connect_select_history_edge_to_vert_path(bm, &selected_orig)) {
+ SWAP(ListBase, bm->selected, selected_orig);
+ }
+ }
+ }
+
+ if (bm_vert_connect_select_history(bm)) {
+ EDBM_selectmode_flush(em);
+ EDBM_update_generic(em, true, true);
+ retval = OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Invalid selection order");
+ retval = OPERATOR_CANCELLED;
+ }
+
+ if (!BLI_listbase_is_empty(&selected_orig)) {
+ BM_select_history_clear(bm);
+ bm->selected = selected_orig;
+ }
+
+ return retval;
+}
+
+void MESH_OT_vert_connect_path(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Connect Path";
+ ot->idname = "MESH_OT_vert_connect_path";
+ ot->description = "Connect vertices by their selection order, creating edges, splitting faces";
+
+ /* api callbacks */
+ ot->exec = edbm_vert_connect_path_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "connect_verts_concave faces=%hf",
+ BM_ELEM_SELECT))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vert_connect_concave(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split Concave Faces";
+ ot->idname = "MESH_OT_vert_connect_concave";
+ ot->description = "Make all faces convex";
+
+ /* api callbacks */
+ ot->exec = edbm_vert_connect_concave_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -978,6 +1323,43 @@ void MESH_OT_vert_connect_nonplanar(wmOperatorType *ot)
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
}
+static int edbm_face_make_planar_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int repeat = RNA_int_get(op->ptr, "repeat");
+ const float fac = RNA_float_get(op->ptr, "factor");
+
+ if (!EDBM_op_callf(
+ em, op, "planar_faces faces=%hf iterations=%i factor=%f",
+ BM_ELEM_SELECT, repeat, fac))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_face_make_planar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Planar Faces";
+ ot->idname = "MESH_OT_face_make_planar";
+ ot->description = "Flatten selected faces";
+
+ /* api callbacks */
+ ot->exec = edbm_face_make_planar_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "factor", 1.0f, -10.0f, 10.0f, "Factor", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200);
+}
+
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
@@ -1212,7 +1594,7 @@ void MESH_OT_hide(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ RNA_def_boolean(ot->srna, "unselected", false, "Unselected", "Hide unselected rather than selected");
}
static int edbm_reveal_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1274,7 +1656,7 @@ void MESH_OT_normals_make_consistent(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
+ RNA_def_boolean(ot->srna, "inside", false, "Inside", "");
}
@@ -1288,7 +1670,8 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
bool mirrx = false, mirry = false, mirrz = false;
int i, repeat;
float clip_dist = 0.0f;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ const float fac = RNA_float_get(op->ptr, "factor");
+ const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
@@ -1322,12 +1705,12 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
repeat = RNA_int_get(op->ptr, "repeat");
if (!repeat)
repeat = 1;
-
+
for (i = 0; i < repeat; i++) {
if (!EDBM_op_callf(em, op,
- "smooth_vert verts=%hv mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b clip_dist=%f "
- "use_axis_x=%b use_axis_y=%b use_axis_z=%b",
- BM_ELEM_SELECT, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
{
return OPERATOR_CANCELLED;
}
@@ -1358,10 +1741,11 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Number of times to smooth the mesh", "", 1, 100);
- RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis");
- RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis");
- RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis");
+ RNA_def_float(ot->srna, "factor", 0.5f, -10.0f, 10.0f, "Smoothing", "Smoothing factor", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Repeat", "Number of times to smooth the mesh", 1, 100);
+ RNA_def_boolean(ot->srna, "xaxis", true, "X-Axis", "Smooth along the X axis");
+ RNA_def_boolean(ot->srna, "yaxis", true, "Y-Axis", "Smooth along the Y axis");
+ RNA_def_boolean(ot->srna, "zaxis", true, "Z-Axis", "Smooth along the Z axis");
}
static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
@@ -1436,16 +1820,16 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "repeat", 1, 1, 200,
+ RNA_def_int(ot->srna, "repeat", 1, 1, 1000,
"Number of iterations to smooth the mesh", "", 1, 200);
- RNA_def_float(ot->srna, "lambda_factor", 0.00005f, 0.0000001f, 1000.0f,
- "Lambda factor", "", 0.0000001f, 1000.0f);
- RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f,
- "Lambda factor in border", "", 0.0000001f, 1000.0f);
- RNA_def_boolean(ot->srna, "use_x", 1, "Smooth X Axis", "Smooth object along X axis");
- RNA_def_boolean(ot->srna, "use_y", 1, "Smooth Y Axis", "Smooth object along Y axis");
- RNA_def_boolean(ot->srna, "use_z", 1, "Smooth Z Axis", "Smooth object along Z axis");
- RNA_def_boolean(ot->srna, "preserve_volume", 1, "Preserve Volume", "Apply volume preservation after smooth");
+ RNA_def_float(ot->srna, "lambda_factor", 5e-5f, 1e-7f, 1000.0f,
+ "Lambda factor", "", 1e-7f, 1000.0f);
+ RNA_def_float(ot->srna, "lambda_border", 5e-5f, 1e-7f, 1000.0f,
+ "Lambda factor in border", "", 1e-7f, 1000.0f);
+ RNA_def_boolean(ot->srna, "use_x", true, "Smooth X Axis", "Smooth object along X axis");
+ RNA_def_boolean(ot->srna, "use_y", true, "Smooth Y Axis", "Smooth object along Y axis");
+ RNA_def_boolean(ot->srna, "use_z", true, "Smooth Z Axis", "Smooth object along Z axis");
+ RNA_def_boolean(ot->srna, "preserve_volume", true, "Preserve Volume", "Apply volume preservation after smooth");
}
/********************** Smooth/Solid Operators *************************/
@@ -1690,6 +2074,14 @@ void MESH_OT_colors_reverse(wmOperatorType *ot)
}
+enum {
+ MESH_MERGE_LAST = 1,
+ MESH_MERGE_CENTER = 3,
+ MESH_MERGE_CURSOR = 4,
+ MESH_MERGE_COLLAPSE = 5,
+ MESH_MERGE_FIRST = 6,
+};
+
static bool merge_firstlast(BMEditMesh *em, const bool use_first, const bool use_uvmerge, wmOperator *wmop)
{
BMVert *mergevert;
@@ -1786,22 +2178,20 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
bool ok = false;
switch (type) {
- case 3:
+ case MESH_MERGE_CENTER:
ok = merge_target(em, scene, v3d, obedit, false, uvs, op);
break;
- case 4:
+ case MESH_MERGE_CURSOR:
ok = merge_target(em, scene, v3d, obedit, true, uvs, op);
break;
- case 1:
+ case MESH_MERGE_LAST:
ok = merge_firstlast(em, false, uvs, op);
break;
- case 6:
+ case MESH_MERGE_FIRST:
ok = merge_firstlast(em, true, uvs, op);
break;
- case 5:
- ok = true;
- if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
- ok = false;
+ case MESH_MERGE_COLLAPSE:
+ ok = EDBM_op_callf(em, op, "collapse edges=%he uvs=%b", BM_ELEM_SELECT, uvs);
break;
default:
BLI_assert(0);
@@ -1814,15 +2204,20 @@ static int edbm_merge_exec(bContext *C, wmOperator *op)
EDBM_update_generic(em, true, true);
+ /* once collapsed, we can't have edge/face selection */
+ if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ }
+
return OPERATOR_FINISHED;
}
static EnumPropertyItem merge_type_items[] = {
- {6, "FIRST", 0, "At First", ""},
- {1, "LAST", 0, "At Last", ""},
- {3, "CENTER", 0, "At Center", ""},
- {4, "CURSOR", 0, "At Cursor", ""},
- {5, "COLLAPSE", 0, "Collapse", ""},
+ {MESH_MERGE_FIRST, "FIRST", 0, "At First", ""},
+ {MESH_MERGE_LAST, "LAST", 0, "At Last", ""},
+ {MESH_MERGE_CENTER, "CENTER", 0, "At Center", ""},
+ {MESH_MERGE_CURSOR, "CURSOR", 0, "At Cursor", ""},
+ {MESH_MERGE_COLLAPSE, "COLLAPSE", 0, "Collapse", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1844,20 +2239,20 @@ static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr),
((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT)
{
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
}
else if (em->bm->selected.first && ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_FIRST);
}
else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_LAST);
}
}
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CENTER);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_CURSOR);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, MESH_MERGE_COLLAPSE);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1884,9 +2279,9 @@ void MESH_OT_merge(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use");
+ ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, MESH_MERGE_CENTER, "Type", "Merge method to use");
RNA_def_enum_funcs(ot->prop, merge_type_itemf);
- RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge");
+ RNA_def_boolean(ot->srna, "uvs", false, "UVs", "Move UVs according to merge");
}
@@ -1962,9 +2357,9 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 0.00001, 10.0);
- RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices");
}
@@ -2158,9 +2553,9 @@ void MESH_OT_blend_from_shape(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna, "shape", DummyRNA_NULL_items, 0, "Shape", "Shape key to use for blending");
RNA_def_enum_funcs(prop, shape_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
- RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather than blend between shapes");
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_NEVER_UNLINK);
+ RNA_def_float(ot->srna, "blend", 1.0f, -1e3f, 1e3f, "Blend", "Blending factor", -2.0f, 2.0f);
+ RNA_def_boolean(ot->srna, "add", true, "Add", "Add rather than blend between shapes");
}
static int edbm_solidify_exec(bContext *C, wmOperator *op)
@@ -2213,8 +2608,8 @@ void MESH_OT_solidify(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
- RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
}
/* ******************************************************************** */
@@ -2507,7 +2902,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
if (mode == KNIFE_MIDPOINT) numcuts = 1;
BMO_slot_int_set(bmop.slots_in, "cuts", numcuts);
- BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_STRAIGHT_CUT);
+ BMO_slot_int_set(bmop.slots_in, "quad_corner_type", SUBD_CORNER_STRAIGHT_CUT);
BMO_slot_bool_set(bmop.slots_in, "use_single_edge", false);
BMO_slot_bool_set(bmop.slots_in, "use_grid_fill", false);
@@ -2547,9 +2942,18 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
}
+
+/* *************** Operator: separate parts *************/
+
+enum {
+ MESH_SEPARATE_SELECTED = 0,
+ MESH_SEPARATE_MATERIAL = 1,
+ MESH_SEPARATE_LOOSE = 2,
+};
+
static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMesh *bm_old)
{
Base *base_new;
@@ -2679,7 +3083,7 @@ static void mesh_separate_material_assign_mat_nr(Object *ob, const short mat_nr)
}
if (mat_nr < *totcolp) {
- ma_obdata = (*matarar)[mat_nr];
+ ma_obdata = (*matarar)[mat_nr];
}
else {
ma_obdata = NULL;
@@ -2833,17 +3237,27 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
}
/* editmode separate */
- if (type == 0) retval = mesh_separate_selected(bmain, scene, base, em->bm);
- else if (type == 1) retval = mesh_separate_material(bmain, scene, base, em->bm);
- else if (type == 2) retval = mesh_separate_loose(bmain, scene, base, em->bm);
- else BLI_assert(0);
+ switch (type) {
+ case MESH_SEPARATE_SELECTED:
+ retval = mesh_separate_selected(bmain, scene, base, em->bm);
+ break;
+ case MESH_SEPARATE_MATERIAL:
+ retval = mesh_separate_material(bmain, scene, base, em->bm);
+ break;
+ case MESH_SEPARATE_LOOSE:
+ retval = mesh_separate_loose(bmain, scene, base, em->bm);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (retval) {
EDBM_update_generic(em, true, true);
}
}
else {
- if (type == 0) {
+ if (type == MESH_SEPARATE_SELECTED) {
BKE_report(op->reports, RPT_ERROR, "Selection not supported in object mode");
return OPERATOR_CANCELLED;
}
@@ -2862,9 +3276,17 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
BM_mesh_bm_from_me(bm_old, me, false, false, 0);
- if (type == 1) retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
- else if (type == 2) retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
- else BLI_assert(0);
+ switch (type) {
+ case MESH_SEPARATE_MATERIAL:
+ retval_iter = mesh_separate_material(bmain, scene, base_iter, bm_old);
+ break;
+ case MESH_SEPARATE_LOOSE:
+ retval_iter = mesh_separate_loose(bmain, scene, base_iter, bm_old);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
if (retval_iter) {
BM_mesh_bm_to_me(bm_old, me, false);
@@ -2893,17 +3315,15 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-/* *************** Operator: separate parts *************/
-
-static EnumPropertyItem prop_separate_types[] = {
- {0, "SELECTED", 0, "Selection", ""},
- {1, "MATERIAL", 0, "By Material", ""},
- {2, "LOOSE", 0, "By loose parts", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
void MESH_OT_separate(wmOperatorType *ot)
{
+ static EnumPropertyItem prop_separate_types[] = {
+ {MESH_SEPARATE_SELECTED, "SELECTED", 0, "Selection", ""},
+ {MESH_SEPARATE_MATERIAL, "MATERIAL", 0, "By Material", ""},
+ {MESH_SEPARATE_LOOSE, "LOOSE", 0, "By loose parts", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Separate";
ot->description = "Separate selected geometry into a new mesh";
@@ -2917,7 +3337,7 @@ void MESH_OT_separate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, MESH_SEPARATE_SELECTED, "Type", "");
}
@@ -2927,7 +3347,14 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool use_beauty = RNA_boolean_get(op->ptr, "use_beauty");
BMOperator bmop;
-
+ const int totface_orig = em->bm->totface;
+ int ret;
+
+ if (em->bm->totedgesel == 0) {
+ BKE_report(op->reports, RPT_WARNING, "No edges selected");
+ return OPERATOR_CANCELLED;
+ }
+
if (!EDBM_op_init(em, &bmop, op,
"triangle_fill edges=%he use_beauty=%b",
BM_ELEM_SELECT, use_beauty))
@@ -2937,17 +3364,24 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
BMO_op_exec(em->bm, &bmop);
- /* select new geometry */
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
-
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return OPERATOR_CANCELLED;
+ if (totface_orig != em->bm->totface) {
+ /* select new geometry */
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, BM_ELEM_SELECT, true);
+
+ EDBM_update_generic(em, true, true);
+
+ ret = OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "No faces filled");
+ ret = OPERATOR_CANCELLED;
}
- EDBM_update_generic(em, true, true);
-
- return OPERATOR_FINISHED;
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ ret = OPERATOR_CANCELLED;
+ }
+ return ret;
}
void MESH_OT_fill(wmOperatorType *ot)
@@ -2997,6 +3431,9 @@ static float edbm_fill_grid_vert_tag_angle(BMVert *v)
*/
static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc)
{
+ /* angle differences below this value are considered 'even'
+ * in that they shouldn't be used to calculate corners used for the 'span' */
+ const float eps_even = 1e-3f;
BMEdge *e;
BMIter iter;
int count;
@@ -3042,13 +3479,15 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
v_act = v_act_link->data;
}
+ /* set this vertex first */
+ BLI_listbase_rotate_first(verts, v_act_link);
+
if (offset != 0) {
v_act_link = BLI_findlink(verts, offset);
v_act = v_act_link->data;
+ BLI_listbase_rotate_first(verts, v_act_link);
}
- /* set this vertex first */
- BLI_listbase_rotate_first(verts, v_act_link);
BM_edgeloop_edges_get(el_store, edges);
@@ -3073,18 +3512,23 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
qsort(ele_sort, verts_len, sizeof(*ele_sort), BLI_sortutil_cmp_float_reverse);
- for (i = 0; i < 4; i++) {
- BMVert *v = ele_sort[i].data;
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- }
+ /* check that we have at least 3 corners,
+ * if the angle on the 3rd angle is roughly the same as the last,
+ * then we can't calculate 3+ corners - fallback to the even span. */
+ if ((ele_sort[2].sort_value - ele_sort[verts_len - 1].sort_value) > eps_even) {
+ for (i = 0; i < 4; i++) {
+ BMVert *v = ele_sort[i].data;
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ }
- /* now find the first... */
- for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) {
- BMVert *v = v_link->data;
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- if (v != v_act) {
- span = i;
- break;
+ /* now find the first... */
+ for (v_link = verts->first, i = 0; i < verts_len / 2; v_link = v_link->next, i++) {
+ BMVert *v = v_link->data;
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (v != v_act) {
+ span = i;
+ break;
+ }
}
}
}
@@ -3196,11 +3640,11 @@ void MESH_OT_fill_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "span", 1, 1, INT_MAX, "Span", "Number of sides (zero disables)", 1, 100);
+ prop = RNA_def_int(ot->srna, "span", 1, 1, 1000, "Span", "Number of sides (zero disables)", 1, 100);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100);
+ prop = RNA_def_int(ot->srna, "offset", 0, -1000, 1000, "Offset", "Number of sides (zero disables)", -100, 100);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_boolean(ot->srna, "use_interp_simple", 0, "Simple Blending", "");
+ RNA_def_boolean(ot->srna, "use_interp_simple", false, "Simple Blending", "");
}
static int edbm_fill_holes_exec(bContext *C, wmOperator *op)
@@ -3238,7 +3682,8 @@ void MESH_OT_fill_holes(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "sides", 4, 0, INT_MAX, "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
+ RNA_def_int(ot->srna, "sides", 4, 0, 1000,
+ "Sides", "Number of sides in hole required to fill (zero fills all holes)", 0, 100);
}
static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
@@ -3358,9 +3803,10 @@ void MESH_OT_poke(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
+ RNA_def_float(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
- RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED, "Poke Center", "Poke Face Center Calculation");
+ RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED,
+ "Poke Center", "Poke Face Center Calculation");
}
/********************** Quad/Tri Operators *************************/
@@ -3414,19 +3860,45 @@ static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int dosharp, douvs, dovcols, domaterials;
- const float limit = RNA_float_get(op->ptr, "limit");
+ bool do_seam, do_sharp, do_uvs, do_vcols, do_materials;
+ float angle_face_threshold, angle_shape_threshold;
+ PropertyRNA *prop;
- dosharp = RNA_boolean_get(op->ptr, "sharp");
- douvs = RNA_boolean_get(op->ptr, "uvs");
- dovcols = RNA_boolean_get(op->ptr, "vcols");
- domaterials = RNA_boolean_get(op->ptr, "materials");
+ /* When joining exactly 2 faces, no limit.
+ * this is useful for one off joins while editing. */
+ prop = RNA_struct_find_property(op->ptr, "face_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_face_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_face_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "shape_threshold");
+ if ((em->bm->totfacesel == 2) &&
+ (RNA_property_is_set(op->ptr, prop) == false))
+ {
+ angle_shape_threshold = DEG2RADF(180.0f);
+ }
+ else {
+ angle_shape_threshold = RNA_property_float_get(op->ptr, prop);
+ }
+
+ do_seam = RNA_boolean_get(op->ptr, "seam");
+ do_sharp = RNA_boolean_get(op->ptr, "sharp");
+ do_uvs = RNA_boolean_get(op->ptr, "uvs");
+ do_vcols = RNA_boolean_get(op->ptr, "vcols");
+ do_materials = RNA_boolean_get(op->ptr, "materials");
if (!EDBM_op_call_and_selectf(
em, op,
"faces.out", true,
- "join_triangles faces=%hf limit=%f cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
- BM_ELEM_SELECT, limit, dosharp, douvs, dovcols, domaterials))
+ "join_triangles faces=%hf angle_face_threshold=%f angle_shape_threshold=%f "
+ "cmp_seam=%b cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
+ BM_ELEM_SELECT, angle_face_threshold, angle_shape_threshold,
+ do_seam, do_sharp, do_uvs, do_vcols, do_materials))
{
return OPERATOR_CANCELLED;
}
@@ -3440,14 +3912,21 @@ static void join_triangle_props(wmOperatorType *ot)
{
PropertyRNA *prop;
- prop = RNA_def_float_rotation(ot->srna, "limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
- "Max Angle", "Angle Limit", 0.0f, DEG2RADF(180.0f));
+ prop = RNA_def_float_rotation(
+ ot->srna, "face_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Face Angle", "Face angle limit", 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_float_default(prop, DEG2RADF(40.0f));
+
+ prop = RNA_def_float_rotation(
+ ot->srna, "shape_threshold", 0, NULL, 0.0f, DEG2RADF(180.0f),
+ "Max Shape Angle", "Shape angle limit", 0.0f, DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(40.0f));
- RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", "");
- RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", "");
- RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", "");
- RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", "");
+ RNA_def_boolean(ot->srna, "uvs", false, "Compare UVs", "");
+ RNA_def_boolean(ot->srna, "vcols", false, "Compare VCols", "");
+ RNA_def_boolean(ot->srna, "seam", false, "Compare Seam", "");
+ RNA_def_boolean(ot->srna, "sharp", false, "Compare Sharp", "");
+ RNA_def_boolean(ot->srna, "materials", false, "Compare Materials", "");
}
void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
@@ -3470,19 +3949,25 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
/* -------------------------------------------------------------------- */
/* Dissolve */
-static void edbm_dissolve_prop__use_verts(wmOperatorType *ot)
+static void edbm_dissolve_prop__use_verts(wmOperatorType *ot, bool value, int flag)
{
- RNA_def_boolean(ot->srna, "use_verts", 0, "Dissolve Verts",
- "Dissolve remaining vertices");
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(ot->srna, "use_verts", value, "Dissolve Verts",
+ "Dissolve remaining vertices");
+
+ if (flag) {
+ RNA_def_property_flag(prop, flag);
+ }
}
static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "use_face_split", 0, "Face Split",
+ RNA_def_boolean(ot->srna, "use_face_split", false, "Face Split",
"Split off face corners to maintain surrounding geometry");
}
static void edbm_dissolve_prop__use_boundary_tear(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "use_boundary_tear", 0, "Tear Boundary",
+ RNA_def_boolean(ot->srna, "use_boundary_tear", false, "Tear Boundary",
"Split off face corners instead of merging faces");
}
@@ -3558,7 +4043,7 @@ void MESH_OT_dissolve_edges(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- edbm_dissolve_prop__use_verts(ot);
+ edbm_dissolve_prop__use_verts(ot, true, 0);
edbm_dissolve_prop__use_face_split(ot);
}
@@ -3597,7 +4082,7 @@ void MESH_OT_dissolve_faces(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- edbm_dissolve_prop__use_verts(ot);
+ edbm_dissolve_prop__use_verts(ot, false, 0);
}
@@ -3605,6 +4090,15 @@ static int edbm_dissolve_mode_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "use_verts");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ /* always enable in edge-mode */
+ if ((em->selectmode & SCE_SELECT_FACE) == 0) {
+ RNA_property_boolean_set(op->ptr, prop, true);
+ }
+ }
if (em->selectmode & SCE_SELECT_VERTEX) {
return edbm_dissolve_verts_exec(C, op);
@@ -3631,7 +4125,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- edbm_dissolve_prop__use_verts(ot);
+ edbm_dissolve_prop__use_verts(ot, false, PROP_SKIP_SAVE);
edbm_dissolve_prop__use_face_split(ot);
edbm_dissolve_prop__use_boundary_tear(ot);
}
@@ -3707,9 +4201,9 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
"Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f));
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
- RNA_def_boolean(ot->srna, "use_dissolve_boundaries", 0, "All Boundaries",
+ RNA_def_boolean(ot->srna, "use_dissolve_boundaries", false, "All Boundaries",
"Dissolve all vertices inbetween face boundaries");
- RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, 0, "Delimit",
+ RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_NORMAL, "Delimit",
"Delimit dissolve operation");
}
@@ -3753,8 +4247,8 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 0.00001, 10.0);
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
}
@@ -3792,6 +4286,8 @@ static int edbm_delete_edgeloop_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
+
EDBM_update_generic(em, true, true);
return OPERATOR_FINISHED;
@@ -4431,8 +4927,9 @@ void MESH_OT_sort_elements(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Type of re-ordering operation to apply");
- RNA_def_enum_flag(ot->srna, "elements", elem_items, 0, "Elements",
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, SRT_VIEW_ZAXIS,
+ "Type", "Type of re-ordering operation to apply");
+ RNA_def_enum_flag(ot->srna, "elements", elem_items, BM_VERT, "Elements",
"Which elements to affect (vertices, edges and/or faces)");
RNA_def_boolean(ot->srna, "reverse", false, "Reverse", "Reverse the sorting effect");
RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for random-based operations", 0, 255);
@@ -4480,7 +4977,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL);
+ externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false);
eve->co[2] += fac * tin;
}
}
@@ -4507,10 +5004,16 @@ void MESH_OT_noise(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "factor", 0.1f, -1e4f, 1e4f, "Factor", "", 0.0f, 1.0f);
}
+enum {
+ MESH_BRIDGELOOP_SINGLE = 0,
+ MESH_BRIDGELOOP_CLOSED = 1,
+ MESH_BRIDGELOOP_PAIRS = 2,
+};
+
static int edbm_bridge_tag_boundary_edges(BMesh *bm)
{
/* tags boundary edges from a face selection */
@@ -4559,8 +5062,8 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int type = RNA_enum_get(op->ptr, "type");
- const bool use_pairs = (type == 2);
- const bool use_cyclic = (type == 1);
+ const bool use_pairs = (type == MESH_BRIDGELOOP_PAIRS);
+ const bool use_cyclic = (type == MESH_BRIDGELOOP_CLOSED);
const bool use_merge = RNA_boolean_get(op->ptr, "use_merge");
const float merge_factor = RNA_float_get(op->ptr, "merge_factor");
const int twist_offset = RNA_int_get(op->ptr, "twist_offset");
@@ -4658,9 +5161,9 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
{
static EnumPropertyItem type_items[] = {
- {0, "SINGLE", 0, "Open Loop", ""},
- {1, "CLOSED", 0, "Closed Loop", ""},
- {2, "PAIRS", 0, "Loop Pairs", ""},
+ {MESH_BRIDGELOOP_SINGLE, "SINGLE", 0, "Open Loop", ""},
+ {MESH_BRIDGELOOP_CLOSED, "CLOSED", 0, "Closed Loop", ""},
+ {MESH_BRIDGELOOP_PAIRS, "PAIRS", 0, "Loop Pairs", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -4676,7 +5179,7 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0,
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, MESH_BRIDGELOOP_SINGLE,
"Connect Loops", "Method of bridging multiple loops");
RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces");
@@ -4737,19 +5240,73 @@ void MESH_OT_wireframe(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
- RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
+ RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
+ RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
- RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, FLT_MAX, "Thickness", "", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
+ prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, FLT_MAX, "Offset", "", 0.0f, 10.0f);
- RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf");
- prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, FLT_MAX, "Crease weight", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f);
+ RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf");
+ prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
}
+static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMOperator bmop;
+ const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
+
+ EDBM_op_init(
+ em, &bmop, op,
+ "offset_edgeloops edges=%he use_cap_endpoint=%b",
+ BM_ELEM_SELECT, use_cap_endpoint);
+
+ BMO_op_exec(em->bm, &bmop);
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ /* If in face-only select mode, switch to edge select mode so that
+ * an edge-only selection is not inconsistent state */
+ if (em->selectmode == SCE_SELECT_FACE) {
+ em->selectmode = SCE_SELECT_EDGE;
+ EDBM_selectmode_set(em);
+ EDBM_selectmode_to_scene(C);
+ }
+
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+ }
+}
+
+void MESH_OT_offset_edge_loops(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Offset Edge Loop";
+ ot->idname = "MESH_OT_offset_edge_loops";
+ ot->description = "Create offset edge loop from the current selection";
+
+ /* api callbacks */
+ ot->exec = edbm_offset_edgeloop_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* Keep internal, since this is only meant to be accessed via 'MESH_OT_offset_edge_loops_slide' */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ RNA_def_boolean(ot->srna, "use_cap_endpoint", false, "Cap Endpoint", "Extend loop around end-points");
+}
+
#ifdef WITH_BULLET
static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
{
@@ -4793,11 +5350,16 @@ static int edbm_convex_hull_exec(bContext *C, wmOperator *op)
/* Merge adjacent triangles */
if (RNA_boolean_get(op->ptr, "join_triangles")) {
- if (!EDBM_op_call_and_selectf(em, op,
- "faces.out", true,
- "join_triangles faces=%S limit=%f",
- &bmop, "geom.out",
- RNA_float_get(op->ptr, "limit")))
+ float angle_face_threshold = RNA_float_get(op->ptr, "face_threshold");
+ float angle_shape_threshold = RNA_float_get(op->ptr, "shape_threshold");
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "join_triangles faces=%S "
+ "angle_face_threshold=%f angle_shape_threshold=%f",
+ &bmop, "geom.out",
+ angle_face_threshold, angle_shape_threshold))
{
EDBM_op_finish(em, &bmop, op, true);
return OPERATOR_CANCELLED;
@@ -4893,7 +5455,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
- RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Threshold", "", 0.00001, 0.1);
+ RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", "", 1e-5f, 0.1f);
}
static int mesh_symmetry_snap_exec(bContext *C, wmOperator *op)
@@ -5017,8 +5579,8 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
- RNA_def_float(ot->srna, "threshold", 0.05, 0.0, 10.0, "Threshold", "", 0.0001, 1.0);
- RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
+ RNA_def_float(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f);
+ RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center");
}
@@ -5085,7 +5647,7 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+ prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -5149,7 +5711,7 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+ prop = RNA_def_boolean(ot->srna, "clear", false, "Clear", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}