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).
This commit is contained in:
Campbell Barton
2021-01-16 11:29:57 +11:00
parent c4bbe44e47
commit cdfa3feb91
4 changed files with 117 additions and 8 deletions

View File

@@ -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():

View File

@@ -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};

View File

@@ -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,

View File

@@ -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,