diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-04-01 14:18:01 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-04-01 14:18:01 +0400 |
commit | 6d8e25dfdc44ecb068ab73fc52af31683483a663 (patch) | |
tree | b44396db84e5984a4519b559356e0e942ad38a36 /source/blender/editors/mesh/editmesh_bevel.c | |
parent | e8d0e77856872037635c1d2bcd9a466a715910c4 (diff) |
code cleanup: split editmesh_tools.c, into inset, bevel (both modal operators) and moved extrude operators into their own file.
also move some selection operators from editmesh_tools.c into editmesh_select.c
Diffstat (limited to 'source/blender/editors/mesh/editmesh_bevel.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_bevel.c | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c new file mode 100644 index 00000000000..d79f12551dd --- /dev/null +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -0,0 +1,368 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Joseph Eagar, Howard Trickey, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_bevel.c + * \ingroup edmesh + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" + +#include "BLI_string.h" +#include "BLI_math.h" + +#include "BLF_translation.h" + +#include "BKE_context.h" +#include "BKE_tessmesh.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_numinput.h" +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_view3d.h" + +#include "mesh_intern.h" /* own include */ + + +#define MVAL_PIXEL_MARGIN 5.0f + +typedef struct { + BMEditMesh *em; + BMBackup mesh_backup; + int mcenter[2]; + float initial_length; + float pixel_size; /* use when mouse input is interpreted as spatial distance */ + int is_modal; + NumInput num_input; + float shift_factor; /* The current factor when shift is pressed. Negative when shift not active. */ +} BevelData; + +#define HEADER_LENGTH 180 + +static void edbm_bevel_update_header(wmOperator *op, bContext *C) +{ + const char *str = IFACE_("Confirm: Enter/LClick, Cancel: (Esc/RMB), Offset: %s, Segments: %d"); + + char msg[HEADER_LENGTH]; + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + char offset_str[NUM_STR_REP_LEN]; + BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset")); + BLI_snprintf(msg, HEADER_LENGTH, str, + offset_str, + RNA_int_get(op->ptr, "segments") + ); + + ED_area_headerprint(sa, msg); + } +} + +static int edbm_bevel_init(bContext *C, wmOperator *op, int is_modal) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BMEdit_FromObject(obedit); + BevelData *opdata; + + if (em == NULL) { + return 0; + } + + op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); + + opdata->em = em; + opdata->is_modal = is_modal; + opdata->shift_factor = -1.0f; + + initNumInput(&opdata->num_input); + opdata->num_input.flag = NUM_NO_NEGATIVE; + + /* avoid the cost of allocating a bm copy */ + if (is_modal) + opdata->mesh_backup = EDBM_redo_state_store(em); + + return 1; +} + +static int edbm_bevel_calc(wmOperator *op) +{ + BevelData *opdata = op->customdata; + BMEditMesh *em = opdata->em; + BMOperator bmop; + const float offset = RNA_float_get(op->ptr, "offset"); + const int segments = RNA_int_get(op->ptr, "segments"); + const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only"); + + /* revert to original mesh */ + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->mesh_backup, em, false); + } + + if (!EDBM_op_init(em, &bmop, op, + "bevel geom=%hev offset=%f segments=%i vertex_only=%b", + BM_ELEM_SELECT, offset, segments, vertex_only)) + { + return 0; + } + + 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)) + return 0; + + EDBM_mesh_normals_update(opdata->em); + + EDBM_update_generic(opdata->em, true, true); + + return 1; +} + +static void edbm_bevel_exit(bContext *C, wmOperator *op) +{ + BevelData *opdata = op->customdata; + + ScrArea *sa = CTX_wm_area(C); + + if (sa) { + ED_area_headerprint(sa, NULL); + } + + if (opdata->is_modal) { + EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); + } + MEM_freeN(opdata); + op->customdata = NULL; +} + +static int edbm_bevel_cancel(bContext *C, wmOperator *op) +{ + BevelData *opdata = op->customdata; + if (opdata->is_modal) { + EDBM_redo_state_free(&opdata->mesh_backup, opdata->em, true); + EDBM_update_generic(opdata->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)); + return OPERATOR_CANCELLED; +} + +/* bevel! yay!!*/ +static int edbm_bevel_exec(bContext *C, wmOperator *op) +{ + if (!edbm_bevel_init(C, op, false)) { + edbm_bevel_exit(C, op); + return OPERATOR_CANCELLED; + } + + if (!edbm_bevel_calc(op)) { + edbm_bevel_cancel(C, op); + return OPERATOR_CANCELLED; + } + + edbm_bevel_exit(C, op); + + return OPERATOR_FINISHED; +} + +static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* TODO make modal keymap (see fly mode) */ + RegionView3D *rv3d = CTX_wm_region_view3d(C); + BevelData *opdata; + float mlen[2]; + float center_3d[3]; + + if (!edbm_bevel_init(C, op, true)) { + return OPERATOR_CANCELLED; + } + + opdata = op->customdata; + + /* initialize mouse values */ + if (!calculateTransformCenter(C, V3D_CENTROID, 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; + } + mlen[0] = opdata->mcenter[0] - event->mval[0]; + mlen[1] = opdata->mcenter[1] - event->mval[1]; + opdata->initial_length = len_v2(mlen); + opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f; + + edbm_bevel_update_header(op, C); + + if (!edbm_bevel_calc(op)) { + edbm_bevel_cancel(C, op); + return OPERATOR_CANCELLED; + } + + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event) +{ + BevelData *opdata = op->customdata; + int use_dist = true; + float mdiff[2]; + float factor; + + mdiff[0] = opdata->mcenter[0] - event->mval[0]; + mdiff[1] = opdata->mcenter[1] - event->mval[1]; + + if (use_dist) { + factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size; + } + else { + factor = (len_v2(mdiff) - MVAL_PIXEL_MARGIN) / opdata->initial_length; + factor = factor - 1.0f; /* a different kind of buffer where nothing happens */ + } + + /* Fake shift-transform... */ + if (event->shift) { + if (opdata->shift_factor < 0.0f) { + opdata->shift_factor = RNA_float_get(op->ptr, "offset"); + } + factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor; + } + else if (opdata->shift_factor >= 0.0f) + opdata->shift_factor = -1.0f; + + /* clamp differently based on distance/factor */ + if (use_dist) { + if (factor < 0.0f) factor = 0.0f; + } + else { + CLAMP(factor, 0.0f, 1.0f); + } + + return factor; +} + +static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + BevelData *opdata = op->customdata; + int segments = RNA_int_get(op->ptr, "segments"); + + if (event->val == KM_PRESS) { + /* Try to handle numeric inputs... */ + + if (handleNumInput(&opdata->num_input, event)) { + float value = RNA_float_get(op->ptr, "offset"); + applyNumInput(&opdata->num_input, &value); + RNA_float_set(op->ptr, "offset", value); + edbm_bevel_calc(op); + edbm_bevel_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + } + + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + edbm_bevel_cancel(C, op); + return OPERATOR_CANCELLED; + + case MOUSEMOVE: + if (!hasNumInput(&opdata->num_input)) { + const float factor = edbm_bevel_mval_factor(op, event); + RNA_float_set(op->ptr, "offset", factor); + + edbm_bevel_calc(op); + edbm_bevel_update_header(op, C); + } + break; + + case LEFTMOUSE: + case PADENTER: + case RETKEY: + edbm_bevel_calc(op); + edbm_bevel_exit(C, op); + return OPERATOR_FINISHED; + + case WHEELUPMOUSE: /* change number of segments */ + case PAGEUPKEY: + if (event->val == KM_RELEASE) + break; + + segments++; + RNA_int_set(op->ptr, "segments", segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(op, C); + break; + + case WHEELDOWNMOUSE: /* change number of segments */ + case PAGEDOWNKEY: + if (event->val == KM_RELEASE) + break; + + segments = max_ii(segments - 1, 1); + RNA_int_set(op->ptr, "segments", segments); + edbm_bevel_calc(op); + edbm_bevel_update_header(op, C); + break; + } + + return OPERATOR_RUNNING_MODAL; +} + +void MESH_OT_bevel(wmOperatorType *ot) +{ + /* 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; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING; + + RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Offset", "", 0.0f, 1.0f); + RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8); + RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex only", "Bevel only vertices"); +} |