UI: move 'Face Nearest' snap option to another section

The snap mode called "Face Nearest" (and the "Increment" but that's for
another time) doesn't behave like the other snap modes.

Unlike the other snap modes, "Face Nearest" does not act on a Snap
Base (or Snap Source).

It always acts on the origin of individually transformed elements, (such
as each vertex individually).

It works just like the "Project Individual Elements" option.

So this commit makes the following changes:
- `Snap With` was moved to the beginning of the popover
- `Align Rotation to Target` and `Backface Culling` have been moved closer to the snap targets
- `Snap With`, `Target Selection` and `Align Rotation to Target` are no longer hidden by varying the mode and options
- `Project Individual Elements` has been replaced with the `Face Project` option
- `Face Nearest` has been moved to stick together with the `Face Project` option

Co-authored-by: Germano Cavalcante <germano.costa@ig.com.br>
Pull Request: https://projects.blender.org/blender/blender/pulls/108555
This commit is contained in:
Germano Cavalcante 2023-06-06 19:35:57 +02:00
parent 8dc70b9e2e
commit 8e059b569b
19 changed files with 162 additions and 150 deletions

View File

@ -7067,72 +7067,70 @@ class VIEW3D_PT_snapping(Panel):
def draw(self, context):
tool_settings = context.tool_settings
snap_elements = tool_settings.snap_elements
obj = context.active_object
object_mode = 'OBJECT' if obj is None else obj.mode
layout = self.layout
col = layout.column()
col.label(text="Snap With")
row = col.row(align=True)
row.prop(tool_settings, "snap_target", expand=True)
col.label(text="Snap To")
col.prop(tool_settings, "snap_elements", expand=True)
col.prop(tool_settings, "snap_elements_base", expand=True)
col.label(text="Snap Individual Elements To")
col.prop(tool_settings, "snap_elements_individual", expand=True)
col.separator()
if 'INCREMENT' in snap_elements:
if 'INCREMENT' in tool_settings.snap_elements:
col.prop(tool_settings, "use_snap_grid_absolute")
if snap_elements != {'INCREMENT'}:
if snap_elements != {'FACE_NEAREST'}:
col.label(text="Snap With")
row = col.row(align=True)
row.prop(tool_settings, "snap_target", expand=True)
if 'VOLUME' in tool_settings.snap_elements:
col.prop(tool_settings, "use_snap_peel_object")
if obj:
col.label(text="Target Selection")
col_targetsel = col.column(align=True)
if object_mode == 'EDIT' and obj.type not in {'LATTICE', 'META', 'FONT'}:
col_targetsel.prop(
tool_settings,
"use_snap_self",
text="Include Active",
icon='EDITMODE_HLT',
)
col_targetsel.prop(
tool_settings,
"use_snap_edit",
text="Include Edited",
icon='OUTLINER_DATA_MESH',
)
col_targetsel.prop(
tool_settings,
"use_snap_nonedit",
text="Include Non-Edited",
icon='OUTLINER_OB_MESH',
)
if 'FACE_NEAREST' in tool_settings.snap_elements:
col.prop(tool_settings, "use_snap_to_same_target")
if object_mode == 'EDIT':
col.prop(tool_settings, "snap_face_nearest_steps")
col.separator()
col.prop(tool_settings, "use_snap_align_rotation")
col.prop(tool_settings, "use_snap_backface_culling")
col.separator()
if obj:
col.label(text="Target Selection")
col_targetsel = col.column(align=True)
if object_mode == 'EDIT' and obj.type not in {'LATTICE', 'META', 'FONT'}:
col_targetsel.prop(
tool_settings,
"use_snap_selectable",
text="Exclude Non-Selectable",
icon='RESTRICT_SELECT_OFF',
"use_snap_self",
text="Include Active",
icon='EDITMODE_HLT',
)
if object_mode in {'OBJECT', 'POSE', 'EDIT', 'WEIGHT_PAINT'}:
col.prop(tool_settings, "use_snap_align_rotation")
col.prop(tool_settings, "use_snap_backface_culling")
is_face_nearest_enabled = 'FACE_NEAREST' in snap_elements
if is_face_nearest_enabled or 'FACE' in snap_elements:
sub = col.column()
sub.active = not is_face_nearest_enabled
sub.prop(tool_settings, "use_snap_project")
if is_face_nearest_enabled:
col.prop(tool_settings, "use_snap_to_same_target")
if object_mode == 'EDIT':
col.prop(tool_settings, "snap_face_nearest_steps")
if 'VOLUME' in snap_elements:
col.prop(tool_settings, "use_snap_peel_object")
col_targetsel.prop(
tool_settings,
"use_snap_edit",
text="Include Edited",
icon='OUTLINER_DATA_MESH',
)
col_targetsel.prop(
tool_settings,
"use_snap_nonedit",
text="Include Non-Edited",
icon='OUTLINER_OB_MESH',
)
col_targetsel.prop(
tool_settings,
"use_snap_selectable",
text="Exclude Non-Selectable",
icon='RESTRICT_SELECT_OFF',
)
col.label(text="Affect")
row = col.row(align=True)

