Object: Switch Object operator

This object operator exits and frees the edit data of the
current object and enters the same mode in another one in a single step,
without going through object mode or keeping multiple edit object data
active. It is assigned to the D key.

This solves all conflicts that the right/click select keymap and the
emulate 3 button mouse produces for this operation and it is independent
of the state of Lock object modes.
Also, as the SculptSession is freed, when using Multires objects go
back to their preview resolution level, so it is possible to work on
high vertex count scenes without slowing down the viewport and other
performance problems.

Reviewed By: #user_interface, pablovazquez

Differential Revision: https://developer.blender.org/D7510
This commit is contained in:
Pablo Dobarro 2020-09-18 19:32:35 +02:00 committed by Pablo Dobarro
parent 6c9ec1c893
commit 827dfd76dd
4 changed files with 126 additions and 0 deletions

View File

@ -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)],)]}),

View File

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

View File

@ -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;
}
/** \} */

View File

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