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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/datafiles/blender_icons16/icon16_force_boid.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_force_boid.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/startup.blendbin870336 -> 893944 bytes
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py85
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h1
-rw-r--r--source/blender/editors/transform/transform_ops.c8
-rw-r--r--source/blender/editors/transform/transform_snap.c42
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc103
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c28
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c7
-rw-r--r--source/blender/windowmanager/WM_api.h5
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c16
-rw-r--r--source/blender/windowmanager/intern/wm_window.c19
14 files changed, 211 insertions, 105 deletions
diff --git a/release/datafiles/blender_icons16/icon16_force_boid.dat b/release/datafiles/blender_icons16/icon16_force_boid.dat
index 71f89bd7c04..f719054d84a 100644
--- a/release/datafiles/blender_icons16/icon16_force_boid.dat
+++ b/release/datafiles/blender_icons16/icon16_force_boid.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_force_boid.dat b/release/datafiles/blender_icons32/icon32_force_boid.dat
index 7fc7cb5ee8c..9043989024b 100644
--- a/release/datafiles/blender_icons32/icon32_force_boid.dat
+++ b/release/datafiles/blender_icons32/icon32_force_boid.dat
Binary files differ
diff --git a/release/datafiles/startup.blend b/release/datafiles/startup.blend
index fe142d7de7e..469986a5576 100644
--- a/release/datafiles/startup.blend
+++ b/release/datafiles/startup.blend
Binary files differ
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 92dc4138530..bd0959a17a7 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -6808,65 +6808,72 @@ class VIEW3D_PT_snapping(Panel):
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
+ object_mode = obj.mode if obj else 'OBJECT'
+ show_target_options = object_mode == 'EDIT' and obj.type not in {'LATTICE', 'META', 'FONT'}
layout = self.layout
col = layout.column()
+
+ if snap_elements != {'INCREMENT'} and show_target_options:
+ col.prop(
+ tool_settings,
+ "use_snap_retopology_mode",
+ text="Use Retopology Mode",
+ # icon='MOD_MESHDEFORM',
+ )
+
col.label(text="Snap To")
col.prop(tool_settings, "snap_elements", expand=True)
- col.separator()
if 'INCREMENT' in snap_elements:
col.prop(tool_settings, "use_snap_grid_absolute")
+ if snap_elements - {'INCREMENT', 'FACE_NEAREST'}:
+ col.label(text="Snap With")
+ row = col.row(align=True)
+ row.prop(tool_settings, "snap_target", expand=True)
+
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 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',
- )
+ col.label(text="Target Selection")
+ col_targetsel = col.column(align=True)
+ if show_target_options:
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',
)
+ 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',
+ )
- 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")
-
+ col.label(text="Options")
+ # TODO(@gfxcoder): Does WEIGHT_PAINT have any snapping?
+ if object_mode in {'OBJECT', 'POSE', 'EDIT', 'WEIGHT_PAINT'}:
+ col.prop(tool_settings, "use_snap_align_rotation")
+ if snap_elements != {'FACE_NEAREST'}:
+ col.prop(tool_settings, "use_snap_backface_culling")
if 'FACE' in snap_elements:
col.prop(tool_settings, "use_snap_project")
-
if 'FACE_NEAREST' in snap_elements:
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")
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index db44d9af706..151bf877460 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -26,7 +26,6 @@ struct View3D;
/* transform_snap_object.cc */
/* ED_transform_snap_object_*** API */
-
typedef enum eSnapEditType {
SNAP_GEOM_FINAL = 0,
SNAP_GEOM_CAGE = 1,
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 7c94241f3e3..7c5569f1a10 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -655,6 +655,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
}
if (flags & P_SNAP) {
+ // TODO: rename `snap` to `use_snap`?
prop = RNA_def_boolean(ot->srna, "snap", false, "Use Snapping Options", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -686,6 +687,13 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_boolean(
ot->srna, "use_snap_selectable_only", false, "Target: Exclude Non-Selectable", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna,
+ "use_snap_retopology_mode",
+ true,
+ "Target: Retopology Mode",
+ "Snap grabbed geometry to vertices and edges of edited objects (if "
+ "enabled) and to faces of non-edited objects (if enabled)");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
/* Face Nearest options */
prop = RNA_def_boolean(
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 22d062a71dc..4a82c5a00fa 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -128,11 +128,11 @@ bool activeSnap(const TransInfo *t)
bool activeSnap_SnappingIndividual(const TransInfo *t)
{
- if (activeSnap(t) && t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) {
+ if (activeSnap(t) && (t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST)) {
return true;
}
- if (!t->tsnap.project) {
+ if ((t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST) && !t->tsnap.project) {
return false;
}
@@ -509,9 +509,13 @@ void applySnappingIndividual(TransInfo *t)
continue;
}
- /* 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 both face raycast and face nearest methods are enabled, start with face raycast and
+ * fallback to face nearest raycast does not hit. */
+ bool hit = false;
+ if (t->tsnap.flag & SCE_SNAP_PROJECT) {
+ /* Only raycast in this function if projecting individual elements. */
+ hit = applyFaceProject(t, tc, td);
+ }
if (!hit) {
applyFaceNearest(t, tc, td);
}
@@ -738,6 +742,7 @@ static eSnapTargetSelect snap_target_select_from_spacetype(TransInfo *t)
bool use_snap_edit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_EDITED) == 0;
bool use_snap_nonedit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_NONEDITED) == 0;
bool use_snap_selectable_only = (t->tsnap.target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0;
+ // bool use_retopology_mode = (t->tsnap.target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE) != 0;
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
@@ -918,6 +923,13 @@ void initSnapping(TransInfo *t, wmOperator *op)
RNA_property_boolean_get(op->ptr, prop),
SCE_SNAP_TARGET_ONLY_SELECTABLE);
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_retopology_mode")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_RETOPOLOGY_MODE);
+ }
}
}
/* use scene defaults only when transform is modal */
@@ -926,6 +938,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->modifiers |= MOD_SNAP;
}
+ t->tsnap.target_select = SCE_SNAP_TARGET_ALL;
t->tsnap.align = ((t->tsnap.flag & SCE_SNAP_ROTATE) != 0);
t->tsnap.project = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
@@ -941,6 +954,9 @@ void initSnapping(TransInfo *t, wmOperator *op)
SET_FLAG_FROM_TEST(t->tsnap.target_select,
(ts->snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE),
SCE_SNAP_TARGET_ONLY_SELECTABLE);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ (t->settings->snap_flag & SCE_SNAP_RETOPOLOGY_MODE),
+ SCE_SNAP_TARGET_RETOPOLOGY_MODE);
}
t->tsnap.source_select = snap_source;
@@ -1446,16 +1462,28 @@ eSnapMode snapObjectsTransform(
TransInfo *t, const float mval[2], float *dist_px, float r_loc[3], float r_no[3])
{
float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
+
+ // filter mode to group snapping modes
+ eSnapMode mode = t->tsnap.mode;
+ mode &= ~(SCE_SNAP_MODE_FACE_NEAREST);
+ if (t->tsnap.flag & SCE_SNAP_PROJECT) {
+ mode &= ~(SCE_SNAP_MODE_FACE_RAYCAST);
+ }
+
+ const bool use_retopo_mode = (t->tsnap.target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE);
+ const bool face_raycast_only = t->settings->snap_mode == SCE_SNAP_MODE_FACE_RAYCAST;
+ const bool use_occlusion_test = use_retopo_mode || !face_raycast_only;
+
return ED_transform_snap_object_project_view3d(
t->tsnap.object_context,
t->depsgraph,
t->region,
t->view,
- t->tsnap.mode,
+ mode,
&(const struct SnapObjectParams){
.snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
- .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE_RAYCAST,
+ .use_occlusion_test = use_occlusion_test,
.use_backface_culling = t->tsnap.use_backface_culling,
},
NULL,
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index 479214ee2d3..f195a13fb6c 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -1025,6 +1025,12 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
/* read/write args */
float *ray_depth = dt->ray_depth;
+ const bool use_retopo_mode = params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE;
+ const bool is_object_edited = BKE_object_is_in_editmode(ob_eval);
+ if (use_retopo_mode && is_object_edited) {
+ return;
+ }
+
bool retval = false;
if (use_occlusion_test) {
if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) {
@@ -1273,8 +1279,8 @@ static bool nearest_world_tree(SnapObjectContext *UNUSED(sctx),
}
else {
/* NOTE: when `params->face_nearest_steps == 1`, the return variables of function below contain
- * the answer. We could return immediately after updating r_loc, r_no, r_index, but that would
- * also complicate the code. Foregoing slight optimization for code clarity. */
+ * the answer. We could return immediately after updating 'r_loc', 'r_no', 'r_index', but that
+ * would also complicate the code. Foregoing slight optimization for code clarity. */
nearest_world_tree_co(
tree, nearest_cb, treedata, curr_co_local, nullptr, nullptr, nullptr, &dist_sq);
}
@@ -1384,6 +1390,12 @@ static void nearest_world_object_fn(SnapObjectContext *sctx,
{
struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data);
+ const bool use_retopo_mode = params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE;
+ const bool is_object_edited = BKE_object_is_in_editmode(ob_eval);
+ if (use_retopo_mode && is_object_edited) {
+ return;
+ }
+
bool retval = false;
switch (ob_eval->type) {
case OB_MESH: {
@@ -3055,6 +3067,12 @@ static void snap_obj_fn(SnapObjectContext *sctx,
SnapObjUserData *dt = static_cast<SnapObjUserData *>(data);
eSnapMode retval = SCE_SNAP_MODE_NONE;
+ const bool use_retopo_mode = (params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE);
+ const bool is_object_edited = BKE_object_is_in_editmode(ob_eval);
+ if (use_retopo_mode && !is_object_edited) {
+ return;
+ }
+
switch (ob_eval->type) {
case OB_MESH: {
const eSnapEditType edit_mode_type = params->edit_mode_type;
@@ -3384,47 +3402,29 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
sctx->runtime.region = region;
sctx->runtime.v3d = v3d;
- BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0);
+ if ((snap_to_flag & SCE_SNAP_MODE_GEOM) == 0) {
+ return SCE_SNAP_MODE_NONE;
+ }
+
+ // BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0);
eSnapMode retval = SCE_SNAP_MODE_NONE;
bool has_hit = false;
Object *ob_eval = nullptr;
+ Object *ob_ray = nullptr;
float loc[3];
/* Not all snapping callbacks set the normal,
* initialize this since any hit copies both the `loc` and `no`. */
float no[3] = {0.0f, 0.0f, 0.0f};
float obmat[4][4];
+ float obmat_ray[4][4];
int index = -1;
const RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
- bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d);
-
- /* Note: if both face raycast and face nearest are enabled, first find result of nearest, then
- * override with raycast. */
- if ((snap_to_flag & SCE_SNAP_MODE_FACE_NEAREST) && !has_hit) {
- has_hit = nearestWorldObjects(
- sctx, params, init_co, prev_co, loc, no, &index, &ob_eval, obmat);
-
- if (has_hit) {
- retval = SCE_SNAP_MODE_FACE_NEAREST;
-
- copy_v3_v3(r_loc, loc);
- if (r_no) {
- copy_v3_v3(r_no, no);
- }
- if (r_ob) {
- *r_ob = ob_eval;
- }
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
- }
- if (r_index) {
- *r_index = index;
- }
- }
- }
+ const bool use_retopo_mode = params->snap_target_select & SCE_SNAP_TARGET_RETOPOLOGY_MODE;
+ const bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d);
if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST || use_occlusion_test) {
float ray_start[3], ray_normal[3];
@@ -3443,8 +3443,8 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
loc,
no,
&index,
- &ob_eval,
- obmat,
+ &ob_ray, // &ob_eval,
+ obmat_ray, // obmat,
nullptr);
if (has_hit) {
@@ -3453,6 +3453,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
}
if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ /* Record snap results only if face raycast snapping mode is enabled. */
retval = SCE_SNAP_MODE_FACE_RAYCAST;
copy_v3_v3(r_loc, loc);
@@ -3460,15 +3461,19 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
copy_v3_v3(r_no, no);
}
if (r_ob) {
- *r_ob = ob_eval;
+ *r_ob = ob_ray; // ob_eval;
}
if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
+ copy_m4_m4(r_obmat, obmat_ray); // obmat
}
if (r_index) {
*r_index = index;
}
}
+ if (use_occlusion_test && !use_retopo_mode) {
+ ob_eval = ob_ray;
+ copy_m4_m4(obmat, obmat_ray);
+ }
}
}
@@ -3503,7 +3508,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
sctx->runtime.has_occlusion_plane = false;
/* By convention we only snap to the original elements of a curve. */
- if (has_hit && ob_eval->type != OB_CURVES_LEGACY) {
+ if (has_hit && ob_ray->type != OB_CURVES_LEGACY) {
/* Compute the new clip_pane but do not add it yet. */
float new_clipplane[4];
BLI_ASSERT_UNIT_V3(no);
@@ -3517,8 +3522,9 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(sctx, params, ob_eval, obmat, &dist_px_tmp, loc, no, &index);
- if (elem_test) {
+ elem_test = snap_mesh_polygon(
+ sctx, params, ob_ray, obmat_ray, &dist_px_tmp, loc, no, &index);
+ if (elem_test && !use_retopo_mode) {
elem = elem_test;
}
@@ -3565,6 +3571,31 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont
}
}
+ /* Note: if both face raycast and face nearest are enabled, first find result of nearest, then
+ * override with raycast. */
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE_NEAREST) && !has_hit) {
+ has_hit = nearestWorldObjects(
+ sctx, params, init_co, prev_co, loc, no, &index, &ob_eval, obmat);
+
+ if (has_hit) {
+ retval = SCE_SNAP_MODE_FACE_NEAREST;
+
+ copy_v3_v3(r_loc, loc);
+ if (r_no) {
+ copy_v3_v3(r_no, no);
+ }
+ if (r_ob) {
+ *r_ob = ob_eval;
+ }
+ if (r_obmat) {
+ copy_m4_m4(r_obmat, obmat);
+ }
+ if (r_index) {
+ *r_index = index;
+ }
+ }
+ }
+
return retval;
}
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f8fcd78d63b..d2fcf2461cb 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -2095,6 +2095,7 @@ typedef enum eSnapFlag {
SCE_SNAP_TO_INCLUDE_EDITED = (1 << 8),
SCE_SNAP_TO_INCLUDE_NONEDITED = (1 << 9),
SCE_SNAP_TO_ONLY_SELECTABLE = (1 << 10),
+ SCE_SNAP_RETOPOLOGY_MODE = (1 << 11),
} eSnapFlag;
/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
/* TODO: move this macro to a more general place. */
@@ -2119,6 +2120,7 @@ typedef enum eSnapTargetSelect {
SCE_SNAP_TARGET_NOT_EDITED = (1 << 2),
SCE_SNAP_TARGET_ONLY_SELECTABLE = (1 << 3),
SCE_SNAP_TARGET_NOT_NONEDITED = (1 << 4),
+ SCE_SNAP_TARGET_RETOPOLOGY_MODE = (1 << 5),
} eSnapTargetSelect;
/** #ToolSettings.snap_mode */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index daf4c99845d..530b18aa8df 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -151,6 +151,16 @@ const EnumPropertyItem rna_enum_snap_element_items[] = {
"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"},
+ {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"},
{SCE_SNAP_MODE_FACE_RAYCAST,
"FACE", /* TODO(@gfxcoder): replace with "FACE_RAYCAST" as "FACE" is not descriptive. */
ICON_SNAP_FACE,
@@ -162,16 +172,6 @@ const EnumPropertyItem rna_enum_snap_element_items[] = {
"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},
};
@@ -3400,6 +3400,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop, "Snap onto Selectable Only", "Snap only onto objects that are selectable");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ prop = RNA_def_property(srna, "use_snap_retopology_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_RETOPOLOGY_MODE);
+ RNA_def_property_ui_text(prop,
+ "Retopology Target Mode",
+ "Snap grabbed geometry to vertices and edges of edited objects (if "
+ "enabled) and to faces of non-edited objects (if enabled)");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
prop = RNA_def_property(srna, "use_snap_translate", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, NULL, "snap_transform_mode_flag", SCE_SNAP_TRANSFORM_MODE_TRANSLATE);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index eb5e2549b1d..63f871bd682 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -721,6 +721,13 @@ void RNA_api_window(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor position");
+ func = RNA_def_function(srna, "cursor_warp_relative", "WM_cursor_warp_relative");
+ parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "", "Offset of x", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "", "Offset of y", INT_MIN, INT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_function_ui_description(func, "Offset the cursor position");
+
func = RNA_def_function(srna, "cursor_set", "WM_cursor_set");
parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 44c5b86857d..c60e728e26c 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -314,6 +314,11 @@ void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region);
* This function requires access to the GHOST_SystemHandle (g_system).
*/
void WM_cursor_warp(struct wmWindow *win, int x, int y);
+void WM_cursor_warp_relative(struct wmWindow *win, int x, int y);
+/**
+ * Set x, y to values we can actually position the cursor to.
+ */
+void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y);
/* Handlers. */
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 43be87fce39..a072eba6056 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -278,14 +278,6 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
}
}
-static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
-{
- /* NOTE: don't use wmEvent coords because of continuous grab T36409. */
- int cx, cy;
- wm_cursor_position_get(win, &cx, &cy);
- WM_cursor_warp(win, cx + x, cy + y);
-}
-
bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
{
/* TODO: give it a modal keymap? Hard coded for now */
@@ -295,19 +287,19 @@ bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
float fac = GHOST_GetNativePixelSize(win->ghostwin);
if (event->type == EVT_UPARROWKEY) {
- wm_cursor_warp_relative(win, 0, fac);
+ WM_cursor_warp_relative(win, 0, fac);
return 1;
}
if (event->type == EVT_DOWNARROWKEY) {
- wm_cursor_warp_relative(win, 0, -fac);
+ WM_cursor_warp_relative(win, 0, -fac);
return 1;
}
if (event->type == EVT_LEFTARROWKEY) {
- wm_cursor_warp_relative(win, -fac, 0);
+ WM_cursor_warp_relative(win, -fac, 0);
return 1;
}
if (event->type == EVT_RIGHTARROWKEY) {
- wm_cursor_warp_relative(win, fac, 0);
+ WM_cursor_warp_relative(win, fac, 0);
return 1;
}
}
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 70640eda605..67fa7db7aec 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -2033,6 +2033,25 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
}
}
+void WM_cursor_warp_relative(wmWindow *win, int x, int y)
+{
+ if (win && win->ghostwin) {
+ /* NOTE: don't use wmEvent coords because of continuous grab T36409. */
+ int cx, cy;
+ wm_cursor_position_get(win, &cx, &cy);
+ WM_cursor_warp(win, cx + x, cy + y);
+ }
+}
+
+void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
+{
+ float f = GHOST_GetNativePixelSize(win->ghostwin);
+ if (f != 1.0f) {
+ *x = (int)(*x / f) * f;
+ *y = (int)(*y / f) * f;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */