diff options
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r-- | source/blender/editors/mesh/editmesh_add_gizmo.c | 100 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_bevel.c | 154 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_bisect.c | 110 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_extrude.c | 68 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_extrude_spin.c | 118 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_inset.c | 8 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife.c | 86 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_loopcut.c | 12 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_select.c | 12 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 1360 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_undo.c | 2 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_utils.c | 23 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_intern.h | 10 | ||||
-rw-r--r-- | source/blender/editors/mesh/mesh_ops.c | 30 |
14 files changed, 1797 insertions, 296 deletions
diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c index be5c01e08df..6fa0eb33b89 100644 --- a/source/blender/editors/mesh/editmesh_add_gizmo.c +++ b/source/blender/editors/mesh/editmesh_add_gizmo.c @@ -160,14 +160,14 @@ static void gizmo_mesh_placement_update_from_op(GizmoPlacementGroup *man) /* translate callbacks */ static void gizmo_placement_prop_matrix_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoPlacementGroup *man = mpr->parent_mgroup->customdata; + GizmoPlacementGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(gz_prop); if (value_p != man->cage->matrix_offset) { mul_m4_m4m4(value_p, man->cage->matrix_basis, man->cage->matrix_offset); @@ -176,14 +176,14 @@ static void gizmo_placement_prop_matrix_get( } static void gizmo_placement_prop_matrix_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value) { - GizmoPlacementGroup *man = mpr->parent_mgroup->customdata; + GizmoPlacementGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; - BLI_assert(mpr_prop->type->array_length == 16); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(gz_prop); float mat[4][4]; mul_m4_m4m4(mat, man->cage->matrix_basis, value); @@ -197,38 +197,38 @@ static void gizmo_placement_prop_matrix_set( gizmo_placement_exec(man); } -static bool gizmo_mesh_placement_poll(const bContext *C, wmGizmoGroupType *wgt) +static bool gizmo_mesh_placement_poll(const bContext *C, wmGizmoGroupType *gzgt) { wmOperator *op = WM_operator_last_redo(C); if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_gizmo")) { - WM_gizmo_group_type_unlink_delayed_ptr(wgt); + WM_gizmo_group_type_unlink_delayed_ptr(gzgt); return false; } return true; } static void gizmo_mesh_placement_modal_from_setup( - const bContext *C, wmGizmoGroup *mgroup) + const bContext *C, wmGizmoGroup *gzgroup) { - GizmoPlacementGroup *man = mgroup->customdata; + GizmoPlacementGroup *man = gzgroup->customdata; /* Initial size. */ { - wmGizmo *mpr = man->cage; - zero_m4(mpr->matrix_offset); - - /* TODO: support zero scaled matrix in 'GIZMO_WT_cage_3d'. */ - mpr->matrix_offset[0][0] = 0.01; - mpr->matrix_offset[1][1] = 0.01; - mpr->matrix_offset[2][2] = 0.01; - mpr->matrix_offset[3][3] = 1.0f; + wmGizmo *gz = man->cage; + zero_m4(gz->matrix_offset); + + /* TODO: support zero scaled matrix in 'GIZMO_GT_cage_3d'. */ + gz->matrix_offset[0][0] = 0.01; + gz->matrix_offset[1][1] = 0.01; + gz->matrix_offset[2][2] = 0.01; + gz->matrix_offset[3][3] = 1.0f; } /* Start off dragging. */ { wmWindow *win = CTX_wm_window(C); ARegion *ar = CTX_wm_region(C); - wmGizmo *mpr = man->cage; + wmGizmo *gz = man->cage; { float mat3[3][3]; @@ -239,19 +239,19 @@ static void gizmo_mesh_placement_modal_from_setup( win->eventstate->y - ar->winrct.ymin, }, location, mat3); - copy_m4_m3(mpr->matrix_basis, mat3); - copy_v3_v3(mpr->matrix_basis[3], location); + copy_m4_m3(gz->matrix_basis, mat3); + copy_v3_v3(gz->matrix_basis[3], location); } if (1) { - wmGizmoMap *mmap = mgroup->parent_mmap; + wmGizmoMap *gzmap = gzgroup->parent_gzmap; WM_gizmo_modal_set_from_setup( - mmap, (bContext *)C, man->cage, ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, win->eventstate); + gzmap, (bContext *)C, man->cage, ED_GIZMO_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, win->eventstate); } } } -static void gizmo_mesh_placement_setup(const bContext *C, wmGizmoGroup *mgroup) +static void gizmo_mesh_placement_setup(const bContext *C, wmGizmoGroup *gzgroup) { wmOperator *op = WM_operator_last_redo(C); @@ -260,11 +260,11 @@ static void gizmo_mesh_placement_setup(const bContext *C, wmGizmoGroup *mgroup) } struct GizmoPlacementGroup *man = MEM_callocN(sizeof(GizmoPlacementGroup), __func__); - mgroup->customdata = man; + gzgroup->customdata = man; - const wmGizmoType *wt_cage = WM_gizmotype_find("GIZMO_WT_cage_3d", true); + const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_3d", true); - man->cage = WM_gizmo_new_ptr(wt_cage, mgroup, NULL); + man->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL); UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, man->cage->color); @@ -293,32 +293,32 @@ static void gizmo_mesh_placement_setup(const bContext *C, wmGizmoGroup *mgroup) }); } - gizmo_mesh_placement_modal_from_setup(C, mgroup); + gizmo_mesh_placement_modal_from_setup(C, gzgroup); } static void gizmo_mesh_placement_draw_prepare( - const bContext *UNUSED(C), wmGizmoGroup *mgroup) + const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - GizmoPlacementGroup *man = mgroup->customdata; + GizmoPlacementGroup *man = gzgroup->customdata; if (man->data.op->next) { man->data.op = WM_operator_last_redo((bContext *)man->data.context); } gizmo_mesh_placement_update_from_op(man); } -static void MESH_WGT_add_bounds(struct wmGizmoGroupType *wgt) +static void MESH_GGT_add_bounds(struct wmGizmoGroupType *gzgt) { - wgt->name = "Mesh Add Bounds"; - wgt->idname = "MESH_WGT_add_bounds"; + gzgt->name = "Mesh Add Bounds"; + gzgt->idname = "MESH_GGT_add_bounds"; - wgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - wgt->poll = gizmo_mesh_placement_poll; - wgt->setup = gizmo_mesh_placement_setup; - wgt->draw_prepare = gizmo_mesh_placement_draw_prepare; + gzgt->poll = gizmo_mesh_placement_poll; + gzgt->setup = gizmo_mesh_placement_setup; + gzgt->draw_prepare = gizmo_mesh_placement_draw_prepare; } /** \} */ @@ -379,18 +379,18 @@ static int add_primitive_cube_gizmo_invoke(bContext *C, wmOperator *op, const wm int ret = add_primitive_cube_gizmo_exec(C, op); if (ret & OPERATOR_FINISHED) { /* Setup gizmos */ - if (v3d && ((v3d->mpr_flag & V3D_GIZMO_HIDE) == 0)) { + if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) { ARegion *ar = CTX_wm_region(C); - wmGizmoMap *mmap = ar->gizmo_map; - wmGizmoGroupType *wgt = WM_gizmogrouptype_find("MESH_WGT_add_bounds", false); - wmGizmoGroup *mgroup = WM_gizmomap_group_find_ptr(mmap, wgt); - if (mgroup != NULL) { - GizmoPlacementGroup *man = mgroup->customdata; + wmGizmoMap *gzmap = ar->gizmo_map; + wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_add_bounds", false); + wmGizmoGroup *gzgroup = WM_gizmomap_group_find_ptr(gzmap, gzgt); + if (gzgroup != NULL) { + GizmoPlacementGroup *man = gzgroup->customdata; man->data.op = op; - gizmo_mesh_placement_modal_from_setup(C, mgroup); + gizmo_mesh_placement_modal_from_setup(C, gzgroup); } else { - WM_gizmo_group_type_ensure_ptr(wgt); + WM_gizmo_group_type_ensure_ptr(gzgt); } } } @@ -420,7 +420,7 @@ void MESH_OT_primitive_cube_add_gizmo(wmOperatorType *ot) PropertyRNA *prop = RNA_def_float_matrix(ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - WM_gizmogrouptype_append(MESH_WGT_add_bounds); + WM_gizmogrouptype_append(MESH_GGT_add_bounds); } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index b73ce410626..e87abc6adf7 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" @@ -38,6 +39,7 @@ #include "BKE_editmesh.h" #include "BKE_unit.h" #include "BKE_layer.h" +#include "BKE_mesh.h" #include "RNA_define.h" #include "RNA_access.h" @@ -95,7 +97,7 @@ typedef struct { /* modal only */ float mcenter[2]; void *draw_handle_pixel; - short mpr_flag; + 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; @@ -134,6 +136,98 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op) } } +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) { Scene *scene = CTX_data_scene(C); @@ -201,8 +295,8 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal) G.moving = G_TRANSFORM_EDIT; if (v3d) { - opdata->mpr_flag = v3d->mpr_flag; - v3d->mpr_flag = V3D_GIZMO_HIDE; + opdata->gizmo_flag = v3d->gizmo_flag; + v3d->gizmo_flag = V3D_GIZMO_HIDE; } } @@ -224,6 +318,10 @@ 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"); for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) { @@ -238,11 +336,12 @@ static bool edbm_bevel_calc(wmOperator *op) material = CLAMPIS(material, -1, em->ob->totcol - 1); } - 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); + 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); BMO_op_exec(em->bm, &bmop); @@ -253,6 +352,10 @@ static bool edbm_bevel_calc(wmOperator *op) BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); } + if (hnmode != BEVEL_HN_NONE) { + bevel_harden_normals(em, &bmop, hn_strength); + } + /* no need to de-select existing geometry */ if (!EDBM_op_finish(em, &bmop, op, true)) { continue; @@ -284,7 +387,7 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op) } ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); if (v3d) { - v3d->mpr_flag = opdata->mpr_flag; + v3d->gizmo_flag = opdata->gizmo_flag; } G.moving = 0; } @@ -603,6 +706,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; + } } @@ -641,6 +764,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"; @@ -666,6 +796,12 @@ 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"); } diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index a9e11b7b411..9416d889a3b 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -70,7 +70,7 @@ typedef struct { /* modal only */ BMBackup mesh_backup; bool is_first; - short mpr_flag; + short gizmo_flag; } BisectData; static bool mesh_bisect_interactive_calc( @@ -156,8 +156,8 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* misc other vars */ G.moving = G_TRANSFORM_EDIT; - opdata->mpr_flag = v3d->mpr_flag; - v3d->mpr_flag = V3D_GIZMO_HIDE; + opdata->gizmo_flag = v3d->gizmo_flag; + v3d->gizmo_flag = V3D_GIZMO_HIDE; /* initialize modal callout */ ED_workspace_status_text(C, IFACE_("LMB: Click and drag to draw cut line")); @@ -169,7 +169,7 @@ static void edbm_bisect_exit(bContext *C, BisectData *opdata) { View3D *v3d = CTX_wm_view3d(C); EDBM_redo_state_free(&opdata->mesh_backup, NULL, false); - v3d->mpr_flag = opdata->mpr_flag; + v3d->gizmo_flag = opdata->gizmo_flag; G.moving = 0; } @@ -199,8 +199,8 @@ static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Setup gizmos */ { View3D *v3d = CTX_wm_view3d(C); - if (v3d && (v3d->mpr_flag & V3D_GIZMO_HIDE) == 0) { - WM_gizmo_group_type_ensure("MESH_WGT_bisect"); + if (v3d && (v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) { + WM_gizmo_group_type_ensure("MESH_GGT_bisect"); } } #endif @@ -334,7 +334,7 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op) } #ifdef USE_GIZMO -static void MESH_WGT_bisect(struct wmGizmoGroupType *wgt); +static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt); #endif void MESH_OT_bisect(struct wmOperatorType *ot) @@ -374,7 +374,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot) WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT); #ifdef USE_GIZMO - WM_gizmogrouptype_append(MESH_WGT_bisect); + WM_gizmogrouptype_append(MESH_GGT_bisect); #endif } @@ -459,40 +459,40 @@ static void gizmo_mesh_bisect_update_from_op(GizmoGroup *man) /* depth callbacks */ static void gizmo_bisect_prop_depth_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoGroup *man = mpr->parent_mgroup->customdata; + GizmoGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_co[3], plane_no[3]; RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co); RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no); - value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]); + value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]); } static void gizmo_bisect_prop_depth_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - GizmoGroup *man = mpr->parent_mgroup->customdata; + GizmoGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; const float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_co[3], plane[4]; RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co); RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane); normalize_v3(plane); - plane[3] = -value[0] - dot_v3v3(plane, mpr->matrix_basis[3]); + plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]); /* Keep our location, may be offset simply to be inside the viewport. */ closest_to_plane_normalized_v3(plane_co, plane, plane_co); @@ -504,27 +504,27 @@ static void gizmo_bisect_prop_depth_set( /* translate callbacks */ static void gizmo_bisect_prop_translate_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoGroup *man = mpr->parent_mgroup->customdata; + GizmoGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; - BLI_assert(mpr_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, value_p); } static void gizmo_bisect_prop_translate_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - GizmoGroup *man = mpr->parent_mgroup->customdata; + GizmoGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; - BLI_assert(mpr_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, value_p); @@ -533,15 +533,15 @@ static void gizmo_bisect_prop_translate_set( /* angle callbacks */ static void gizmo_bisect_prop_angle_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoGroup *man = mpr->parent_mgroup->customdata; + GizmoGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_no[4]; RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no); @@ -560,15 +560,15 @@ static void gizmo_bisect_prop_angle_get( } static void gizmo_bisect_prop_angle_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - GizmoGroup *man = mpr->parent_mgroup->customdata; + GizmoGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; const float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_no[4]; RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no); @@ -593,17 +593,17 @@ static void gizmo_bisect_prop_angle_set( } } -static bool gizmo_mesh_bisect_poll(const bContext *C, wmGizmoGroupType *wgt) +static bool gizmo_mesh_bisect_poll(const bContext *C, wmGizmoGroupType *gzgt) { wmOperator *op = WM_operator_last_redo(C); if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) { - WM_gizmo_group_type_unlink_delayed_ptr(wgt); + WM_gizmo_group_type_unlink_delayed_ptr(gzgt); return false; } return true; } -static void gizmo_mesh_bisect_setup(const bContext *C, wmGizmoGroup *mgroup) +static void gizmo_mesh_bisect_setup(const bContext *C, wmGizmoGroup *gzgroup) { wmOperator *op = WM_operator_last_redo(C); @@ -612,15 +612,15 @@ static void gizmo_mesh_bisect_setup(const bContext *C, wmGizmoGroup *mgroup) } struct GizmoGroup *man = MEM_callocN(sizeof(GizmoGroup), __func__); - mgroup->customdata = man; + gzgroup->customdata = man; - const wmGizmoType *wt_arrow = WM_gizmotype_find("GIZMO_WT_arrow_3d", true); - const wmGizmoType *wt_grab = WM_gizmotype_find("GIZMO_WT_grab_3d", true); - const wmGizmoType *wt_dial = WM_gizmotype_find("GIZMO_WT_dial_3d", true); + const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); + const wmGizmoType *gzt_grab = WM_gizmotype_find("GIZMO_GT_grab_3d", true); + const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); - man->translate_z = WM_gizmo_new_ptr(wt_arrow, mgroup, NULL); - man->translate_c = WM_gizmo_new_ptr(wt_grab, mgroup, NULL); - man->rotate_c = WM_gizmo_new_ptr(wt_dial, mgroup, NULL); + man->translate_z = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + man->translate_c = WM_gizmo_new_ptr(gzt_grab, gzgroup, NULL); + man->rotate_c = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, man->translate_z->color); UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, man->translate_c->color); @@ -673,28 +673,28 @@ static void gizmo_mesh_bisect_setup(const bContext *C, wmGizmoGroup *mgroup) } static void gizmo_mesh_bisect_draw_prepare( - const bContext *UNUSED(C), wmGizmoGroup *mgroup) + const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - GizmoGroup *man = mgroup->customdata; + GizmoGroup *man = gzgroup->customdata; if (man->data.op->next) { man->data.op = WM_operator_last_redo((bContext *)man->data.context); } gizmo_mesh_bisect_update_from_op(man); } -static void MESH_WGT_bisect(struct wmGizmoGroupType *wgt) +static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt) { - wgt->name = "Mesh Bisect"; - wgt->idname = "MESH_WGT_bisect"; + gzgt->name = "Mesh Bisect"; + gzgt->idname = "MESH_GGT_bisect"; - wgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - wgt->poll = gizmo_mesh_bisect_poll; - wgt->setup = gizmo_mesh_bisect_setup; - wgt->draw_prepare = gizmo_mesh_bisect_draw_prepare; + gzgt->poll = gizmo_mesh_bisect_poll; + gzgt->setup = gizmo_mesh_bisect_setup; + gzgt->draw_prepare = gizmo_mesh_bisect_draw_prepare; } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index dd167c1fc15..c5ef2a06059 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -365,11 +365,11 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) #ifdef USE_GIZMO -const float extrude_button_scale = 0.15f; -const float extrude_button_offset_scale = 1.5f; -const float extrude_arrow_scale = 1.0f; -const float extrude_arrow_xyz_axis_scale = 1.0f; -const float extrude_arrow_normal_axis_scale = 1.75f; +static const float extrude_button_scale = 0.15f; +static const float extrude_button_offset_scale = 1.5f; +static const float extrude_arrow_scale = 1.0f; +static const float extrude_arrow_xyz_axis_scale = 1.0f; +static const float extrude_arrow_normal_axis_scale = 1.75f; static const uchar shape_plus[] = { 0x5f, 0xfb, 0x40, 0xee, 0x25, 0xda, 0x11, 0xbf, 0x4, 0xa0, 0x0, 0x80, 0x4, 0x5f, 0x11, @@ -417,31 +417,31 @@ static void gizmo_mesh_extrude_orientation_matrix_set( } } -static bool gizmo_mesh_extrude_poll(const bContext *C, wmGizmoGroupType *wgt) +static bool gizmo_mesh_extrude_poll(const bContext *C, wmGizmoGroupType *gzgt) { ScrArea *sa = CTX_wm_area(C); bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL; if ((tref_rt == NULL) || - !STREQ(wgt->idname, tref_rt->gizmo_group) || + !STREQ(gzgt->idname, tref_rt->gizmo_group) || !ED_operator_editmesh_view3d((bContext *)C)) { - WM_gizmo_group_type_unlink_delayed_ptr(wgt); + WM_gizmo_group_type_unlink_delayed_ptr(gzgt); return false; } return true; } -static void gizmo_mesh_extrude_setup(const bContext *UNUSED(C), wmGizmoGroup *mgroup) +static void gizmo_mesh_extrude_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { struct GizmoExtrudeGroup *man = MEM_callocN(sizeof(GizmoExtrudeGroup), __func__); - mgroup->customdata = man; + gzgroup->customdata = man; - const wmGizmoType *wt_arrow = WM_gizmotype_find("GIZMO_WT_arrow_3d", true); - const wmGizmoType *wt_grab = WM_gizmotype_find("GIZMO_WT_button_2d", true); + const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); + const wmGizmoType *gzt_grab = WM_gizmotype_find("GIZMO_GT_button_2d", true); for (int i = 0; i < 4; i++) { - man->adjust_xyz_no[i] = WM_gizmo_new_ptr(wt_arrow, mgroup, NULL); - man->invoke_xyz_no[i] = WM_gizmo_new_ptr(wt_grab, mgroup, NULL); + man->adjust_xyz_no[i] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + man->invoke_xyz_no[i] = WM_gizmo_new_ptr(gzt_grab, gzgroup, NULL); man->invoke_xyz_no[i]->flag |= WM_GIZMO_DRAW_OFFSET_SCALE; } @@ -503,9 +503,9 @@ static void gizmo_mesh_extrude_setup(const bContext *UNUSED(C), wmGizmoGroup *mg } } -static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *mgroup) +static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) { - GizmoExtrudeGroup *man = mgroup->customdata; + GizmoExtrudeGroup *man = gzgroup->customdata; for (int i = 0; i < 4; i++) { WM_gizmo_set_flag(man->invoke_xyz_no[i], WM_GIZMO_HIDDEN, true); @@ -623,9 +623,9 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *mgroup) } } -static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *mgroup) +static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - GizmoExtrudeGroup *man = mgroup->customdata; + GizmoExtrudeGroup *man = gzgroup->customdata; switch (man->data.orientation_type) { case V3D_MANIP_VIEW: { @@ -640,38 +640,38 @@ static void gizmo_mesh_extrude_draw_prepare(const bContext *C, wmGizmoGroup *mgr } static void gizmo_mesh_extrude_message_subscribe( - const bContext *C, wmGizmoGroup *mgroup, struct wmMsgBus *mbus) + const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus) { ARegion *ar = CTX_wm_region(C); /* Subscribe to view properties */ - wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { .owner = ar, - .user_data = mgroup->parent_mmap, + .user_data = gzgroup->parent_gzmap, .notify = WM_gizmo_do_msg_notify_tag_refresh, }; { - WM_msg_subscribe_rna_anon_prop(mbus, Scene, transform_orientation, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, Scene, transform_orientation, &msg_sub_value_gz_tag_refresh); } } -static void MESH_WGT_extrude(struct wmGizmoGroupType *wgt) +static void MESH_GGT_extrude(struct wmGizmoGroupType *gzgt) { - wgt->name = "Mesh Extrude"; - wgt->idname = "MESH_WGT_extrude"; + gzgt->name = "Mesh Extrude"; + gzgt->idname = "MESH_GGT_extrude"; - wgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - wgt->poll = gizmo_mesh_extrude_poll; - wgt->setup = gizmo_mesh_extrude_setup; - wgt->refresh = gizmo_mesh_extrude_refresh; - wgt->draw_prepare = gizmo_mesh_extrude_draw_prepare; - wgt->message_subscribe = gizmo_mesh_extrude_message_subscribe; + gzgt->poll = gizmo_mesh_extrude_poll; + gzgt->setup = gizmo_mesh_extrude_setup; + gzgt->refresh = gizmo_mesh_extrude_refresh; + gzgt->draw_prepare = gizmo_mesh_extrude_draw_prepare; + gzgt->message_subscribe = gizmo_mesh_extrude_message_subscribe; } #endif /* USE_GIZMO */ @@ -826,7 +826,7 @@ void MESH_OT_extrude_context(wmOperatorType *ot) Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); #ifdef USE_GIZMO - WM_gizmogrouptype_append(MESH_WGT_extrude); + WM_gizmogrouptype_append(MESH_GGT_extrude); #endif } diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 3864bd63036..adb7ee71ee0 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -143,40 +143,40 @@ static void gizmo_mesh_spin_update_from_op(GizmoSpinGroup *man) /* depth callbacks */ static void gizmo_spin_prop_depth_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_co[3], plane_no[3]; RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co); RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no); - value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]); + value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, gz->matrix_basis[3]); } static void gizmo_spin_prop_depth_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; const float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_co[3], plane[4]; RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, plane_co); RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane); normalize_v3(plane); - plane[3] = -value[0] - dot_v3v3(plane, mpr->matrix_basis[3]); + plane[3] = -value[0] - dot_v3v3(plane, gz->matrix_basis[3]); /* Keep our location, may be offset simply to be inside the viewport. */ closest_to_plane_normalized_v3(plane_co, plane, plane_co); @@ -188,28 +188,28 @@ static void gizmo_spin_prop_depth_set( /* translate callbacks */ static void gizmo_spin_prop_translate_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); RNA_property_float_get_array(op->ptr, man->data.prop_axis_co, value); } static void gizmo_spin_prop_translate_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; - BLI_assert(mpr_prop->type->array_length == 3); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 3); + UNUSED_VARS_NDEBUG(gz_prop); RNA_property_float_set_array(op->ptr, man->data.prop_axis_co, value); @@ -218,15 +218,15 @@ static void gizmo_spin_prop_translate_set( /* angle callbacks */ static void gizmo_spin_prop_axis_angle_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_no[4]; RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no); @@ -245,15 +245,15 @@ static void gizmo_spin_prop_axis_angle_get( } static void gizmo_spin_prop_axis_angle_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; const float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); float plane_no[4]; RNA_property_float_get_array(op->ptr, man->data.prop_axis_no, plane_no); @@ -280,43 +280,43 @@ static void gizmo_spin_prop_axis_angle_set( /* angle callbacks */ static void gizmo_spin_prop_angle_get( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); value[0] = RNA_property_float_get(op->ptr, man->data.prop_angle); } static void gizmo_spin_prop_angle_set( - const wmGizmo *mpr, wmGizmoProperty *mpr_prop, + const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - GizmoSpinGroup *man = mpr->parent_mgroup->customdata; + GizmoSpinGroup *man = gz->parent_gzgroup->customdata; wmOperator *op = man->data.op; - BLI_assert(mpr_prop->type->array_length == 1); - UNUSED_VARS_NDEBUG(mpr_prop); + BLI_assert(gz_prop->type->array_length == 1); + UNUSED_VARS_NDEBUG(gz_prop); const float *value = value_p; RNA_property_float_set(op->ptr, man->data.prop_angle, value[0]); gizmo_spin_exec(man); } -static bool gizmo_mesh_spin_poll(const bContext *C, wmGizmoGroupType *wgt) +static bool gizmo_mesh_spin_poll(const bContext *C, wmGizmoGroupType *gzgt) { wmOperator *op = WM_operator_last_redo(C); if (op == NULL || !STREQ(op->type->idname, "MESH_OT_spin")) { - WM_gizmo_group_type_unlink_delayed_ptr(wgt); + WM_gizmo_group_type_unlink_delayed_ptr(gzgt); return false; } return true; } -static void gizmo_mesh_spin_setup(const bContext *C, wmGizmoGroup *mgroup) +static void gizmo_mesh_spin_setup(const bContext *C, wmGizmoGroup *gzgroup) { wmOperator *op = WM_operator_last_redo(C); @@ -325,16 +325,16 @@ static void gizmo_mesh_spin_setup(const bContext *C, wmGizmoGroup *mgroup) } struct GizmoSpinGroup *man = MEM_callocN(sizeof(GizmoSpinGroup), __func__); - mgroup->customdata = man; + gzgroup->customdata = man; - const wmGizmoType *wt_arrow = WM_gizmotype_find("GIZMO_WT_arrow_3d", true); - const wmGizmoType *wt_grab = WM_gizmotype_find("GIZMO_WT_grab_3d", true); - const wmGizmoType *wt_dial = WM_gizmotype_find("GIZMO_WT_dial_3d", true); + const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); + const wmGizmoType *gzt_grab = WM_gizmotype_find("GIZMO_GT_grab_3d", true); + const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true); - man->translate_z = WM_gizmo_new_ptr(wt_arrow, mgroup, NULL); - man->translate_c = WM_gizmo_new_ptr(wt_grab, mgroup, NULL); - man->rotate_c = WM_gizmo_new_ptr(wt_dial, mgroup, NULL); - man->angle_z = WM_gizmo_new_ptr(wt_dial, mgroup, NULL); + man->translate_z = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + man->translate_c = WM_gizmo_new_ptr(gzt_grab, gzgroup, NULL); + man->rotate_c = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); + man->angle_z = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, man->translate_z->color); UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, man->translate_c->color); @@ -403,28 +403,28 @@ static void gizmo_mesh_spin_setup(const bContext *C, wmGizmoGroup *mgroup) } static void gizmo_mesh_spin_draw_prepare( - const bContext *UNUSED(C), wmGizmoGroup *mgroup) + const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - GizmoSpinGroup *man = mgroup->customdata; + GizmoSpinGroup *man = gzgroup->customdata; if (man->data.op->next) { man->data.op = WM_operator_last_redo((bContext *)man->data.context); } gizmo_mesh_spin_update_from_op(man); } -static void MESH_WGT_spin(struct wmGizmoGroupType *wgt) +static void MESH_GGT_spin(struct wmGizmoGroupType *gzgt) { - wgt->name = "Mesh Spin"; - wgt->idname = "MESH_WGT_spin"; + gzgt->name = "Mesh Spin"; + gzgt->idname = "MESH_GGT_spin"; - wgt->flag = WM_GIZMOGROUPTYPE_3D; + gzgt->flag = WM_GIZMOGROUPTYPE_3D; - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; - wgt->poll = gizmo_mesh_spin_poll; - wgt->setup = gizmo_mesh_spin_setup; - wgt->draw_prepare = gizmo_mesh_spin_draw_prepare; + gzgt->poll = gizmo_mesh_spin_poll; + gzgt->setup = gizmo_mesh_spin_setup; + gzgt->draw_prepare = gizmo_mesh_spin_draw_prepare; } /** \} */ @@ -511,8 +511,8 @@ static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e #ifdef USE_GIZMO if (ret & OPERATOR_FINISHED) { /* Setup gizmos */ - if (v3d && ((v3d->mpr_flag & V3D_GIZMO_HIDE) == 0)) { - WM_gizmo_group_type_ensure("MESH_WGT_spin"); + if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) { + WM_gizmo_group_type_ensure("MESH_GGT_spin"); } } #endif @@ -549,6 +549,6 @@ void MESH_OT_spin(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); #ifdef USE_GIZMO - WM_gizmogrouptype_append(MESH_WGT_spin); + WM_gizmogrouptype_append(MESH_GGT_spin); #endif } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 1be180b852c..486203462a0 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -78,7 +78,7 @@ typedef struct { /* modal only */ float mcenter[2]; void *draw_handle_pixel; - short mpr_flag; + short gizmo_flag; } InsetData; @@ -173,8 +173,8 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); G.moving = G_TRANSFORM_EDIT; if (v3d) { - opdata->mpr_flag = v3d->mpr_flag; - v3d->mpr_flag = V3D_GIZMO_HIDE; + opdata->gizmo_flag = v3d->gizmo_flag; + v3d->gizmo_flag = V3D_GIZMO_HIDE; } } @@ -196,7 +196,7 @@ static void edbm_inset_exit(bContext *C, wmOperator *op) } ED_region_draw_cb_exit(ar->type, opdata->draw_handle_pixel); if (v3d) { - v3d->mpr_flag = opdata->mpr_flag; + v3d->gizmo_flag = opdata->gizmo_flag; } G.moving = 0; } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 8a9a5eadbdd..c98aef74ae7 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1007,13 +1007,13 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) copy_v3_v3(v2, ray_hit_best[1]); } - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformThemeColor(TH_TRANSFORM); GPU_line_width(2.0); - immBegin(GWN_PRIM_LINES, 2); + immBegin(GPU_PRIM_LINES, 2); immVertex3fv(pos, v1); immVertex3fv(pos, v2); immEnd(); @@ -1040,26 +1040,27 @@ static void knife_init_colors(KnifeColors *colors) static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) { const KnifeTool_OpData *kcd = arg; - GPU_depth_test(false); glPolygonOffset(1.0f, 1.0f); - gpuPushMatrix(); - gpuMultMatrix(kcd->ob->obmat); + GPU_matrix_push(); + GPU_matrix_mul(kcd->ob->obmat); + + if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) { + knifetool_draw_angle_snapping(kcd); + } - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); if (kcd->mode == MODE_DRAGGING) { - if (kcd->is_angle_snapping) - knifetool_draw_angle_snapping(kcd); - immUniformColor3ubv(kcd->colors.line); GPU_line_width(2.0); - immBegin(GWN_PRIM_LINES, 2); + immBegin(GPU_PRIM_LINES, 2); immVertex3fv(pos, kcd->prev.cage); immVertex3fv(pos, kcd->curr.cage); immEnd(); @@ -1069,7 +1070,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.point); GPU_point_size(11); - immBegin(GWN_PRIM_POINTS, 1); + immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->prev.cage); immEnd(); } @@ -1078,7 +1079,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.curpoint); GPU_point_size(9); - immBegin(GWN_PRIM_POINTS, 1); + immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->prev.cage); immEnd(); } @@ -1087,7 +1088,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.edge); GPU_line_width(2.0); - immBegin(GWN_PRIM_LINES, 2); + immBegin(GPU_PRIM_LINES, 2); immVertex3fv(pos, kcd->curr.edge->v1->cageco); immVertex3fv(pos, kcd->curr.edge->v2->cageco); immEnd(); @@ -1096,7 +1097,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.point); GPU_point_size(11); - immBegin(GWN_PRIM_POINTS, 1); + immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->curr.cage); immEnd(); } @@ -1105,47 +1106,50 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.curpoint); GPU_point_size(9); - immBegin(GWN_PRIM_POINTS, 1); + immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->curr.cage); immEnd(); } if (kcd->totlinehit > 0) { KnifeLineHit *lh; - int i; + int i, v, vs; + float fcol[4]; GPU_blend(true); GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - /* draw any snapped verts first */ - immUniformColor4ubv(kcd->colors.point_a); - GPU_point_size(11); - - immBeginAtMost(GWN_PRIM_POINTS, kcd->totlinehit); + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, kcd->totlinehit); lh = kcd->linehits; - for (i = 0; i < kcd->totlinehit; i++, lh++) { + for (i = 0, v = 0, vs = kcd->totlinehit - 1; i < kcd->totlinehit; i++, lh++) { if (lh->v) { - immVertex3fv(pos, lh->cagehit); + GPU_vertbuf_attr_set(vert, pos, v++, lh->cagehit); + } + else { + GPU_vertbuf_attr_set(vert, pos, vs--, lh->cagehit); } } - immEnd(); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); + + /* draw any snapped verts first */ + rgba_uchar_to_float(fcol, kcd->colors.point_a); + GPU_batch_uniform_4fv(batch, "color", fcol); + GPU_matrix_bind(batch->interface); + GPU_point_size(11); + GPU_batch_draw_range_ex(batch, 0, v - 1, false); /* now draw the rest */ - immUniformColor4ubv(kcd->colors.curpoint_a); + rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); + GPU_batch_uniform_4fv(batch, "color", fcol); GPU_point_size(7); + GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false); - immBeginAtMost(GWN_PRIM_POINTS, kcd->totlinehit); - - lh = kcd->linehits; - for (i = 0; i < kcd->totlinehit; i++, lh++) { - if (!lh->v) { - immVertex3fv(pos, lh->cagehit); - } - } - - immEnd(); + GPU_batch_program_use_end(batch); + GPU_batch_discard(batch); GPU_blend(false); } @@ -1157,7 +1161,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.line); GPU_line_width(1.0); - immBeginAtMost(GWN_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); BLI_mempool_iternew(kcd->kedges, &iter); for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { @@ -1169,6 +1173,9 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void } immEnd(); + + GPU_batch_draw(batch); + GPU_batch_discard(batch); } if (kcd->totkvert > 0) { @@ -1178,7 +1185,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.point); GPU_point_size(5.0); - immBeginAtMost(GWN_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); BLI_mempool_iternew(kcd->kverts, &iter); for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { @@ -1189,11 +1196,14 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void } immEnd(); + + GPU_batch_draw(batch); + GPU_batch_discard(batch); } immUnbindProgram(); - gpuPopMatrix(); + GPU_matrix_pop(); /* Reset default */ GPU_depth_test(true); diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 87c006095ed..95c94c146e4 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -113,16 +113,16 @@ static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *a if ((lcd->totedge > 0) || (lcd->totpoint > 0)) { GPU_depth_test(false); - gpuPushMatrix(); - gpuMultMatrix(lcd->ob->obmat); + GPU_matrix_push(); + GPU_matrix_mul(lcd->ob->obmat); - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor3ub(255, 0, 255); if (lcd->totedge > 0) { - immBegin(GWN_PRIM_LINES, lcd->totedge * 2); + immBegin(GPU_PRIM_LINES, lcd->totedge * 2); for (int i = 0; i < lcd->totedge; i++) { immVertex3fv(pos, lcd->edges[i][0]); @@ -135,7 +135,7 @@ static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *a if (lcd->totpoint > 0) { GPU_point_size(3.0f); - immBegin(GWN_PRIM_POINTS, lcd->totpoint); + immBegin(GPU_PRIM_POINTS, lcd->totpoint); for (int i = 0; i < lcd->totpoint; i++) { immVertex3fv(pos, lcd->points[i]); @@ -146,7 +146,7 @@ static void ringsel_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *a immUnbindProgram(); - gpuPopMatrix(); + GPU_matrix_pop(); /* Reset default */ GPU_depth_test(true); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 2e7cf1fc76f..cdb8981801a 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -1462,6 +1462,18 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op) static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */ + if (CTX_wm_space_image(C)) { + ToolSettings *ts = CTX_data_tool_settings(C); + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { + return OPERATOR_PASS_THROUGH; + } + /* Bypass when no action is needed. */ + if (!RNA_struct_property_is_set(op->ptr, "type")) { + return OPERATOR_CANCELLED; + } + } + /* detecting these options based on shift/ctrl here is weak, but it's done * to make this work when clicking buttons or menus */ if (!RNA_struct_property_is_set(op->ptr, "use_extend")) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index d7617a14ff3..76ba2e5c67e 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -41,11 +41,16 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BLI_bitmap.h" +#include "BLI_heap.h" #include "BLI_listbase.h" +#include "BLI_linklist.h" +#include "BLI_linklist_stack.h" #include "BLI_noise.h" #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_sort_utils.h" +#include "BLI_string.h" #include "BKE_layer.h" #include "BKE_material.h" @@ -54,6 +59,7 @@ #include "BKE_report.h" #include "BKE_texture.h" #include "BKE_main.h" +#include "BKE_mesh.h" #include "BKE_editmesh.h" #include "DEG_depsgraph.h" @@ -6001,10 +6007,10 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool edbm_sort_elements_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); - const int action = RNA_enum_get(ptr, "type"); + const int action = RNA_enum_get(op->ptr, "type"); /* Only show seed for randomize action! */ if (STREQ(prop_id, "seed")) { @@ -6025,18 +6031,6 @@ static bool edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *pro return true; } -static void edbm_sort_elements_ui(bContext *C, wmOperator *op) -{ - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - - /* Main auto-draw call. */ - uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, UI_BUT_LABEL_ALIGN_NONE, false); -} - void MESH_OT_sort_elements(wmOperatorType *ot) { static const EnumPropertyItem type_items[] = { @@ -6072,7 +6066,7 @@ void MESH_OT_sort_elements(wmOperatorType *ot) ot->invoke = WM_menu_invoke; ot->exec = edbm_sort_elements_exec; ot->poll = ED_operator_editmesh; - ot->ui = edbm_sort_elements_ui; + ot->poll_property = edbm_sort_elements_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -6924,3 +6918,1339 @@ void MESH_OT_mark_freestyle_face(wmOperatorType *ot) /** \} */ #endif /* WITH_FREESTYLE */ + +/********************** Loop normals editing tools modal map. **********************/ + +/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ +/* NOTE: We could add more here, like e.g. a switch between local or global coordinates of target, + * use numinput to type in explicit vector values... */ +enum { + /* Generic commands. */ + EDBM_CLNOR_MODAL_CANCEL = 1, + EDBM_CLNOR_MODAL_CONFIRM = 2, + + /* Point To operator. */ + EDBM_CLNOR_MODAL_POINTTO_RESET = 101, + EDBM_CLNOR_MODAL_POINTTO_INVERT = 102, + EDBM_CLNOR_MODAL_POINTTO_SPHERIZE = 103, + EDBM_CLNOR_MODAL_POINTTO_ALIGN = 104, + + EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE = 110, + EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT = 111, + EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT = 112, + EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR = 113, + EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED = 114, +}; + +/* called in transform_ops.c, on each regeneration of keymaps */ +wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {EDBM_CLNOR_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {EDBM_CLNOR_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + + /* Point To operator. */ + {EDBM_CLNOR_MODAL_POINTTO_RESET, "RESET", 0, "Reset", "Reset normals to initial ones"}, + {EDBM_CLNOR_MODAL_POINTTO_INVERT, "INVERT", 0, "Invert", "Toggle inversion of affected normals"}, + {EDBM_CLNOR_MODAL_POINTTO_SPHERIZE, "SPHERIZE", 0, "Spherize", "Interpolate between new and original normals"}, + {EDBM_CLNOR_MODAL_POINTTO_ALIGN, "ALIGN", 0, "Align", "Make all affected normals parallel"}, + + {EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE, "USE_MOUSE", 0, "Use Mouse", "Follow mouse cursor position"}, + {EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT, "USE_PIVOT", 0, "Use Pivot", + "Use current rotation/scaling pivot point coordinates"}, + {EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT, "USE_OBJECT", 0, "Use Object", "Use current edited object's location"}, + {EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR, "SET_USE_3DCURSOR", 0, "Set and Use 3D Cursor", + "Set new 3D cursor position and use it"}, + {EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED, "SET_USE_SELECTED", 0, "Select and Use Mesh Item", + "Select new active mesh element and use its location"}, + {0, NULL, 0, NULL, NULL} + }; + static const char *keymap_name = "Custom Normals Modal Map"; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, keymap_name); + + /* We only need to add map once */ + if (keymap && keymap->modal_items) + return NULL; + + keymap = WM_modalkeymap_add(keyconf, keymap_name, modal_items); + + /* Generic items for modal map. */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EDBM_CLNOR_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_CANCEL); + + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, EDBM_CLNOR_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, EDBM_CLNOR_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_CONFIRM); + + /* Point To items for modal map */ + WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_RESET); + WM_modalkeymap_add_item(keymap, IKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_INVERT); + WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_SPHERIZE); + WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_ALIGN); + + WM_modalkeymap_add_item(keymap, MKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE); + WM_modalkeymap_add_item(keymap, LKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT); + WM_modalkeymap_add_item(keymap, OKEY, KM_PRESS, KM_NOTHING, 0, EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT); + + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_CLICK, KM_CTRL, 0, EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_CLICK, KM_CTRL, 0, EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED); + + WM_modalkeymap_assign(keymap, "MESH_OT_point_normals"); + + return keymap; +} + +#define CLNORS_VALID_VEC_LEN (1e-4f) + +/********************** 'Point to' Loop Normals **********************/ + +enum { + EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1, + EDBM_CLNOR_POINTTO_MODE_MOUSE = 2, +}; + +static EnumPropertyItem clnors_pointto_mode_items[] = { + {EDBM_CLNOR_POINTTO_MODE_COORDINATES, "COORDINATES", 0, "Coordinates", + "Use static coordinates (defined by various means)"}, + {EDBM_CLNOR_POINTTO_MODE_MOUSE, "MOUSE", 0, "Mouse", "Follow mouse cursor"}, + {0, NULL, 0, NULL, NULL} +}; + +/* Initialize loop normal data */ +static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + + op->customdata = lnors_ed_arr; + + return lnors_ed_arr->totloop; +} + +static void point_normals_free(bContext *C, wmOperator *op) +{ + BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; + BM_loop_normal_editdata_array_free(lnors_ed_arr); + op->customdata = NULL; + ED_area_status_text(CTX_wm_area(C), NULL); +} + +static void point_normals_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); + +#define WM_MODALKEY(_id) \ + WM_modalkeymap_operator_items_to_string_buf(op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) + + BLI_snprintf(header, sizeof(header), IFACE_("%s: confirm, %s: cancel, " + "%s: point to mouse (%s), %s: point to Pivot, " + "%s: point to object origin, %s: reset normals, " + "%s: set & point to 3D cursor, %s: select & point to mesh item, " + "%s: invert normals (%s), %s: spherize (%s), %s: align (%s)"), + WM_MODALKEY(EDBM_CLNOR_MODAL_CONFIRM), WM_MODALKEY(EDBM_CLNOR_MODAL_CANCEL), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE), + WM_bool_as_string(RNA_enum_get(op->ptr, "mode") == EDBM_CLNOR_POINTTO_MODE_MOUSE), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_RESET), WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_INVERT), WM_bool_as_string(RNA_boolean_get(op->ptr, "invert")), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_SPHERIZE), + WM_bool_as_string(RNA_boolean_get(op->ptr, "spherize")), + WM_MODALKEY(EDBM_CLNOR_MODAL_POINTTO_ALIGN), WM_bool_as_string(RNA_boolean_get(op->ptr, "align"))); + +#undef WM_MODALKEY + + ED_area_status_text(CTX_wm_area(C), header); +} + +/* TODO move that to generic function in BMesh? */ +static void bmesh_selected_verts_center_calc(BMesh *bm, float *r_center) +{ + BMVert *v; + BMIter viter; + int i = 0; + + zero_v3(r_center); + BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + add_v3_v3(r_center, v->co); + i++; + } + } + mul_v3_fl(r_center, 1.0f / (float)i); +} + +static void point_normals_apply(bContext *C, wmOperator *op, float target[3], const bool do_reset) +{ + Object *obedit = CTX_data_edit_object(C); + BMesh *bm = BKE_editmesh_from_object(obedit)->bm; + BMLoopNorEditDataArray *lnors_ed_arr = op->customdata; + + const bool do_invert = RNA_boolean_get(op->ptr, "invert"); + const bool do_spherize = RNA_boolean_get(op->ptr, "spherize"); + const bool do_align = RNA_boolean_get(op->ptr, "align"); + float center[3]; + + if (do_align && !do_reset) { + bmesh_selected_verts_center_calc(bm, center); + } + + sub_v3_v3(target, obedit->loc); /* Move target to local coordinates. */ + + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (do_reset) { + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + else if (do_spherize) { + /* Note that this is *not* real spherical interpolation. Probably good enough in this case though? */ + const float strength = RNA_float_get(op->ptr, "spherize_strength"); + float spherized_normal[3]; + + sub_v3_v3v3(spherized_normal, target, lnor_ed->loc); + normalize_v3(spherized_normal); /* otherwise, multiplication by strength is meaningless... */ + mul_v3_fl(spherized_normal, strength); + mul_v3_v3fl(lnor_ed->nloc, lnor_ed->niloc, 1.0f - strength); + add_v3_v3(lnor_ed->nloc, spherized_normal); + } + else if (do_align) { + sub_v3_v3v3(lnor_ed->nloc, target, center); + } + else { + sub_v3_v3v3(lnor_ed->nloc, target, lnor_ed->loc); + } + + if (do_invert && !do_reset) { + negate_v3(lnor_ed->nloc); + } + if (normalize_v3(lnor_ed->nloc) >= CLNORS_VALID_VEC_LEN) { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + } +} + +static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + float target[3]; + + int ret = OPERATOR_PASS_THROUGH; + int mode = RNA_enum_get(op->ptr, "mode"); + int new_mode = mode; + bool force_mousemove = false; + bool do_reset = false; + + PropertyRNA *prop_target = RNA_struct_find_property(op->ptr, "target_location"); + + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EDBM_CLNOR_MODAL_CONFIRM: + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_FINISHED; + break; + + case EDBM_CLNOR_MODAL_CANCEL: + do_reset = true; + ret = OPERATOR_CANCELLED; + break; + + case EDBM_CLNOR_MODAL_POINTTO_RESET: + do_reset = true; + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_INVERT: + { + PropertyRNA *prop_invert = RNA_struct_find_property(op->ptr, "invert"); + RNA_property_boolean_set(op->ptr, prop_invert, !RNA_property_boolean_get(op->ptr, prop_invert)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_SPHERIZE: + { + PropertyRNA *prop_spherize = RNA_struct_find_property(op->ptr, "spherize"); + RNA_property_boolean_set(op->ptr, prop_spherize, !RNA_property_boolean_get(op->ptr, prop_spherize)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_ALIGN: + { + PropertyRNA *prop_align = RNA_struct_find_property(op->ptr, "align"); + RNA_property_boolean_set(op->ptr, prop_align, !RNA_property_boolean_get(op->ptr, prop_align)); + RNA_property_float_get_array(op->ptr, prop_target, target); + ret = OPERATOR_RUNNING_MODAL; + break; + } + + case EDBM_CLNOR_MODAL_POINTTO_USE_MOUSE: + new_mode = EDBM_CLNOR_POINTTO_MODE_MOUSE; + force_mousemove = true; /* We want to immediately update to mouse cursor position... */ + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_USE_OBJECT: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + copy_v3_v3(target, obedit->loc); + ret = OPERATOR_RUNNING_MODAL; + break; + + case EDBM_CLNOR_MODAL_POINTTO_SET_USE_3DCURSOR: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + ED_view3d_cursor3d_update(C, event->mval, false, V3D_CURSOR_ORIENT_NONE); + copy_v3_v3(target, ED_view3d_cursor3d_get(scene, v3d)->location); + break; + + case EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + view3d_operator_needs_opengl(C); + if (EDBM_select_pick(C, event->mval, false, false, false)) { + ED_object_editmode_calc_active_center(obedit, false, target); /* Point to newly selected active. */ + add_v3_v3(target, obedit->loc); + ret = OPERATOR_RUNNING_MODAL; + } + break; + + case EDBM_CLNOR_MODAL_POINTTO_USE_PIVOT: + new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; + switch (scene->toolsettings->transform_pivot_point) { + case V3D_AROUND_CENTER_BOUNDS: /* calculateCenterBound */ + { + BMVert *v; + BMIter viter; + float min[3], max[3]; + int i = 0; + + BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + if (i) { + minmax_v3v3_v3(min, max, v->co); + } + else { + copy_v3_v3(min, v->co); + copy_v3_v3(max, v->co); + } + i++; + } + } + mid_v3_v3v3(target, min, max); + add_v3_v3(target, obedit->loc); + break; + } + + case V3D_AROUND_CENTER_MEAN: + { + bmesh_selected_verts_center_calc(bm, target); + add_v3_v3(target, obedit->loc); + break; + } + + case V3D_AROUND_CURSOR: + copy_v3_v3(target, ED_view3d_cursor3d_get(scene, v3d)->location); + break; + + case V3D_AROUND_ACTIVE: + if (!ED_object_editmode_calc_active_center(obedit, false, target)) { + zero_v3(target); + } + add_v3_v3(target, obedit->loc); + break; + + default: + BKE_report(op->reports, RPT_WARNING, "Does not support Individual Origin as pivot"); + copy_v3_v3(target, obedit->loc); + } + ret = OPERATOR_RUNNING_MODAL; + break; + default: + break; + } + } + + if (new_mode != mode) { + mode = new_mode; + RNA_enum_set(op->ptr, "mode", mode); + } + + /* Only handle mousemove event in case we are in mouse mode. */ + if (event->type == MOUSEMOVE || force_mousemove) { + if (mode == EDBM_CLNOR_POINTTO_MODE_MOUSE) { + ARegion *ar = CTX_wm_region(C); + float center[3]; + + bmesh_selected_verts_center_calc(bm, center); + + ED_view3d_win_to_3d_int(v3d, ar, center, event->mval, target); + + ret = OPERATOR_RUNNING_MODAL; + } + } + + if (ret != OPERATOR_PASS_THROUGH) { + if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { + RNA_property_float_set_array(op->ptr, prop_target, target); + } + point_normals_apply(C, op, target, do_reset); + EDBM_update_generic(em, true, false); /* Recheck bools. */ + + point_normals_update_header(C, op); + } + + if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) { + point_normals_free(C, op); + } + + return ret; +} + +static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!point_normals_init(C, op, event)) { + point_normals_free(C, op); + return OPERATOR_CANCELLED; + } + + WM_event_add_modal_handler(C, op); + + point_normals_update_header(C, op); + + op->flag |= OP_IS_MODAL_GRAB_CURSOR; + return OPERATOR_RUNNING_MODAL; +} + +static int edbm_point_normals_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!point_normals_init(C, op, NULL)) { + point_normals_free(C, op); + return OPERATOR_CANCELLED; + } + + /* Note that 'mode' is ignored in exec case, we directly use vector stored in target_location, whatever that is. */ + + float target[3]; + RNA_float_get_array(op->ptr, "target_location", target); + + point_normals_apply(C, op, target, false); + + EDBM_update_generic(em, true, false); + point_normals_free(C, op); + + return OPERATOR_FINISHED; +} + +static bool point_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +{ + const char *prop_id = RNA_property_identifier(prop); + + /* Only show strength option if spherize is enabled. */ + if (STREQ(prop_id, "spherize_strength")) { + return (bool)RNA_boolean_get(ptr, "spherize"); + } + + /* Else, show it! */ + return true; +} + +static void edbm_point_normals_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, point_normals_draw_check_prop, NULL, '\0', false); +} + +void MESH_OT_point_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Point Normals to Target"; + ot->description = "Point selected custom normals to specified Target"; + ot->idname = "MESH_OT_point_normals"; + + /* api callbacks */ + ot->exec = edbm_point_normals_exec; + ot->invoke = edbm_point_normals_invoke; + ot->modal = edbm_point_normals_modal; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_point_normals_ui; + ot->cancel = point_normals_free; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", clnors_pointto_mode_items, EDBM_CLNOR_POINTTO_MODE_COORDINATES, + "Mode", "How to define coordinates to point custom normals to"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert affected normals"); + + RNA_def_boolean(ot->srna, "align", false, "Align", "Make all affected normals parallel"); + + RNA_def_float_vector(ot->srna, "target_location", 3, (float[3]){0.0f, 0.0f, 0.0f}, -FLT_MAX, FLT_MAX, + "Target", "Target location to which normals will point", -1000.0f, 1000.0f); + + RNA_def_boolean(ot->srna, "spherize", false, + "Spherize", "Interpolate between original and new normals"); + + RNA_def_float(ot->srna, "spherize_strength", 0.1, 0.0f, 1.0f, + "Spherize Strength", "Ratio of spherized normal to original normal", 0.0f, 1.0f); +} + +/********************** Split/Merge Loop Normals **********************/ + +static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) +{ + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + BLI_SMALLSTACK_DECLARE(clnors, short *); + + BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); + + BM_normals_loops_edges_tag(bm, false); + + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) { + continue; + } + + MLoopNorSpace *lnor_space = bm->lnor_spacearr->lspacearr[lnor_ed->loop_index]; + + if ((lnor_space->flags & MLNOR_SPACE_IS_SINGLE) == 0) { + LinkNode *loops = lnor_space->loops; + float avg_normal[3] = {0.0f, 0.0f, 0.0f}; + short *clnors_data; + + for (; loops; loops = loops->next) { + BMLoop *l = loops->link; + const int loop_index = BM_elem_index_get(l); + + BMLoopNorEditData *lnor_ed_tmp = lnors_ed_arr->lidx_to_lnor_editdata[loop_index]; + BLI_assert(lnor_ed_tmp->loop_index == loop_index && lnor_ed_tmp->loop == l); + add_v3_v3(avg_normal, lnor_ed_tmp->nloc); + BLI_SMALLSTACK_PUSH(clnors, lnor_ed_tmp->clnors_data); + BM_elem_flag_enable(l, BM_ELEM_TAG); + } + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + while ((clnors_data = BLI_SMALLSTACK_POP(clnors))) { + BKE_lnor_space_custom_normal_to_data(lnor_space, avg_normal, clnors_data); + } + } + } +} + +static void normals_split(BMesh *bm) +{ + BMFace *f; + BMLoop *l, *l_curr, *l_first; + BMIter fiter; + + BLI_assert(bm->lnor_spacearr->data_type == MLNOR_SPACEARR_BMLOOP_PTR); + + BM_normals_loops_edges_tag(bm, true); + + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) + { + if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_curr); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_curr->v; + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_curr; + e_next = lfan_pivot->e; + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float avg_normal[3] = { 0.0f }; + + 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); + add_v3_v3(avg_normal, lfan_pivot->f->no); + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + 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); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); + } + } + } + } while ((l_curr = l_curr->next) != l_first); + } +} + +static int normals_split_merge(bContext *C, const bool do_merge) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMEdge *e; + BMIter eiter; + + BKE_editmesh_lnorspace_update(em); + + BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm) : NULL; + + mesh_set_smooth_faces(em, do_merge); + + BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge); + } + } + if (do_merge == 0) { + Mesh *me = obedit->data; + me->drawflag |= ME_DRAWSHARP; + } + + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); + + if (do_merge) { + normals_merge(bm, lnors_ed_arr); + } + else { + normals_split(bm); + } + + if (lnors_ed_arr) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + } + + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; +} + +static int edbm_merge_normals_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return normals_split_merge(C, true); +} + +void MESH_OT_merge_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Merge Normals"; + ot->description = "Merge custom normals of selected vertices"; + ot->idname = "MESH_OT_merge_normals"; + + /* api callbacks */ + ot->exec = edbm_merge_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int edbm_split_normals_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return normals_split_merge(C, false); +} + +void MESH_OT_split_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split Normals"; + ot->description = "Split custom normals of selected vertices"; + ot->idname = "MESH_OT_split_normals"; + + /* api callbacks */ + ot->exec = edbm_split_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************** Average Loop Normals **********************/ + +enum { + EDBM_CLNOR_AVERAGE_LOOP = 1, + EDBM_CLNOR_AVERAGE_FACE_AREA = 2, + EDBM_CLNOR_AVERAGE_ANGLE = 3, +}; + +static EnumPropertyItem average_method_items[] = { + {EDBM_CLNOR_AVERAGE_LOOP, "CUSTOM_NORMAL", 0, "Custom Normal", "Take Average of vert Normals"}, + {EDBM_CLNOR_AVERAGE_FACE_AREA, "FACE_AREA", 0, "Face Area", "Set all vert normals by Face Area"}, + {EDBM_CLNOR_AVERAGE_ANGLE, "CORNER_ANGLE", 0, "Corner Angle", "Set all vert normals by Corner Angle"}, + {0, NULL, 0, NULL, NULL} +}; + +static int edbm_average_normals_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l, *l_curr, *l_first; + BMIter fiter; + + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BKE_editmesh_lnorspace_update(em); + + const int average_type = RNA_enum_get(op->ptr, "average_type"); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + const float absweight = (float) RNA_int_get(op->ptr, "weight"); + const float threshold = RNA_float_get(op->ptr, "threshold"); + + float weight = absweight / 50.0f; + if (absweight == 100.0f) { + weight = (float)SHRT_MAX; + } + else if (absweight == 1.0f) { + weight = 1 / (float)SHRT_MAX; + } + else if ((weight - 1) * 25 > 1) { + weight = (weight - 1) * 25; + } + + BM_normals_loops_edges_tag(bm, true); + + Heap *loop_weight = BLI_heap_new(); + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + l_curr = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) && (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) || + (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) + { + if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) { + const int loop_index = BM_elem_index_get(l_curr); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors); + } + else { + BMVert *v_pivot = l_curr->v; + BMEdge *e_next; + const BMEdge *e_org = l_curr->e; + BMLoop *lfan_pivot, *lfan_pivot_next; + + lfan_pivot = l_curr; + e_next = lfan_pivot->e; + + 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; + } + + float val = 1.0f; + if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) { + val = 1.0f / BM_face_calc_area(lfan_pivot->f); + } + else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) { + val = 1.0f / BM_loop_calc_face_angle(lfan_pivot); + } + + BLI_heap_insert(loop_weight, val, lfan_pivot); + + if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) { + break; + } + lfan_pivot = lfan_pivot_next; + } + + BLI_SMALLSTACK_DECLARE(loops, BMLoop *); + float wnor[3], avg_normal[3] = { 0.0f }, count = 0; + float val = BLI_heap_node_value(BLI_heap_top(loop_weight)); + + while (!BLI_heap_is_empty(loop_weight)) { + const float cur_val = BLI_heap_node_value(BLI_heap_top(loop_weight)); + if (!compare_ff(val, cur_val, threshold)) { + count++; + val = cur_val; + } + l = BLI_heap_pop_min(loop_weight); + BLI_SMALLSTACK_PUSH(loops, l); + + const float n_weight = pow(weight, count); + + if (average_type == EDBM_CLNOR_AVERAGE_LOOP) { + const int l_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index], clnors, wnor); + } + else { + copy_v3_v3(wnor, l->f->no); + } + mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight)); + add_v3_v3(avg_normal, wnor); + } + + if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) { + /* If avg normal is nearly 0, set clnor to default value. */ + zero_v3(avg_normal); + } + 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); + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors); + } + } + } + } while ((l_curr = l_curr->next) != l_first); + } + + BLI_heap_free(loop_weight, NULL); + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; +} + +static bool average_normals_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +{ + const char *prop_id = RNA_property_identifier(prop); + const int average_type = RNA_enum_get(ptr, "average_type"); + + /* Only show weight/threshold options in loop average type. */ + if (STREQ(prop_id, "weight")) { + return (average_type == EDBM_CLNOR_AVERAGE_LOOP); + } + else if (STREQ(prop_id, "threshold")) { + return (average_type == EDBM_CLNOR_AVERAGE_LOOP); + } + + /* Else, show it! */ + return true; +} + +static void edbm_average_normals_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, average_normals_draw_check_prop, NULL, '\0', false); +} + +void MESH_OT_average_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Average Normals"; + ot->description = "Average custom normals of selected vertices"; + ot->idname = "MESH_OT_average_normals"; + + /* api callbacks */ + ot->exec = edbm_average_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_average_normals_ui; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "average_type", average_method_items, EDBM_CLNOR_AVERAGE_LOOP, + "Type", "Averaging method"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + RNA_def_int(ot->srna, "weight", 50, 1, 100, "Weight", "Weight applied per face", 1, 100); + + RNA_def_float(ot->srna, "threshold", 0.01f, 0, 10, "Threshold", + "Threshold value for different weights to be considered equal", 0, 5); +} + +/********************** Custom Normal Interface Tools **********************/ + +enum { + EDBM_CLNOR_TOOLS_COPY = 1, + EDBM_CLNOR_TOOLS_PASTE = 2, + EDBM_CLNOR_TOOLS_MULTIPLY = 3, + EDBM_CLNOR_TOOLS_ADD = 4, + EDBM_CLNOR_TOOLS_RESET = 5, +}; + +static EnumPropertyItem normal_vector_tool_items[] = { + {EDBM_CLNOR_TOOLS_COPY, "COPY", 0, "Copy Normal", "Copy normal to buffer"}, + {EDBM_CLNOR_TOOLS_PASTE, "PASTE", 0, "Paste Normal", "Paste normal from buffer"}, + {EDBM_CLNOR_TOOLS_ADD, "ADD", 0, "Add Normal", "Add normal vector with selection"}, + {EDBM_CLNOR_TOOLS_MULTIPLY, "MULTIPLY", 0, "Multiply Normal", "Multiply normal vector with selection"}, + {EDBM_CLNOR_TOOLS_RESET, "RESET", 0, "Reset Normal", "Reset buffer and/or normal of selected element"}, + {0, NULL, 0, NULL, NULL} +}; + +static int edbm_normals_tools_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + const int mode = RNA_enum_get(op->ptr, "mode"); + const bool absolute = RNA_boolean_get(op->ptr, "absolute"); + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + float *normal_vector = scene->toolsettings->normal_vector; + + switch (mode) { + case EDBM_CLNOR_TOOLS_COPY: + if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) { + BKE_report(op->reports, RPT_ERROR, "Can only copy custom normal, vertex normal or face normal"); + BM_loop_normal_editdata_array_free(lnors_ed_arr); + return OPERATOR_CANCELLED; + } + bool join = true; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) { + join = false; + } + } + if (lnors_ed_arr->totloop == 1) { + copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); + } + else if (bm->totfacesel == 1) { + BMFace *f; + BMIter fiter; + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + copy_v3_v3(scene->toolsettings->normal_vector, f->no); + } + } + } + else if (join) { + copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc); + } + break; + + case EDBM_CLNOR_TOOLS_PASTE: + if (!absolute) { + if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) { + /* If normal is nearly 0, do nothing. */ + break; + } + } + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + if (absolute) { + float abs_normal[3]; + copy_v3_v3(abs_normal, lnor_ed->loc); + negate_v3(abs_normal); + add_v3_v3(abs_normal, normal_vector); + + if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(abs_normal, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data); + } + else { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data); + } + } + break; + + case EDBM_CLNOR_TOOLS_MULTIPLY: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + mul_v3_v3(lnor_ed->nloc, normal_vector); + + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + break; + + case EDBM_CLNOR_TOOLS_ADD: + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + add_v3_v3(lnor_ed->nloc, normal_vector); + + if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) { + /* If abs normal is nearly 0, set clnor to initial value. */ + copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc); + } + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data); + } + break; + + case EDBM_CLNOR_TOOLS_RESET: + zero_v3(normal_vector); + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], normal_vector, lnor_ed->clnors_data); + } + break; + + default: + BLI_assert(0); + break; + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + + EDBM_update_generic(em, true, false); + return OPERATOR_FINISHED; +} + +static bool normals_tools_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +{ + const char *prop_id = RNA_property_identifier(prop); + const int mode = RNA_enum_get(ptr, "mode"); + + /* Only show absolute option in paste mode. */ + if (STREQ(prop_id, "absolute")) { + return (mode == EDBM_CLNOR_TOOLS_PASTE); + } + + /* Else, show it! */ + return true; +} + +static void edbm_normals_tools_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, normals_tools_draw_check_prop, NULL, '\0', false); +} + +void MESH_OT_normals_tools(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Normals Vector Tools"; + ot->description = "Custom normals tools using Normal Vector of UI"; + ot->idname = "MESH_OT_normals_tools"; + + /* api callbacks */ + ot->exec = edbm_normals_tools_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + ot->ui = edbm_normals_tools_ui; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", normal_vector_tool_items, EDBM_CLNOR_TOOLS_COPY, + "Mode", "Mode of tools taking input from Interface"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); + + RNA_def_boolean(ot->srna, "absolute", false, "Absolute Coordinates", "Copy Absolute coordinates or Normal vector"); +} + +static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMVert *v; + BMEdge *e; + BMLoop *l; + BMIter fiter, viter, eiter, liter; + + const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp"); + + BKE_editmesh_lnorspace_update(em); + + float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * bm->totvert, __func__); + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_ITER_ELEM(v, &viter, f, BM_VERTS_OF_FACE) { + const int v_index = BM_elem_index_get(v); + add_v3_v3(vnors[v_index], f->no); + } + } + } + for (int i = 0; i < bm->totvert; i++) { + if (!is_zero_v3(vnors[i]) && normalize_v3(vnors[i]) < CLNORS_VALID_VEC_LEN) { + zero_v3(vnors[i]); + } + } + + BLI_bitmap *loop_set = BLI_BITMAP_NEW(bm->totloop, __func__); + const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); + + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM(e, &eiter, f, BM_EDGES_OF_FACE) { + if (!keep_sharp || (BM_elem_flag_test(e, BM_ELEM_SMOOTH) && BM_elem_flag_test(e, BM_ELEM_SELECT))) { + BM_ITER_ELEM(v, &viter, e, BM_VERTS_OF_EDGE) { + l = BM_face_vert_share_loop(f, v); + const int l_index = BM_elem_index_get(l); + const int v_index = BM_elem_index_get(l->v); + + if (!is_zero_v3(vnors[v_index])) { + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[l_index], vnors[v_index], clnors); + + if (bm->lnor_spacearr->lspacearr[l_index]->flags & MLNOR_SPACE_IS_SINGLE) { + BLI_BITMAP_ENABLE(loop_set, l_index); + } + else { + LinkNode *loops = bm->lnor_spacearr->lspacearr[l_index]->loops; + for (; loops; loops = loops->next) { + BLI_BITMAP_ENABLE(loop_set, BM_elem_index_get((BMLoop *)loops->link)); + } + } + } + } + } + } + } + + int v_index; + BM_ITER_MESH_INDEX(v, &viter, bm, BM_VERTS_OF_MESH, v_index) { + BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) { + if (BLI_BITMAP_TEST(loop_set, BM_elem_index_get(l))) { + const int loop_index = BM_elem_index_get(l); + short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset); + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[loop_index], vnors[v_index], clnors); + } + } + } + + MEM_freeN(loop_set); + MEM_freeN(vnors); + EDBM_update_generic(em, true, false); + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Normals From Faces"; + ot->description = "Set the custom normals from the selected faces ones"; + ot->idname = "MESH_OT_set_normals_from_faces"; + + /* api callbacks */ + ot->exec = edbm_set_normals_from_faces_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face"); +} + +static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + + BKE_editmesh_lnorspace_update(em); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm); + + float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__); + + /* This is weird choice of operation, taking all loops of faces of current vertex... Could lead to some rather + * far away loops weighting as much as very close ones (topologically speaking), with complex polygons. + * Using topological distance here (rather than geometrical one) makes sense imho, but would rather go with + * a more consistent and flexible code, we could even add max topological distance to take into account, + * and a weighting curve... + * Would do that later though, think for now we can live with that choice. --mont29 */ + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + l = lnor_ed->loop; + float loop_normal[3]; + + BM_ITER_ELEM(f, &fiter, l->v, BM_FACES_OF_VERT) { + BMLoop *l_other; + BM_ITER_ELEM(l_other, &liter, f, BM_LOOPS_OF_FACE) { + const int l_index_other = BM_elem_index_get(l_other); + short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset); + BKE_lnor_space_custom_data_to_normal(bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal); + add_v3_v3(smooth_normal[i], loop_normal); + } + } + } + + const float factor = RNA_float_get(op->ptr, "factor"); + + lnor_ed = lnors_ed_arr->lnor_editdata; + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + float current_normal[3]; + + if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } + + BKE_lnor_space_custom_data_to_normal( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal); + + /* Note: again, this is not true spherical interpolation that normals would need... + * But it's probably good enough for now. */ + mul_v3_fl(current_normal, 1.0f - factor); + mul_v3_fl(smooth_normal[i], factor); + add_v3_v3(current_normal, smooth_normal[i]); + + if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) { + /* Skip in case smoothen normal is invalid... */ + continue; + } + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data); + } + + BM_loop_normal_editdata_array_free(lnors_ed_arr); + MEM_freeN(smooth_normal); + + EDBM_update_generic(em, true, false); + + return OPERATOR_FINISHED; +} + +void MESH_OT_smoothen_normals(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Smoothen Normals"; + ot->description = "Smoothen custom normals based on adjacent vertex normals"; + ot->idname = "MESH_OT_smoothen_normals"; + + /* api callbacks */ + ot->exec = edbm_smoothen_normals_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", + "Specifies weight of smooth vs original normal", 0.0f, 1.0f); +} + +/********************** Weighted Normal Modifier Face Strength **********************/ + +static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + BMFace *f; + BMIter fiter; + + BM_select_history_clear(bm); + + const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID; + int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + if (cd_prop_int_index == -1) { + BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id); + cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id); + } + cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT); + const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_index); + + const int face_strength = scene->toolsettings->face_strength; + const bool set = RNA_boolean_get(op->ptr, "set"); + BM_mesh_elem_index_ensure(bm, BM_FACE); + + if (set) { + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + *strength = face_strength; + } + } + } + else { + BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) { + int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset); + if (*strength == face_strength) { + BM_face_select_set(bm, f, true); + BM_select_history_store(bm, f); + } + else { + BM_face_select_set(bm, f, false); + } + } + } + + EDBM_update_generic(em, false, false); + return OPERATOR_FINISHED; +} + +void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Face Strength"; + ot->description = "Set/Get strength of face (used in Weighted Normal modifier)"; + ot->idname = "MESH_OT_mod_weighted_strength"; + + /* api callbacks */ + ot->exec = edbm_mod_weighted_strength_exec; + ot->poll = ED_operator_editmesh_auto_smooth; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_boolean(ot->srna, "set", 0, "Set value", "Set Value of faces"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN); +} diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 11606840b42..26f3c17a97c 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -598,6 +598,8 @@ static void undomesh_to_editmesh(UndoMesh *um, BMEditMesh *em, Mesh *obmesh) bm->selectmode = um->selectmode; em->ob = ob; + bm->spacearr_dirty = BM_SPACEARR_DIRTY_ALL; + /* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens * if the active is a basis for any other. */ if (key && (key->type == KEY_RELATIVE)) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 2ee3362063b..fd87ba32653 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -565,8 +565,8 @@ UvVertMap *BM_uv_vert_map_create( } BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) { - buf->tfindex = i; - buf->f = a; + buf->loop_of_poly_index = i; + buf->poly_index = a; buf->separate = 0; buf->next = vmap->vert[BM_elem_index_get(l->v)]; @@ -597,9 +597,9 @@ UvVertMap *BM_uv_vert_map_create( v->next = newvlist; newvlist = v; - efa = BM_face_at_index(bm, v->f); + efa = BM_face_at_index(bm, v->poly_index); - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex); + l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->loop_of_poly_index); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv = luv->uv; @@ -608,15 +608,15 @@ UvVertMap *BM_uv_vert_map_create( while (iterv) { next = iterv->next; - efa = BM_face_at_index(bm, iterv->f); - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); + efa = BM_face_at_index(bm, iterv->poly_index); + l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->loop_of_poly_index); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv2 = luv->uv; sub_v2_v2v2(uvdiff, uv2, uv); if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] && - (!use_winding || winding[iterv->f] == winding[v->f])) + (!use_winding || winding[iterv->poly_index] == winding[v->poly_index])) { if (lastv) lastv->next = next; else vlist = next; @@ -713,7 +713,7 @@ UvElementMap *BM_uv_element_map_create( buf->l = l; buf->separate = 0; buf->island = INVALID_ISLAND; - buf->tfindex = i; + buf->loop_of_poly_index = i; buf->next = element_map->vert[BM_elem_index_get(l->v)]; element_map->vert[BM_elem_index_get(l->v)] = buf; @@ -826,7 +826,7 @@ UvElementMap *BM_uv_element_map_create( map[element - element_map->buf] = islandbufsize; islandbuf[islandbufsize].l = element->l; islandbuf[islandbufsize].separate = element->separate; - islandbuf[islandbufsize].tfindex = element->tfindex; + islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index; islandbuf[islandbufsize].island = nislands; islandbufsize++; @@ -1348,7 +1348,10 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d /* in debug mode double check we didn't need to recalculate */ BLI_assert(BM_mesh_elem_table_check(em->bm) == true); } - + if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) { + BM_lnorspace_invalidate(em->bm, false); + em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET; + } /* don't keep stale derivedMesh data around, see: [#38872] */ BKE_editmesh_free_derivedmesh(em); diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index cc9448e5e06..4a67dea9d4b 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -240,6 +240,16 @@ void MESH_OT_duplicate(struct wmOperatorType *ot); void MESH_OT_merge(struct wmOperatorType *ot); void MESH_OT_remove_doubles(struct wmOperatorType *ot); void MESH_OT_poke(struct wmOperatorType *ot); +void MESH_OT_point_normals(struct wmOperatorType *ot); +void MESH_OT_merge_normals(struct wmOperatorType *ot); +void MESH_OT_split_normals(struct wmOperatorType *ot); +void MESH_OT_normals_tools(struct wmOperatorType *ot); +void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot); +void MESH_OT_average_normals(struct wmOperatorType *ot); +void MESH_OT_smoothen_normals(struct wmOperatorType *ot); +void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot); + +struct wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf); #ifdef WITH_FREESTYLE void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 0fcc5ada854..842a1ecab35 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -200,6 +200,15 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_bisect); WM_operatortype_append(MESH_OT_symmetrize); WM_operatortype_append(MESH_OT_symmetry_snap); + + WM_operatortype_append(MESH_OT_point_normals); + WM_operatortype_append(MESH_OT_merge_normals); + WM_operatortype_append(MESH_OT_split_normals); + WM_operatortype_append(MESH_OT_normals_tools); + WM_operatortype_append(MESH_OT_set_normals_from_faces); + WM_operatortype_append(MESH_OT_average_normals); + WM_operatortype_append(MESH_OT_smoothen_normals); + WM_operatortype_append(MESH_OT_mod_weighted_strength); } #if 0 /* UNUSED, remove? */ @@ -335,22 +344,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "MESH_OT_bevel", BKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "vertex_only", true); - /* selecting */ - for (int i = 0; i < 4; i++) { - const bool is_extend = (i & 1); - const bool is_expand = (i & 2); - const int key_modifier = (is_extend ? KM_SHIFT : 0) | (is_expand ? KM_CTRL : 0); - for (int j = 0; j < 3; j++) { - kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY + j, KM_PRESS, key_modifier, 0); - RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX << j); - if (is_extend) { - RNA_boolean_set(kmi->ptr, "use_extend", true); - } - if (is_expand) { - RNA_boolean_set(kmi->ptr, "use_expand", true); - } - } - } + /* Selec Vert/Edge/Face. */ + ED_keymap_editmesh_elem_mode(keyconf, keymap); /* standard mouse selection goes via space_view3d */ kmi = WM_keymap_add_item(keymap, "MESH_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); @@ -479,6 +474,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_vert_connect_path", JKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MESH_OT_point_normals", LKEY, KM_PRESS, KM_ALT, 0); + /* Vertex Slide */ WM_keymap_add_item(keymap, "TRANSFORM_OT_vert_slide", VKEY, KM_PRESS, KM_SHIFT, 0); /* use KM_CLICK because same key is used for tweaks */ @@ -528,4 +525,5 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) ED_keymap_proportional_editmode(keyconf, keymap, true); knifetool_modal_keymap(keyconf); + point_normals_modal_keymap(keyconf); } |