diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 0955c4ad58f..be5d2f2c0d6 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4349,6 +4349,8 @@ def km_sculpt(params): ) items.extend([ + # Switch Object + ("object.switch_object", {"type": 'D', "value": 'PRESS'}, None), # Brush strokes ("sculpt.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": [("mode", 'NORMAL')]}), @@ -4465,6 +4467,8 @@ def km_mesh(params): ) items.extend([ + #Switch Object + ("object.switch_object", {"type": 'D', "value": 'PRESS'}, None), # Tools. ("mesh.loopcut_slide", {"type": 'R', "value": 'PRESS', "ctrl": True}, {"properties": [("TRANSFORM_OT_edge_slide", [("release_confirm", False)],)]}), diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 99e139b823e..0a243a56dee 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -89,6 +89,8 @@ void OBJECT_OT_forcefield_toggle(struct wmOperatorType *ot); void OBJECT_OT_move_to_collection(struct wmOperatorType *ot); void OBJECT_OT_link_to_collection(struct wmOperatorType *ot); +void OBJECT_OT_switch_object(struct wmOperatorType *ot); + /* object_select.c */ void OBJECT_OT_select_all(struct wmOperatorType *ot); void OBJECT_OT_select_random(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index bc05a62759f..caba10c820b 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -26,6 +26,8 @@ #include "DNA_scene_types.h" #include "DNA_workspace_types.h" +#include "BLI_kdopbvh.h" +#include "BLI_math.h" #include "BLI_utildefines.h" #include "BKE_context.h" @@ -44,10 +46,15 @@ #include "RNA_access.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "ED_armature.h" #include "ED_gpencil.h" #include "ED_screen.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "WM_toolsystem.h" #include "ED_object.h" /* own include */ @@ -390,3 +397,114 @@ bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, struct Object } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Switch Object + * + * Enters the same mode of the current active object in another object, leaving the mode of the + *current object. + * + * \{ */ + +bool OBJECT_switch_object_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + if (!CTX_wm_region_view3d(C)) { + return false; + } + return ob && ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_SCULPT); +} + +static int object_switch_object_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ARegion *ar = CTX_wm_region(C); + struct Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + struct SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, 0); + + float global_normal[3], global_loc[3]; + float r_obmat[4][4]; + + float mouse[2]; + mouse[0] = event->mval[0]; + mouse[1] = event->mval[1]; + + float ray_co[3], ray_no[3]; + float ray_dist = BVH_RAYCAST_DIST_MAX; + int r_index; + ED_view3d_win_to_origin(ar, mouse, ray_co); + ED_view3d_win_to_vector(ar, mouse, ray_no); + + Object *r_ob = NULL; + + bool ret = ED_transform_snap_object_project_ray_ex(sctx, + depsgraph, + &(const struct SnapObjectParams){ + .snap_select = SNAP_NOT_ACTIVE, + }, + ray_co, + ray_no, + &ray_dist, + global_loc, + global_normal, + &r_index, + &r_ob, + (float(*)[4])r_obmat); + ED_transform_snap_object_context_destroy(sctx); + + Object *c_ob = CTX_data_active_object(C); + if (!ret || r_ob == NULL) { + return OPERATOR_CANCELLED; + } + if (r_ob == NULL || r_ob == c_ob) { + return OPERATOR_CANCELLED; + } + + eObjectMode last_mode = (eObjectMode)c_ob->mode; + if (!ED_object_mode_compat_test(r_ob, last_mode)) { + return OPERATOR_CANCELLED; + } + ED_object_mode_generic_exit(bmain, depsgraph, scene, c_ob); + + Object *ob_orig = DEG_get_original_object(r_ob); + Base *base = BKE_view_layer_base_find(view_layer, ob_orig); + BKE_view_layer_base_deselect_all(view_layer); + BKE_view_layer_base_select_and_set_active(view_layer, base); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + + depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + ob_orig = DEG_get_original_object(r_ob); + ED_object_mode_set(C, last_mode); + + /* Update the viewport rotation origin to the mouse cursor. */ + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + copy_v3_v3(ups->average_stroke_accum, global_loc); + ups->average_stroke_counter = 1; + ups->last_stroke_valid = true; + + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_toolsystem_update_from_context_view3d(C); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_switch_object(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Switch Object"; + ot->idname = "OBJECT_OT_switch_object"; + ot->description = + "Switches the active object and assigns the same mode to a new one under the mouse cursor, " + "leaving the active mode in the current one"; + + /* api callbacks */ + ot->invoke = object_switch_object_invoke; + ot->poll = OBJECT_switch_object_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 8b3837edce2..390770d5c5c 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -71,6 +71,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_paths_range_update); WM_operatortype_append(OBJECT_OT_forcefield_toggle); + WM_operatortype_append(OBJECT_OT_switch_object); + WM_operatortype_append(OBJECT_OT_parent_set); WM_operatortype_append(OBJECT_OT_parent_no_inverse_set); WM_operatortype_append(OBJECT_OT_parent_clear);