View File

@ -27,7 +27,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 4
#define BLENDER_FILE_SUBVERSION 5
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file

View File

@ -124,6 +124,16 @@ void blo_do_versions_400(FileData * /*fd*/, Library * /*lib*/, Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 400, 4)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
#define SCE_SNAP_PROJECT (1 << 3)
if (scene->toolsettings->snap_flag & SCE_SNAP_PROJECT) {
scene->toolsettings->snap_mode |= SCE_SNAP_MODE_FACE_RAYCAST;
}
#undef SCE_SNAP_PROJECT
}
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -5610,7 +5610,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Curve *cu;
float location[3];
const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
(vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE_RAYCAST));
(vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
Nurb *nu;
BezTriple *bezt;
@ -5642,7 +5642,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
vc.depsgraph,
vc.region,
vc.v3d,
SCE_SNAP_MODE_FACE_RAYCAST,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_target_select = (vc.obedit != NULL) ? SCE_SNAP_TARGET_NOT_ACTIVE :
SCE_SNAP_TARGET_ALL,

View File

@ -280,7 +280,7 @@ static int gizmo_move_modal(bContext *C,
CTX_data_ensure_evaluated_depsgraph(C),
region,
CTX_wm_view3d(C),
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST),
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
&(const struct SnapObjectParams){
.snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_EDIT,

View File

@ -710,7 +710,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
(vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE_RAYCAST));
(vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
/* First calculate the center of transformation. */
zero_v3(center);

View File

@ -1946,7 +1946,7 @@ void EDBM_project_snap_verts(
depsgraph,
region,
CTX_wm_view3d(C),
SCE_SNAP_MODE_FACE_RAYCAST,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_target_select = target_op,
.edit_mode_type = SNAP_GEOM_FINAL,

View File

@ -611,9 +611,9 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
v3d_cursor_snap_context_ensure(scene);
data_intern->snap_elem_hidden = SCE_SNAP_MODE_NONE;
if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE_RAYCAST)) {
data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE_RAYCAST;
snap_elements |= SCE_SNAP_MODE_FACE_RAYCAST;
if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE)) {
data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
snap_elements |= SCE_SNAP_MODE_FACE;
}
snap_data->is_enabled = true;
@ -628,7 +628,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
snap_data->snap_elem = SCE_SNAP_MODE_NONE;
return;
}
snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE_RAYCAST;
snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
}
}
#endif
@ -771,7 +771,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
{
snap_elem_index[1] = index;
}
else if (snap_elem == SCE_SNAP_MODE_FACE_RAYCAST) {
else if (snap_elem == SCE_SNAP_MODE_FACE) {
snap_elem_index[2] = index;
}

View File

@ -911,7 +911,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
CTX_data_ensure_evaluated_depsgraph(C),
region,
v3d,
SCE_SNAP_MODE_FACE_RAYCAST,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,

View File

@ -374,7 +374,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
depsgraph,
ruler_info->region,
v3d,
SCE_SNAP_MODE_FACE_RAYCAST,
SCE_SNAP_MODE_FACE,
&snap_object_params,
nullptr,
mval_fl,

View File

@ -1658,7 +1658,8 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "snap_elements"))) {
RNA_property_enum_set(op->ptr, prop, t->tsnap.mode);
RNA_boolean_set(op->ptr, "use_snap_project", (t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
RNA_boolean_set(
op->ptr, "use_snap_project", (t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST) != 0);
RNA_enum_set(op->ptr, "snap_target", t->tsnap.source_operation);
eSnapTargetOP target = t->tsnap.target_operation;

View File

@ -399,7 +399,7 @@ static void applyAxisConstraintVec(const TransInfo *t,
if (transform_snap_is_active(t)) {
if (validSnap(t)) {
is_snap_to_edge = (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) != 0;
is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE_RAYCAST) != 0;
is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE) != 0;
is_snap_to_point = !is_snap_to_edge && !is_snap_to_face;
}
else if (t->tsnap.snapElem & SCE_SNAP_MODE_GRID) {

View File

@ -1294,7 +1294,7 @@ static void edge_slide_snap_apply(TransInfo *t, float *value)
side_index = t_snap >= t_mid;
}
if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) {
if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) {
float co_dir[3];
sub_v3_v3v3(co_dir, co_dest[side_index], co_orig);
normalize_v3(co_dir);

View File

@ -105,7 +105,7 @@ static void snapsource_confirm(TransInfo *t)
transform_input_reset(t, mval);
/* Remote individual snap projection since this mode does not use the new `snap_source`. */
t->tsnap.flag &= ~SCE_SNAP_PROJECT;
t->tsnap.mode &= ~(SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST);
}
static eRedrawFlag snapsource_handle_event_fn(TransInfo *t, const wmEvent *event)

View File

@ -539,7 +539,7 @@ static void vert_slide_snap_apply(TransInfo *t, float *value)
getSnapPoint(t, dvec);
sub_v3_v3(dvec, t->tsnap.snap_source);
if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) {
if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) {
float co_dir[3];
sub_v3_v3v3(co_dir, co_curr_3d, co_orig_3d);
normalize_v3(co_dir);

View File

@ -412,10 +412,6 @@ eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td)
{
if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) {
return false;
}
float iloc[3], loc[3], no[3];
float mval_fl[2];
@ -443,7 +439,7 @@ static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td
t->depsgraph,
t->region,
static_cast<const View3D *>(t->view),
SCE_SNAP_MODE_FACE_RAYCAST,
SCE_SNAP_MODE_FACE,
&snap_object_params,
nullptr,
mval_fl,
@ -451,7 +447,7 @@ static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td
nullptr,
loc,
no);
if (hit != SCE_SNAP_MODE_FACE_RAYCAST) {
if (hit != SCE_SNAP_MODE_FACE) {
return false;
}
@ -481,10 +477,6 @@ static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td
static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td)
{
if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST)) {
return;
}
float init_loc[3];
float prev_loc[3];
float snap_loc[3], snap_no[3];
@ -539,11 +531,7 @@ bool transform_snap_project_individual_is_active(const TransInfo *t)
return false;
}
if (!(t->tsnap.flag & SCE_SNAP_PROJECT)) {
return false;
}
return true;
return (t->tsnap.mode & (SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST)) != 0;
}
void transform_snap_project_individual_apply(TransInfo *t)
@ -566,8 +554,12 @@ void transform_snap_project_individual_apply(TransInfo *t)
/* If both face ray-cast and face nearest methods are enabled, start with face ray-cast and
* fallback to face nearest ray-cast does not hit. */
bool hit = applyFaceProject(t, tc, td);
if (!hit) {
bool hit = false;
if (t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST) {
hit = applyFaceProject(t, tc, td);
}
if (!hit && t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) {
applyFaceNearest(t, tc, td);
}
#if 0 /* TODO: support this? */
@ -583,15 +575,9 @@ static bool transform_snap_mixed_is_active(const TransInfo *t)
return false;
}
if ((t->tsnap.mode == SCE_SNAP_MODE_FACE_RAYCAST) && (t->tsnap.flag & SCE_SNAP_PROJECT)) {
return false;
}
if (t->tsnap.mode == SCE_SNAP_MODE_FACE_NEAREST) {
return false;
}
return true;
return (t->tsnap.mode &
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_VOLUME |
SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) != 0;
}
void transform_snap_mixed_apply(TransInfo *t, float *vec)
@ -842,17 +828,9 @@ static void initSnappingMode(TransInfo *t)
t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
}
if ((t->spacetype != SPACE_VIEW3D) ||
!(t->tsnap.mode & (SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST)) ||
(t->flag & T_NO_PROJECT))
{
if ((t->spacetype != SPACE_VIEW3D) || (t->flag & T_NO_PROJECT)) {
/* Force project off when not supported. */
t->tsnap.flag &= ~SCE_SNAP_PROJECT;
}
if (t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) {
/* This mode only works with individual projection. */
t->tsnap.flag |= SCE_SNAP_PROJECT;
t->tsnap.mode &= ~(SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST);
}
setSnappingCallback(t);
@ -925,7 +903,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
RNA_property_is_set(op->ptr, prop))
{
SET_FLAG_FROM_TEST(
t->tsnap.flag, RNA_property_boolean_get(op->ptr, prop), SCE_SNAP_PROJECT);
t->tsnap.mode, RNA_property_boolean_get(op->ptr, prop), SCE_SNAP_MODE_FACE_RAYCAST);
}
/* use_snap_self is misnamed and should be use_snap_active */
@ -1473,7 +1451,7 @@ eSnapMode snapObjectsTransform(
SnapObjectParams snap_object_params{};
snap_object_params.snap_target_select = t->tsnap.target_operation;
snap_object_params.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL;
snap_object_params.use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE_RAYCAST;
snap_object_params.use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE;
snap_object_params.use_backface_culling = (t->tsnap.flag & SCE_SNAP_BACKFACE_CULLING) != 0;
float *target = (t->tsnap.status & SNAP_SOURCE_FOUND) ? t->tsnap.snap_source : t->center_global;

View File

@ -1057,7 +1057,7 @@ static eSnapMode raycast_obj_fn(SnapObjectContext *sctx,
sctx->ret.ob = ob_eval;
sctx->ret.data = ob_data;
sctx->ret.is_edit = is_edit;
return SCE_SNAP_MODE_FACE_RAYCAST;
return SCE_SNAP_MODE_FACE;
}
return SCE_SNAP_MODE_NONE;
}
@ -2072,7 +2072,7 @@ static eSnapMode snapArmature(SnapObjectContext *sctx,
{
eSnapMode retval = SCE_SNAP_MODE_NONE;
if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE_RAYCAST) {
if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) {
/* Currently only edge and vert. */
return retval;
}
@ -2553,7 +2553,7 @@ static eSnapMode snapMesh(SnapObjectContext *sctx,
float r_no[3],
int *r_index)
{
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if (me_eval->totvert == 0) {
return SCE_SNAP_MODE_NONE;
}
@ -2718,9 +2718,9 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx,
float r_no[3],
int *r_index)
{
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE_RAYCAST) == SCE_SNAP_MODE_VERTEX) {
if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
if (em->bm->totvert == 0) {
return SCE_SNAP_MODE_NONE;
}
@ -3275,10 +3275,10 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
const RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
if (snap_to_flag & (SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST)) {
if (snap_to_flag & (SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_FACE_NEAREST)) {
if (params->use_occlusion_test && XRAY_ENABLED(v3d)) {
/* Remove Snap to Face with Occlusion Test as they are not visible in wireframe mode. */
snap_to_flag &= ~(SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST);
snap_to_flag &= ~(SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_FACE_NEAREST);
}
else if (prev_co == nullptr || init_co == nullptr) {
/* No location to work with #SCE_SNAP_MODE_FACE_NEAREST. */
@ -3312,7 +3312,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d);
if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST) || use_occlusion_test) {
if ((snap_to_flag & SCE_SNAP_MODE_FACE) || use_occlusion_test) {
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_clipped_ex(
depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true))
@ -3329,8 +3329,8 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
copy_v3_v3(r_face_nor, sctx->ret.no);
}
if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST) {
retval = SCE_SNAP_MODE_FACE_RAYCAST;
if (snap_to_flag & SCE_SNAP_MODE_FACE) {
retval = SCE_SNAP_MODE_FACE;
copy_v3_v3(r_loc, sctx->ret.loc);
if (r_no) {

View File

@ -2255,7 +2255,7 @@ typedef enum eSnapFlag {
SCE_SNAP_ROTATE = (1 << 1),
SCE_SNAP_PEEL_OBJECT = (1 << 2),
/** Project individual elements instead of whole object. */
SCE_SNAP_PROJECT = (1 << 3),
/* SCE_SNAP_PROJECT = (1 << 3), DEPRECATED * /
/** Was `SCE_SNAP_NO_SELF`, but self should be active. */
SCE_SNAP_NOT_TO_ACTIVE = (1 << 4),
SCE_SNAP_ABS_GRID = (1 << 5),
@ -2300,13 +2300,17 @@ ENUM_OPERATORS(eSnapTargetOP, SCE_SNAP_TARGET_NOT_NONEDITED)
/** #ToolSettings.snap_mode */
typedef enum eSnapMode {
SCE_SNAP_MODE_NONE = 0,
SCE_SNAP_MODE_VERTEX = (1 << 0),
SCE_SNAP_MODE_EDGE = (1 << 1),
SCE_SNAP_MODE_FACE_RAYCAST = (1 << 2),
SCE_SNAP_MODE_FACE = (1 << 2),
SCE_SNAP_MODE_VOLUME = (1 << 3),
SCE_SNAP_MODE_EDGE_MIDPOINT = (1 << 4),
SCE_SNAP_MODE_EDGE_PERPENDICULAR = (1 << 5),
/* For snap individual elements. */
SCE_SNAP_MODE_FACE_NEAREST = (1 << 8),
SCE_SNAP_MODE_FACE_RAYCAST = (1 << 9),
/** #ToolSettings.snap_node_mode */
SCE_SNAP_MODE_NODE_X = (1 << 0),
@ -2319,11 +2323,11 @@ typedef enum eSnapMode {
/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
/* TODO: move this macro to a more general place. */
#ifdef ENUM_OPERATORS
ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_FACE_NEAREST)
ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_FACE_RAYCAST)
#endif
#define SCE_SNAP_MODE_GEOM \
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST | \
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \
SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_FACE_NEAREST)
/** #SequencerToolSettings.snap_mode */

View File

@ -151,16 +151,21 @@ const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[] = {
{0, NULL, 0, NULL, NULL},
};
/* clang-format off */
#define RNA_SNAP_ELEMENTS_BASE \
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments"}, \
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, \
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"}, \
{SCE_SNAP_MODE_FACE, "FACE", ICON_SNAP_FACE, "Face", "Snap by projecting onto faces"}, \
{SCE_SNAP_MODE_VOLUME, "VOLUME", ICON_SNAP_VOLUME, "Volume", "Snap to volume"}, \
{SCE_SNAP_MODE_EDGE_MIDPOINT, "EDGE_MIDPOINT", ICON_SNAP_MIDPOINT, "Edge Center", "Snap to the middle of edges"}, \
{SCE_SNAP_MODE_EDGE_PERPENDICULAR, "EDGE_PERPENDICULAR", ICON_SNAP_PERPENDICULAR, "Edge Perpendicular", "Snap to the nearest point on an edge"}
/* clang-format on */
const EnumPropertyItem rna_enum_snap_element_items[] = {
{SCE_SNAP_MODE_INCREMENT,
"INCREMENT",
ICON_SNAP_INCREMENT,
"Increment",
"Snap to increments of grid"},
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"},
RNA_SNAP_ELEMENTS_BASE,
{SCE_SNAP_MODE_FACE_RAYCAST,
"FACE", /* TODO(@gfxcoder): replace with "FACE_RAYCAST" as "FACE" is not descriptive. */
"FACE_PROJECT",
ICON_SNAP_FACE,
"Face Project",
"Snap by projecting onto faces"},
@ -169,20 +174,18 @@ const EnumPropertyItem rna_enum_snap_element_items[] = {
ICON_SNAP_FACE_NEAREST,
"Face Nearest",
"Snap to nearest point on faces"},
{SCE_SNAP_MODE_VOLUME, "VOLUME", ICON_SNAP_VOLUME, "Volume", "Snap to volume"},
{SCE_SNAP_MODE_EDGE_MIDPOINT,
"EDGE_MIDPOINT",
ICON_SNAP_MIDPOINT,
"Edge Center",
"Snap to the middle of edges"},
{SCE_SNAP_MODE_EDGE_PERPENDICULAR,
"EDGE_PERPENDICULAR",
ICON_SNAP_PERPENDICULAR,
"Edge Perpendicular",
"Snap to the nearest point on an edge"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_snap_element_base_items[] = {
RNA_SNAP_ELEMENTS_BASE,
{0, NULL, 0, NULL, NULL},
};
/* Last two snap elements from #rna_enum_snap_element_items. */
const EnumPropertyItem *rna_enum_snap_element_individual_items =
&rna_enum_snap_element_items[ARRAY_SIZE(rna_enum_snap_element_items) - 3];
const EnumPropertyItem rna_enum_snap_node_element_items[] = {
{SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"},
{SCE_SNAP_MODE_NODE_X, "NODE_X", ICON_NODE_SIDE, "Node X", "Snap to left/right node border"},
@ -738,6 +741,12 @@ static const EnumPropertyItem snap_to_items[] = {
# include "FRS_freestyle.h"
# endif
static int rna_ToolSettings_snap_mode_get(PointerRNA *ptr)
{
ToolSettings *ts = (ToolSettings *)(ptr->data);
return ts->snap_mode;
}
static void rna_ToolSettings_snap_mode_set(struct PointerRNA *ptr, int value)
{
ToolSettings *ts = (ToolSettings *)ptr->data;
@ -3399,11 +3408,31 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "snap_elements", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_element_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_ToolSettings_snap_mode_set", NULL);
RNA_def_property_enum_funcs(
prop, "rna_ToolSettings_snap_mode_get", "rna_ToolSettings_snap_mode_set", NULL);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Snap Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "snap_elements_base", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_element_base_items);
RNA_def_property_enum_funcs(
prop, "rna_ToolSettings_snap_mode_get", "rna_ToolSettings_snap_mode_set", NULL);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Snap Element", "Type of element for the 'Snap With' to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "snap_elements_individual", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_mode");
RNA_def_property_enum_items(prop, rna_enum_snap_element_individual_items);
RNA_def_property_enum_funcs(
prop, "rna_ToolSettings_snap_mode_get", "rna_ToolSettings_snap_mode_set", NULL);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(
prop, "Project Mode", "Type of element for individual transformed elements to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "snap_face_nearest_steps", PROP_INT, PROP_FACTOR);
RNA_def_property_int_sdna(prop, NULL, "snap_face_nearest_steps");
RNA_def_property_range(prop, 1, 100);
@ -3456,14 +3485,6 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop, "Snap Peel Object", "Consider objects as whole when finding volume center");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_project", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_PROJECT);
RNA_def_property_ui_text(prop,
"Project Individual Elements",
"Project individual elements on the surface of other objects (Always "
"enabled with Face Nearest)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_backface_culling", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_BACKFACE_CULLING);
RNA_def_property_ui_text(prop, "Backface Culling", "Exclude back facing geometry from snapping");