Fix navmesh creation w/ multiple objects
[blender-staging.git] / source / blender / editors / mesh / editmesh_bevel.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar, Howard Trickey, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/mesh/editmesh_bevel.c
24  *  \ingroup edmesh
25  */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_object_types.h"
30
31 #include "BLI_string.h"
32 #include "BLI_math.h"
33
34 #include "BLT_translation.h"
35
36 #include "BKE_context.h"
37 #include "BKE_global.h"
38 #include "BKE_editmesh.h"
39 #include "BKE_unit.h"
40
41 #include "RNA_define.h"
42 #include "RNA_access.h"
43
44 #include "WM_api.h"
45 #include "WM_types.h"
46
47 #include "UI_interface.h"
48
49 #include "ED_mesh.h"
50 #include "ED_numinput.h"
51 #include "ED_screen.h"
52 #include "ED_space_api.h"
53 #include "ED_transform.h"
54 #include "ED_view3d.h"
55
56 #include "mesh_intern.h"  /* own include */
57
58
59 #define MVAL_PIXEL_MARGIN  5.0f
60
61 #define PROFILE_HARD_MIN 0.0f
62
63 #define SEGMENTS_HARD_MAX 1000
64
65 /* which value is mouse movement and numeric input controlling? */
66 #define OFFSET_VALUE 0
67 #define OFFSET_VALUE_PERCENT 1
68 #define PROFILE_VALUE 2
69 #define SEGMENTS_VALUE 3
70 #define NUM_VALUE_KINDS 4
71
72 static const char *value_rna_name[NUM_VALUE_KINDS] = {"offset", "offset", "profile", "segments"};
73 static const float value_clamp_min[NUM_VALUE_KINDS] = {0.0f, 0.0f, PROFILE_HARD_MIN, 1.0f};
74 static const float value_clamp_max[NUM_VALUE_KINDS] = {1e6, 100.0f, 1.0f, SEGMENTS_HARD_MAX};
75 static const float value_start[NUM_VALUE_KINDS] = {0.0f, 0.0f, 0.5f, 1.0f};
76 static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f, 4.0f};
77
78 typedef struct {
79         BMEditMesh *em;
80         float initial_length[NUM_VALUE_KINDS];
81         float scale[NUM_VALUE_KINDS];
82         NumInput num_input[NUM_VALUE_KINDS]; 
83         float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */
84         bool is_modal;
85
86         /* modal only */
87         float mcenter[2];
88         BMBackup mesh_backup;
89         void *draw_handle_pixel;
90         short twtype;
91         short value_mode;  /* Which value does mouse movement and numeric input affect? */
92         float segments;     /* Segments as float so smooth mouse pan works in small increments */
93 } BevelData;
94
95 static void edbm_bevel_update_header(bContext *C, wmOperator *op)
96 {
97         const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
98                                  "Vertex Only: %s (V), Profile Control: %s (P), Offset: %s, Segments: %d, Profile: %.3f");
99
100         char msg[UI_MAX_DRAW_STR];
101         ScrArea *sa = CTX_wm_area(C);
102         Scene *sce = CTX_data_scene(C);
103
104         if (sa) {
105                 BevelData *opdata = op->customdata;
106                 char offset_str[NUM_STR_REP_LEN];
107                 const char *type_str;
108                 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
109
110                 if (hasNumInput(&opdata->num_input[OFFSET_VALUE])) {
111                         outputNumInput(&opdata->num_input[OFFSET_VALUE], offset_str, &sce->unit);
112                 }
113                 else {
114                         BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset"));
115                 }
116
117                 RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str);
118
119                 BLI_snprintf(msg, sizeof(msg), str, type_str,
120                              WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
121                              WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
122                              WM_bool_as_string(opdata->value_mode == PROFILE_VALUE),
123                              offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile"));
124
125                 ED_area_headerprint(sa, msg);
126         }
127 }
128
129 static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
130 {
131         Object *obedit = CTX_data_edit_object(C);
132         Scene *scene = CTX_data_scene(C);
133         BMEditMesh *em = BKE_editmesh_from_object(obedit);
134         BevelData *opdata;
135         float pixels_per_inch;
136         int i;
137
138         if (em->bm->totvertsel == 0) {
139                 return false;
140         }
141
142         op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator");
143
144         opdata->em = em;
145         opdata->is_modal = is_modal;
146         opdata->value_mode = OFFSET_VALUE;
147         opdata->segments = (float) RNA_int_get(op->ptr, "segments");
148         pixels_per_inch = U.dpi * U.pixelsize;
149
150         for (i = 0; i < NUM_VALUE_KINDS; i++) {
151                 opdata->shift_value[i] = -1.0f;
152                 opdata->initial_length[i] = -1.0f;
153                 /* note: scale for OFFSET_VALUE will get overwritten in edbm_bevel_invoke */
154                 opdata->scale[i] = value_scale_per_inch[i] / pixels_per_inch; 
155
156                 initNumInput(&opdata->num_input[i]);
157                 opdata->num_input[i].idx_max = 0;
158                 opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE;
159                 if (i == SEGMENTS_VALUE) {
160                         opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO;
161                 }
162                 if (i == OFFSET_VALUE) {
163                         opdata->num_input[i].unit_sys = scene->unit.system;
164                 }
165                 opdata->num_input[i].unit_type[0] = B_UNIT_NONE;  /* Not sure this is a factor or a unit? */
166         }
167
168         /* avoid the cost of allocating a bm copy */
169         if (is_modal) {
170                 View3D *v3d = CTX_wm_view3d(C);
171                 ARegion *ar = CTX_wm_region(C);
172
173                 opdata->mesh_backup = EDBM_redo_state_store(em);
174                 opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb,
175                         opdata->mcenter, REGION_DRAW_POST_PIXEL);
176                 G.moving = G_TRANSFORM_EDIT;
177
178                 if (v3d) {
179                         opdata->twtype = v3d->twtype;
180                         v3d->twtype = 0;
181                 }
182         }
183
184         return true;
185 }
186
187 static bool edbm_bevel_calc(wmOperator *op)
188 {
189         BevelData *opdata = op->customdata;
190         BMEditMesh *em = opdata->em;
191         BMOperator bmop;
192         const float offset = RNA_float_get(op->ptr, "offset");
193         const int offset_type = RNA_enum_get(op->ptr, "offset_type");
194         const int segments = RNA_int_get(op->ptr, "segments");
195         const float profile = RNA_float_get(op->ptr, "profile");
196         const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
197         const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
198         int material = RNA_int_get(op->ptr, "material");
199         const bool loop_slide = RNA_boolean_get(op->ptr, "loop_slide");
200
201         /* revert to original mesh */
202         if (opdata->is_modal) {
203                 EDBM_redo_state_restore(opdata->mesh_backup, em, false);
204         }
205
206         if (em->ob) {
207                 material = CLAMPIS(material, -1, em->ob->totcol - 1);
208         }
209
210         EDBM_op_init(em, &bmop, op,
211                      "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
212                      "material=%i loop_slide=%b",
213                      BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
214                      clamp_overlap, material, loop_slide);
215
216         BMO_op_exec(em->bm, &bmop);
217
218         if (offset != 0.0f) {
219                 /* not essential, but we may have some loose geometry that
220                  * won't get bevel'd and better not leave it selected */
221                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
222                 BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
223         }
224
225         /* no need to de-select existing geometry */
226         if (!EDBM_op_finish(em, &bmop, op, true)) {
227                 return false;
228         }
229
230         EDBM_mesh_normals_update(opdata->em);
231
232         EDBM_update_generic(opdata->em, true, true);
233
234         return true;
235 }
236
237 static void edbm_bevel_exit(bContext *C, wmOperator *op)
238 {
239         BevelData *opdata = op->customdata;
240
241         ScrArea *sa = CTX_wm_area(C);
242
243         if (sa) {
244                 ED_area_headerprint(sa, NULL);
245         }
246
247         if (opdata->is_modal) {
248                 View3D *v3d = CTX_wm_view3d(C);
249                 ARegion *ar = CTX_wm_region(C);
250                 EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
251                 ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel);
252                 if (v3d) {
253                         v3d->twtype = opdata->twtype;
254                 }
255                 G.moving = 0;
256         }
257         MEM_freeN(opdata);
258         op->customdata = NULL;
259 }
260
261 static void edbm_bevel_cancel(bContext *C, wmOperator *op)
262 {
263         BevelData *opdata = op->customdata;
264         if (opdata->is_modal) {
265                 EDBM_redo_state_free(&opdata->mesh_backup, opdata->em, true);
266                 EDBM_update_generic(opdata->em, false, true);
267         }
268
269         edbm_bevel_exit(C, op);
270
271         /* need to force redisplay or we may still view the modified result */
272         ED_region_tag_redraw(CTX_wm_region(C));
273 }
274
275 /* bevel! yay!!*/
276 static int edbm_bevel_exec(bContext *C, wmOperator *op)
277 {
278         if (!edbm_bevel_init(C, op, false)) {
279                 return OPERATOR_CANCELLED;
280         }
281
282         if (!edbm_bevel_calc(op)) {
283                 edbm_bevel_cancel(C, op);
284                 return OPERATOR_CANCELLED;
285         }
286
287         edbm_bevel_exit(C, op);
288
289         return OPERATOR_FINISHED;
290 }
291
292 static void edbm_bevel_calc_initial_length(wmOperator *op, const wmEvent *event, bool mode_changed)
293 {
294         BevelData *opdata;
295         float mlen[2], len, value, sc, st;
296         int vmode;
297
298         opdata = op->customdata;
299         mlen[0] = opdata->mcenter[0] - event->mval[0];
300         mlen[1] = opdata->mcenter[1] - event->mval[1];
301         len = len_v2(mlen);
302         vmode = opdata->value_mode;
303         if (mode_changed || opdata->initial_length[vmode] == -1.0f) {
304                 /* If current value is not default start value, adjust len so that 
305                  * the scaling and offset in edbm_bevel_mouse_set_value will
306                  * start at current value */
307                 value = (vmode == SEGMENTS_VALUE) ?
308                         opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
309                 sc = opdata->scale[vmode];
310                 st = value_start[vmode];
311                 if (value != value_start[vmode]) {
312                         len = (st + sc * (len - MVAL_PIXEL_MARGIN) - value) / sc;
313                 }
314         }
315         opdata->initial_length[opdata->value_mode] = len;
316 }
317
318 static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
319 {
320         /* TODO make modal keymap (see fly mode) */
321         RegionView3D *rv3d = CTX_wm_region_view3d(C);
322         BevelData *opdata;
323         float center_3d[3];
324
325         if (!edbm_bevel_init(C, op, true)) {
326                 return OPERATOR_CANCELLED;
327         }
328
329         opdata = op->customdata;
330
331         /* initialize mouse values */
332         if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEAN, center_3d, opdata->mcenter)) {
333                 /* in this case the tool will likely do nothing,
334                  * ideally this will never happen and should be checked for above */
335                 opdata->mcenter[0] = opdata->mcenter[1] = 0;
336         }
337
338         /* for OFFSET_VALUE only, the scale is the size of a pixel under the mouse in 3d space */
339         opdata->scale[OFFSET_VALUE] = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
340
341         edbm_bevel_calc_initial_length(op, event, false);
342
343         edbm_bevel_update_header(C, op);
344
345         if (!edbm_bevel_calc(op)) {
346                 edbm_bevel_cancel(C, op);
347                 return OPERATOR_CANCELLED;
348         }
349
350         WM_event_add_modal_handler(C, op);
351
352         return OPERATOR_RUNNING_MODAL;
353 }
354
355 static void edbm_bevel_mouse_set_value(wmOperator *op, const wmEvent *event)
356 {
357         BevelData *opdata = op->customdata;
358         int vmode = opdata->value_mode;
359         float mdiff[2];
360         float value;
361
362         mdiff[0] = opdata->mcenter[0] - event->mval[0];
363         mdiff[1] = opdata->mcenter[1] - event->mval[1];
364
365         value = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length[vmode]);
366
367         /* Scale according to value mode */
368         value = value_start[vmode] + value * opdata->scale[vmode];
369
370         /* Fake shift-transform... */
371         if (event->shift) {
372                 if (opdata->shift_value[vmode] < 0.0f) {
373                         opdata->shift_value[vmode] = (vmode == SEGMENTS_VALUE) ?
374                                 opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
375                 }
376                 value = (value - opdata->shift_value[vmode]) * 0.1f + opdata->shift_value[vmode];
377         }
378         else if (opdata->shift_value[vmode] >= 0.0f) {
379                 opdata->shift_value[vmode] = -1.0f;
380         }
381
382         /* clamp accordingto value mode, and store value back */
383         CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
384         if (vmode == SEGMENTS_VALUE) {
385                 opdata->segments = value;
386                 RNA_int_set(op->ptr, "segments", (int)(value + 0.5f));
387         }
388         else {
389                 RNA_float_set(op->ptr, value_rna_name[vmode], value);
390         }
391 }
392
393 static void edbm_bevel_numinput_set_value(wmOperator *op)
394 {
395         BevelData *opdata = op->customdata;
396         float value;
397         int vmode;
398
399         vmode = opdata->value_mode;
400         value = (vmode == SEGMENTS_VALUE) ?
401                 opdata->segments : RNA_float_get(op->ptr, value_rna_name[vmode]);
402         applyNumInput(&opdata->num_input[vmode], &value);
403         CLAMP(value, value_clamp_min[vmode], value_clamp_max[vmode]);
404         if (vmode == SEGMENTS_VALUE) {
405                 opdata->segments = value;
406                 RNA_int_set(op->ptr, "segments", (int)value);
407         }
408         else {
409                 RNA_float_set(op->ptr, value_rna_name[vmode], value);
410         }
411 }
412
413 static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
414 {
415         BevelData *opdata = op->customdata;
416         const bool has_numinput = hasNumInput(&opdata->num_input[opdata->value_mode]);
417
418         /* Modal numinput active, try to handle numeric inputs first... */
419         if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
420                 edbm_bevel_numinput_set_value(op);
421                 edbm_bevel_calc(op);
422                 edbm_bevel_update_header(C, op);
423                 return OPERATOR_RUNNING_MODAL;
424         }
425         else {
426                 bool handled = false;
427                 switch (event->type) {
428                         case ESCKEY:
429                         case RIGHTMOUSE:
430                                 edbm_bevel_cancel(C, op);
431                                 return OPERATOR_CANCELLED;
432
433                         case MOUSEMOVE:
434                                 if (!has_numinput) {
435                                         edbm_bevel_mouse_set_value(op, event);
436                                         edbm_bevel_calc(op);
437                                         edbm_bevel_update_header(C, op);
438                                         handled = true;
439                                 }
440                                 break;
441
442                         case LEFTMOUSE:
443                         case PADENTER:
444                         case RETKEY:
445                                 if (event->val == KM_PRESS) {
446                                         edbm_bevel_calc(op);
447                                         edbm_bevel_exit(C, op);
448                                         return OPERATOR_FINISHED;
449                                 }
450                                 break;
451
452                         case MOUSEPAN: {
453                                 float delta = 0.02f * (event->y - event->prevy);
454                                 if (opdata->segments >= 1 && opdata->segments + delta < 1)
455                                         opdata->segments = 1;
456                                 else
457                                         opdata->segments += delta;
458                                 RNA_int_set(op->ptr, "segments", (int)opdata->segments);
459                                 edbm_bevel_calc(op);
460                                 edbm_bevel_update_header(C, op);
461                                 handled = true;
462                                 break;
463                         }
464
465                         /* Note this will prevent padplus and padminus to ever activate modal numinput.
466                          * This is not really an issue though, as we only expect positive values here...
467                          * Else we could force them to only modify segments number when shift is pressed, or so.
468                          */
469
470                         case WHEELUPMOUSE:  /* change number of segments */
471                         case PADPLUSKEY:
472                                 if (event->val == KM_RELEASE)
473                                         break;
474
475                                 opdata->segments = opdata->segments + 1;
476                                 RNA_int_set(op->ptr, "segments", (int)opdata->segments);
477                                 edbm_bevel_calc(op);
478                                 edbm_bevel_update_header(C, op);
479                                 handled = true;
480                                 break;
481
482                         case WHEELDOWNMOUSE:  /* change number of segments */
483                         case PADMINUS:
484                                 if (event->val == KM_RELEASE)
485                                         break;
486
487                                 opdata->segments = max_ff(opdata->segments - 1, 1);
488                                 RNA_int_set(op->ptr, "segments", (int)opdata->segments);
489                                 edbm_bevel_calc(op);
490                                 edbm_bevel_update_header(C, op);
491                                 handled = true;
492                                 break;
493
494                         case MKEY:
495                                 if (event->val == KM_RELEASE)
496                                         break;
497
498                                 {
499                                         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
500                                         int type = RNA_property_enum_get(op->ptr, prop);
501                                         type++;
502                                         if (type > BEVEL_AMT_PERCENT) {
503                                                 type = BEVEL_AMT_OFFSET;
504                                         }
505                                         if (opdata->value_mode == OFFSET_VALUE && type == BEVEL_AMT_PERCENT)
506                                                 opdata->value_mode = OFFSET_VALUE_PERCENT;
507                                         else if (opdata->value_mode == OFFSET_VALUE_PERCENT && type != BEVEL_AMT_PERCENT)
508                                                 opdata->value_mode = OFFSET_VALUE;
509                                         RNA_property_enum_set(op->ptr, prop, type);
510                                         if (opdata->initial_length[opdata->value_mode] == -1.0f)
511                                                 edbm_bevel_calc_initial_length(op, event, true);
512                                 }
513                                 /* Update offset accordingly to new offset_type. */
514                                 if (!has_numinput &&
515                                     (opdata->value_mode == OFFSET_VALUE || opdata->value_mode == OFFSET_VALUE_PERCENT))
516                                 {
517                                         edbm_bevel_mouse_set_value(op, event);
518                                 }               
519                                 edbm_bevel_calc(op);
520                                 edbm_bevel_update_header(C, op);
521                                 handled = true;
522                                 break;
523                         case CKEY:
524                                 if (event->val == KM_RELEASE)
525                                         break;
526
527                                 {
528                                         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "clamp_overlap");
529                                         RNA_property_boolean_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
530                                 }
531                                 edbm_bevel_calc(op);
532                                 edbm_bevel_update_header(C, op);
533                                 handled = true;
534                                 break;
535                         case PKEY:
536                                 if (event->val == KM_RELEASE)
537                                         break;
538                                 if (opdata->value_mode == PROFILE_VALUE) {
539                                         opdata->value_mode = OFFSET_VALUE;
540                                 }
541                                 else {
542                                         opdata->value_mode = PROFILE_VALUE;
543                                 }
544                                 edbm_bevel_calc_initial_length(op, event, true);
545                                 break;
546                         case SKEY:
547                                 if (event->val == KM_RELEASE)
548                                         break;
549                                 if (opdata->value_mode == SEGMENTS_VALUE) {
550                                         opdata->value_mode = OFFSET_VALUE;
551                                 }
552                                 else {
553                                         opdata->value_mode = SEGMENTS_VALUE;
554                                 }
555                                 edbm_bevel_calc_initial_length(op, event, true);
556                                 break;
557                         case VKEY:
558                                 if (event->val == KM_RELEASE)
559                                         break;
560                                 
561                                 {
562                                         PropertyRNA *prop = RNA_struct_find_property(op->ptr, "vertex_only");
563                                         RNA_property_boolean_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
564                                 }
565                                 edbm_bevel_calc(op);
566                                 edbm_bevel_update_header(C, op);
567                                 handled = true;
568                                 break;
569                                 
570                 }
571
572                 /* Modal numinput inactive, try to handle numeric inputs last... */
573                 if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input[opdata->value_mode], event)) {
574                         edbm_bevel_numinput_set_value(op);
575                         edbm_bevel_calc(op);
576                         edbm_bevel_update_header(C, op);
577                         return OPERATOR_RUNNING_MODAL;
578                 }
579         }
580
581         return OPERATOR_RUNNING_MODAL;
582 }
583
584 static void mesh_ot_bevel_offset_range_func(PointerRNA *ptr, PropertyRNA *UNUSED(prop),
585                                             float *min, float *max, float *softmin, float *softmax)
586 {
587         const int offset_type = RNA_enum_get(ptr, "offset_type");
588
589         *min = -FLT_MAX;
590         *max = FLT_MAX;
591         *softmin = 0.0f;
592         *softmax = (offset_type == BEVEL_AMT_PERCENT) ? 100.0f : 1.0f;
593 }
594
595 void MESH_OT_bevel(wmOperatorType *ot)
596 {
597         PropertyRNA *prop;
598
599         static const EnumPropertyItem offset_type_items[] = {
600                 {BEVEL_AMT_OFFSET, "OFFSET", 0, "Offset", "Amount is offset of new edges from original"},
601                 {BEVEL_AMT_WIDTH, "WIDTH", 0, "Width", "Amount is width of new face"},
602                 {BEVEL_AMT_DEPTH, "DEPTH", 0, "Depth", "Amount is perpendicular distance from original edge to bevel face"},
603                 {BEVEL_AMT_PERCENT, "PERCENT", 0, "Percent", "Amount is percent of adjacent edge length"},
604                 {0, NULL, 0, NULL, NULL},
605         };
606
607         /* identifiers */
608         ot->name = "Bevel";
609         ot->description = "Edge Bevel";
610         ot->idname = "MESH_OT_bevel";
611
612         /* api callbacks */
613         ot->exec = edbm_bevel_exec;
614         ot->invoke = edbm_bevel_invoke;
615         ot->modal = edbm_bevel_modal;
616         ot->cancel = edbm_bevel_cancel;
617         ot->poll = ED_operator_editmesh;
618
619         /* flags */
620         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
621
622         RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
623         prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
624         RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
625         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
626         RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8);
627         RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
628                 "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
629         RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
630         RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
631                 "Do not allow beveled edges/vertices to overlap each other");
632         RNA_def_boolean(ot->srna, "loop_slide", true, "Loop Slide", "Prefer slide along edge to even widths");
633         RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material",
634                 "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
635 }