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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/mesh/editmesh_bevel.c')
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c268
1 files changed, 221 insertions, 47 deletions
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index e44a43c4c3a..39bebc9a980 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -30,6 +30,7 @@
#include "BLI_string.h"
#include "BLI_math.h"
+#include "BLI_linklist_stack.h"
#include "BLT_translation.h"
@@ -37,6 +38,8 @@
#include "BKE_global.h"
#include "BKE_editmesh.h"
#include "BKE_unit.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "RNA_define.h"
#include "RNA_access.h"
@@ -77,17 +80,24 @@ static const float value_scale_per_inch[NUM_VALUE_KINDS] = { 0.0f, 100.0f, 1.0f,
typedef struct {
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];
float shift_value[NUM_VALUE_KINDS]; /* The current value when shift is pressed. Negative when shift not active. */
bool is_modal;
+ BevelObjectStore *ob_store;
+ uint ob_store_len;
+
/* modal only */
float mcenter[2];
- BMBackup mesh_backup;
void *draw_handle_pixel;
- short twtype;
+ 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;
@@ -122,30 +132,133 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
WM_bool_as_string(opdata->value_mode == PROFILE_VALUE),
offset_str, RNA_int_get(op->ptr, "segments"), RNA_float_get(op->ptr, "profile"));
- ED_area_headerprint(sa, msg);
+ ED_area_status_text(sa, msg);
+ }
+}
+
+static void bevel_harden_normals(BMEditMesh *em, BMOperator *bmop, float face_strength)
+{
+ BKE_editmesh_lnorspace_update(em);
+ BM_normals_loops_edges_tag(em->bm, true);
+ const int cd_clnors_offset = CustomData_get_offset(&em->bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l, *l_cur, *l_first;
+ BMIter fiter;
+
+ BMOpSlot *nslot = BMO_slot_get(bmop->slots_out, "normals.out"); /* Per vertex normals depending on hn_mode */
+
+ /* Similar functionality to bm_mesh_loops_calc_normals... Edges that can be smoothed are tagged */
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ l_cur = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if ((BM_elem_flag_test(l_cur->v, BM_ELEM_SELECT)) &&
+ ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG)) ||
+ (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur))))
+ {
+ /* Both adjacent loops are sharp, set clnor to face normal */
+ if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_cur);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ /* Find next corresponding sharp edge in this smooth fan */
+ BMVert *v_pivot = l_cur->v;
+ float *calc_n = BLI_ghash_lookup(nslot->data.ghash, v_pivot);
+
+ BMEdge *e_next;
+ const BMEdge *e_org = l_cur->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+
+ lfan_pivot = l_cur;
+ e_next = lfan_pivot->e;
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float cn_wght[3] = { 0.0f, 0.0f, 0.0f }, cn_unwght[3] = { 0.0f, 0.0f, 0.0f };
+
+ /* Fan through current vert and accumulate normals and loops */
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
+
+ BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
+ float cur[3];
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+
+ if (BM_elem_flag_test(lfan_pivot->f, BM_ELEM_SELECT))
+ add_v3_v3(cn_unwght, cur);
+
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
+ }
+
+ normalize_v3(cn_wght);
+ normalize_v3(cn_unwght);
+ if (calc_n) {
+ mul_v3_fl(cn_wght, face_strength);
+ mul_v3_fl(calc_n, 1.0f - face_strength);
+ add_v3_v3(calc_n, cn_wght);
+ normalize_v3(calc_n);
+ }
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ if (calc_n) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], calc_n, clnors);
+ }
+ else {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], cn_unwght, clnors);
+ }
+ }
+ BLI_ghash_remove(nslot->data.ghash, v_pivot, NULL, MEM_freeN);
+ }
+ }
+ } while ((l_cur = l_cur->next) != l_first);
}
}
static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
{
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
BevelData *opdata;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
float pixels_per_inch;
int i;
- if (em->bm->totvertsel == 0) {
- return false;
- }
-
if (is_modal) {
RNA_float_set(op->ptr, "offset", 0.0f);
}
op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator");
+ uint objects_used_len = 0;
+
+ {
+ uint ob_store_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &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];
+ 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->em = em;
opdata->is_modal = is_modal;
opdata->value_mode = OFFSET_VALUE;
opdata->segments = (float) RNA_int_get(op->ptr, "segments");
@@ -174,14 +287,16 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
- opdata->mesh_backup = EDBM_redo_state_store(em);
+ 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->twtype = v3d->twtype;
- v3d->twtype = 0;
+ opdata->gizmo_flag = v3d->gizmo_flag;
+ v3d->gizmo_flag = V3D_GIZMO_HIDE;
}
}
@@ -191,8 +306,10 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
static bool edbm_bevel_calc(wmOperator *op)
{
BevelData *opdata = op->customdata;
- BMEditMesh *em = opdata->em;
+ BMEditMesh *em;
BMOperator bmop;
+ bool changed = false;
+
const float offset = RNA_float_get(op->ptr, "offset");
const int offset_type = RNA_enum_get(op->ptr, "offset_type");
const int segments = RNA_int_get(op->ptr, "segments");
@@ -201,41 +318,55 @@ static bool edbm_bevel_calc(wmOperator *op)
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 float hn_strength = RNA_float_get(op->ptr, "strength");
+ const int hnmode = RNA_enum_get(op->ptr, "hnmode");
- /* revert to original mesh */
- if (opdata->is_modal) {
- EDBM_redo_state_restore(opdata->mesh_backup, em, false);
- }
- if (em->ob) {
- material = CLAMPIS(material, -1, em->ob->totcol - 1);
- }
+ 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);
+ }
- 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",
- BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
- clamp_overlap, material, loop_slide);
+ if (em->ob) {
+ material = CLAMPIS(material, -1, em->ob->totcol - 1);
+ }
- BMO_op_exec(em->bm, &bmop);
+ 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 strength=%f hnmode=%i",
+ BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile,
+ clamp_overlap, material, loop_slide, mark_seam, mark_sharp, hn_strength, hnmode);
- 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);
- }
+ BMO_op_exec(em->bm, &bmop);
- /* no need to de-select existing geometry */
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- return false;
- }
+ 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);
+ }
- EDBM_mesh_normals_update(opdata->em);
+ if (hnmode != BEVEL_HN_NONE) {
+ bevel_harden_normals(em, &bmop, hn_strength);
+ }
- EDBM_update_generic(opdata->em, true, true);
+ /* no need to de-select existing geometry */
+ if (!EDBM_op_finish(em, &bmop, op, true)) {
+ continue;
+ }
- return true;
+ EDBM_mesh_normals_update(em);
+
+ EDBM_update_generic(em, true, true);
+ changed = true;
+ }
+ return changed;
}
static void edbm_bevel_exit(bContext *C, wmOperator *op)
@@ -245,20 +376,23 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op)
ScrArea *sa = CTX_wm_area(C);
if (sa) {
- ED_area_headerprint(sa, NULL);
+ ED_area_status_text(sa, NULL);
}
if (opdata->is_modal) {
View3D *v3d = CTX_wm_view3d(C);
ARegion *ar = CTX_wm_region(C);
- EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
+ 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->twtype = opdata->twtype;
+ v3d->gizmo_flag = opdata->gizmo_flag;
}
G.moving = 0;
}
- MEM_freeN(opdata);
+ MEM_SAFE_FREE(opdata->ob_store);
+ MEM_SAFE_FREE(op->customdata);
op->customdata = NULL;
}
@@ -266,8 +400,10 @@ static void 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);
+ 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);
@@ -446,7 +582,9 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
case LEFTMOUSE:
case PADENTER:
case RETKEY:
- if (event->val == KM_PRESS) {
+ if ((event->val == KM_PRESS) ||
+ ((event->val == KM_RELEASE) && RNA_boolean_get(op->ptr, "release_confirm")))
+ {
edbm_bevel_calc(op);
edbm_bevel_exit(C, op);
return OPERATOR_FINISHED;
@@ -570,6 +708,26 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
edbm_bevel_update_header(C, op);
handled = true;
break;
+ case UKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ else {
+ bool mark_seam = RNA_boolean_get(op->ptr, "mark_seam");
+ RNA_boolean_set(op->ptr, "mark_seam", !mark_seam);
+ edbm_bevel_calc(op);
+ handled = true;
+ break;
+ }
+ case KKEY:
+ if (event->val == KM_RELEASE)
+ break;
+ else {
+ bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
+ RNA_boolean_set(op->ptr, "mark_sharp", !mark_sharp);
+ edbm_bevel_calc(op);
+ handled = true;
+ break;
+ }
}
@@ -608,6 +766,13 @@ void MESH_OT_bevel(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL},
};
+ static EnumPropertyItem harden_normals_items[] = {
+ { BEVEL_HN_NONE, "HN_NONE", 0, "Off", "Do not use Harden Normals" },
+ { BEVEL_HN_FACE, "HN_FACE", 0, "Face Area", "Use faces as weight" },
+ { BEVEL_HN_ADJ, "HN_ADJ", 0, "Vertex average", "Use adjacent vertices as weight" },
+ { 0, NULL, 0, NULL, NULL },
+ };
+
/* identifiers */
ot->name = "Bevel";
ot->description = "Edge Bevel";
@@ -633,6 +798,15 @@ void MESH_OT_bevel(wmOperatorType *ot)
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_float(ot->srna, "strength", 0.5f, 0.0f, 1.0f, "Normal Strength",
+ "Strength of calculated normal", 0.0f, 1.0f);
+ RNA_def_enum(ot->srna, "hnmode", harden_normals_items, BEVEL_HN_NONE, "Normal Mode",
+ "Weighting mode for Harden Normals");
+ prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
}