diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_bevel.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_bevel.c | 1575 |
1 files changed, 830 insertions, 745 deletions
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 1059374dcc5..2c0c8b2c708 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -51,10 +51,9 @@ #include "ED_transform.h" #include "ED_view3d.h" -#include "mesh_intern.h" /* own include */ +#include "mesh_intern.h" /* own include */ - -#define MVAL_PIXEL_MARGIN 5.0f +#define MVAL_PIXEL_MARGIN 5.0f #define PROFILE_HARD_MIN 0.0f @@ -67,839 +66,925 @@ #define SEGMENTS_VALUE 3 #define NUM_VALUE_KINDS 4 -static const char *value_rna_name[NUM_VALUE_KINDS] = {"offset", "offset_pct", "profile", "segments"}; +static const char *value_rna_name[NUM_VALUE_KINDS] = { + "offset", "offset_pct", "profile", "segments"}; static const float value_clamp_min[NUM_VALUE_KINDS] = {0.0f, 0.0f, PROFILE_HARD_MIN, 1.0f}; static const float value_clamp_max[NUM_VALUE_KINDS] = {1e6, 100.0f, 1.0f, SEGMENTS_HARD_MAX}; static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f}; -static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, 4.0f}; +static const float value_scale_per_inch[NUM_VALUE_KINDS] = {0.0f, 100.0f, 1.0f, 4.0f}; typedef struct { - BMEditMesh *em; - BMBackup mesh_backup; + BMEditMesh *em; + BMBackup mesh_backup; } BevelObjectStore; - typedef struct { - float initial_length[NUM_VALUE_KINDS]; - float scale[NUM_VALUE_KINDS]; - NumInput num_input[NUM_VALUE_KINDS]; - /** The current value when shift is pressed. Negative when shift not active. */ - float shift_value[NUM_VALUE_KINDS]; - float max_obj_scale; - bool is_modal; - - BevelObjectStore *ob_store; - uint ob_store_len; - - /* modal only */ - float mcenter[2]; - void *draw_handle_pixel; - short gizmo_flag; - short value_mode; /* Which value does mouse movement and numeric input affect? */ - float segments; /* Segments as float so smooth mouse pan works in small increments */ + float initial_length[NUM_VALUE_KINDS]; + float scale[NUM_VALUE_KINDS]; + NumInput num_input[NUM_VALUE_KINDS]; + /** The current value when shift is pressed. Negative when shift not active. */ + float shift_value[NUM_VALUE_KINDS]; + float max_obj_scale; + bool is_modal; + + BevelObjectStore *ob_store; + uint ob_store_len; + + /* modal only */ + float mcenter[2]; + void *draw_handle_pixel; + short gizmo_flag; + short value_mode; /* Which value does mouse movement and numeric input affect? */ + float segments; /* Segments as float so smooth mouse pan works in small increments */ } BevelData; enum { - BEV_MODAL_CANCEL = 1, - BEV_MODAL_CONFIRM, - BEV_MODAL_VALUE_OFFSET, - BEV_MODAL_VALUE_PROFILE, - BEV_MODAL_VALUE_SEGMENTS, - BEV_MODAL_SEGMENTS_UP, - BEV_MODAL_SEGMENTS_DOWN, - BEV_MODAL_OFFSET_MODE_CHANGE, - BEV_MODAL_CLAMP_OVERLAP_TOGGLE, - BEV_MODAL_VERTEX_ONLY_TOGGLE, - BEV_MODAL_HARDEN_NORMALS_TOGGLE, - BEV_MODAL_MARK_SEAM_TOGGLE, - BEV_MODAL_MARK_SHARP_TOGGLE, - BEV_MODAL_OUTER_MITER_CHANGE, - BEV_MODAL_INNER_MITER_CHANGE, + BEV_MODAL_CANCEL = 1, + BEV_MODAL_CONFIRM, + BEV_MODAL_VALUE_OFFSET, + BEV_MODAL_VALUE_PROFILE, + BEV_MODAL_VALUE_SEGMENTS, + BEV_MODAL_SEGMENTS_UP, + BEV_MODAL_SEGMENTS_DOWN, + BEV_MODAL_OFFSET_MODE_CHANGE, + BEV_MODAL_CLAMP_OVERLAP_TOGGLE, + BEV_MODAL_VERTEX_ONLY_TOGGLE, + BEV_MODAL_HARDEN_NORMALS_TOGGLE, + BEV_MODAL_MARK_SEAM_TOGGLE, + BEV_MODAL_MARK_SHARP_TOGGLE, + BEV_MODAL_OUTER_MITER_CHANGE, + BEV_MODAL_INNER_MITER_CHANGE, }; static float get_bevel_offset(wmOperator *op) { - float val; + float val; - if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) - val = RNA_float_get(op->ptr, "offset_pct"); - else - val = RNA_float_get(op->ptr, "offset"); - return val; + if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) + val = RNA_float_get(op->ptr, "offset_pct"); + else + val = RNA_float_get(op->ptr, "offset"); + return val; } static void edbm_bevel_update_header(bContext *C, wmOperator *op) { - char header[UI_MAX_DRAW_STR]; - char buf[UI_MAX_DRAW_STR]; - char *p = buf; - int available_len = sizeof(buf); - Scene *sce = CTX_data_scene(C); - char offset_str[NUM_STR_REP_LEN]; - const char *mode_str, *omiter_str, *imiter_str; - PropertyRNA *prop; + char header[UI_MAX_DRAW_STR]; + char buf[UI_MAX_DRAW_STR]; + char *p = buf; + int available_len = sizeof(buf); + Scene *sce = CTX_data_scene(C); + char offset_str[NUM_STR_REP_LEN]; + const char *mode_str, *omiter_str, *imiter_str; + PropertyRNA *prop; #define WM_MODALKEY(_id) \ - WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) - - if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) { - BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct")); - } - else { - bUnit_AsString2( - offset_str, NUM_STR_REP_LEN, (double)RNA_float_get(op->ptr, "offset"), 3, - B_UNIT_LENGTH, &sce->unit, true); - } - - prop = RNA_struct_find_property(op->ptr, "offset_type"); - RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &mode_str); - prop = RNA_struct_find_property(op->ptr, "miter_outer"); - RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &omiter_str); - prop = RNA_struct_find_property(op->ptr, "miter_inner"); - RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &imiter_str); - - BLI_snprintf( - header, sizeof(header), - IFACE_("%s: confirm, " - "%s: cancel, " - "%s: mode (%s), " - "%s: width (%s), " - "%s: segments (%d), " - "%s: profile (%.3f), " - "%s: clamp overlap (%s), " - "%s: vertex only (%s), " - "%s: outer miter (%s), " - "%s: inner miter (%s), " - "%s: harden normals (%s), " - "%s: mark seam (%s), " - "%s: mark sharp (%s)" - ), - WM_MODALKEY(BEV_MODAL_CONFIRM), - WM_MODALKEY(BEV_MODAL_CANCEL), - WM_MODALKEY(BEV_MODAL_OFFSET_MODE_CHANGE), - mode_str, - WM_MODALKEY(BEV_MODAL_VALUE_OFFSET), - offset_str, - WM_MODALKEY(BEV_MODAL_VALUE_SEGMENTS), - RNA_int_get(op->ptr, "segments"), - WM_MODALKEY(BEV_MODAL_VALUE_PROFILE), - RNA_float_get(op->ptr, "profile"), - WM_MODALKEY(BEV_MODAL_CLAMP_OVERLAP_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")), - WM_MODALKEY(BEV_MODAL_VERTEX_ONLY_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")), - WM_MODALKEY(BEV_MODAL_OUTER_MITER_CHANGE), - omiter_str, - WM_MODALKEY(BEV_MODAL_INNER_MITER_CHANGE), - imiter_str, - WM_MODALKEY(BEV_MODAL_HARDEN_NORMALS_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "harden_normals")), - WM_MODALKEY(BEV_MODAL_MARK_SEAM_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_seam")), - WM_MODALKEY(BEV_MODAL_MARK_SHARP_TOGGLE), - WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")) - ); + WM_modalkeymap_operator_items_to_string_buf( \ + op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) + + if (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT) { + BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct")); + } + else { + bUnit_AsString2(offset_str, + NUM_STR_REP_LEN, + (double)RNA_float_get(op->ptr, "offset"), + 3, + B_UNIT_LENGTH, + &sce->unit, + true); + } + + prop = RNA_struct_find_property(op->ptr, "offset_type"); + RNA_property_enum_name_gettexted( + C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &mode_str); + prop = RNA_struct_find_property(op->ptr, "miter_outer"); + RNA_property_enum_name_gettexted( + C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &omiter_str); + prop = RNA_struct_find_property(op->ptr, "miter_inner"); + RNA_property_enum_name_gettexted( + C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &imiter_str); + + BLI_snprintf(header, + sizeof(header), + IFACE_("%s: confirm, " + "%s: cancel, " + "%s: mode (%s), " + "%s: width (%s), " + "%s: segments (%d), " + "%s: profile (%.3f), " + "%s: clamp overlap (%s), " + "%s: vertex only (%s), " + "%s: outer miter (%s), " + "%s: inner miter (%s), " + "%s: harden normals (%s), " + "%s: mark seam (%s), " + "%s: mark sharp (%s)"), + WM_MODALKEY(BEV_MODAL_CONFIRM), + WM_MODALKEY(BEV_MODAL_CANCEL), + WM_MODALKEY(BEV_MODAL_OFFSET_MODE_CHANGE), + mode_str, + WM_MODALKEY(BEV_MODAL_VALUE_OFFSET), + offset_str, + WM_MODALKEY(BEV_MODAL_VALUE_SEGMENTS), + RNA_int_get(op->ptr, "segments"), + WM_MODALKEY(BEV_MODAL_VALUE_PROFILE), + RNA_float_get(op->ptr, "profile"), + WM_MODALKEY(BEV_MODAL_CLAMP_OVERLAP_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")), + WM_MODALKEY(BEV_MODAL_VERTEX_ONLY_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")), + WM_MODALKEY(BEV_MODAL_OUTER_MITER_CHANGE), + omiter_str, + WM_MODALKEY(BEV_MODAL_INNER_MITER_CHANGE), + imiter_str, + WM_MODALKEY(BEV_MODAL_HARDEN_NORMALS_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "harden_normals")), + WM_MODALKEY(BEV_MODAL_MARK_SEAM_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_seam")), + WM_MODALKEY(BEV_MODAL_MARK_SHARP_TOGGLE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp"))); #undef WM_MODALKEY - ED_workspace_status_text(C, header); + ED_workspace_status_text(C, header); } static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) { - Scene *scene = CTX_data_scene(C); - BevelData *opdata; - ViewLayer *view_layer = CTX_data_view_layer(C); - float pixels_per_inch; - int i, otype; - - if (is_modal) { - RNA_float_set(op->ptr, "offset", 0.0f); - RNA_float_set(op->ptr, "offset_pct", 0.0f); - } - - op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); - uint objects_used_len = 0; - opdata->max_obj_scale = FLT_MIN; - - { - uint ob_store_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( - view_layer, CTX_wm_view3d(C), &ob_store_len); - opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); - for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { - Object *obedit = objects[ob_index]; - float scale = mat4_to_scale(obedit->obmat); - opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totvertsel > 0) { - opdata->ob_store[objects_used_len].em = em; - objects_used_len++; - } - } - MEM_freeN(objects); - opdata->ob_store_len = objects_used_len; - } - - opdata->is_modal = is_modal; - otype = RNA_enum_get(op->ptr, "offset_type"); - opdata->value_mode = (otype == BEVEL_AMT_PERCENT) ? OFFSET_VALUE_PERCENT : OFFSET_VALUE; - opdata->segments = (float) RNA_int_get(op->ptr, "segments"); - pixels_per_inch = U.dpi * U.pixelsize; - - for (i = 0; i < NUM_VALUE_KINDS; i++) { - opdata->shift_value[i] = -1.0f; - opdata->initial_length[i] = -1.0f; - /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */ - opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; - - initNumInput(&opdata->num_input[i]); - opdata->num_input[i].idx_max = 0; - opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE; - if (i == SEGMENTS_VALUE) { - opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO; - } - if (i == OFFSET_VALUE) { - opdata->num_input[i].unit_sys = scene->unit.system; - } - /* Not sure this is a factor or a unit? */ - opdata->num_input[i].unit_type[0] = B_UNIT_NONE; - } - - /* avoid the cost of allocating a bm copy */ - if (is_modal) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store(opdata->ob_store[ob_index].em); - } - opdata->draw_handle_pixel = ED_region_draw_cb_activate( - ar->type, ED_region_draw_mouse_line_cb, - opdata->mcenter, REGION_DRAW_POST_PIXEL); - G.moving = G_TRANSFORM_EDIT; - - if (v3d) { - opdata->gizmo_flag = v3d->gizmo_flag; - v3d->gizmo_flag = V3D_GIZMO_HIDE; - } - } - - return true; + Scene *scene = CTX_data_scene(C); + BevelData *opdata; + ViewLayer *view_layer = CTX_data_view_layer(C); + float pixels_per_inch; + int i, otype; + + if (is_modal) { + RNA_float_set(op->ptr, "offset", 0.0f); + RNA_float_set(op->ptr, "offset_pct", 0.0f); + } + + op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); + uint objects_used_len = 0; + opdata->max_obj_scale = FLT_MIN; + + { + uint ob_store_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + view_layer, CTX_wm_view3d(C), &ob_store_len); + opdata->ob_store = MEM_malloc_arrayN(ob_store_len, sizeof(*opdata->ob_store), __func__); + for (uint ob_index = 0; ob_index < ob_store_len; ob_index++) { + Object *obedit = objects[ob_index]; + float scale = mat4_to_scale(obedit->obmat); + opdata->max_obj_scale = max_ff(opdata->max_obj_scale, scale); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + if (em->bm->totvertsel > 0) { + opdata->ob_store[objects_used_len].em = em; + objects_used_len++; + } + } + MEM_freeN(objects); + opdata->ob_store_len = objects_used_len; + } + + opdata->is_modal = is_modal; + otype = RNA_enum_get(op->ptr, "offset_type"); + opdata->value_mode = (otype == BEVEL_AMT_PERCENT) ? OFFSET_VALUE_PERCENT : OFFSET_VALUE; + opdata->segments = (float)RNA_int_get(op->ptr, "segments"); + pixels_per_inch = U.dpi * U.pixelsize; + + for (i = 0; i < NUM_VALUE_KINDS; i++) { + opdata->shift_value[i] = -1.0f; + opdata->initial_length[i] = -1.0f; + /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */ + opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; + + initNumInput(&opdata->num_input[i]); + opdata->num_input[i].idx_max = 0; + opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE; + if (i == SEGMENTS_VALUE) { + opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO; + } + if (i == OFFSET_VALUE) { + opdata->num_input[i].unit_sys = scene->unit.system; + } + /* Not sure this is a factor or a unit? */ + opdata->num_input[i].unit_type[0] = B_UNIT_NONE; + } + + /* avoid the cost of allocating a bm copy */ + if (is_modal) { + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + opdata->ob_store[ob_index].mesh_backup = EDBM_redo_state_store( + opdata->ob_store[ob_index].em); + } + opdata->draw_handle_pixel = ED_region_draw_cb_activate( + ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); + G.moving = G_TRANSFORM_EDIT; + + if (v3d) { + opdata->gizmo_flag = v3d->gizmo_flag; + v3d->gizmo_flag = V3D_GIZMO_HIDE; + } + } + + return true; } static bool edbm_bevel_calc(wmOperator *op) { - BevelData *opdata = op->customdata; - BMEditMesh *em; - BMOperator bmop; - bool changed = false; - - const float offset = get_bevel_offset(op); - const int offset_type = RNA_enum_get(op->ptr, "offset_type"); - const int segments = RNA_int_get(op->ptr, "segments"); - const float profile = RNA_float_get(op->ptr, "profile"); - const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); - const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); - int material = RNA_int_get(op->ptr, "material"); - const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); - const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); - const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); - const bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); - const int face_strength_mode = RNA_enum_get(op->ptr, "face_strength_mode"); - const int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); - const int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); - const float spread = RNA_float_get(op->ptr, "spread"); - - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - em = opdata->ob_store[ob_index].em; - - /* revert to original mesh */ - if (opdata->is_modal) { - EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); - } - - if (em->ob) { - material = CLAMPIS(material, -1, em->ob->totcol - 1); - } - - Mesh *me = em->ob->data; - - if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) { - /* harden_normals only has a visible effect if autosmooth is on, so turn it on */ - me->flag |= ME_AUTOSMOOTH; - } - - EDBM_op_init( - em, &bmop, op, - "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f " - "clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b " - "harden_normals=%b face_strength_mode=%i " - "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f", - BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, - clamp_overlap, material, loop_slide, mark_seam, mark_sharp, harden_normals, face_strength_mode, - miter_outer, miter_inner, spread, me->smoothresh); - - BMO_op_exec(em->bm, &bmop); - - if (offset != 0.0f) { - /* not essential, but we may have some loose geometry that - * won't get bevel'd and better not leave it selected */ - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); - } - - /* no need to de-select existing geometry */ - if (!EDBM_op_finish(em, &bmop, op, true)) { - continue; - } - - EDBM_mesh_normals_update(em); - - EDBM_update_generic(em, true, true); - changed = true; - } - return changed; + BevelData *opdata = op->customdata; + BMEditMesh *em; + BMOperator bmop; + bool changed = false; + + const float offset = get_bevel_offset(op); + const int offset_type = RNA_enum_get(op->ptr, "offset_type"); + const int segments = RNA_int_get(op->ptr, "segments"); + const float profile = RNA_float_get(op->ptr, "profile"); + const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); + const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); + int material = RNA_int_get(op->ptr, "material"); + const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide"); + const bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); + const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + const bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); + const int face_strength_mode = RNA_enum_get(op->ptr, "face_strength_mode"); + const int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); + const int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); + const float spread = RNA_float_get(op->ptr, "spread"); + + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + em = opdata->ob_store[ob_index].em; + + /* revert to original mesh */ + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->ob_store[ob_index].mesh_backup, em, false); + } + + if (em->ob) { + material = CLAMPIS(material, -1, em->ob->totcol - 1); + } + + Mesh *me = em->ob->data; + + if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) { + /* harden_normals only has a visible effect if autosmooth is on, so turn it on */ + me->flag |= ME_AUTOSMOOTH; + } + + EDBM_op_init(em, + &bmop, + op, + "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f " + "clamp_overlap=%b material=%i loop_slide=%b mark_seam=%b mark_sharp=%b " + "harden_normals=%b face_strength_mode=%i " + "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f", + BM_ELEM_SELECT, + offset, + segments, + vertex_only, + offset_type, + profile, + clamp_overlap, + material, + loop_slide, + mark_seam, + mark_sharp, + harden_normals, + face_strength_mode, + miter_outer, + miter_inner, + spread, + me->smoothresh); + + BMO_op_exec(em->bm, &bmop); + + if (offset != 0.0f) { + /* not essential, but we may have some loose geometry that + * won't get bevel'd and better not leave it selected */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable( + em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); + } + + /* no need to de-select existing geometry */ + if (!EDBM_op_finish(em, &bmop, op, true)) { + continue; + } + + EDBM_mesh_normals_update(em); + + EDBM_update_generic(em, true, true); + changed = true; + } + return changed; } static void edbm_bevel_exit(bContext *C, wmOperator *op) { - BevelData *opdata = op->customdata; - - ScrArea *sa = CTX_wm_area(C); - - if (sa) { - ED_area_status_text(sa, NULL); - } - - if (opdata->is_modal) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false); - } - ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); - if (v3d) { - v3d->gizmo_flag = opdata->gizmo_flag; - } - G.moving = 0; - } - MEM_SAFE_FREE(opdata->ob_store); - MEM_SAFE_FREE(op->customdata); - op->customdata = NULL; + BevelData *opdata = op->customdata; + + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + ED_area_status_text(sa, NULL); + } + + if (opdata->is_modal) { + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, NULL, false); + } + ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); + if (v3d) { + v3d->gizmo_flag = opdata->gizmo_flag; + } + G.moving = 0; + } + MEM_SAFE_FREE(opdata->ob_store); + MEM_SAFE_FREE(op->customdata); + op->customdata = NULL; } static void edbm_bevel_cancel(bContext *C, wmOperator *op) { - BevelData *opdata = op->customdata; - if (opdata->is_modal) { - for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { - EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true); - EDBM_update_generic(opdata->ob_store[ob_index].em, false, true); - } - } - - edbm_bevel_exit(C, op); - - /* need to force redisplay or we may still view the modified result */ - ED_region_tag_redraw(CTX_wm_region(C)); + BevelData *opdata = op->customdata; + if (opdata->is_modal) { + for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { + EDBM_redo_state_free( + &opdata->ob_store[ob_index].mesh_backup, opdata->ob_store[ob_index].em, true); + EDBM_update_generic(opdata->ob_store[ob_index].em, false, true); + } + } + + edbm_bevel_exit(C, op); + + /* need to force redisplay or we may still view the modified result */ + ED_region_tag_redraw(CTX_wm_region(C)); } /* bevel! yay!!*/ static int edbm_bevel_exec(bContext *C, wmOperator *op) { - if (!edbm_bevel_init(C, op, false)) { - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_init(C, op, false)) { + return OPERATOR_CANCELLED; + } - if (!edbm_bevel_calc(op)) { - edbm_bevel_cancel(C, op); - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_calc(op)) { + edbm_bevel_cancel(C, op); + return OPERATOR_CANCELLED; + } - edbm_bevel_exit(C, op); + edbm_bevel_exit(C, op); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, bool mode_changed) { - BevelData *opdata; - float mlen[2], len, value, sc, st; - int vmode; - - opdata = op->customdata; - mlen[0] = opdata->mcenter[0] - event->mval[0]; - mlen[1] = opdata->mcenter[1] - event->mval[1]; - len = len_v2(mlen); - vmode = opdata->value_mode; - if (mode_changed || opdata->initial_length[vmode] == -1.0f) { - /* If current value is not default start value, adjust len so that - * the scaling and offset in edbm_bevel_mouse_set_value will - * start at current value */ - value = (vmode == SEGMENTS_VALUE) ? - opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); - sc = opdata->scale[vmode]; - st = value_start[vmode]; - if (value != value_start[vmode]) { - len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc; - } - } - opdata->initial_length[opdata->value_mode] = len; + BevelData *opdata; + float mlen[2], len, value, sc, st; + int vmode; + + opdata = op->customdata; + mlen[0] = opdata->mcenter[0] - event->mval[0]; + mlen[1] = opdata->mcenter[1] - event->mval[1]; + len = len_v2(mlen); + vmode = opdata->value_mode; + if (mode_changed || opdata->initial_length[vmode] == -1.0f) { + /* If current value is not default start value, adjust len so that + * the scaling and offset in edbm_bevel_mouse_set_value will + * start at current value */ + value = (vmode == SEGMENTS_VALUE) ? opdata->segments : + RNA_float_get(op->ptr, value_rna_name[vmode]); + sc = opdata->scale[vmode]; + st = value_start[vmode]; + if (value != value_start[vmode]) { + len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc; + } + } + opdata->initial_length[opdata->value_mode] = len; } static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - BevelData *opdata; - float center_3d[3]; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + BevelData *opdata; + float center_3d[3]; - if (!edbm_bevel_init(C, op, true)) { - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_init(C, op, true)) { + return OPERATOR_CANCELLED; + } - opdata = op->customdata; + opdata = op->customdata; - /* initialize mouse values */ - if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) { - /* in this case the tool will likely do nothing, - * ideally this will never happen and should be checked for above */ - opdata->mcenter[0] = opdata->mcenter[1] = 0; - } + /* initialize mouse values */ + if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEDIAN, center_3d, opdata->mcenter)) { + /* in this case the tool will likely do nothing, + * ideally this will never happen and should be checked for above */ + opdata->mcenter[0] = opdata->mcenter[1] = 0; + } - /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */ - opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; - /* since we are affecting untransformed object but seeing in transformed space, compensate for that */ - opdata->scale[OFFSET_VALUE] /= opdata->max_obj_scale; + /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */ + opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; + /* since we are affecting untransformed object but seeing in transformed space, compensate for that */ + opdata->scale[OFFSET_VALUE] /= opdata->max_obj_scale; - edbm_bevel_calc_initial_length(op, event, false); + edbm_bevel_calc_initial_length(op, event, false); - edbm_bevel_update_header(C, op); + edbm_bevel_update_header(C, op); - if (!edbm_bevel_calc(op)) { - edbm_bevel_cancel(C, op); - ED_workspace_status_text(C, NULL); - return OPERATOR_CANCELLED; - } + if (!edbm_bevel_calc(op)) { + edbm_bevel_cancel(C, op); + ED_workspace_status_text(C, NULL); + return OPERATOR_CANCELLED; + } - WM_event_add_modal_handler(C, op); + WM_event_add_modal_handler(C, op); - return OPERATOR_RUNNING_MODAL; + return OPERATOR_RUNNING_MODAL; } static void edbm_bevel_mouse_set_value(wmOperator *op, const wmEvent *event) { - BevelData *opdata = op->customdata; - int vmode = opdata->value_mode; - float mdiff[2]; - float value; - - mdiff[0] = opdata->mcenter[0] - event->mval[0]; - mdiff[1] = opdata->mcenter[1] - event->mval[1]; - - value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]); - - /* Scale according to value mode */ - value = value_start[vmode] + value * opdata->scale[vmode]; - - /* Fake shift-transform... */ - if (event->shift) { - if (opdata->shift_value[vmode] < 0.0f) { - opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ? - opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); - } - value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode]; - } - else if (opdata->shift_value[vmode] >= 0.0f) { - opdata->shift_value[vmode] = -1.0f; - } - - /* clamp accordingto value mode, and store value back */ - CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); - if (vmode == SEGMENTS_VALUE) { - opdata->segments = value; - RNA_int_set(op->ptr, "segments", (int)(value + 0.5f)); - } - else { - RNA_float_set(op->ptr, value_rna_name[vmode], value); - } + BevelData *opdata = op->customdata; + int vmode = opdata->value_mode; + float mdiff[2]; + float value; + + mdiff[0] = opdata->mcenter[0] - event->mval[0]; + mdiff[1] = opdata->mcenter[1] - event->mval[1]; + + value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]); + + /* Scale according to value mode */ + value = value_start[vmode] + value * opdata->scale[vmode]; + + /* Fake shift-transform... */ + if (event->shift) { + if (opdata->shift_value[vmode] < 0.0f) { + opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ? + opdata->segments : + RNA_float_get(op->ptr, value_rna_name[vmode]); + } + value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode]; + } + else if (opdata->shift_value[vmode] >= 0.0f) { + opdata->shift_value[vmode] = -1.0f; + } + + /* clamp accordingto value mode, and store value back */ + CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); + if (vmode == SEGMENTS_VALUE) { + opdata->segments = value; + RNA_int_set(op->ptr, "segments", (int)(value + 0.5f)); + } + else { + RNA_float_set(op->ptr, value_rna_name[vmode], value); + } } static void edbm_bevel_numinput_set_value(wmOperator *op) { - BevelData *opdata = op->customdata; - float value; - int vmode; - - vmode = opdata->value_mode; - value = (vmode == SEGMENTS_VALUE) ? - opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]); - applyNumInput(&opdata->num_input[vmode], &value); - CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); - if (vmode == SEGMENTS_VALUE) { - opdata->segments = value; - RNA_int_set(op->ptr, "segments", (int)value); - } - else { - RNA_float_set(op->ptr, value_rna_name[vmode], value); - } + BevelData *opdata = op->customdata; + float value; + int vmode; + + vmode = opdata->value_mode; + value = (vmode == SEGMENTS_VALUE) ? opdata->segments : + RNA_float_get(op->ptr, value_rna_name[vmode]); + applyNumInput(&opdata->num_input[vmode], &value); + CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]); + if (vmode == SEGMENTS_VALUE) { + opdata->segments = value; + RNA_int_set(op->ptr, "segments", (int)value); + } + else { + RNA_float_set(op->ptr, value_rna_name[vmode], value); + } } /* Hide one of offset or offset_pct, depending on offset_type */ -static bool edbm_bevel_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) +static bool edbm_bevel_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) { - const char *prop_id = RNA_property_identifier(prop); + const char *prop_id = RNA_property_identifier(prop); - if (STRPREFIX(prop_id, "offset")) { - int offset_type = RNA_enum_get(op->ptr, "offset_type"); + if (STRPREFIX(prop_id, "offset")) { + int offset_type = RNA_enum_get(op->ptr, "offset_type"); - if (STREQ(prop_id, "offset") && offset_type == BEVEL_AMT_PERCENT) - return false; - else if (STREQ(prop_id, "offset_pct") && offset_type != BEVEL_AMT_PERCENT) - return false; - } + if (STREQ(prop_id, "offset") && offset_type == BEVEL_AMT_PERCENT) + return false; + else if (STREQ(prop_id, "offset_pct") && offset_type != BEVEL_AMT_PERCENT) + return false; + } - return true; + return true; } wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf) { - static const EnumPropertyItem modal_items[] = { - {BEV_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel bevel"}, - {BEV_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", "Confirm bevel"}, - {BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Value is offset", - "Value changes offset"}, - {BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Value is profile", - "Value changes profile"}, - {BEV_MODAL_VALUE_SEGMENTS, "VALUE_SEGMENTS", 0, "Value is segments", - "Value changes segments"}, - {BEV_MODAL_SEGMENTS_UP, "SEGMENTS_UP", 0, "Increase segments", - "Increase segments"}, - {BEV_MODAL_SEGMENTS_DOWN, "SEGMENTS_DOWN", 0, "Decrease segments", - "Decrease segments"}, - {BEV_MODAL_OFFSET_MODE_CHANGE, "OFFSET_MODE_CHANGE", 0, "Change offset mode", - "Cycle through offset modes"}, - {BEV_MODAL_CLAMP_OVERLAP_TOGGLE, "CLAMP_OVERLAP_TOGGLE", 0, "Toggle clamp overlap", - "Toggle clamp overlap flag"}, - {BEV_MODAL_VERTEX_ONLY_TOGGLE, "VERTEX_ONLY_TOGGLE", 0, "Toggle vertex only", - "Toggle vertex only flag"}, - {BEV_MODAL_HARDEN_NORMALS_TOGGLE, "HARDEN_NORMALS_TOGGLE", 0, "Toggle harden normals", - "Toggle harden normals flag"}, - {BEV_MODAL_MARK_SEAM_TOGGLE, "MARK_SEAM_TOGGLE", 0, "Toggle mark seam", - "Toggle mark seam flag"}, - {BEV_MODAL_MARK_SHARP_TOGGLE, "MARK_SHARP_TOGGLE", 0, "Toggle mark sharp", - "Toggle mark sharp flag"}, - {BEV_MODAL_OUTER_MITER_CHANGE, "OUTER_MITER_CHANGE", 0, "Change outer miter", - "Cycle through outer miter kinds"}, - {BEV_MODAL_INNER_MITER_CHANGE, "INNER_MITER_CHANGE", 0, "Change inner miter", - "Cycle through inner miter kinds"}, - {0, NULL, 0, NULL, NULL}, - }; - - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map"); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) - return NULL; - - keymap = WM_modalkeymap_add(keyconf, "Bevel Modal Map", modal_items); - - WM_modalkeymap_assign(keymap, "MESH_OT_bevel"); - - return keymap; + static const EnumPropertyItem modal_items[] = { + {BEV_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel bevel"}, + {BEV_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", "Confirm bevel"}, + {BEV_MODAL_VALUE_OFFSET, "VALUE_OFFSET", 0, "Value is offset", "Value changes offset"}, + {BEV_MODAL_VALUE_PROFILE, "VALUE_PROFILE", 0, "Value is profile", "Value changes profile"}, + {BEV_MODAL_VALUE_SEGMENTS, + "VALUE_SEGMENTS", + 0, + "Value is segments", + "Value changes segments"}, + {BEV_MODAL_SEGMENTS_UP, "SEGMENTS_UP", 0, "Increase segments", "Increase segments"}, + {BEV_MODAL_SEGMENTS_DOWN, "SEGMENTS_DOWN", 0, "Decrease segments", "Decrease segments"}, + {BEV_MODAL_OFFSET_MODE_CHANGE, + "OFFSET_MODE_CHANGE", + 0, + "Change offset mode", + "Cycle through offset modes"}, + {BEV_MODAL_CLAMP_OVERLAP_TOGGLE, + "CLAMP_OVERLAP_TOGGLE", + 0, + "Toggle clamp overlap", + "Toggle clamp overlap flag"}, + {BEV_MODAL_VERTEX_ONLY_TOGGLE, + "VERTEX_ONLY_TOGGLE", + 0, + "Toggle vertex only", + "Toggle vertex only flag"}, + {BEV_MODAL_HARDEN_NORMALS_TOGGLE, + "HARDEN_NORMALS_TOGGLE", + 0, + "Toggle harden normals", + "Toggle harden normals flag"}, + {BEV_MODAL_MARK_SEAM_TOGGLE, + "MARK_SEAM_TOGGLE", + 0, + "Toggle mark seam", + "Toggle mark seam flag"}, + {BEV_MODAL_MARK_SHARP_TOGGLE, + "MARK_SHARP_TOGGLE", + 0, + "Toggle mark sharp", + "Toggle mark sharp flag"}, + {BEV_MODAL_OUTER_MITER_CHANGE, + "OUTER_MITER_CHANGE", + 0, + "Change outer miter", + "Cycle through outer miter kinds"}, + {BEV_MODAL_INNER_MITER_CHANGE, + "INNER_MITER_CHANGE", + 0, + "Change inner miter", + "Cycle through inner miter kinds"}, + {0, NULL, 0, NULL, NULL}, + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map"); + + /* this function is called for each spacetype, only needs to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, "Bevel Modal Map", modal_items); + + WM_modalkeymap_assign(keymap, "MESH_OT_bevel"); + + return keymap; } static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) { - BevelData *opdata = op->customdata; - const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]); - bool handled = false; - short etype = event->type; - short eval = event->val; - - /* When activated from toolbar, need to convert leftmouse release to confirm */ - if (etype == LEFTMOUSE && eval == KM_RELEASE && - RNA_boolean_get(op->ptr, "release_confirm")) - { - etype = EVT_MODAL_MAP; - eval = BEV_MODAL_CONFIRM; - } - /* Modal numinput active, try to handle numeric inputs first... */ - if (etype != EVT_MODAL_MAP && eval == KM_PRESS && has_numinput && - handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) - { - edbm_bevel_numinput_set_value(op); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - return OPERATOR_RUNNING_MODAL; - } - else if (etype == MOUSEMOVE) { - if (!has_numinput) { - edbm_bevel_mouse_set_value(op, event); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - } - } - else if (etype == MOUSEPAN) { - float delta = 0.02f * (event->y - event->prevy); - if (opdata->segments >= 1 && opdata->segments + delta < 1) - opdata->segments = 1; - else - opdata->segments += delta; - RNA_int_set(op->ptr, "segments", (int)opdata->segments); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - } - else if (etype == EVT_MODAL_MAP) { - switch (eval) { - case BEV_MODAL_CANCEL: - edbm_bevel_cancel(C, op); - ED_workspace_status_text(C, NULL); - return OPERATOR_CANCELLED; - - case BEV_MODAL_CONFIRM: - edbm_bevel_calc(op); - edbm_bevel_exit(C, op); - ED_workspace_status_text(C, NULL); - return OPERATOR_FINISHED; - - case BEV_MODAL_SEGMENTS_UP: - opdata->segments = opdata->segments + 1; - RNA_int_set(op->ptr, "segments", (int)opdata->segments); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - - case BEV_MODAL_SEGMENTS_DOWN: - opdata->segments = max_ff(opdata->segments - 1, 1); - RNA_int_set(op->ptr, "segments", (int)opdata->segments); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - - case BEV_MODAL_OFFSET_MODE_CHANGE: - { - int type = RNA_enum_get(op->ptr, "offset_type"); - type++; - if (type > BEVEL_AMT_PERCENT) { - type = BEVEL_AMT_OFFSET; - } - if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT) - opdata->value_mode = OFFSET_VALUE_PERCENT; - else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT) - opdata->value_mode = OFFSET_VALUE; - RNA_enum_set(op->ptr, "offset_type", type); - if (opdata->initial_length[opdata->value_mode] == -1.0f) - edbm_bevel_calc_initial_length(op, event, true); - } - /* Update offset accordingly to new offset_type. */ - if (!has_numinput && - (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT)) - { - edbm_bevel_mouse_set_value(op, event); - } - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - - case BEV_MODAL_CLAMP_OVERLAP_TOGGLE: - { - bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); - RNA_boolean_set(op->ptr, "clamp_overlap", !clamp_overlap); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_VALUE_OFFSET: - opdata->value_mode = OFFSET_VALUE; - edbm_bevel_calc_initial_length(op, event, true); - break; - - case BEV_MODAL_VALUE_PROFILE: - opdata->value_mode = PROFILE_VALUE; - edbm_bevel_calc_initial_length(op, event, true); - break; - - case BEV_MODAL_VALUE_SEGMENTS: - opdata->value_mode = SEGMENTS_VALUE; - edbm_bevel_calc_initial_length(op, event, true); - break; - - case BEV_MODAL_VERTEX_ONLY_TOGGLE: - { - bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); - RNA_boolean_set(op->ptr, "vertex_only", !vertex_only); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_MARK_SEAM_TOGGLE: - { - bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); - RNA_boolean_set(op->ptr, "mark_seam", !mark_seam); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_MARK_SHARP_TOGGLE: - { - bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); - RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_INNER_MITER_CHANGE: - { - int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); - miter_inner++; - if (miter_inner == BEVEL_MITER_PATCH) - miter_inner++; /* no patch option for inner miter */ - if (miter_inner > BEVEL_MITER_ARC) - miter_inner = BEVEL_MITER_SHARP; - RNA_enum_set(op->ptr, "miter_inner", miter_inner); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_OUTER_MITER_CHANGE: - { - int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); - miter_outer++; - if (miter_outer > BEVEL_MITER_ARC) - miter_outer = BEVEL_MITER_SHARP; - RNA_enum_set(op->ptr, "miter_outer", miter_outer); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - - case BEV_MODAL_HARDEN_NORMALS_TOGGLE: - { - bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); - RNA_boolean_set(op->ptr, "harden_normals", !harden_normals); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - handled = true; - break; - } - } - } - - /* Modal numinput inactive, try to handle numeric inputs last... */ - if (!handled && eval == KM_PRESS && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { - edbm_bevel_numinput_set_value(op); - edbm_bevel_calc(op); - edbm_bevel_update_header(C, op); - return OPERATOR_RUNNING_MODAL; - } - - return OPERATOR_RUNNING_MODAL; + BevelData *opdata = op->customdata; + const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]); + bool handled = false; + short etype = event->type; + short eval = event->val; + + /* When activated from toolbar, need to convert leftmouse release to confirm */ + if (etype == LEFTMOUSE && eval == KM_RELEASE && RNA_boolean_get(op->ptr, "release_confirm")) { + etype = EVT_MODAL_MAP; + eval = BEV_MODAL_CONFIRM; + } + /* Modal numinput active, try to handle numeric inputs first... */ + if (etype != EVT_MODAL_MAP && eval == KM_PRESS && has_numinput && + handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { + edbm_bevel_numinput_set_value(op); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; + } + else if (etype == MOUSEMOVE) { + if (!has_numinput) { + edbm_bevel_mouse_set_value(op, event); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + } + } + else if (etype == MOUSEPAN) { + float delta = 0.02f * (event->y - event->prevy); + if (opdata->segments >= 1 && opdata->segments + delta < 1) + opdata->segments = 1; + else + opdata->segments += delta; + RNA_int_set(op->ptr, "segments", (int)opdata->segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + } + else if (etype == EVT_MODAL_MAP) { + switch (eval) { + case BEV_MODAL_CANCEL: + edbm_bevel_cancel(C, op); + ED_workspace_status_text(C, NULL); + return OPERATOR_CANCELLED; + + case BEV_MODAL_CONFIRM: + edbm_bevel_calc(op); + edbm_bevel_exit(C, op); + ED_workspace_status_text(C, NULL); + return OPERATOR_FINISHED; + + case BEV_MODAL_SEGMENTS_UP: + opdata->segments = opdata->segments + 1; + RNA_int_set(op->ptr, "segments", (int)opdata->segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + + case BEV_MODAL_SEGMENTS_DOWN: + opdata->segments = max_ff(opdata->segments - 1, 1); + RNA_int_set(op->ptr, "segments", (int)opdata->segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + + case BEV_MODAL_OFFSET_MODE_CHANGE: { + int type = RNA_enum_get(op->ptr, "offset_type"); + type++; + if (type > BEVEL_AMT_PERCENT) { + type = BEVEL_AMT_OFFSET; + } + if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT) + opdata->value_mode = OFFSET_VALUE_PERCENT; + else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT) + opdata->value_mode = OFFSET_VALUE; + RNA_enum_set(op->ptr, "offset_type", type); + if (opdata->initial_length[opdata->value_mode] == -1.0f) + edbm_bevel_calc_initial_length(op, event, true); + } + /* Update offset accordingly to new offset_type. */ + if (!has_numinput && + (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT)) { + edbm_bevel_mouse_set_value(op, event); + } + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + + case BEV_MODAL_CLAMP_OVERLAP_TOGGLE: { + bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap"); + RNA_boolean_set(op->ptr, "clamp_overlap", !clamp_overlap); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_VALUE_OFFSET: + opdata->value_mode = OFFSET_VALUE; + edbm_bevel_calc_initial_length(op, event, true); + break; + + case BEV_MODAL_VALUE_PROFILE: + opdata->value_mode = PROFILE_VALUE; + edbm_bevel_calc_initial_length(op, event, true); + break; + + case BEV_MODAL_VALUE_SEGMENTS: + opdata->value_mode = SEGMENTS_VALUE; + edbm_bevel_calc_initial_length(op, event, true); + break; + + case BEV_MODAL_VERTEX_ONLY_TOGGLE: { + bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); + RNA_boolean_set(op->ptr, "vertex_only", !vertex_only); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_MARK_SEAM_TOGGLE: { + bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam"); + RNA_boolean_set(op->ptr, "mark_seam", !mark_seam); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_MARK_SHARP_TOGGLE: { + bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); + RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_INNER_MITER_CHANGE: { + int miter_inner = RNA_enum_get(op->ptr, "miter_inner"); + miter_inner++; + if (miter_inner == BEVEL_MITER_PATCH) + miter_inner++; /* no patch option for inner miter */ + if (miter_inner > BEVEL_MITER_ARC) + miter_inner = BEVEL_MITER_SHARP; + RNA_enum_set(op->ptr, "miter_inner", miter_inner); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_OUTER_MITER_CHANGE: { + int miter_outer = RNA_enum_get(op->ptr, "miter_outer"); + miter_outer++; + if (miter_outer > BEVEL_MITER_ARC) + miter_outer = BEVEL_MITER_SHARP; + RNA_enum_set(op->ptr, "miter_outer", miter_outer); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + + case BEV_MODAL_HARDEN_NORMALS_TOGGLE: { + bool harden_normals = RNA_boolean_get(op->ptr, "harden_normals"); + RNA_boolean_set(op->ptr, "harden_normals", !harden_normals); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + handled = true; + break; + } + } + } + + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && eval == KM_PRESS && + handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) { + edbm_bevel_numinput_set_value(op); + edbm_bevel_calc(op); + edbm_bevel_update_header(C, op); + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_RUNNING_MODAL; } void MESH_OT_bevel(wmOperatorType *ot) { - PropertyRNA *prop; - - static const EnumPropertyItem offset_type_items[] = { - {BEVEL_AMT_OFFSET, "OFFSET", 0, "Offset", "Amount is offset of new edges from original"}, - {BEVEL_AMT_WIDTH, "WIDTH", 0, "Width", "Amount is width of new face"}, - {BEVEL_AMT_DEPTH, "DEPTH", 0, "Depth", "Amount is perpendicular distance from original edge to bevel face"}, - {BEVEL_AMT_PERCENT, "PERCENT", 0, "Percent", "Amount is percent of adjacent edge length"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem face_strength_mode_items[] = { - {BEVEL_FACE_STRENGTH_NONE, "NONE", 0, "None", "Do not set face strength"}, - {BEVEL_FACE_STRENGTH_NEW, "NEW", 0, "New", "Set face strength on new faces only"}, - {BEVEL_FACE_STRENGTH_AFFECTED, "AFFECTED", 0, "Affected", "Set face strength on new and modified faces only"}, - {BEVEL_FACE_STRENGTH_ALL, "ALL", 0, "All", "Set face strength on all faces"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem miter_outer_items[] = { - {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Outside of miter is sharp"}, - {BEVEL_MITER_PATCH, "PATCH", 0, "Patch", "Outside of miter is squared-off patch"}, - {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Outside of miter is arc"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem miter_inner_items[] = { - {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Inside of miter is sharp"}, - {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Inside of miter is arc"}, - {0, NULL, 0, NULL, NULL}, - }; - - /* identifiers */ - ot->name = "Bevel"; - ot->description = "Edge Bevel"; - ot->idname = "MESH_OT_bevel"; - - /* api callbacks */ - ot->exec = edbm_bevel_exec; - ot->invoke = edbm_bevel_invoke; - ot->modal = edbm_bevel_modal; - ot->cancel = edbm_bevel_cancel; - ot->poll = ED_operator_editmesh; - ot->poll_property = edbm_bevel_poll_property; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; - - RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures"); - prop = RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_range(prop, 0.0, 1e6); - RNA_def_property_ui_range(prop, 0.0f, 100.0, 1, 3); - RNA_def_property_ui_text(prop, "Width", "Bevel amount"); - prop = RNA_def_property(ot->srna, "offset_pct", PROP_FLOAT, PROP_PERCENTAGE); - RNA_def_property_range(prop, 0.0, 100); - RNA_def_property_ui_text(prop, "Width Percent", "Bevel amount for percentage method"); - RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 100); - RNA_def_float( - ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile", - "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f); - RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices"); - RNA_def_boolean( - ot->srna, "clamp_overlap", false, "Clamp Overlap", - "Do not allow beveled edges/vertices to overlap each other"); - RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths"); - RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges"); - RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); - RNA_def_int( - ot->srna, "material", -1, -1, INT_MAX, "Material", - "Material for bevel faces (-1 means use adjacent faces)", -1, 100); - RNA_def_boolean( - ot->srna, "harden_normals", false, "Harden Normals", - "Match normals of new faces to adjacent faces"); - RNA_def_enum( - ot->srna, "face_strength_mode", face_strength_mode_items, BEVEL_FACE_STRENGTH_NONE, - "Face Strength Mode", "Whether to set face strength, and which faces to set face strength on"); - RNA_def_enum( - ot->srna, "miter_outer", miter_outer_items, BEVEL_MITER_SHARP, - "Outer Miter", "Pattern to use for outside of miters"); - RNA_def_enum( - ot->srna, "miter_inner", miter_inner_items, BEVEL_MITER_SHARP, - "Inner Miter", "Pattern to use for inside of miters"); - RNA_def_float( - ot->srna, "spread", 0.1f, 0.0f, 1e6f, "Spread", - "Amount to spread arcs for arc inner miters", 0.0f, 100.0f); - prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - + PropertyRNA *prop; + + static const EnumPropertyItem offset_type_items[] = { + {BEVEL_AMT_OFFSET, "OFFSET", 0, "Offset", "Amount is offset of new edges from original"}, + {BEVEL_AMT_WIDTH, "WIDTH", 0, "Width", "Amount is width of new face"}, + {BEVEL_AMT_DEPTH, + "DEPTH", + 0, + "Depth", + "Amount is perpendicular distance from original edge to bevel face"}, + {BEVEL_AMT_PERCENT, "PERCENT", 0, "Percent", "Amount is percent of adjacent edge length"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem face_strength_mode_items[] = { + {BEVEL_FACE_STRENGTH_NONE, "NONE", 0, "None", "Do not set face strength"}, + {BEVEL_FACE_STRENGTH_NEW, "NEW", 0, "New", "Set face strength on new faces only"}, + {BEVEL_FACE_STRENGTH_AFFECTED, + "AFFECTED", + 0, + "Affected", + "Set face strength on new and modified faces only"}, + {BEVEL_FACE_STRENGTH_ALL, "ALL", 0, "All", "Set face strength on all faces"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem miter_outer_items[] = { + {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Outside of miter is sharp"}, + {BEVEL_MITER_PATCH, "PATCH", 0, "Patch", "Outside of miter is squared-off patch"}, + {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Outside of miter is arc"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem miter_inner_items[] = { + {BEVEL_MITER_SHARP, "SHARP", 0, "Sharp", "Inside of miter is sharp"}, + {BEVEL_MITER_ARC, "ARC", 0, "Arc", "Inside of miter is arc"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* identifiers */ + ot->name = "Bevel"; + ot->description = "Edge Bevel"; + ot->idname = "MESH_OT_bevel"; + + /* api callbacks */ + ot->exec = edbm_bevel_exec; + ot->invoke = edbm_bevel_invoke; + ot->modal = edbm_bevel_modal; + ot->cancel = edbm_bevel_cancel; + ot->poll = ED_operator_editmesh; + ot->poll_property = edbm_bevel_poll_property; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; + + RNA_def_enum( + ot->srna, "offset_type", offset_type_items, 0, "Width Type", "What distance Width measures"); + prop = RNA_def_property(ot->srna, "offset", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_range(prop, 0.0, 1e6); + RNA_def_property_ui_range(prop, 0.0f, 100.0, 1, 3); + RNA_def_property_ui_text(prop, "Width", "Bevel amount"); + prop = RNA_def_property(ot->srna, "offset_pct", PROP_FLOAT, PROP_PERCENTAGE); + RNA_def_property_range(prop, 0.0, 100); + RNA_def_property_ui_text(prop, "Width Percent", "Bevel amount for percentage method"); + RNA_def_int(ot->srna, + "segments", + 1, + 1, + SEGMENTS_HARD_MAX, + "Segments", + "Segments for curved edge", + 1, + 100); + RNA_def_float(ot->srna, + "profile", + 0.5f, + PROFILE_HARD_MIN, + 1.0f, + "Profile", + "Controls profile shape (0.5 = round)", + PROFILE_HARD_MIN, + 1.0f); + RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices"); + RNA_def_boolean(ot->srna, + "clamp_overlap", + false, + "Clamp Overlap", + "Do not allow beveled edges/vertices to overlap each other"); + RNA_def_boolean( + ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths"); + RNA_def_boolean(ot->srna, "mark_seam", false, "Mark Seams", "Mark Seams along beveled edges"); + RNA_def_boolean(ot->srna, "mark_sharp", false, "Mark Sharp", "Mark beveled edges as sharp"); + RNA_def_int(ot->srna, + "material", + -1, + -1, + INT_MAX, + "Material", + "Material for bevel faces (-1 means use adjacent faces)", + -1, + 100); + RNA_def_boolean(ot->srna, + "harden_normals", + false, + "Harden Normals", + "Match normals of new faces to adjacent faces"); + RNA_def_enum(ot->srna, + "face_strength_mode", + face_strength_mode_items, + BEVEL_FACE_STRENGTH_NONE, + "Face Strength Mode", + "Whether to set face strength, and which faces to set face strength on"); + RNA_def_enum(ot->srna, + "miter_outer", + miter_outer_items, + BEVEL_MITER_SHARP, + "Outer Miter", + "Pattern to use for outside of miters"); + RNA_def_enum(ot->srna, + "miter_inner", + miter_inner_items, + BEVEL_MITER_SHARP, + "Inner Miter", + "Pattern to use for inside of miters"); + RNA_def_float(ot->srna, + "spread", + 0.1f, + 0.0f, + 1e6f, + "Spread", + "Amount to spread arcs for arc inner miters", + 0.0f, + 100.0f); + prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } |