From cdfa3feb911164118fcc5b574b3e1a35c8f99c72 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 16 Jan 2021 11:29:57 +1100 Subject: Add Object Tool: support incremental snapping This adds a "Snap to" option that allows using all the scenes snap settings which includes incremental & absolute grid snapping options. This is optional because always following scene snapping would not snap to geometry by default (which seems to be the most useful default). --- .../startup/bl_ui/space_toolsystem_toolbar.py | 2 + .../gizmo_library/gizmo_types/snap3d_gizmo.c | 13 +++ source/blender/editors/include/ED_gizmo_library.h | 1 + .../editors/space_view3d/view3d_placement.c | 109 +++++++++++++++++++-- 4 files changed, 117 insertions(+), 8 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index d0122536e94..d9661322821 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -462,6 +462,8 @@ class _defs_view3d_add: row = layout.row() row.scale_x = 0.7 row.prop(props, "plane_origin") + row.scale_x = 0.8 + row.prop(props, "snap_target") @ToolDef.from_fn def cube_add(): diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index 8755dea51e1..b8ee1722cb3 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -80,6 +80,9 @@ typedef struct SnapGizmo3D { #endif int use_snap_override; short snap_elem; + + /** Enabled when snap is activated, even if it didn't find anything. */ + bool is_enabled; } SnapGizmo3D; /* Checks if the current event is different from the one captured in the last update. */ @@ -284,6 +287,12 @@ void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz) snap_gizmo->use_snap_override = -1; } +bool ED_gizmotypes_snap_3d_is_enabled(wmGizmo *gz) +{ + SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + return snap_gizmo->is_enabled; +} + short ED_gizmotypes_snap_3d_update(wmGizmo *gz, struct Depsgraph *depsgraph, const ARegion *region, @@ -294,6 +303,8 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, float r_nor[3]) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; + snap_gizmo->is_enabled = false; + if (snap_gizmo->use_snap_override != -1) { if (snap_gizmo->use_snap_override == false) { snap_gizmo->snap_elem = 0; @@ -318,6 +329,8 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, } #endif + snap_gizmo->is_enabled = true; + float co[3], no[3]; short snap_elem = 0; int snap_elem_index[3] = {-1, -1, -1}; diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index 434ab743d18..dfc8cfea5ce 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -264,6 +264,7 @@ struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *sce bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz); void ED_gizmotypes_snap_3d_toggle_set(struct wmGizmo *gz, bool enable); void ED_gizmotypes_snap_3d_toggle_clear(struct wmGizmo *gz); +bool ED_gizmotypes_snap_3d_is_enabled(struct wmGizmo *gz); short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz, struct Depsgraph *depsgraph, diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index 5bd1b3458e2..2bbe512222c 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -102,6 +102,11 @@ enum ePlace_Orient { PLACE_ORIENT_DEFAULT = 2, }; +enum ePlace_SnapTo { + PLACE_SNAP_TO_GEOMETRY = 1, + PLACE_SNAP_TO_DEFAULT = 2, +}; + struct InteractivePlaceData { /* Window manager variables (set these even when waiting for input). */ Scene *scene; @@ -184,6 +189,8 @@ struct InteractivePlaceData { /** Optional snap gizmo, needed for snapping. */ wmGizmo *snap_gizmo; + + enum ePlace_SnapTo snap_to; }; /** \} */ @@ -359,6 +366,56 @@ static wmGizmoGroup *idp_gizmogroup_from_region(ARegion *region) return gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL; } +/** + * Calculate 3D view incremental (grid) snapping. + * + * \note This could be moved to a public function. + */ +static bool idp_snap_calc_incremental( + Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3]) +{ + if ((scene->toolsettings->snap_mode & SCE_SNAP_MODE_INCREMENT) == 0) { + return false; + } + + const float grid_size = ED_view3d_grid_view_scale(scene, v3d, region, NULL); + if (UNLIKELY(grid_size == 0.0f)) { + return false; + } + + if (scene->toolsettings->snap_flag & SCE_SNAP_ABS_GRID) { + co_relative = NULL; + } + + if (co_relative != NULL) { + sub_v3_v3(co, co_relative); + } + mul_v3_fl(co, 1.0f / grid_size); + co[0] = roundf(co[0]); + co[1] = roundf(co[1]); + co[2] = roundf(co[2]); + mul_v3_fl(co, grid_size); + if (co_relative != NULL) { + add_v3_v3(co, co_relative); + } + + return true; +} + +static void idp_snap_gizmo_update_snap_elements(Scene *scene, + enum ePlace_SnapTo snap_to, + wmGizmo *gizmo) +{ + const int snap_mode = + (snap_to == PLACE_SNAP_TO_GEOMETRY) ? + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | + /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) : + scene->toolsettings->snap_mode; + + RNA_enum_set(gizmo->ptr, "snap_elements_force", snap_mode); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -784,8 +841,9 @@ static void view3d_interactive_add_calc_plane(bContext *C, Scene *scene, View3D *v3d, ARegion *region, - wmGizmo *snap_gizmo, const float mval_fl[2], + wmGizmo *snap_gizmo, + const enum ePlace_SnapTo snap_to, const enum ePlace_Depth plane_depth, const enum ePlace_Orient plane_orient, const int plane_axis, @@ -914,6 +972,12 @@ static void view3d_interactive_add_calc_plane(bContext *C, } } + if (!is_snap_found && ((snap_gizmo != NULL) && ED_gizmotypes_snap_3d_is_enabled(snap_gizmo))) { + if (snap_to == PLACE_SNAP_TO_DEFAULT) { + idp_snap_calc_incremental(scene, v3d, region, NULL, r_co_src); + } + } + if (snap_context_free) { ED_transform_snap_object_context_destroy(snap_context); } @@ -929,6 +993,7 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv { const int plane_axis = RNA_enum_get(op->ptr, "plane_axis"); + const enum ePlace_SnapTo snap_to = RNA_enum_get(op->ptr, "snap_target"); const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth"); const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin"); const enum ePlace_Orient plane_orient = RNA_enum_get(op->ptr, "plane_orientation"); @@ -976,8 +1041,9 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv ipd->scene, ipd->v3d, ipd->region, - ipd->snap_gizmo, mval_fl, + ipd->snap_gizmo, + snap_to, plane_depth, plane_orient, plane_axis, @@ -989,6 +1055,7 @@ static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEv ipd->step[0].is_centered = ipd->is_centered_init; ipd->step[1].is_centered = ipd->is_centered_init; ipd->step_index = STEP_BASE; + ipd->snap_to = snap_to; plane_from_point_normal_v3(ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[plane_axis]); @@ -1415,6 +1482,12 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve ipd->step[STEP_BASE].co_dst)) { /* pass */ } + + if (ipd->use_snap && (ipd->snap_to == PLACE_SNAP_TO_DEFAULT)) { + if (idp_snap_calc_incremental( + ipd->scene, ipd->v3d, ipd->region, ipd->co_src, ipd->step[STEP_BASE].co_dst)) { + } + } } } else if (ipd->step_index == STEP_DEPTH) { @@ -1431,6 +1504,12 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve ipd->step[STEP_DEPTH].co_dst)) { /* pass */ } + + if (ipd->use_snap && (ipd->snap_to == PLACE_SNAP_TO_DEFAULT)) { + if (idp_snap_calc_incremental( + ipd->scene, ipd->v3d, ipd->region, ipd->co_src, ipd->step[STEP_DEPTH].co_dst)) { + } + } } /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */ @@ -1550,6 +1629,17 @@ void VIEW3D_OT_interactive_add(struct wmOperatorType *ot) RNA_def_property_enum_items(prop, plane_orientation_items); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + static const EnumPropertyItem snap_to_items[] = { + {PLACE_SNAP_TO_GEOMETRY, "GEOMETRY", 0, "Geometry", "Snap to all geometry"}, + {PLACE_SNAP_TO_DEFAULT, "DEFAULT", 0, "Default", "Use the current snap settings"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_property(ot->srna, "snap_target", PROP_ENUM, PROP_NONE); + RNA_def_property_ui_text(prop, "Snap to", "The target to use while snapping"); + RNA_def_property_enum_default(prop, PLACE_SNAP_TO_GEOMETRY); + RNA_def_property_enum_items(prop, snap_to_items); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* When not accessed via a tool. */ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); @@ -1573,11 +1663,6 @@ static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup const wmGizmoType *gzt_snap; gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true); gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL); - RNA_enum_set(gizmo->ptr, - "snap_elements_force", - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */ - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT)); WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f}); @@ -1630,6 +1715,7 @@ static void gizmo_plane_update_cursor(const bContext *C, bToolRef *tref = area->runtime.tool; WM_toolsystem_ref_properties_ensure_from_operator(tref, ot, &ptr); + const enum ePlace_SnapTo snap_to = RNA_enum_get(&ptr, "snap_target"); const int plane_axis = RNA_enum_get(&ptr, "plane_axis"); const enum ePlace_Depth plane_depth = RNA_enum_get(&ptr, "plane_depth"); const enum ePlace_Orient plane_orient = RNA_enum_get(&ptr, "plane_orientation"); @@ -1648,12 +1734,19 @@ static void gizmo_plane_update_cursor(const bContext *C, } } + /* This ensures the snap gizmo has settings from this tool. + * This function call could be moved a more appropriate place, + * responding to the setting being changed for example, + * however setting the value isn't expensive, so do it here. */ + idp_snap_gizmo_update_snap_elements(scene, snap_to, snap_gizmo); + view3d_interactive_add_calc_plane((bContext *)C, scene, v3d, region, - snap_gizmo, mval_fl, + snap_gizmo, + snap_to, plane_depth, plane_orient, plane_axis, -- cgit v1.2.3