diff options
-rw-r--r-- | release/datafiles/blender_icons16/icon16_force_boid.dat | bin | 1048 -> 1048 bytes | |||
-rw-r--r-- | release/datafiles/blender_icons32/icon32_force_boid.dat | bin | 4120 -> 4120 bytes | |||
-rw-r--r-- | release/datafiles/startup.blend | bin | 870336 -> 893944 bytes | |||
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 85 | ||||
-rw-r--r-- | source/blender/editors/include/ED_transform_snap_object_context.h | 1 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_ops.c | 8 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap.c | 42 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_snap_object.cc | 103 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_scene_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_scene.c | 28 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_wm_api.c | 7 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 5 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_cursors.c | 16 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 19 |
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 Binary files differindex 71f89bd7c04..f719054d84a 100644 --- a/release/datafiles/blender_icons16/icon16_force_boid.dat +++ b/release/datafiles/blender_icons16/icon16_force_boid.dat diff --git a/release/datafiles/blender_icons32/icon32_force_boid.dat b/release/datafiles/blender_icons32/icon32_force_boid.dat Binary files differindex 7fc7cb5ee8c..9043989024b 100644 --- a/release/datafiles/blender_icons32/icon32_force_boid.dat +++ b/release/datafiles/blender_icons32/icon32_force_boid.dat diff --git a/release/datafiles/startup.blend b/release/datafiles/startup.blend Binary files differindex fe142d7de7e..469986a5576 100644 --- a/release/datafiles/startup.blend +++ b/release/datafiles/startup.blend 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; + } +} + /** \} */ /* -------------------------------------------------------------------- */ |