From d9e10e6ddb96765bde358a25bab6b321cc89151a Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Mon, 13 Mar 2023 04:07:07 -0700 Subject: [PATCH 01/20] Blender 3.5, custom build initial stage with just keymap direction and mesh select toosettings --- scripts/modules/rna_keymap_ui.py | 19 +- scripts/startup/bl_operators/userpref.py | 110 +++ scripts/startup/bl_ui/space_userpref.py | 2 + scripts/startup/bl_ui/space_view3d_toolbar.py | 59 +- source/blender/blenlib/BLI_lasso_2d.h | 3 +- source/blender/blenlib/intern/lasso_2d.c | 35 +- .../blenloader/intern/versioning_defaults.cc | 26 + .../editors/curves/intern/curves_selection.cc | 3 +- source/blender/editors/include/ED_view3d.h | 11 +- .../blender/editors/mesh/editmesh_select.cc | 4 +- .../editors/space_view3d/view3d_iterators.cc | 151 +++- .../editors/space_view3d/view3d_select.cc | 735 +++++++++++++++--- source/blender/editors/uvedit/uvedit_select.c | 8 +- source/blender/makesdna/DNA_scene_defaults.h | 26 + source/blender/makesdna/DNA_scene_types.h | 52 +- source/blender/makesdna/DNA_userdef_types.h | 19 +- source/blender/makesrna/intern/rna_scene.c | 179 +++++ source/blender/makesrna/intern/rna_userdef.c | 37 + source/blender/makesrna/intern/rna_wm_api.c | 60 ++ source/blender/windowmanager/WM_api.h | 2 +- .../windowmanager/intern/wm_event_query.c | 84 +- .../windowmanager/intern/wm_event_system.cc | 3 +- .../windowmanager/intern/wm_operator_props.c | 145 +++- 23 files changed, 1596 insertions(+), 177 deletions(-) diff --git a/scripts/modules/rna_keymap_ui.py b/scripts/modules/rna_keymap_ui.py index 8daacc2e12e..2aa004bbb7d 100644 --- a/scripts/modules/rna_keymap_ui.py +++ b/scripts/modules/rna_keymap_ui.py @@ -182,7 +182,24 @@ def draw_kmi(display_keymaps, kc, km, kmi, layout, level): if map_type in {'KEYBOARD', 'MOUSE'} and kmi.value == 'CLICK_DRAG': subrow = sub.row() - subrow.prop(kmi, "direction") + if bpy.context.preferences.inputs.click_drag_direction == 'LEFT_RIGHT': + if kmi.direction == 'ANY' or kmi.direction == 'EAST' or kmi.direction == 'WEST': + subrow.label(text="Direction:") + else: + subrow.label(text="WARNING - No Direction:") + subrow.operator("preferences.set_direction_any", text="Any", depress= kmi.direction == 'ANY').item_id = kmi.id + subrow.operator("preferences.set_direction_left", text="Left", depress= kmi.direction == 'WEST').item_id = kmi.id + subrow.operator("preferences.set_direction_right", text="Right", depress= kmi.direction == 'EAST').item_id = kmi.id + elif bpy.context.preferences.inputs.click_drag_direction == 'UP_DOWN': + if kmi.direction == 'ANY' or kmi.direction == 'NORTH' or kmi.direction == 'SOUTH': + subrow.label(text="Direction:") + else: + subrow.label(text="WARNING - No Direction:") + subrow.operator("preferences.set_direction_any", text="Any", depress= kmi.direction == 'ANY').item_id = kmi.id + subrow.operator("preferences.set_direction_up", text="Up", depress= kmi.direction == 'NORTH').item_id = kmi.id + subrow.operator("preferences.set_direction_down", text="Down", depress= kmi.direction == 'SOUTH').item_id = kmi.id + else: + subrow.prop(kmi, "direction") subrow = sub.row() subrow.scale_x = 0.75 diff --git a/scripts/startup/bl_operators/userpref.py b/scripts/startup/bl_operators/userpref.py index d0134bd076f..f2d9d5cb428 100644 --- a/scripts/startup/bl_operators/userpref.py +++ b/scripts/startup/bl_operators/userpref.py @@ -400,6 +400,111 @@ class PREFERENCES_OT_keyitem_remove(Operator): return {'FINISHED'} +class PREFERENCES_OT_set_direction_any(Operator): + """Drag in any direction""" + bl_idname = "preferences.set_direction_any" + bl_label = "Set Direction Any" + + item_id: IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + return hasattr(context, "keymap") + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + km.keymap_items.set_direction_any(kmi) + return {'FINISHED'} + + +class PREFERENCES_OT_set_direction_left(Operator): + """Drag to the left""" + bl_idname = "preferences.set_direction_left" + bl_label = "Set Direction Left" + + item_id: IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + return hasattr(context, "keymap") + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + km.keymap_items.set_direction_left(kmi) + return {'FINISHED'} + + +class PREFERENCES_OT_set_direction_right(Operator): + """Drag to the right""" + bl_idname = "preferences.set_direction_right" + bl_label = "Set Direction Right" + + item_id: IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + return hasattr(context, "keymap") + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + km.keymap_items.set_direction_right(kmi) + return {'FINISHED'} + + +class PREFERENCES_OT_set_direction_up(Operator): + """Drag upwards""" + bl_idname = "preferences.set_direction_up" + bl_label = "Set Direction Up" + + item_id: IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + return hasattr(context, "keymap") + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + km.keymap_items.set_direction_up(kmi) + return {'FINISHED'} + + +class PREFERENCES_OT_set_direction_down(Operator): + """Drag downwards""" + bl_idname = "preferences.set_direction_down" + bl_label = "Set Direction Down" + + item_id: IntProperty( + name="Item Identifier", + description="Identifier of the item to remove", + ) + + @classmethod + def poll(cls, context): + return hasattr(context, "keymap") + + def execute(self, context): + km = context.keymap + kmi = km.keymap_items.from_id(self.item_id) + km.keymap_items.set_direction_down(kmi) + return {'FINISHED'} + + class PREFERENCES_OT_keyconfig_remove(Operator): """Remove key config""" bl_idname = "preferences.keyconfig_remove" @@ -1156,6 +1261,11 @@ classes = ( PREFERENCES_OT_keyconfig_test, PREFERENCES_OT_keyitem_add, PREFERENCES_OT_keyitem_remove, + PREFERENCES_OT_set_direction_any, + PREFERENCES_OT_set_direction_left, + PREFERENCES_OT_set_direction_right, + PREFERENCES_OT_set_direction_up, + PREFERENCES_OT_set_direction_down, PREFERENCES_OT_keyitem_restore, PREFERENCES_OT_keymap_restore, PREFERENCES_OT_theme_install, diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index f0dedc42c54..b0025e391c5 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -1559,6 +1559,8 @@ class USERPREF_PT_input_mouse(InputPanel, CenterAlignMixIn, Panel): flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) + flow.prop(inputs, "click_drag_direction") + flow.prop(inputs, "drag_select_mesh_control") flow.prop(inputs, "use_mouse_emulate_3_button") if sys.platform[:3] != "win": rowsub = flow.row() diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index c6d6a77eec2..654e78fd268 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-or-later +import bpy from bpy.types import Menu, Panel, UIList, WindowManager from bl_ui.properties_grease_pencil_common import ( GreasePencilSculptAdvancedPanel, @@ -153,7 +154,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): bl_context = ".mesh_edit" # dot on purpose (access from topbar) bl_label = "Options" bl_options = {'DEFAULT_CLOSED'} - bl_ui_units_x = 12 + bl_ui_units_x = 14 @classmethod def poll(cls, context): @@ -169,6 +170,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): ob = context.active_object mesh = ob.data + row = layout.row(align=True) row = layout.row(align=True, heading="Transform") row.prop(tool_settings, "use_transform_correct_face_attributes") @@ -189,6 +191,61 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z row.prop(mesh, "use_mirror_topology") + if bpy.context.preferences.inputs.drag_select_mesh_control == 'USER_MESH_TOOLSETTING': + from bl_ui.space_toolsystem_common import ToolSelectPanelHelper + _cls = ToolSelectPanelHelper._tool_class_from_space_type('VIEW_3D') + + if tool_settings.workspace_tool_type == 'FALLBACK': + tool = _cls._tool_get_by_id_active(context, _cls.tool_fallback_id)[0].idname + else: + tool = ToolSelectPanelHelper.tool_active_from_context(context).idname + + if tool == "builtin.select_box" or tool == "builtin.select_lasso" or tool == "builtin.select_circle": + row = layout.row(align=True, heading="Drag Select") + if tool == "builtin.select_box": + row.prop(tool_settings, "box_drag_direction") + row = layout.row(align=True) + if tool_settings.box_drag_direction == 'MESH_DIRECTION_ANY': + row.prop(tool_settings, "box_edge") + row = layout.row(align=True) + row.prop(tool_settings, "box_face") + elif tool_settings.box_drag_direction == 'MESH_DIRECTION_LEFT_RIGHT': + row.prop(tool_settings, "box_edge_left", text="Box Edge", icon='TRIA_LEFT') + row.prop(tool_settings, "box_edge_right", text="", icon='TRIA_RIGHT') + row = layout.row(align=True) + row.prop(tool_settings, "box_face_left", text="Box Face", icon='TRIA_LEFT') + row.prop(tool_settings, "box_face_right", text="", icon='TRIA_RIGHT') + else: + row.prop(tool_settings, "box_edge_up", text="Box Edge", icon='TRIA_UP') + row.prop(tool_settings, "box_edge_down", text="", icon='TRIA_DOWN') + row = layout.row(align=True) + row.prop(tool_settings, "box_face_up", text="Box Face", icon='TRIA_UP') + row.prop(tool_settings, "box_face_down", text="", icon='TRIA_DOWN') + elif tool == "builtin.select_lasso": + row.prop(tool_settings, "lasso_drag_direction") + row = layout.row(align=True) + if tool_settings.lasso_drag_direction == 'MESH_DIRECTION_ANY': + row.prop(tool_settings, "lasso_edge") + row = layout.row(align=True) + row.prop(tool_settings, "lasso_face") + elif tool_settings.lasso_drag_direction == 'MESH_DIRECTION_LEFT_RIGHT': + row.prop(tool_settings, "lasso_edge_left", text="Lasso Edge", icon='TRIA_LEFT') + row.prop(tool_settings, "lasso_edge_right", text="", icon='TRIA_RIGHT') + row = layout.row(align=True) + row.prop(tool_settings, "lasso_face_left", text="Lasso Face", icon='TRIA_LEFT') + row.prop(tool_settings, "lasso_face_right", text="", icon='TRIA_RIGHT') + else: + row.prop(tool_settings, "lasso_edge_up", text="Lasso Edge", icon='TRIA_UP') + row.prop(tool_settings, "lasso_edge_down", text="", icon='TRIA_DOWN') + row = layout.row(align=True) + row.prop(tool_settings, "lasso_face_up", text="Lasso Face", icon='TRIA_UP') + row.prop(tool_settings, "lasso_face_down", text="", icon='TRIA_DOWN') + elif tool == "builtin.select_circle": + row = layout.row(align=True) + row.prop(tool_settings, "circle_edge") + row = layout.row(align=True) + row.prop(tool_settings, "circle_face") + class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel): bl_category = "Tool" diff --git a/source/blender/blenlib/BLI_lasso_2d.h b/source/blender/blenlib/BLI_lasso_2d.h index 69625a9da83..1e2bbb1e1b2 100644 --- a/source/blender/blenlib/BLI_lasso_2d.h +++ b/source/blender/blenlib/BLI_lasso_2d.h @@ -25,7 +25,8 @@ bool BLI_lasso_is_edge_inside(const int mcoords[][2], int y0, int x1, int y1, - int error_value); + int error_value, + bool fully_inside); #ifdef __cplusplus } diff --git a/source/blender/blenlib/intern/lasso_2d.c b/source/blender/blenlib/intern/lasso_2d.c index 4752864ea3a..04978febdae 100644 --- a/source/blender/blenlib/intern/lasso_2d.c +++ b/source/blender/blenlib/intern/lasso_2d.c @@ -55,7 +55,8 @@ bool BLI_lasso_is_edge_inside(const int mcoords[][2], int y0, int x1, int y1, - const int error_value) + const int error_value, + bool fully_inside) { if (x0 == error_value || x1 == error_value || mcoords_len == 0) { @@ -64,23 +65,31 @@ bool BLI_lasso_is_edge_inside(const int mcoords[][2], const int v1[2] = {x0, y0}, v2[2] = {x1, y1}; - /* check points in lasso */ - if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v1[0], v1[1], error_value)) { - return true; - } - if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v2[0], v2[1], error_value)) { + /* enclosed faces only checks for both points inside selection area */ + if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v1[0], v1[1], error_value) && + BLI_lasso_is_point_inside(mcoords, mcoords_len, v2[0], v2[1], error_value)) { return true; } - /* no points in lasso, so we have to intersect with lasso edge */ - - if (isect_seg_seg_v2_int(mcoords[0], mcoords[mcoords_len - 1], v1, v2) > 0) { - return true; - } - for (uint a = 0; a < mcoords_len - 1; a++) { - if (isect_seg_seg_v2_int(mcoords[a], mcoords[a + 1], v1, v2) > 0) { + if (!fully_inside) { + /* check points in lasso */ + if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v1[0], v1[1], error_value)) { return true; } + if (BLI_lasso_is_point_inside(mcoords, mcoords_len, v2[0], v2[1], error_value)) { + return true; + } + + /* no points in lasso, so we have to intersect with lasso edge */ + + if (isect_seg_seg_v2_int(mcoords[0], mcoords[mcoords_len - 1], v1, v2) > 0) { + return true; + } + for (unsigned int a = 0; a < mcoords_len - 1; a++) { + if (isect_seg_seg_v2_int(mcoords[a], mcoords[a + 1], v1, v2) > 0) { + return true; + } + } } return false; diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index d19616223cd..298a32c21bc 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -373,6 +373,32 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) if (idprop) { IDP_ClearProperty(idprop); } + + /* Mesh select. */ + ts->box_drag_direction = 1; + ts->lasso_drag_direction = 1; + ts->box_edge = 1; + ts->box_edge_left = 1; + ts->box_edge_right = 1; + ts->box_edge_up = 1; + ts->box_edge_down = 1; + ts->box_face = 1; + ts->box_face_left = 1; + ts->box_face_right = 1; + ts->box_face_up = 1; + ts->box_face_down = 1; + ts->lasso_edge = 1; + ts->lasso_edge_left = 1; + ts->lasso_edge_right = 1; + ts->lasso_edge_up = 1; + ts->lasso_edge_down = 1; + ts->lasso_face = 1; + ts->lasso_face_left = 1; + ts->lasso_face_right = 1; + ts->lasso_face_up = 1; + ts->lasso_face_down = 1; + ts->circle_edge = 2; + ts->circle_face = 1; } void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) diff --git a/source/blender/editors/curves/intern/curves_selection.cc b/source/blender/editors/curves/intern/curves_selection.cc index 4c3c3374f2e..ff78cedc081 100644 --- a/source/blender/editors/curves/intern/curves_selection.cc +++ b/source/blender/editors/curves/intern/curves_selection.cc @@ -705,7 +705,8 @@ bool select_lasso(const ViewContext &vc, int(pos1_proj.y), int(pos2_proj.x), int(pos2_proj.y), - IS_CLIPPED)) { + IS_CLIPPED, + false)) { apply_selection_operation_at_index(selection.span, curve_i, sel_op); changed = true; break; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index dc3951ab770..1c8efac1a34 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -390,11 +390,20 @@ void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc, void *userData, eV3DProjTest clip_flag); -void mesh_foreachScreenFace( +void mesh_foreachScreenFaceCenter( struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index), void *userData, eV3DProjTest clip_flag); +void mesh_foreachScreenFaceVerts(struct ViewContext *vc, + void (*func)(void *userData, + struct BMFace *efa, + const float screen_co[][2], + int total_count, + struct rctf *poly_rect, + bool *face_hit), + void *userData, + const eV3DProjTest clip_flag); void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc index 94c2e3352b3..5f03a1686dc 100644 --- a/source/blender/editors/mesh/editmesh_select.cc +++ b/source/blender/editors/mesh/editmesh_select.cc @@ -752,7 +752,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenFace( + mesh_foreachScreenFaceCenter( vc, find_nearest_face_center__doZBuf, &data, V3D_PROJ_TEST_CLIP_DEFAULT); *r_dist_center = data.dist_px_manhattan; @@ -804,7 +804,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, *dist_px_manhattan_p; ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data, clip_flag); + mesh_foreachScreenFaceCenter(vc, findnearestface__doClosest, &data, clip_flag); hit = (data.use_cycle && data.hit_cycle.face) ? &data.hit_cycle : &data.hit; diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc index e7e8eb5b275..d5e560331c4 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.cc +++ b/source/blender/editors/space_view3d/view3d_iterators.cc @@ -13,6 +13,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BLI_bitmap.h" #include "BLI_math_geom.h" #include "BLI_rect.h" #include "BLI_utildefines.h" @@ -38,6 +39,8 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "MEM_guardedalloc.h" + /* -------------------------------------------------------------------- */ /** \name Internal Clipping Utilities * \{ */ @@ -238,7 +241,7 @@ struct foreachScreenEdge_userData { int content_planes_len; }; -struct foreachScreenFace_userData { +struct foreachScreenFaceCenter_userData { void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index); void *userData; ViewContext vc; @@ -536,12 +539,12 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc, /** \name Edit-Mesh: For Each Screen Face Center * \{ */ -static void mesh_foreachScreenFace__mapFunc(void *userData, +static void mesh_foreachScreenFaceCenter__mapFunc(void *userData, int index, const float cent[3], const float /*no*/[3]) { - foreachScreenFace_userData *data = static_cast(userData); + foreachScreenFaceCenter_userData *data = static_cast(userData); BMFace *efa = BM_face_at_index(data->vc.em->bm, index); if (UNLIKELY(BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) { return; @@ -556,14 +559,14 @@ static void mesh_foreachScreenFace__mapFunc(void *userData, data->func(data->userData, efa, screen_co, index); } -void mesh_foreachScreenFace( +void mesh_foreachScreenFaceCenter( ViewContext *vc, void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index), void *userData, const eV3DProjTest clip_flag) { BLI_assert((clip_flag & V3D_PROJ_TEST_CLIP_CONTENT) == 0); - foreachScreenFace_userData data; + foreachScreenFaceCenter_userData data; Mesh *me = editbmesh_get_eval_cage_from_orig( vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH); @@ -580,16 +583,150 @@ void mesh_foreachScreenFace( const int face_dot_tags_num = me->runtime->subsurf_face_dot_tags.size(); if (face_dot_tags_num && (face_dot_tags_num != me->totvert)) { BKE_mesh_foreach_mapped_subdiv_face_center( - me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + me, mesh_foreachScreenFaceCenter__mapFunc, &data, MESH_FOREACH_NOP); } else { BKE_mesh_foreach_mapped_face_center( - me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + me, mesh_foreachScreenFaceCenter__mapFunc, &data, MESH_FOREACH_NOP); } } /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Edit-Mesh: For Each Screen Face Verts + * \{ */ + +void mesh_foreachScreenFaceVerts(ViewContext *vc, + void (*func)(void *userData, + struct BMFace *efa, + const float screen_co[][2], + int total_count, + rctf *screen_rect, + bool *face_hit), + void *userData, + const eV3DProjTest clip_flag) +{ + ED_view3d_check_mats_rv3d(vc->rv3d); + BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); + + BMFace *efa; + const BMesh *bm = vc->em->bm; + + float temp_screen_co[2]; + int total_length = 0; + + float(*screen_coords)[2] = static_cast( + MEM_mallocN(sizeof(float) * 2 * bm->totvert, __func__)); + int face_screen_verts_size = 4; + float(*face_screen_verts)[2] = static_cast( + MEM_mallocN(sizeof(int) * 2 * face_screen_verts_size, __func__)); + + /* This makes only sense on subdivided meshes.*/ + BLI_bitmap *faces_visited; + int cage_index = BKE_modifiers_get_cage_index(vc->scene, vc->obedit, NULL, 1); + const bool cage_display = cage_index != -1; + if (cage_display) { + faces_visited = BLI_BITMAP_NEW((size_t)bm->totface, __func__); + } + + /* Transform and store all visible verts into screen coords. */ + for (int i = 0; i < bm->totvert; i++) { + BMVert *bmvert = BM_vert_at_index(vc->em->bm, i); + + if (BM_elem_flag_test_bool(bmvert, BM_ELEM_HIDDEN)) { + continue; + } + + if (ED_view3d_project_float_object(vc->region, bmvert->co, temp_screen_co, clip_flag) == + V3D_PROJ_RET_OK) { + screen_coords[i][0] = temp_screen_co[0]; + screen_coords[i][1] = temp_screen_co[1]; + } + else { + screen_coords[i][0] = 0.0f; + screen_coords[i][1] = 0.0f; + } + } + + const int *poly_index = static_cast(CustomData_get_layer(&bm->pdata, CD_ORIGINDEX)); + const bool use_original_index = poly_index != 0; + + rctf poly_rect_data; + rctf *poly_rect = &poly_rect_data; + bool face_hit = false; + + /* Collect polygon verts and send off per poly callback. */ + for (int i = 0; i < bm->totface; i++) { + int original_index = i; + if (use_original_index) { + original_index = *poly_index++; + if (original_index == ORIGINDEX_NONE) { + continue; + } + } + + if (cage_display && BLI_BITMAP_TEST(faces_visited, original_index)) { + continue; + } + + efa = BM_face_at_index(vc->em->bm, original_index); + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + + if (bm->totvert > face_screen_verts_size) { + face_screen_verts_size = bm->totvert; + MEM_freeN(face_screen_verts); + face_screen_verts = static_cast( + MEM_mallocN(sizeof(float) * 2 * face_screen_verts_size, __func__)); + } + + total_length = 0; + BLI_rctf_init_minmax(poly_rect); + + bool skip = false; + + BMLoop *l_first, *l_iter; + int j = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const int k = BM_elem_index_get(l_iter->v); + face_screen_verts[j][0] = screen_coords[k][0]; + face_screen_verts[j][1] = screen_coords[k][1]; + + /* Ignore polygons with invalid screen coords.*/ + if (face_screen_verts[j][0] == 0.0f && face_screen_verts[j][1] == 0.0f) { + skip = true; + break; + } + + total_length++, j++; + BLI_rctf_do_minmax_v(poly_rect, screen_coords[k]); + } while ((l_iter = l_iter->next) != l_first); + + if (skip) { + continue; + } + + face_hit = false; + + func( + userData, efa, (const float(*)[2])face_screen_verts, total_length, poly_rect, &face_hit); + + if (cage_display && face_hit) { + BLI_BITMAP_ENABLE(faces_visited, original_index); + } + } + } + + if (cage_display) { + MEM_freeN(faces_visited); + } + MEM_freeN(screen_coords); + MEM_freeN(face_screen_verts); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Edit-Nurbs: For Each Screen Vertex * \{ */ diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 3c91480b6cc..2bf02e9660e 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -239,6 +239,54 @@ static void editselect_buf_cache_init_with_generic_userdata(wmGenericUserData *w /** \name Internal Edit-Mesh Utilities * \{ */ +struct BoxSelectUserData { + ViewContext *vc; + const rcti *rect; + const rctf *rect_fl; + rctf _rect_fl; + eSelectOp sel_op; + eBezTriple_Flag select_flag; + int edge_style; + int face_style; + + /* runtime */ + bool is_done; + bool is_changed; +}; + +struct LassoSelectUserData { + ViewContext *vc; + const rcti *rect; + const rctf *rect_fl; + rctf _rect_fl; + const int (*mcoords)[2]; + int mcoords_len; + eSelectOp sel_op; + eBezTriple_Flag select_flag; + int edge_style; + int face_style; + + /* runtime */ + int pass; + bool is_done; + bool is_changed; +}; + +struct CircleSelectUserData { + ViewContext *vc; + bool select; + int mval[2]; + float mval_fl[2]; + float radius; + float radius_squared; + eBezTriple_Flag select_flag; + int edge_style; + int face_style; + + /* runtime */ + bool is_changed; +}; + static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, @@ -271,15 +319,19 @@ static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel, return changed; } -static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel, +static bool edbm_backbuf_check_and_select_edges(void *userData, + EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, const eSelectOp sel_op) { + CircleSelectUserData *data = static_cast(userData); BMEdge *eed; - BMIter iter; + BMVert *eve; + BMIter iter, viter; bool changed = false; + int style = data->edge_style; const BLI_bitmap *select_bitmap = esel->select_bitmap; uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_EDGE); @@ -292,7 +344,23 @@ static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel, if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + bool enclose_edge = true; + /* enclose edge */ + if (style == 4 && is_inside) { + BM_ITER_ELEM (eve, &viter, eed, BM_VERTS_OF_EDGE) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose_edge = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; + if (!enclose_edge) { + break; + } + } + } + + const int sel_op_result = ED_select_op_action_deselected( + sel_op, is_select, is_inside && enclose_edge); if (sel_op_result != -1) { BM_edge_select_set(em->bm, eed, sel_op_result); changed = true; @@ -303,28 +371,135 @@ static bool edbm_backbuf_check_and_select_edges(EditSelectBuf_Cache *esel, return changed; } -static bool edbm_backbuf_check_and_select_faces(EditSelectBuf_Cache *esel, +static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, + EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, - const eSelectOp sel_op) + const eSelectOp sel_op, + const rcti *rect, + const int face_style, + void *lassoData, + void *circleData) { + BMIter iter, viter; BMFace *efa; - BMIter iter; + BMVert *eve; bool changed = false; const BLI_bitmap *select_bitmap = esel->select_bitmap; + rctf rectf; + LassoSelectUserData *ldata = static_cast(lassoData); + CircleSelectUserData *cdata = static_cast(circleData); uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE); - if (index == 0) { + uint vindex = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX); + int style = face_style; + if (rect != NULL) { + BLI_rctf_rcti_copy(&rectf, rect); + } + if (index == 0 || vindex == 0) { return false; } index -= 1; + vindex -= 1; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + bool enclose_face = true; + bool center_face = true; + if (style > 2 && is_inside) { + /* enclose face */ + if (style == 4) { + BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { + /* circle enclose */ + if (cdata != NULL) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose_face = len_squared_v2v2(cdata->mval_fl, vertv2) <= cdata->radius_squared; + if (!enclose_face) { + break; + } + } + /* box and lasso enclose */ + else { + if (!BLI_BITMAP_TEST_BOOL(select_bitmap, vindex + BM_elem_index_get(eve))) { + enclose_face = false; + break; + } + } + } + } + /* center face */ + else { + float centerv3[3] = {0.0f, 0.0f, 0.0f}; + float centerv2[2] = {0.0f, 0.0f}; + /* tri */ + if (efa->len == 3) { + float tri_vco[3][3] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + int tri_index = 0; + BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { + tri_vco[tri_index][0] = eve->co[0]; + tri_vco[tri_index][1] = eve->co[1]; + tri_vco[tri_index][2] = eve->co[2]; + tri_index++; + } + float triv1[3] = {tri_vco[0][0], tri_vco[0][1], tri_vco[0][2]}; + float triv2[3] = {tri_vco[1][0], tri_vco[1][1], tri_vco[1][2]}; + float triv3[3] = {tri_vco[2][0], tri_vco[2][1], tri_vco[2][2]}; + mid_v3_v3v3v3(centerv3, triv1, triv2, triv3); + } + /* quad */ + else if (efa->len == 4) { + float quad_vco[4][3] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + int quad_index = 0; + BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { + quad_vco[quad_index][0] = eve->co[0]; + quad_vco[quad_index][1] = eve->co[1]; + quad_vco[quad_index][2] = eve->co[2]; + quad_index++; + } + float quadv1[3] = {quad_vco[0][0], quad_vco[0][1], quad_vco[0][2]}; + float quadv2[3] = {quad_vco[1][0], quad_vco[1][1], quad_vco[1][2]}; + float quadv3[3] = {quad_vco[2][0], quad_vco[2][1], quad_vco[2][2]}; + float quadv4[3] = {quad_vco[3][0], quad_vco[3][1], quad_vco[3][2]}; + mid_v3_v3v3v3v3(centerv3, quadv1, quadv2, quadv3, quadv4); + } + /* ngon */ + else { + const float w = 1.0f / (float)efa->len; + BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { + madd_v3_v3fl(centerv3, eve->co, w); + } + } + ED_view3d_project_float_object( + vc->region, centerv3, centerv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + /* lasso center */ + if (lassoData != NULL) { + center_face = BLI_rctf_isect_pt_v(&rectf, centerv2) && + BLI_lasso_is_point_inside(ldata->mcoords, + ldata->mcoords_len, + centerv2[0], + centerv2[1], + IS_CLIPPED); + } + /* circle center */ + else if (circleData != NULL) { + center_face = (len_squared_v2v2(cdata->mval_fl, centerv2) <= cdata->radius_squared); + } + /* box center */ + else { + center_face = BLI_rctf_isect_pt_v(&rectf, centerv2); + } + } + } + + const int sel_op_result = ED_select_op_action_deselected( + sel_op, is_select, is_inside && enclose_face && center_face); if (sel_op_result != -1) { BM_face_select_set(em->bm, efa, sel_op_result); changed = true; @@ -403,28 +578,14 @@ static bool edbm_backbuf_check_and_select_faces_obmode(Mesh *me, /** \name Lasso Select * \{ */ -struct LassoSelectUserData { - ViewContext *vc; - const rcti *rect; - const rctf *rect_fl; - rctf _rect_fl; - const int (*mcoords)[2]; - int mcoords_len; - eSelectOp sel_op; - eBezTriple_Flag select_flag; - - /* runtime */ - int pass; - bool is_done; - bool is_changed; -}; - static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, ViewContext *vc, const rcti *rect, const int (*mcoords)[2], const int mcoords_len, - const eSelectOp sel_op) + const eSelectOp sel_op, + const int edge_style, + const int face_style) { r_data->vc = vc; @@ -437,6 +598,8 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->sel_op = sel_op; /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ r_data->select_flag = (eBezTriple_Flag)SELECT; + r_data->edge_style = edge_style; + r_data->face_style = face_style; /* runtime */ r_data->pass = 0; @@ -526,8 +689,12 @@ static void do_lasso_select_pose__do_tag(void *userData, } if (BLI_rctf_isect_segment(data->rect_fl, screen_co_a, screen_co_b) && - BLI_lasso_is_edge_inside( - data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + INT_MAX, + false)) { pchan->bone->flag |= BONE_DONE; data->is_changed = true; } @@ -551,7 +718,7 @@ static void do_lasso_tag_pose(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); view3d_userdata_lassoselect_init( - &data, vc, &rect, mcoords, mcoords_len, static_cast(0)); + &data, vc, &rect, mcoords, mcoords_len, static_cast(0), 0, 0); ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d); @@ -771,7 +938,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), - IS_CLIPPED)); + IS_CLIPPED, + false)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -779,7 +947,7 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, } } -static void do_lasso_select_mesh__doSelectFace(void *userData, +static void do_lasso_select_mesh__doSelectFaceCenter(void *userData, BMFace *efa, const float screen_co[2], int /*index*/) @@ -797,11 +965,77 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, } } +static void do_lasso_select_mesh__doSelectFace(void *user_data, + BMFace *efa, + const float screen_co[][2], + int total_count, + rctf *screen_rect, + bool *face_hit) +{ + + LassoSelectUserData *data = static_cast(user_data); + int style = data->face_style; + + if (!BLI_rctf_isect(data->rect_fl, screen_rect, NULL)) + return; + + bool inside = false; + for (int i = 0; i < total_count; i++) { + + int a = i; + int b = (i + 1) % total_count; + + /* enclose */ + if (style == 4) { + inside = BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co[a]), + UNPACK2(screen_co[b]), + IS_CLIPPED, + true); + if (!inside) { + break; + } + } + /* touch */ + else { + inside = BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co[a]), + UNPACK2(screen_co[b]), + IS_CLIPPED, + false); + if (inside) { + break; + } + } + } + + /* touch interior of face */ + if (style == 2) { + if (!inside) { + float point[2] = {static_cast(data->mcoords[0][0]), static_cast(data->mcoords[0][1])}; + inside = isect_point_poly_v2(point, screen_co, total_count, true); + } + } + + *face_hit = inside; + + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside); + + if (sel_op_result != -1) { + BM_face_select_set(data->vc->em->bm, efa, sel_op_result); + data->is_changed = true; + } +} + static bool do_lasso_select_mesh(ViewContext *vc, wmGenericUserData *wm_userdata, const int mcoords[][2], const int mcoords_len, - const eSelectOp sel_op) + const eSelectOp sel_op, + wmOperator *op) { LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; @@ -812,7 +1046,40 @@ static bool do_lasso_select_mesh(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); + int edge_style, face_style; + if (U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING) { + if (ts->lasso_drag_direction > 1) { + if (ts->lasso_drag_direction == 2) { + if (ts->lasso_direction_upright) { + edge_style = ts->lasso_edge_right; + face_style = ts->lasso_face_right; + } + else { + edge_style = ts->lasso_edge_left; + face_style = ts->lasso_face_left; + } + } + else if (ts->lasso_direction_upright) { + edge_style = ts->lasso_edge_up; + face_style = ts->lasso_face_up; + } + else { + edge_style = ts->lasso_edge_down; + face_style = ts->lasso_face_down; + } + } + else { + edge_style = ts->lasso_edge; + face_style = ts->lasso_face; + } + } + else { + edge_style = RNA_enum_get(op->ptr, "edge_type"); + face_style = RNA_enum_get(op->ptr, "face_type"); + } + + view3d_userdata_lassoselect_init( + &data, vc, &rect, mcoords, mcoords_len, sel_op, edge_style, face_style); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (vc->em->bm->totvertsel) { @@ -831,7 +1098,15 @@ static bool do_lasso_select_mesh(ViewContext *vc, EditSelectBuf_Cache *esel = static_cast(wm_userdata->data); if (use_zbuf) { if (wm_userdata->data == nullptr) { - editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); + /* for near enclose face */ + if (data.face_style == 4 && ts->selectmode & SCE_SELECT_FACE && + !(ts->selectmode & SCE_SELECT_VERTEX)) { + editselect_buf_cache_init_with_generic_userdata( + wm_userdata, vc, ts->selectmode | SCE_SELECT_VERTEX); + } + else { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); + } esel = static_cast(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, nullptr); @@ -859,12 +1134,13 @@ static bool do_lasso_select_mesh(ViewContext *vc, const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB); - /* Fully inside. */ - mesh_foreachScreenEdge_clip_bb_segment( - vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag); - if (data.is_done == false) { - /* Fall back to partially inside. - * Clip content to account for edges partially behind the view. */ + /* Fully inside, hybrid and enclose edge */ + if (data.edge_style != 2) { + mesh_foreachScreenEdge_clip_bb_segment( + vc, do_lasso_select_mesh__doSelectEdge_pass0, &data_for_edge, clip_flag); + } + /* Partially inside, hybrid and touch edge */ + if (data.edge_style == 2 || data.edge_style == 1 && data.is_done == false) { mesh_foreachScreenEdge_clip_bb_segment(vc, do_lasso_select_mesh__doSelectEdge_pass1, &data_for_edge, @@ -873,13 +1149,32 @@ static bool do_lasso_select_mesh(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_FACE) { - if (use_zbuf) { - data.is_changed |= edbm_backbuf_check_and_select_faces( - esel, vc->depsgraph, vc->obedit, vc->em, sel_op); + /* xray center and auto face with fallback for touch and enclose intersect */ + if (!use_zbuf && + (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op))) { + mesh_foreachScreenFaceCenter( + vc, do_lasso_select_mesh__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } + /* xray touch and enclose face */ + else if (!use_zbuf) { + /* works for everything except intersect for some reason */ + mesh_foreachScreenFaceVerts(vc, + do_lasso_select_mesh__doSelectFace, + &data, + V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + } + /* near face */ else { - mesh_foreachScreenFace( - vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + data.is_changed |= edbm_backbuf_check_and_select_faces(vc, + esel, + vc->depsgraph, + vc->obedit, + vc->em, + sel_op, + &rect, + data.face_style, + &data, + NULL); } } @@ -943,7 +1238,7 @@ static bool do_lasso_select_curve(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0); Curve *curve = (Curve *)vc->obedit->data; ListBase *nurbs = BKE_curve_editNurbs_get(curve); @@ -992,7 +1287,7 @@ static bool do_lasso_select_lattice(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_lattice_flags_set(vc->obedit, 0); @@ -1021,7 +1316,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_a[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && BLI_lasso_is_point_inside( - data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) { + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX), + false) { is_inside_flag |= BONESEL_ROOT; } } @@ -1032,7 +1328,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_b[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && BLI_lasso_is_point_inside( - data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) { + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX), + false) { is_inside_flag |= BONESEL_TIP; } } @@ -1046,7 +1343,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), - INT_MAX)) { + INT_MAX, + false)) { is_inside_flag |= BONESEL_BONE; } } @@ -1075,7 +1373,7 @@ static void do_lasso_select_armature__doSelectBone_clip_content(void *userData, } if (BLI_lasso_is_edge_inside( - data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX, false)) { is_inside_flag |= BONESEL_BONE; } @@ -1092,7 +1390,7 @@ static bool do_lasso_select_armature(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit); @@ -1152,7 +1450,7 @@ static bool do_lasso_select_meta(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= BKE_mball_deselect_all(mb); @@ -1236,7 +1534,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc, LassoSelectUserData_ForMeshVert data; data.select_vert = select_vert.span; - view3d_userdata_lassoselect_init(&data.lasso_data, vc, &rect, mcoords, mcoords_len, sel_op); + view3d_userdata_lassoselect_init( + &data.lasso_data, vc, &rect, mcoords, mcoords_len, sel_op, 0, 0); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -1301,7 +1600,8 @@ static bool view3d_lasso_select(bContext *C, ViewContext *vc, const int mcoords[][2], const int mcoords_len, - const eSelectOp sel_op) + const eSelectOp sel_op, + wmOperator *op) { using namespace blender; Object *ob = CTX_data_active_object(C); @@ -1345,7 +1645,7 @@ static bool view3d_lasso_select(bContext *C, switch (vc->obedit->type) { case OB_MESH: - changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op); + changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op, op); break; case OB_CURVES_LEGACY: case OB_SURF: @@ -1416,7 +1716,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) ED_view3d_viewcontext_init(C, &vc, depsgraph); eSelectOp sel_op = static_cast(RNA_enum_get(op->ptr, "mode")); - bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op); + bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op, op); MEM_freeN((void *)mcoords); @@ -3224,23 +3524,12 @@ void VIEW3D_OT_select(wmOperatorType *ot) /** \name Box Select * \{ */ -struct BoxSelectUserData { - ViewContext *vc; - const rcti *rect; - const rctf *rect_fl; - rctf _rect_fl; - eSelectOp sel_op; - eBezTriple_Flag select_flag; - - /* runtime */ - bool is_done; - bool is_changed; -}; - static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, ViewContext *vc, const rcti *rect, - const eSelectOp sel_op) + const eSelectOp sel_op, + const int edge_style, + const int face_style) { r_data->vc = vc; @@ -3251,6 +3540,8 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, r_data->sel_op = sel_op; /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ r_data->select_flag = (eBezTriple_Flag)SELECT; + r_data->edge_style = edge_style; + r_data->face_style = face_style; /* runtime */ r_data->is_done = false; @@ -3326,7 +3617,7 @@ static bool do_paintvert_box_select(ViewContext *vc, BoxSelectUserData_ForMeshVert data; data.select_vert = select_vert.span; - view3d_userdata_boxselect_init(&data.box_data, vc, rect, sel_op); + view3d_userdata_boxselect_init(&data.box_data, vc, rect, sel_op, 0, 0); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -3432,7 +3723,7 @@ static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel const bool deselect_all = (sel_op == SEL_OP_SET); BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, sel_op); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op, 0, 0); Curve *curve = (Curve *)vc->obedit->data; ListBase *nurbs = BKE_curve_editNurbs_get(curve); @@ -3471,7 +3762,7 @@ static bool do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp s { BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, sel_op); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_lattice_flags_set(vc->obedit, 0); @@ -3551,7 +3842,60 @@ static void do_mesh_box_select__doSelectEdge_pass1( data->is_changed = true; } } + static void do_mesh_box_select__doSelectFace(void *userData, + BMFace *efa, + const float screen_co[][2], + int total_count, + rctf *screen_rect, + bool *face_hit) +{ + BoxSelectUserData *data = static_cast(userData); + int style = data->face_style; + + if (!BLI_rctf_isect(data->rect_fl, screen_rect, NULL)) + return; + + bool inside = false; + for (int i = 0; i < total_count; i++) { + + int a = i; + int b = (i + 1) % total_count; + + /* enclose */ + if (style == 4) { + inside = edge_fully_inside_rect(data->rect_fl, screen_co[a], screen_co[b]); + if (!inside) { + break; + } + } + /* touch */ + else { + inside = edge_inside_rect(data->rect_fl, screen_co[a], screen_co[b]); + if (inside) { + break; + } + } + } + + /* touch interior of face */ + if (style == 2 && !inside) { + float point[2] = {data->rect_fl->xmax, data->rect_fl->ymax}; + inside = isect_point_poly_v2(point, screen_co, total_count, true); + } + + *face_hit = inside; + + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside); + + if (sel_op_result != -1) { + BM_face_select_set(data->vc->em->bm, efa, sel_op_result); + data->is_changed = true; + } +} + +static void do_mesh_box_select__doSelectFaceCenter(void *userData, BMFace *efa, const float screen_co[2], int /*index*/) @@ -3568,12 +3912,45 @@ static void do_mesh_box_select__doSelectFace(void *userData, static bool do_mesh_box_select(ViewContext *vc, wmGenericUserData *wm_userdata, const rcti *rect, - const eSelectOp sel_op) + const eSelectOp sel_op, + wmOperator *op) { BoxSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; - view3d_userdata_boxselect_init(&data, vc, rect, sel_op); + int edge_style, face_style; + if (U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING) { + if (ts->box_drag_direction > 1) { + if (ts->box_drag_direction == 2) { + if (ts->box_direction_upright) { + edge_style = ts->box_edge_right; + face_style = ts->box_face_right; + } + else { + edge_style = ts->box_edge_left; + face_style = ts->box_face_left; + } + } + else if (ts->box_direction_upright) { + edge_style = ts->box_edge_up; + face_style = ts->box_face_up; + } + else { + edge_style = ts->box_edge_down; + face_style = ts->box_face_down; + } + } + else { + edge_style = ts->box_edge; + face_style = ts->box_face; + } + } + else { + edge_style = RNA_enum_get(op->ptr, "edge_type"); + face_style = RNA_enum_get(op->ptr, "face_type"); + } + + view3d_userdata_boxselect_init(&data, vc, rect, sel_op, edge_style, face_style); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (vc->em->bm->totvertsel) { @@ -3592,7 +3969,15 @@ static bool do_mesh_box_select(ViewContext *vc, EditSelectBuf_Cache *esel = static_cast(wm_userdata->data); if (use_zbuf) { if (wm_userdata->data == nullptr) { - editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); + /* for near enclose face */ + if (data.face_style == 4 && ts->selectmode & SCE_SELECT_FACE && + !(ts->selectmode & SCE_SELECT_VERTEX)) { + editselect_buf_cache_init_with_generic_userdata( + wm_userdata, vc, ts->selectmode | SCE_SELECT_VERTEX); + } + else { + editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); + } esel = static_cast(wm_userdata->data); esel->select_bitmap = DRW_select_buffer_bitmap_from_rect( vc->depsgraph, vc->region, vc->v3d, rect, nullptr); @@ -3621,12 +4006,13 @@ static bool do_mesh_box_select(ViewContext *vc, const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB); - /* Fully inside. */ - mesh_foreachScreenEdge_clip_bb_segment( - vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag); - if (data.is_done == false) { - /* Fall back to partially inside. - * Clip content to account for edges partially behind the view. */ + /* Fully inside, hybrid and enclose edge */ + if (data.edge_style != 2) { + mesh_foreachScreenEdge_clip_bb_segment( + vc, do_mesh_box_select__doSelectEdge_pass0, &cb_data, clip_flag); + } + /* Partially inside, hybrid and touch edge */ + if (data.edge_style == 2 || data.edge_style == 1 && data.is_done == false) { mesh_foreachScreenEdge_clip_bb_segment(vc, do_mesh_box_select__doSelectEdge_pass1, &cb_data, @@ -3635,13 +4021,24 @@ static bool do_mesh_box_select(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_FACE) { - if (use_zbuf) { - data.is_changed |= edbm_backbuf_check_and_select_faces( - esel, vc->depsgraph, vc->obedit, vc->em, sel_op); + /* xray center and auto face with fallback for touch and enclose intersect */ + if (!use_zbuf && + (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op))) { + mesh_foreachScreenFaceCenter( + vc, do_mesh_box_select__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } + /* xray touch and enclose face */ + else if (!use_zbuf) { + /* works for everything except intersect for some reason */ + mesh_foreachScreenFaceVerts(vc, + do_mesh_box_select__doSelectFace, + &data, + V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + } + /* near face */ else { - mesh_foreachScreenFace( - vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + data.is_changed |= edbm_backbuf_check_and_select_faces( + vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, rect, data.face_style, NULL, NULL); } } @@ -3981,7 +4378,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) switch (vc.obedit->type) { case OB_MESH: vc.em = BKE_editmesh_from_object(vc.obedit); - changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op); + changed = do_mesh_box_select(&vc, wm_userdata, &rect, sel_op, op); if (changed) { DEG_id_tag_update(static_cast(vc.obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); @@ -4098,24 +4495,13 @@ void VIEW3D_OT_select_box(wmOperatorType *ot) /** \name Circle Select * \{ */ -struct CircleSelectUserData { - ViewContext *vc; - bool select; - int mval[2]; - float mval_fl[2]; - float radius; - float radius_squared; - eBezTriple_Flag select_flag; - - /* runtime */ - bool is_changed; -}; - static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, ViewContext *vc, const bool select, const int mval[2], - const float rad) + const float rad, + const int edge_style, + const int face_style) { r_data->vc = vc; r_data->select = select; @@ -4128,6 +4514,8 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, /* SELECT by default, but can be changed if needed (only few cases use and respect this). */ r_data->select_flag = (eBezTriple_Flag)SELECT; + r_data->edge_style = edge_style; + r_data->face_style = face_style; /* runtime */ r_data->is_changed = false; @@ -4152,13 +4540,88 @@ static void mesh_circle_doSelectEdge(void *userData, int /*index*/) { CircleSelectUserData *data = static_cast(userData); + const int style = data->edge_style; + BMVert *eve; + BMIter iter; if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) { - BM_edge_select_set(data->vc->em->bm, eed, data->select); + bool enclose_edge = true; + /* enclose edge */ + if (style == 4) { + BM_ITER_ELEM (eve, &iter, eed, BM_VERTS_OF_EDGE) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose_edge = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; + if (!enclose_edge) { + break; + } + } + } + + if (enclose_edge) { + BM_edge_select_set(data->vc->em->bm, eed, data->select); + data->is_changed = true; + } + } +} + +static void mesh_circle_doSelectFace(void *userData, + BMFace *efa, + const float screen_co[][2], + int total_count, + rctf *screen_rect, + bool *face_hit) +{ + CircleSelectUserData *data = static_cast(userData); + BMIter iter; + BMVert *eve; + int style = data->face_style; + + if (!BLI_rctf_isect_circle(screen_rect, data->mval_fl, data->radius)) { + return; + } + + bool inside = false; + for (int i = 0; i < total_count; i++) { + + int a = i; + int b = (i + 1) % total_count; + + inside = edge_inside_circle(data->mval_fl, data->radius, screen_co[a], screen_co[b]); + if (inside) + break; + } + + if (!inside) { + inside = isect_point_poly_v2(data->mval_fl, screen_co, total_count, true); + } + + *face_hit = inside; + + bool enclose_face = true; + /* enclose face */ + if (style == 4 && inside) { + BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose_face = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; + if (!enclose_face) { + break; + } + } + } + + if (inside && enclose_face) { + BM_face_select_set(data->vc->em->bm, efa, data->select); data->is_changed = true; } } -static void mesh_circle_doSelectFace(void *userData, + +static void mesh_circle_doSelectFaceCenter(void *userData, BMFace *efa, const float screen_co[2], int /*index*/) @@ -4175,7 +4638,8 @@ static bool mesh_circle_select(ViewContext *vc, wmGenericUserData *wm_userdata, eSelectOp sel_op, const int mval[2], - float rad) + float rad, + wmOperator *op) { ToolSettings *ts = vc->scene->toolsettings; CircleSelectUserData data; @@ -4195,7 +4659,17 @@ static bool mesh_circle_select(ViewContext *vc, ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ - view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + int edge_style, face_style; + if (U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING) { + edge_style = ts->circle_edge; + face_style = ts->circle_face; + } + else { + edge_style = RNA_enum_get(op->ptr, "edge_type"); + face_style = RNA_enum_get(op->ptr, "face_type"); + } + + view3d_userdata_circleselect_init(&data, vc, select, mval, rad, edge_style, face_style); const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); @@ -4229,7 +4703,7 @@ static bool mesh_circle_select(ViewContext *vc, if (use_zbuf) { if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_edges( - esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + &data, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } } else { @@ -4242,14 +4716,30 @@ static bool mesh_circle_select(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_FACE) { - if (use_zbuf) { - if (esel->select_bitmap != nullptr) { - changed |= edbm_backbuf_check_and_select_faces( - esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); - } + /* xray center and auto face */ + if (!use_zbuf && (data.face_style == 1 || data.face_style == 8)) { + mesh_foreachScreenFaceCenter( + vc, mesh_circle_doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } + /* xray touch and enclose face */ + else if (!use_zbuf) { + mesh_foreachScreenFaceVerts( + vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + } + /* near face */ else { - mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + if (esel->select_bitmap != NULL) { + changed |= edbm_backbuf_check_and_select_faces(vc, + esel, + vc->depsgraph, + vc->obedit, + vc->em, + select ? SEL_OP_ADD : SEL_OP_SUB, + NULL, + data.face_style, + NULL, + &data); + } } } @@ -4363,7 +4853,7 @@ static bool paint_vertsel_circle_select(ViewContext *vc, ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */ - view3d_userdata_circleselect_init(&data.circle_data, vc, select, mval, rad); + view3d_userdata_circleselect_init(&data.circle_data, vc, select, mval, rad, 0, 0); meshobject_foreachScreenVert( vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); changed |= data.circle_data.is_changed; @@ -4417,7 +4907,7 @@ static bool nurbscurve_circle_select(ViewContext *vc, const bool deselect_all = (sel_op == SEL_OP_SET); CircleSelectUserData data; - view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0); Curve *curve = (Curve *)vc->obedit->data; ListBase *nurbs = BKE_curve_editNurbs_get(curve); @@ -4458,7 +4948,7 @@ static bool lattice_circle_select(ViewContext *vc, CircleSelectUserData data; const bool select = (sel_op != SEL_OP_SUB); - view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_lattice_flags_set(vc->obedit, 0); @@ -4549,7 +5039,7 @@ static bool pose_circle_select(ViewContext *vc, CircleSelectUserData data; const bool select = (sel_op != SEL_OP_SUB); - view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_pose_deselect_all(vc->obact, SEL_DESELECT, false); @@ -4686,7 +5176,7 @@ static bool armature_circle_select(ViewContext *vc, const bool select = (sel_op != SEL_OP_SUB); - view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit); @@ -4739,7 +5229,7 @@ static bool mball_circle_select(ViewContext *vc, const bool select = (sel_op != SEL_OP_SUB); - view3d_userdata_circleselect_init(&data, vc, select, mval, rad); + view3d_userdata_circleselect_init(&data, vc, select, mval, rad, 0, 0); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= BKE_mball_deselect_all(static_cast(vc->obedit->data)); @@ -4760,14 +5250,15 @@ static bool obedit_circle_select(bContext *C, wmGenericUserData *wm_userdata, const eSelectOp sel_op, const int mval[2], - float rad) + float rad, + wmOperator *op) { using namespace blender; bool changed = false; BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB)); switch (vc->obedit->type) { case OB_MESH: - changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad); + changed = mesh_circle_select(vc, wm_userdata, sel_op, mval, rad, op); break; case OB_CURVES_LEGACY: case OB_SURF: @@ -4928,7 +5419,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) obedit = vc.obedit; if (obedit) { - obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, float(radius)); + obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, float(radius), op); } else if (BKE_paint_select_face_test(obact)) { paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, float(radius)); diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 6897b171d8b..b4951e7aab6 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -3947,8 +3947,12 @@ static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region, if (UI_view2d_view_to_region_segment_clip( ®ion->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) && BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) && - BLI_lasso_is_edge_inside( - mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) { + BLI_lasso_is_edge_inside(mcoords, + mcoords_len, + UNPACK2(co_screen_a), + UNPACK2(co_screen_b), + V2D_IS_CLIPPED, + false)) { return true; } return false; diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index 6cc01d254ce..d89daedc25f 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -366,6 +366,32 @@ /* UV painting */ \ .uv_sculpt_settings = 0, \ .uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN, \ + \ + /* Mesh Select */ \ + .box_drag_direction = 1, \ + .lasso_drag_direction = 1, \ + .box_edge = 1, \ + .box_edge_left = 1, \ + .box_edge_right = 1, \ + .box_edge_up = 1, \ + .box_edge_down = 1, \ + .box_face = 1, \ + .box_face_left = 1, \ + .box_face_right = 1, \ + .box_face_up = 1, \ + .box_face_down = 1, \ + .lasso_edge = 1, \ + .lasso_edge_left = 1, \ + .lasso_edge_right = 1, \ + .lasso_edge_up = 1, \ + .lasso_edge_down = 1, \ + .lasso_face = 1, \ + .lasso_face_left = 1, \ + .lasso_face_right = 1, \ + .lasso_face_up = 1, \ + .lasso_face_down = 1, \ + .circle_edge = 2, \ + .circle_face = 1, \ } /* clang-format off */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ca1d878110f..cfabd92835d 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1682,7 +1682,35 @@ typedef struct ToolSettings { /** Normal Editing. */ float normal_vector[3]; - char _pad6[4]; + + /** Mesh Select Options. */ + char box_drag_direction; + char lasso_drag_direction; + char box_direction_upright; + char lasso_direction_upright; + char box_edge; + char box_edge_left; + char box_edge_right; + char box_edge_up; + char box_edge_down; + char box_face; + char box_face_left; + char box_face_right; + char box_face_up; + char box_face_down; + char lasso_edge; + char lasso_edge_left; + char lasso_edge_right; + char lasso_edge_up; + char lasso_edge_down; + char lasso_face; + char lasso_face_left; + char lasso_face_right; + char lasso_face_up; + char lasso_face_down; + char circle_edge; + char circle_face; + char _pad6[2]; /** * Custom Curve Profile for bevel tool: @@ -2331,6 +2359,28 @@ typedef enum eSnapTransformMode { SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2), } eSnapTransformMode; +/** #ToolSettings.face_select */ +enum { + FACE_AUTO = (1 << 0), + FACE_TOUCH = (1 << 1), + FACE_ENCLOSE = (1 << 2), + FACE_CENTER = (1 << 3), +}; + +/** #ToolSettings.edge_select */ +enum { + EDGE_HYBRID = (1 << 0), + EDGE_TOUCH = (1 << 1), + EDGE_ENCLOSE = (1 << 2), +}; + +/** #ToolSettings.mesh_drag_direction */ +enum { + MESH_DIRECTION_ANY = (1 << 0), + MESH_DIRECTION_LEFT_RIGHT = (1 << 1), + MESH_DIRECTION_UP_DOWN = (1 << 2), +}; + /** #ToolSettings.selectmode */ #define SCE_SELECT_VERTEX (1 << 0) /* for mesh */ #define SCE_SELECT_EDGE (1 << 1) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 01b2c0464ce..96670c0f31b 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -840,7 +840,11 @@ typedef struct UserDef { /** #eGPUBackendType */ short gpu_backend; - char _pad7[4]; + /** Keymap click-drag direction style. */ + char click_drag_direction; + /** Box, lasso, and circle select mesh control style. */ + char drag_select_mesh_control; + char _pad7[2]; /** Private, defaults to 20 for 72 DPI setting. */ short widget_unit; @@ -1153,6 +1157,19 @@ typedef enum eUserpref_TableAPI { USER_TABLET_WINTAB = 2, } eUserpref_TabletAPI; +/** #UserDef.click_drag_direction_types */ +typedef enum eUserpref_Click_Drag_Direction { + USER_CLICK_DRAG_DIRECTION_EIGHT_WAY = 0, + USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT = 1, + USER_CLICK_DRAG_DIRECTION_UP_DOWN = 2, +} eUserpref_Click_Drag_Direction; + +/** #UserDef.drag_select_mesh_control_types */ +typedef enum eUserpref_Drag_Select_Mesh_Control { + USER_DRAG_SELECT_MESH_KEYMAP = 0, + USER_DRAG_SELECT_MESH_TOOLSETTING = 1, +} eUserpref_Drag_Select_Mesh_Control; + /** #UserDef.app_flag */ typedef enum eUserpref_APP_Flag { USER_APP_LOCK_CORNER_SPLIT = (1 << 0), diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index ffedea37c33..a416efe87e6 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3049,10 +3049,189 @@ static void rna_def_tool_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem mesh_drag_direction_items[] = { + {MESH_DIRECTION_ANY, "MESH_DIRECTION_ANY", 0, "Any", "Drag in any direction"}, + {MESH_DIRECTION_LEFT_RIGHT, + "MESH_DIRECTION_LEFT_RIGHT", + 0, + "Left Right", + "Drag to the left and right"}, + {MESH_DIRECTION_UP_DOWN, + "MESH_DIRECTION_UP_DOWN", + 0, + "Up Down", + "Drag upwards and downwards"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem edge_select_items[] = { + {EDGE_HYBRID, + "EDGE_HYBRID", + 0, + "Hybrid", + "Select edges that are fully inside the selection area. If no edges are fully inside the " + "selection area, select edges that are touched by the selection area"}, + {EDGE_TOUCH, + "EDGE_TOUCH", + 0, + "Touch", + "Select edges that are touched by the selection area"}, + {EDGE_ENCLOSE, + "EDGE_ENCLOSE", + 0, + "Enclose", + "Select edges that are fully inside the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem edge_circle_select_items[] = { + {EDGE_TOUCH, + "EDGE_TOUCH", + 0, + "Touch", + "Select edges that are touched by the selection area"}, + {EDGE_ENCLOSE, + "EDGE_ENCLOSE", + 0, + "Enclose", + "Select edges that are fully inside the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem face_select_items[] = { + {FACE_AUTO, + "FACE_AUTO", + 0, + "Auto", + "Select faces that are touched by the selection area in near select. Select faces whose " + "center is touched by the selection area in X-Ray select"}, + {FACE_TOUCH, + "FACE_TOUCH", + 0, + "Touch", + "Select faces that are touched by the selection area"}, + {FACE_ENCLOSE, + "FACE_ENCLOSE", + 0, + "Enclose", + "Select faces that are fully inside the selection area"}, + {FACE_CENTER, + "FACE_CENTER", + 0, + "Center", + "Select faces whose center is touched by the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "ToolSettings", NULL); RNA_def_struct_path_func(srna, "rna_ToolSettings_path"); RNA_def_struct_ui_text(srna, "Tool Settings", ""); + /* Mesh select settings. */ + prop = RNA_def_property(srna, "box_drag_direction", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, mesh_drag_direction_items); + RNA_def_property_ui_text(prop, "Box Direction", "Click-drag direction style for box select"); + + prop = RNA_def_property(srna, "lasso_drag_direction", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, mesh_drag_direction_items); + RNA_def_property_ui_text(prop, "Lasso Direction", "Click-drag direction style for lasso select"); + + prop = RNA_def_property(srna, "box_direction_upright", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "box_direction_upright", 0); + RNA_def_property_ui_text(prop, "Box Direction Helper", ""); + + prop = RNA_def_property(srna, "lasso_direction_upright", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "lasso_direction_upright", 0); + RNA_def_property_ui_text(prop, "Lasso Direction Helper", ""); + + prop = RNA_def_property(srna, "box_edge", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Box Edge", "Box edge selection style"); + + prop = RNA_def_property(srna, "box_edge_left", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Box Edge Left", "Box edge selection style when dragging left"); + + prop = RNA_def_property(srna, "box_edge_right", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Box Edge Right", "Box edge selection style when dragging right"); + + prop = RNA_def_property(srna, "box_edge_up", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Box Edge Up", "Box edge selection style when dragging up"); + + prop = RNA_def_property(srna, "box_edge_down", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Box Edge Down", "Box edge selection style when dragging down"); + + prop = RNA_def_property(srna, "box_face", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Box Face", "Box face selection style"); + + prop = RNA_def_property(srna, "box_face_left", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Box Face Left", "Box face selection style when dragging left"); + + prop = RNA_def_property(srna, "box_face_right", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Box Face Right", "Box face selection style when dragging right"); + + prop = RNA_def_property(srna, "box_face_up", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Box Face Up", "Box face selection style when dragging up"); + + prop = RNA_def_property(srna, "box_face_down", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Box Face Down", "Box face selection style when dragging down"); + + prop = RNA_def_property(srna, "lasso_edge", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Lasso Edge", "Lasso edge selection style"); + + prop = RNA_def_property(srna, "lasso_edge_left", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Lasso Edge Left", "Lasso edge selection style when dragging left"); + + prop = RNA_def_property(srna, "lasso_edge_right", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Lasso Edge Right", "Lasso edge selection style when dragging right"); + + prop = RNA_def_property(srna, "lasso_edge_up", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Lasso Edge Up", "Lasso edge selection style when dragging up"); + + prop = RNA_def_property(srna, "lasso_edge_down", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_select_items); + RNA_def_property_ui_text(prop, "Lasso Edge Down", "Lasso edge selection style when dragging down"); + + prop = RNA_def_property(srna, "lasso_face", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Lasso Face", "Lasso face selection style"); + + prop = RNA_def_property(srna, "lasso_face_left", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Lasso Face Left", "Lasso face selection style when dragging left"); + + prop = RNA_def_property(srna, "lasso_face_right", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Lasso Face Right", "Lasso face selection style when dragging right"); + + prop = RNA_def_property(srna, "lasso_face_up", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Lasso Face Up", "Lasso face selection style when dragging up"); + + prop = RNA_def_property(srna, "lasso_face_down", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Lasso Face Down", "Lasso face selection style when dragging down"); + + prop = RNA_def_property(srna, "circle_edge", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, edge_circle_select_items); + RNA_def_property_ui_text(prop, "Circle Edge", "Circle edge selection style"); + + prop = RNA_def_property(srna, "circle_face", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, face_select_items); + RNA_def_property_ui_text(prop, "Circle Face", "Circle face selection style"); + prop = RNA_def_property(srna, "sculpt", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Sculpt"); RNA_def_property_ui_text(prop, "Sculpt", ""); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 62f7118df1d..a60c2be9703 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5774,6 +5774,31 @@ static void rna_def_userdef_input(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem click_drag_direction_types[] = { + {USER_CLICK_DRAG_DIRECTION_EIGHT_WAY, + "EIGHT_WAY", + 0, + "Eight", + "Eight directions (N, NE, E, SE, S, SW, W, NW)"}, + {USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT, "LEFT_RIGHT", 0, "Left Right", "Left and right"}, + {USER_CLICK_DRAG_DIRECTION_UP_DOWN, "UP_DOWN", 0, "Up Down", "Up and down"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem drag_select_mesh_control_types[] = { + {USER_DRAG_SELECT_MESH_KEYMAP, + "USER_MESH_KEYMAP", + 0, + "Keymap", + "Use the keymap to control mesh selection style for box, lasso, and circle"}, + {USER_DRAG_SELECT_MESH_TOOLSETTING, + "USER_MESH_TOOLSETTING", + 0, + "Toolsetting", + "Use toolsettings to control mesh selection style for box, lasso, and circle"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem view_zoom_styles[] = { {USER_ZOOM_CONTINUE, "CONTINUE", @@ -5880,6 +5905,18 @@ static void rna_def_userdef_input(BlenderRNA *brna) "Release Confirms", "Moving things with a mouse drag confirms when releasing the button"); + prop = RNA_def_property(srna, "click_drag_direction", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, click_drag_direction_types); + RNA_def_property_ui_text( + prop, "Keymap Drag Directions", "Style of click-drag direction the keymap will use"); + + prop = RNA_def_property(srna, "drag_select_mesh_control", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, drag_select_mesh_control_types); + RNA_def_property_ui_text(prop, + "Mesh Drag Select Control", + "Use either the keymap or toolsettings to control edge and face selection style " + "for box, lasso, and circle select"); + prop = RNA_def_property(srna, "use_numeric_input_advanced", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_FLAG_NUMINPUT_ADVANCED); RNA_def_property_ui_text(prop, diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 5d8bb533d7e..9952cfb1a57 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -389,6 +389,41 @@ static void rna_KeyMap_item_remove(wmKeyMap *km, ReportList *reports, PointerRNA RNA_POINTER_INVALIDATE(kmi_ptr); } +static void rna_keymap_set_direction_any(wmKeyMap *km, PointerRNA *kmi_ptr) +{ + wmKeyMapItem *kmi = kmi_ptr->data; + kmi->direction = -1; + WM_keyconfig_update_tag(km, kmi); +} + +static void rna_keymap_set_direction_left(wmKeyMap *km, PointerRNA *kmi_ptr) +{ + wmKeyMapItem *kmi = kmi_ptr->data; + kmi->direction = 7; + WM_keyconfig_update_tag(km, kmi); +} + +static void rna_keymap_set_direction_right(wmKeyMap *km, PointerRNA *kmi_ptr) +{ + wmKeyMapItem *kmi = kmi_ptr->data; + kmi->direction = 3; + WM_keyconfig_update_tag(km, kmi); +} + +static void rna_keymap_set_direction_up(wmKeyMap *km, PointerRNA *kmi_ptr) +{ + wmKeyMapItem *kmi = kmi_ptr->data; + kmi->direction = 1; + WM_keyconfig_update_tag(km, kmi); +} + +static void rna_keymap_set_direction_down(wmKeyMap *km, PointerRNA *kmi_ptr) +{ + wmKeyMapItem *kmi = kmi_ptr->data; + kmi->direction = 5; + WM_keyconfig_update_tag(km, kmi); +} + static PointerRNA rna_KeyMap_item_find_from_operator(ID *id, wmKeyMap *km, const char *idname, @@ -1197,6 +1232,31 @@ void RNA_api_keymapitems(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "set_direction_any", "rna_keymap_set_direction_any"); + parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "set_direction_left", "rna_keymap_set_direction_left"); + parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "set_direction_right", "rna_keymap_set_direction_right"); + parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "set_direction_up", "rna_keymap_set_direction_up"); + parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "set_direction_down", "rna_keymap_set_direction_down"); + parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "from_id", "WM_keymap_item_find_id"); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 6c3d72e5406..754a30c5c2b 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -1611,7 +1611,7 @@ bool WM_event_is_modal_drag_exit(const struct wmEvent *event, short init_event_val); bool WM_event_is_mouse_drag(const struct wmEvent *event); bool WM_event_is_mouse_drag_or_press(const wmEvent *event); -int WM_event_drag_direction(const wmEvent *event); +int WM_event_drag_direction(const wmEvent *event, const struct Scene *scene); char WM_event_utf8_to_ascii(const struct wmEvent *event) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; /** diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index 2e1afe808ad..beb66b9c032 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -264,36 +264,78 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event) (ISMOUSE_BUTTON(event->type) && (event->val == KM_PRESS)); } -int WM_event_drag_direction(const wmEvent *event) +int WM_event_drag_direction(const wmEvent *event, const Scene *scene) { const int delta[2] = { event->xy[0] - event->prev_press_xy[0], event->xy[1] - event->prev_press_xy[1], }; - int theta = round_fl_to_int(4.0f * atan2f((float)delta[1], (float)delta[0]) / (float)M_PI); - int val = KM_DIRECTION_W; + bool left_right = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT; + bool up_down = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_UP_DOWN; + bool drag_select_toolsetting = U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING; + int theta = left_right ? + round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) : + up_down ? + round_fl_to_int(atan2f(0.0f, (float)delta[1]) / (float)M_PI) : + round_fl_to_int(4.0f * atan2f((float)delta[1], (float)delta[0]) / (float)M_PI); + int val = up_down ? KM_DIRECTION_S : KM_DIRECTION_W; - if (theta == 0) { - val = KM_DIRECTION_E; + if (left_right || up_down) { + if (theta == 0) { + val = up_down ? KM_DIRECTION_N : KM_DIRECTION_E; + } } - else if (theta == 1) { - val = KM_DIRECTION_NE; + else { + if (theta == 0) { + val = KM_DIRECTION_E; + } + else if (theta == 1) { + val = KM_DIRECTION_NE; + } + else if (theta == 2) { + val = KM_DIRECTION_N; + } + else if (theta == 3) { + val = KM_DIRECTION_NW; + } + else if (theta == -1) { + val = KM_DIRECTION_SE; + } + else if (theta == -2) { + val = KM_DIRECTION_S; + } + else if (theta == -3) { + val = KM_DIRECTION_SW; + } } - else if (theta == 2) { - val = KM_DIRECTION_N; - } - else if (theta == 3) { - val = KM_DIRECTION_NW; - } - else if (theta == -1) { - val = KM_DIRECTION_SE; - } - else if (theta == -2) { - val = KM_DIRECTION_S; - } - else if (theta == -3) { - val = KM_DIRECTION_SW; + + if (drag_select_toolsetting) { + ToolSettings *ts = scene->toolsettings; + int box = ts->box_drag_direction; + int lasso = ts->lasso_drag_direction; + + if (box > 1) { + ts->box_direction_upright = false; + theta = box == 2 ? round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) : + round_fl_to_int(atan2f(0.0f, (float)delta[1]) / (float)M_PI); + if (theta == 0) { + ts->box_direction_upright = true; + } + } + if (lasso > 1) { + if (lasso == box) { + ts->lasso_direction_upright = ts->box_direction_upright; + } + else { + ts->lasso_direction_upright = false; + theta = lasso == 2 ? round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) : + round_fl_to_int(atan2f(0.0f, (float)delta[1]) / (float)M_PI); + if (theta == 0) { + ts->lasso_direction_upright = true; + } + } + } } #if 0 diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 52e0f43567e..157d4ae896f 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -3432,7 +3432,8 @@ static eHandlerActionFlag wm_handlers_do(bContext *C, wmEvent *event, ListBase * if ((event->flag & WM_EVENT_FORCE_DRAG_THRESHOLD) || WM_event_drag_test(event, event->prev_press_xy)) { win->event_queue_check_drag_handled = true; - const int direction = WM_event_drag_direction(event); + const Scene *scene = CTX_data_scene(C); + const int direction = WM_event_drag_direction(event, scene); /* Intentionally leave `event->xy` as-is, event users are expected to use * `event->prev_press_xy` if they need to access the drag start location. */ diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index bd3322a8023..5ff12a9c250 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -411,8 +411,58 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo { PropertyRNA *prop; + static const EnumPropertyItem face_select_items[] = { + {FACE_AUTO, + "FACE_AUTO", + 0, + "Auto", + "Select faces that are touched by the selection area in near select. Select faces whose " + "center is touched by the selection area in X-Ray select"}, + {FACE_TOUCH, + "FACE_TOUCH", + 0, + "Touch", + "Select faces that are touched by the selection area"}, + {FACE_ENCLOSE, + "FACE_ENCLOSE", + 0, + "Enclose", + "Select faces that are fully inside the selection area"}, + {FACE_CENTER, + "FACE_CENTER", + 0, + "Center", + "Select faces whose center is touched by the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem edge_select_items[] = { + {EDGE_HYBRID, + "EDGE_HYBRID", + 0, + "Hybrid", + "Select edges that are fully inside the selection area. If no edges are fully inside the " + "selection area, select edges that are touched by the selection area"}, + {EDGE_TOUCH, + "EDGE_TOUCH", + 0, + "Touch", + "Select edges that are touched by the selection area"}, + {EDGE_ENCLOSE, + "EDGE_ENCLOSE", + 0, + "Enclose", + "Select edges that are fully inside the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + WM_operator_properties_border(ot); + prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + if (deselect) { prop = RNA_def_boolean( ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); @@ -440,7 +490,8 @@ void WM_operator_properties_use_cursor_init(wmOperatorType *ot) void WM_operator_properties_gesture_box_select(wmOperatorType *ot) { - WM_operator_properties_gesture_box_ex(ot, true, true); + WM_operator_properties_gesture_box_ex( + ot, true, true); } void WM_operator_properties_gesture_box(wmOperatorType *ot) { @@ -519,6 +570,54 @@ void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot) void WM_operator_properties_gesture_lasso(wmOperatorType *ot) { PropertyRNA *prop; + static const EnumPropertyItem face_select_items[] = { + {FACE_AUTO, + "FACE_AUTO", + 0, + "Auto", + "Select faces that are touched by the selection area in near select. Select faces whose " + "center is touched by the selection area in X-Ray select"}, + {FACE_TOUCH, + "FACE_TOUCH", + 0, + "Touch", + "Select faces that are touched by the selection area"}, + {FACE_ENCLOSE, + "FACE_ENCLOSE", + 0, + "Enclose", + "Select faces that are fully inside the selection area"}, + {FACE_CENTER, + "FACE_CENTER", + 0, + "Center", + "Select faces whose center is touched by the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem edge_select_items[] = { + {EDGE_HYBRID, + "EDGE_HYBRID", + 0, + "Hybrid", + "Select edges that are fully inside the selection area. If no edges are fully inside the " + "selection area, select edges that are touched by the selection area"}, + {EDGE_TOUCH, + "EDGE_TOUCH", + 0, + "Touch", + "Select edges that are touched by the selection area"}, + {EDGE_ENCLOSE, + "EDGE_ENCLOSE", + 0, + "Enclose", + "Select edges that are fully inside the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } @@ -557,6 +656,45 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot) PropertyRNA *prop; const int radius_default = 25; + static const EnumPropertyItem face_select_items[] = { + {FACE_AUTO, + "FACE_AUTO", + 0, + "Auto", + "Select faces that are touched by the selection area in near select. Select faces whose " + "center is touched by the selection area in X-Ray select"}, + {FACE_TOUCH, + "FACE_TOUCH", + 0, + "Touch", + "Select faces that are touched by the selection area"}, + {FACE_ENCLOSE, + "FACE_ENCLOSE", + 0, + "Enclose", + "Select faces that are fully inside the selection area"}, + {FACE_CENTER, + "FACE_CENTER", + 0, + "Center", + "Select faces whose center is touched by the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem edge_select_items[] = { + {EDGE_TOUCH, + "EDGE_TOUCH", + 0, + "Touch", + "Select edges that are touched by the selection area"}, + {EDGE_ENCLOSE, + "EDGE_ENCLOSE", + 0, + "Enclose", + "Select edges that are fully inside the selection area"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); @@ -565,6 +703,11 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } void WM_operator_properties_mouse_select(wmOperatorType *ot) -- 2.30.2 From ccebf5b9c292b8f770b8482710bcd53ca141e804 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Wed, 15 Mar 2023 04:45:28 -0700 Subject: [PATCH 02/20] fix mesh ts --- source/blender/windowmanager/WM_api.h | 2 +- .../windowmanager/intern/wm_event_query.c | 17 ++++++----------- .../windowmanager/intern/wm_event_system.cc | 4 ++-- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 754a30c5c2b..a48ef91e7f7 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -1611,7 +1611,7 @@ bool WM_event_is_modal_drag_exit(const struct wmEvent *event, short init_event_val); bool WM_event_is_mouse_drag(const struct wmEvent *event); bool WM_event_is_mouse_drag_or_press(const wmEvent *event); -int WM_event_drag_direction(const wmEvent *event, const struct Scene *scene); +int WM_event_drag_direction(const wmEvent *event, struct ToolSettings *ts); char WM_event_utf8_to_ascii(const struct wmEvent *event) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; /** diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index beb66b9c032..e53627d638e 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -264,7 +264,7 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event) (ISMOUSE_BUTTON(event->type) && (event->val == KM_PRESS)); } -int WM_event_drag_direction(const wmEvent *event, const Scene *scene) +int WM_event_drag_direction(const wmEvent *event, ToolSettings *ts) { const int delta[2] = { event->xy[0] - event->prev_press_xy[0], @@ -324,16 +324,11 @@ int WM_event_drag_direction(const wmEvent *event, const Scene *scene) } } if (lasso > 1) { - if (lasso == box) { - ts->lasso_direction_upright = ts->box_direction_upright; - } - else { - ts->lasso_direction_upright = false; - theta = lasso == 2 ? round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) : - round_fl_to_int(atan2f(0.0f, (float)delta[1]) / (float)M_PI); - if (theta == 0) { - ts->lasso_direction_upright = true; - } + ts->lasso_direction_upright = false; + theta = lasso == 2 ? round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) : + round_fl_to_int(atan2f(0.0f, (float)delta[1]) / (float)M_PI); + if (theta == 0) { + ts->lasso_direction_upright = true; } } } diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 157d4ae896f..5069685e7d9 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -3432,8 +3432,8 @@ static eHandlerActionFlag wm_handlers_do(bContext *C, wmEvent *event, ListBase * if ((event->flag & WM_EVENT_FORCE_DRAG_THRESHOLD) || WM_event_drag_test(event, event->prev_press_xy)) { win->event_queue_check_drag_handled = true; - const Scene *scene = CTX_data_scene(C); - const int direction = WM_event_drag_direction(event, scene); + ToolSettings *ts = CTX_data_tool_settings(C); + const int direction = WM_event_drag_direction(event, ts); /* Intentionally leave `event->xy` as-is, event users are expected to use * `event->prev_press_xy` if they need to access the drag start location. */ -- 2.30.2 From 826f8de974789913cd4c14c99c85832ddd25f5e0 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Wed, 15 Mar 2023 04:48:50 -0700 Subject: [PATCH 03/20] fix mesh ts again --- source/blender/windowmanager/intern/wm_event_query.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index e53627d638e..03cc653811f 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -311,7 +311,6 @@ int WM_event_drag_direction(const wmEvent *event, ToolSettings *ts) } if (drag_select_toolsetting) { - ToolSettings *ts = scene->toolsettings; int box = ts->box_drag_direction; int lasso = ts->lasso_drag_direction; -- 2.30.2 From 4686169584866dae96c0fad4a0647f0bc772d522 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Fri, 31 Mar 2023 01:44:50 -0700 Subject: [PATCH 04/20] add auto xray and select through with keymap toolsetting switch --- scripts/startup/bl_ui/space_userpref.py | 2 +- scripts/startup/bl_ui/space_view3d.py | 145 +++++++- scripts/startup/bl_ui/space_view3d_toolbar.py | 6 +- .../blenloader/intern/versioning_defaults.cc | 13 + .../editors/space_view3d/view3d_edit.c | 208 +++++++++++ .../editors/space_view3d/view3d_intern.h | 2 + .../blender/editors/space_view3d/view3d_ops.c | 2 + .../editors/space_view3d/view3d_select.cc | 340 ++++++++++++++---- source/blender/makesdna/DNA_scene_defaults.h | 13 + source/blender/makesdna/DNA_scene_types.h | 39 +- source/blender/makesdna/DNA_userdef_types.h | 12 +- source/blender/makesrna/intern/rna_scene.c | 101 +++++- source/blender/makesrna/intern/rna_userdef.c | 26 +- .../windowmanager/intern/wm_event_query.c | 2 +- .../windowmanager/intern/wm_gesture_ops.c | 119 +++++- .../windowmanager/intern/wm_operator_props.c | 111 ++++++ 16 files changed, 1021 insertions(+), 120 deletions(-) diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index b0025e391c5..d77ab7162cf 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -1560,7 +1560,7 @@ class USERPREF_PT_input_mouse(InputPanel, CenterAlignMixIn, Panel): flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) flow.prop(inputs, "click_drag_direction") - flow.prop(inputs, "drag_select_mesh_control") + flow.prop(inputs, "drag_select_control") flow.prop(inputs, "use_mouse_emulate_3_button") if sys.platform[:3] != "win": rowsub = flow.row() diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index fe1c4ee2984..c4cf6e040de 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -889,9 +889,47 @@ class VIEW3D_HT_header(Header): sub.active = overlay.show_overlays sub.popover(panel="VIEW3D_PT_overlay", text="") - row = layout.row() + row = layout.row(align=True) row.active = (object_mode == 'EDIT') or (shading.type in {'WIREFRAME', 'SOLID'}) + from bl_ui.space_toolsystem_common import ToolSelectPanelHelper + _cls = ToolSelectPanelHelper._tool_class_from_space_type('VIEW_3D') + + if tool_settings.workspace_tool_type == 'FALLBACK': + tool = _cls._tool_get_by_id_active(context, _cls.tool_fallback_id)[0].idname + else: + tool = ToolSelectPanelHelper.tool_active_from_context(context).idname + + if object_mode in 'EDIT': + mode_match_auto_xray = tool_settings.auto_xray_edit and tool_settings.auto_xray + mode_match_select_through = tool_settings.select_through_edit and tool_settings.select_through + elif object_mode in 'OBJECT': + mode_match_auto_xray = tool_settings.auto_xray_object and tool_settings.auto_xray + mode_match_select_through = tool_settings.select_through_object and tool_settings.select_through + else: + mode_match_auto_xray = False + mode_match_select_through = False + + if tool == "builtin.select_box": + depress_auto_xray = mode_match_auto_xray and tool_settings.auto_xray_box + depress_select_through = mode_match_select_through and tool_settings.select_through_box + elif tool == "builtin.select_lasso": + depress_auto_xray = mode_match_auto_xray and tool_settings.auto_xray_lasso + depress_select_through = mode_match_select_through and tool_settings.select_through_lasso + elif tool == "builtin.select_circle": + depress_auto_xray = mode_match_auto_xray and tool_settings.auto_xray_circle + depress_select_through = mode_match_select_through and tool_settings.select_through_circle + else: + depress_auto_xray = False + depress_select_through = False + + if object_mode in 'EDIT' or object_mode in 'OBJECT': + if bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': + if tool_settings.auto_xray_button: + row.operator("view3d.toggle_auto_xray", text="", icon='XRAY', depress=depress_auto_xray) + if tool_settings.select_through_button: + row.operator("view3d.toggle_select_through", text="", icon='XRAY', depress=depress_select_through) + # While exposing `shading.show_xray(_wireframe)` is correct. # this hides the key shortcut from users: #70433. if has_pose_mode: @@ -900,12 +938,15 @@ class VIEW3D_HT_header(Header): draw_depressed = shading.show_xray_wireframe else: draw_depressed = shading.show_xray - row.operator( - "view3d.toggle_xray", - text="", - icon='XRAY', - depress=draw_depressed, - ) + + if bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': + if tool_settings.xray_button: + row.operator("view3d.toggle_xray", text="", icon='XRAY', depress=draw_depressed) + elif not tool_settings.auto_xray_button and not tool_settings.select_through_button: + row.operator("view3d.toggle_xray", text="", icon='XRAY', depress=draw_depressed) + else: + row.operator("view3d.toggle_xray", text="", icon='XRAY', depress=draw_depressed) + row.popover(panel="VIEW3D_PT_xray", text="") row = layout.row(align=True) row.prop(shading, "type", text="", expand=True) @@ -6068,17 +6109,7 @@ class VIEW3D_PT_shading_options(Panel): row = col.row(align=True) - if shading.type == 'WIREFRAME': - row.prop(shading, "show_xray_wireframe", text="") - sub = row.row() - sub.active = shading.show_xray_wireframe - sub.prop(shading, "xray_alpha_wireframe", text="X-Ray") - elif shading.type == 'SOLID': - row.prop(shading, "show_xray", text="") - sub = row.row() - sub.active = shading.show_xray - sub.prop(shading, "xray_alpha", text="X-Ray") - # X-ray mode is off when alpha is 1.0 + if shading.type == 'SOLID': xray_active = shading.show_xray and shading.xray_alpha != 1 row = col.row(align=True) @@ -6263,6 +6294,83 @@ class VIEW3D_PT_gizmo_display(Panel): col.prop(view, "show_gizmo_camera_dof_distance", text="Focus Distance") +class VIEW3D_PT_xray(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "X-Ray Settings" + bl_ui_units_x = 14 + + def draw(self, context): + layout = self.layout + layout.label(text="X-Ray Settings") + shading = VIEW3D_PT_shading.get_shading(context) + + col = layout.column() + row = col.row(align=True) + if shading.type == 'WIREFRAME': + row.prop(shading, "show_xray_wireframe", text="") + sub = row.row() + sub.active = shading.show_xray_wireframe + sub.prop(shading, "xray_alpha_wireframe", text="X-Ray Wireframe") + elif shading.type == 'SOLID': + row.prop(shading, "show_xray", text="") + sub = row.row() + sub.active = shading.show_xray + sub.prop(shading, "xray_alpha", text="X-Ray Solid") + + if bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': + tool_settings = context.tool_settings + + row = layout.row(align=True) + row = layout.row(align=True) + row = layout.row(align=True) + + row = layout.row(heading="Automatic X-Ray") + row.prop(tool_settings, "ui_prop", text="", emboss=False) + row = layout.row(align=True) + row.prop(tool_settings, "auto_xray", text="Enable") + sub = row.row(align=True) + sub.active = tool_settings.auto_xray + sub.prop(tool_settings, "auto_xray_object", text="Object") + sub.prop(tool_settings, "auto_xray_edit", text="Edit") + row = layout.row(align=True) + sub = row.row(align=True) + sub.active = tool_settings.auto_xray + sub.prop(tool_settings, "auto_xray_box", text="Box", toggle=True) + sub.prop(tool_settings, "auto_xray_lasso", text="Lasso", toggle=True) + sub.prop(tool_settings, "auto_xray_circle", text="Circle", toggle=True) + + row = layout.row(align=True) + row = layout.row(align=True) + row = layout.row(align=True) + + row = layout.row(heading="Select Through") + row.prop(tool_settings, "ui_prop", text="", emboss=False) + row = layout.row(align=True) + row.prop(tool_settings, "select_through", text="Enable") + sub = row.row(align=True) + sub.active = tool_settings.select_through + sub.prop(tool_settings, "select_through_object", text="Object") + sub.prop(tool_settings, "select_through_edit", text="Edit") + row = layout.row(align=True) + sub = row.row(align=True) + sub.active = tool_settings.select_through + sub.prop(tool_settings, "select_through_box", text="Box", toggle=True) + sub.prop(tool_settings, "select_through_lasso", text="Lasso", toggle=True) + sub.prop(tool_settings, "select_through_circle", text="Circle", toggle=True) + + row = layout.row(align=True) + row = layout.row(align=True) + row = layout.row(align=True) + + row = layout.row(heading="Header Buttons") + row.prop(tool_settings, "ui_prop", text="", emboss=False) + row = layout.row(align=True) + row.prop(tool_settings, "auto_xray_button", text="Auto X-Ray", toggle=True) + row.prop(tool_settings, "select_through_button", text="Select Through", toggle=True) + row.prop(tool_settings, "xray_button", text="X-Ray", toggle=True) + + class VIEW3D_PT_overlay(Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'HEADER' @@ -8209,6 +8317,7 @@ classes = ( VIEW3D_PT_shading_render_pass, VIEW3D_PT_shading_compositor, VIEW3D_PT_gizmo_display, + VIEW3D_PT_xray, VIEW3D_PT_overlay, VIEW3D_PT_overlay_guides, VIEW3D_PT_overlay_object, diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index 654e78fd268..059c9e9255c 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -154,7 +154,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): bl_context = ".mesh_edit" # dot on purpose (access from topbar) bl_label = "Options" bl_options = {'DEFAULT_CLOSED'} - bl_ui_units_x = 14 + bl_ui_units_x = 15 @classmethod def poll(cls, context): @@ -191,7 +191,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z row.prop(mesh, "use_mirror_topology") - if bpy.context.preferences.inputs.drag_select_mesh_control == 'USER_MESH_TOOLSETTING': + if bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': from bl_ui.space_toolsystem_common import ToolSelectPanelHelper _cls = ToolSelectPanelHelper._tool_class_from_space_type('VIEW_3D') @@ -201,7 +201,7 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): tool = ToolSelectPanelHelper.tool_active_from_context(context).idname if tool == "builtin.select_box" or tool == "builtin.select_lasso" or tool == "builtin.select_circle": - row = layout.row(align=True, heading="Drag Select") + row = layout.row(align=True) if tool == "builtin.select_box": row.prop(tool_settings, "box_drag_direction") row = layout.row(align=True) diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index 298a32c21bc..cea068678cf 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -399,6 +399,19 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) ts->lasso_face_down = 1; ts->circle_edge = 2; ts->circle_face = 1; + + /* X-Ray. */ + ts->xray_button = true; + ts->auto_xray_object = true; + ts->auto_xray_edit = true; + ts->auto_xray_box = true; + ts->auto_xray_lasso = true; + ts->auto_xray_circle = true; + ts->select_through = true; + ts->select_through_object = true; + ts->select_through_box = true; + ts->select_through_lasso = true; + ts->select_through_circle = true; } void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index d5b96e03f13..aa239596e8d 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1235,3 +1235,211 @@ void VIEW3D_OT_toggle_xray(wmOperatorType *ot) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Automatic XRay + * \{ */ + +static int toggle_auto_xray_exec(bContext *C, wmOperator *op) +{ + ScrArea *area = CTX_wm_area(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Object *obedit = CTX_data_edit_object(C); + bToolRef *tref = area->runtime.tool; + const bool mode_match = obedit ? ts->auto_xray_edit : ts->auto_xray_object; + + if (STREQ(tref->idname, "builtin.select_box") || + STREQ(tref->idname_fallback, "builtin.select_box")) { + if (mode_match && ts->auto_xray && ts->auto_xray_box) { + ts->auto_xray ^= true; + } + else { + if (!mode_match) { + if (obedit) { + ts->auto_xray_edit ^= true; + } + else { + ts->auto_xray_object ^= true; + } + } + + if (!ts->auto_xray) { + ts->auto_xray ^= true; + } + + if (!ts->auto_xray_box) { + ts->auto_xray_box ^= true; + } + } + } + else if (STREQ(tref->idname, "builtin.select_lasso") || + STREQ(tref->idname_fallback, "builtin.select_lasso")) { + if (mode_match && ts->auto_xray && ts->auto_xray_lasso) { + ts->auto_xray ^= true; + } + else { + if (!mode_match) { + if (obedit) { + ts->auto_xray_edit ^= true; + } + else { + ts->auto_xray_object ^= true; + } + } + + if (!ts->auto_xray) { + ts->auto_xray ^= true; + } + + if (!ts->auto_xray_lasso) { + ts->auto_xray_lasso ^= true; + } + } + } + else if (STREQ(tref->idname, "builtin.select_circle") || + STREQ(tref->idname_fallback, "builtin.select_circle")) { + if (mode_match && ts->auto_xray && ts->auto_xray_circle) { + ts->auto_xray ^= true; + } + else { + if (!mode_match) { + if (obedit) { + ts->auto_xray_edit ^= true; + } + else { + ts->auto_xray_object ^= true; + } + } + + if (!ts->auto_xray) { + ts->auto_xray ^= true; + } + + if (!ts->auto_xray_circle) { + ts->auto_xray_circle ^= true; + } + } + } + + ED_area_tag_redraw(area); + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_toggle_auto_xray(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Automatic X-Ray"; + ot->idname = "VIEW3D_OT_toggle_auto_xray"; + ot->description = "Transparent scene display during box, lasso, and circle select"; + + /* api callbacks */ + ot->exec = toggle_auto_xray_exec; + ot->poll = ED_operator_view3d_active; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Select Through + * \{ */ + +static int toggle_select_through_exec(bContext *C, wmOperator *op) +{ + ScrArea *area = CTX_wm_area(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Object *obedit = CTX_data_edit_object(C); + bToolRef *tref = area->runtime.tool; + const bool mode_match = obedit ? ts->select_through_edit : ts->select_through_object; + + if (STREQ(tref->idname, "builtin.select_box") || + STREQ(tref->idname_fallback, "builtin.select_box")) { + if (mode_match && ts->select_through && ts->select_through_box) { + ts->select_through ^= true; + } + else { + if (!mode_match) { + if (obedit) { + ts->select_through_edit ^= true; + } + else { + ts->select_through_object ^= true; + } + } + + if (!ts->select_through) { + ts->select_through ^= true; + } + + if (!ts->select_through_box) { + ts->select_through_box ^= true; + } + } + } + else if (STREQ(tref->idname, "builtin.select_lasso") || + STREQ(tref->idname_fallback, "builtin.select_lasso")) { + if (mode_match && ts->select_through && ts->select_through_lasso) { + ts->select_through ^= true; + } + else { + if (!mode_match) { + if (obedit) { + ts->select_through_edit ^= true; + } + else { + ts->select_through_object ^= true; + } + } + + if (!ts->select_through) { + ts->select_through ^= true; + } + + if (!ts->select_through_lasso) { + ts->select_through_lasso ^= true; + } + } + } + else if (STREQ(tref->idname, "builtin.select_circle") || + STREQ(tref->idname_fallback, "builtin.select_circle")) { + if (mode_match && ts->select_through && ts->select_through_circle) { + ts->select_through ^= true; + } + else { + if (!mode_match) { + if (obedit) { + ts->select_through_edit ^= true; + } + else { + ts->select_through_object ^= true; + } + } + + if (!ts->select_through) { + ts->select_through ^= true; + } + + if (!ts->select_through_circle) { + ts->select_through_circle ^= true; + } + } + } + + ED_area_tag_redraw(area); + + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_toggle_select_through(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Select Through"; + ot->idname = "VIEW3D_OT_toggle_select_through"; + ot->description = "Select occluded objects and mesh elements with box, lasso, and circle select"; + + /* api callbacks */ + ot->exec = toggle_select_through_exec; + ot->poll = ED_operator_view3d_active; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index b94833dd276..f85453b7a96 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -55,6 +55,8 @@ void VIEW3D_OT_render_border(struct wmOperatorType *ot); void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot); void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot); void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_auto_xray(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_select_through(struct wmOperatorType *ot); /* view3d_draw.c */ diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index ad12aef6d67..c8fdbd8f044 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -200,6 +200,8 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_toggle_shading); WM_operatortype_append(VIEW3D_OT_toggle_xray); WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip); + WM_operatortype_append(VIEW3D_OT_toggle_auto_xray); + WM_operatortype_append(VIEW3D_OT_toggle_select_through); WM_operatortype_append(VIEW3D_OT_ruler_add); WM_operatortype_append(VIEW3D_OT_ruler_remove); diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 2bf02e9660e..e45a7492dc1 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -729,42 +729,225 @@ static void do_lasso_tag_pose(ViewContext *vc, V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_CONTENT_DEFAULT); } +/** + * Compare result of 'GPU_select': 'GPUSelectResult', + * Needed for stable sorting, so cycling through all items near the cursor behaves predictably. + */ +static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b_p) +{ + GPUSelectResult *a = (GPUSelectResult *)sel_a_p; + GPUSelectResult *b = (GPUSelectResult *)sel_b_p; + + if (a->depth < b->depth) { + return -1; + } + if (a->depth > b->depth) { + return 1; + } + + /* Depths match, sort by id. */ + uint sel_a = a->id; + uint sel_b = b->id; + +#ifdef __BIG_ENDIAN__ + BLI_endian_switch_uint32(&sel_a); + BLI_endian_switch_uint32(&sel_b); +#endif + + if (sel_a < sel_b) { + return -1; + } + if (sel_a > sel_b) { + return 1; + } + return 0; +} + static bool do_lasso_select_objects(ViewContext *vc, const int mcoords[][2], const int mcoords_len, - const eSelectOp sel_op) + const eSelectOp sel_op, + wmOperator *op, + int circle_data[3]) { View3D *v3d = vc->v3d; + int totobj = MAXPICKELEMS; /* XXX solve later */ + /* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */ + GPUSelectResult *buffer = static_cast( + MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__)); + ToolSettings *ts = vc->scene->toolsettings; - bool changed = false; - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - changed |= object_deselect_all_visible(vc->scene, vc->view_layer, vc->v3d); + const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool select_through = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + select_through_int == 2 || select_through_int == 8 : + circle_data == NULL ? + ts->select_through && ts->select_through_object && + ts->select_through_lasso : + ts->select_through && ts->select_through_object && + ts->select_through_circle; + float region_co[2]; + float mval_fl[2]; + if (circle_data != NULL) { + mval_fl[0] = circle_data[0]; + mval_fl[1] = circle_data[1]; } - BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); - LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) { - if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */ - float region_co[2]; - const bool is_select = base->flag & BASE_SELECTED; - const bool is_inside = (ED_view3d_project_base(vc->region, base, region_co) == - V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside(mcoords, - mcoords_len, - int(region_co[0]), - int(region_co[1]), - /* Dummy value. */ - INT_MAX); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); - if (sel_op_result != -1) { - ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); - changed = true; + bool changed = false; + + if (select_through && circle_data == NULL) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + changed |= object_deselect_all_visible(vc->scene, vc->view_layer, vc->v3d); + } + BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); + LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) { + if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */ + float region_co[2]; + const bool is_select = base->flag & BASE_SELECTED; + const bool is_inside = (ED_view3d_project_base(vc->region, base, region_co) == + V3D_PROJ_RET_OK) && + BLI_lasso_is_point_inside(mcoords, + mcoords_len, + int(region_co[0]), + int(region_co[1]), + /* Dummy value. */ + INT_MAX); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); + changed = true; + } } } + + if (changed) { + DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene); + } } - if (changed) { - DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); - WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene); + else { + int hits = 0; + rcti rect_data; + rcti *rect = &rect_data; + blender::Vector bases; + + if (circle_data != NULL) { + int point[4][2] = {}; + + for (int i = 0; i < 4; i++) { + float angle = 6.28f * (i + 1) / 4; + point[i][0] = circle_data[0] + circle_data[2] * cosf(angle); + point[i][1] = circle_data[1] + circle_data[2] * sinf(angle); + } + rect->xmin = rect->xmax = point[0][0]; + rect->ymin = rect->ymax = point[0][1]; + uint a; + for (a = 1; a < 4; a++) { + if (point[a][0] < rect->xmin) { + rect->xmin = point[a][0]; + } + else if (point[a][0] > rect->xmax) { + rect->xmax = point[a][0]; + } + if (point[a][1] < rect->ymin) { + rect->ymin = point[a][1]; + } + else if (point[a][1] > rect->ymax) { + rect->ymax = point[a][1]; + } + } + } + else { + BLI_lasso_boundbox(rect, mcoords, mcoords_len); + } + const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, + vc->obact); + if (XRAY_FLAG_ENABLED(vc->v3d) || select_through) { + hits = view3d_opengl_select( + vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); + } + else { + hits = view3d_opengl_select( + vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_PICK_NEAREST, select_filter); + } + BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); + LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) { + base->object->id.tag &= ~LIB_TAG_DOIT; + } + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + changed |= object_deselect_all_visible(vc->scene, vc->view_layer, vc->v3d); + } + + ListBase *object_bases = BKE_view_layer_object_bases_get(vc->view_layer); + if ((hits == -1) && !SEL_OP_USE_OUTSIDE(sel_op)) { + goto finally; + } + + LISTBASE_FOREACH (Base *, base, object_bases) { + if (BASE_SELECTABLE(v3d, base)) { + if ((base->object->runtime.select_id & 0x0000FFFF) != 0) { + bases.append(base); + } + } + } + + /* The draw order doesn't always match the order we populate the engine, see: T51695. */ + qsort(buffer, hits, sizeof(GPUSelectResult), gpu_select_buffer_depth_id_cmp); + + for (const GPUSelectResult *buf_iter = buffer, *buf_end = buf_iter + hits; buf_iter < buf_end; + buf_iter++) { + bPoseChannel *pchan_dummy; + Base *base = ED_armature_base_and_pchan_from_select_buffer( + bases.data(), bases.size(), buf_iter->id, &pchan_dummy); + if (base != nullptr) { + base->object->id.tag |= LIB_TAG_DOIT; + } + } + + for (Base *base = static_cast(object_bases->first); base && hits; base = base->next) { + if (BASE_SELECTABLE(v3d, base)) { + const bool is_select = base->flag & BASE_SELECTED; + bool is_inside = false; + + if (circle_data == NULL) { + is_inside = base->object->id.tag & LIB_TAG_DOIT && + (ED_view3d_project_base(vc->region, base, region_co) == V3D_PROJ_RET_OK) && + BLI_lasso_is_point_inside(mcoords, + mcoords_len, + int(region_co[0]), + int(region_co[1]), + /* Dummy value. */ + INT_MAX); + } + else { + is_inside = base->object->id.tag & LIB_TAG_DOIT ? + (ED_view3d_project_float_global(vc->region, + base->object->object_to_world[3], + region_co, + V3D_PROJ_TEST_CLIP_DEFAULT) == + V3D_PROJ_RET_OK) && + len_squared_v2v2(mval_fl, region_co) <= + circle_data[2] * circle_data[2] : + false; + } + + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); + changed = true; + } + } + } + + finally: + + MEM_freeN(buffer); + + if (changed) { + DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(vc->C, NC_SCENE | ND_OB_SELECT, vc->scene); + } } + return changed; } @@ -1047,7 +1230,7 @@ static bool do_lasso_select_mesh(ViewContext *vc, BLI_lasso_boundbox(&rect, mcoords, mcoords_len); int edge_style, face_style; - if (U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING) { + if (U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING) { if (ts->lasso_drag_direction > 1) { if (ts->lasso_drag_direction == 2) { if (ts->lasso_direction_upright) { @@ -1093,7 +1276,12 @@ static bool do_lasso_select_mesh(ViewContext *vc, GPU_matrix_set(vc->rv3d->viewmat); - const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool select_through = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + select_through_int > 2 : + ts->select_through && ts->select_through_edit && + ts->select_through_lasso; + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d) && !select_through; EditSelectBuf_Cache *esel = static_cast(wm_userdata->data); if (use_zbuf) { @@ -1631,7 +1819,7 @@ static bool view3d_lasso_select(bContext *C, } } else { - changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op); + changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op, op, NULL); if (changed_multi) { ED_outliner_select_sync_from_object_tag(C); } @@ -2439,40 +2627,6 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc, return hits; } -/** - * Compare result of 'GPU_select': 'GPUSelectResult', - * Needed for stable sorting, so cycling through all items near the cursor behaves predictably. - */ -static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b_p) -{ - GPUSelectResult *a = (GPUSelectResult *)sel_a_p; - GPUSelectResult *b = (GPUSelectResult *)sel_b_p; - - if (a->depth < b->depth) { - return -1; - } - if (a->depth > b->depth) { - return 1; - } - - /* Depths match, sort by id. */ - uint sel_a = a->id; - uint sel_b = b->id; - -#ifdef __BIG_ENDIAN__ - BLI_endian_switch_uint32(&sel_a); - BLI_endian_switch_uint32(&sel_b); -#endif - - if (sel_a < sel_b) { - return -1; - } - if (sel_a > sel_b) { - return 1; - } - return 0; -} - /** * \param has_bones: When true, skip non-bone hits, also allow bases to be used * that are visible but not select-able, @@ -3919,7 +4073,7 @@ static bool do_mesh_box_select(ViewContext *vc, ToolSettings *ts = vc->scene->toolsettings; int edge_style, face_style; - if (U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING) { + if (U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING) { if (ts->box_drag_direction > 1) { if (ts->box_drag_direction == 2) { if (ts->box_direction_upright) { @@ -3964,7 +4118,12 @@ static bool do_mesh_box_select(ViewContext *vc, GPU_matrix_set(vc->rv3d->viewmat); - const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool select_through = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + select_through_int > 2 : + ts->select_through && ts->select_through_edit && + ts->select_through_box; + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d) && !select_through; EditSelectBuf_Cache *esel = static_cast(wm_userdata->data); if (use_zbuf) { @@ -4199,18 +4358,32 @@ static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_ return 0; } -static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op) +static bool do_object_box_select( + bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op, wmOperator *op) { View3D *v3d = vc->v3d; int totobj = MAXPICKELEMS; /* XXX solve later */ + ToolSettings *ts = vc->scene->toolsettings; /* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */ GPUSelectResult *buffer = static_cast( MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__)); const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); - const int hits = view3d_opengl_select( - vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); + const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool select_through = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + select_through_int == 2 || select_through_int == 8 : + ts->select_through && ts->select_through_object && + ts->select_through_box; + int hits = 0; + if (XRAY_FLAG_ENABLED(vc->v3d) || select_through) { + hits = view3d_opengl_select( + vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter); + } + else { + hits = view3d_opengl_select( + vc, buffer, (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_PICK_NEAREST, select_filter); + } BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) { base->object->id.tag &= ~LIB_TAG_DOIT; @@ -4452,7 +4625,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) } } else { /* object mode with none active */ - changed_multi = do_object_box_select(C, &vc, &rect, sel_op); + changed_multi = do_object_box_select(C, &vc, &rect, sel_op, op); if (changed_multi) { ED_outliner_select_sync_from_object_tag(C); } @@ -4660,7 +4833,7 @@ static bool mesh_circle_select(ViewContext *vc, ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ int edge_style, face_style; - if (U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING) { + if (U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING) { edge_style = ts->circle_edge; face_style = ts->circle_face; } @@ -4671,7 +4844,12 @@ static bool mesh_circle_select(ViewContext *vc, view3d_userdata_circleselect_init(&data, vc, select, mval, rad, edge_style, face_style); - const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d); + const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool select_through = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + select_through_int > 2 : + ts->select_through && ts->select_through_edit && + ts->select_through_circle; + const bool use_zbuf = !XRAY_FLAG_ENABLED(vc->v3d) && !select_through; if (use_zbuf) { if (wm_userdata->data == nullptr) { @@ -5399,9 +5577,17 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) const eSelectOp sel_op = ED_select_op_modal( static_cast(RNA_enum_get(op->ptr, "mode")), WM_gesture_is_modal_first(gesture)); - ED_view3d_viewcontext_init(C, &vc, depsgraph); + ToolSettings *ts = vc.scene->toolsettings; + const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool select_through_object = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + select_through_int == 2 || select_through_int == 8 : + ts->select_through && ts->select_through_object && + ts->select_through_circle; + if (!select_through_object) { + BKE_object_update_select_id(CTX_data_main(C)); + } Object *obact = vc.obact; Object *obedit = vc.obedit; @@ -5447,11 +5633,17 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } else { - if (object_circle_select(&vc, sel_op, mval, float(radius))) { - DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene); + if (select_through_object) { + if (object_circle_select(&vc, sel_op, mval, float(radius))) { + DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene); - ED_outliner_select_sync_from_object_tag(C); + ED_outliner_select_sync_from_object_tag(C); + } + } + else { + int circle_data[3] = {mval[0], mval[1], radius}; + do_lasso_select_objects(&vc, NULL, NULL, sel_op, op, circle_data); } } diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index d89daedc25f..05c50e19a32 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -392,6 +392,19 @@ .lasso_face_down = 1, \ .circle_edge = 2, \ .circle_face = 1, \ + \ + /* X-Ray */ \ + .xray_button = true, \ + .auto_xray_object = true, \ + .auto_xray_edit = true, \ + .auto_xray_box = true, \ + .auto_xray_lasso = true, \ + .auto_xray_circle = true, \ + .select_through = true, \ + .select_through_object = true, \ + .select_through_box = true, \ + .select_through_lasso = true, \ + .select_through_circle = true, \ } /* clang-format off */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index cfabd92835d..aa90e3dd7c8 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1557,7 +1557,28 @@ typedef struct ToolSettings { char gpencil_v3d_align; /** General 2D Editor. */ char gpencil_v2d_align; - char _pad0[2]; + + /* Give the UI an empty prop to expand formatting */ + char ui_prop; + + /* X-Ray Options */ + char xray_button; + char auto_xray; + char auto_xray_button; + char auto_xray_reset; + char auto_xray_object; + char auto_xray_edit; + char auto_xray_box; + char auto_xray_lasso; + char auto_xray_circle; + char select_through; + char select_through_button; + char select_through_object; + char select_through_edit; + char select_through_box; + char select_through_lasso; + char select_through_circle; + char _pad0[1]; /* Annotations. */ /** Stroke placement settings - 3D View. */ @@ -2381,6 +2402,22 @@ enum { MESH_DIRECTION_UP_DOWN = (1 << 2), }; +/** #ToolSettings.auto_xray_mode */ +enum { + AUTO_XRAY_DISABLE = (1 << 0), + AUTO_XRAY_OBJECT = (1 << 1), + AUTO_XRAY_EDIT = (1 << 2), + AUTO_XRAY_BOTH = (1 << 3), +}; + +/** #ToolSettings.select_through_mode */ +enum { + SELECT_THROUGH_DISABLE = (1 << 0), + SELECT_THROUGH_OBJECT = (1 << 1), + SELECT_THROUGH_EDIT = (1 << 2), + SELECT_THROUGH_BOTH = (1 << 3), +}; + /** #ToolSettings.selectmode */ #define SCE_SELECT_VERTEX (1 << 0) /* for mesh */ #define SCE_SELECT_EDGE (1 << 1) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 96670c0f31b..cd8640e0b91 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -843,7 +843,7 @@ typedef struct UserDef { /** Keymap click-drag direction style. */ char click_drag_direction; /** Box, lasso, and circle select mesh control style. */ - char drag_select_mesh_control; + char drag_select_control; char _pad7[2]; /** Private, defaults to 20 for 72 DPI setting. */ @@ -1164,11 +1164,11 @@ typedef enum eUserpref_Click_Drag_Direction { USER_CLICK_DRAG_DIRECTION_UP_DOWN = 2, } eUserpref_Click_Drag_Direction; -/** #UserDef.drag_select_mesh_control_types */ -typedef enum eUserpref_Drag_Select_Mesh_Control { - USER_DRAG_SELECT_MESH_KEYMAP = 0, - USER_DRAG_SELECT_MESH_TOOLSETTING = 1, -} eUserpref_Drag_Select_Mesh_Control; +/** #UserDef.drag_select_control_types */ +typedef enum eUserpref_Drag_Select_Control { + USER_DRAG_SELECT_TOOLSETTING = 0, + USER_DRAG_SELECT_KEYMAP = 1, +} eUserpref_Drag_Select_Control; /** #UserDef.app_flag */ typedef enum eUserpref_APP_Flag { diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index a416efe87e6..cd3e8671575 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3130,11 +3130,11 @@ static void rna_def_tool_settings(BlenderRNA *brna) /* Mesh select settings. */ prop = RNA_def_property(srna, "box_drag_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mesh_drag_direction_items); - RNA_def_property_ui_text(prop, "Box Direction", "Click-drag direction style for box select"); + RNA_def_property_ui_text(prop, "Mesh Drag Direction", "Click-drag direction style for box select"); prop = RNA_def_property(srna, "lasso_drag_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mesh_drag_direction_items); - RNA_def_property_ui_text(prop, "Lasso Direction", "Click-drag direction style for lasso select"); + RNA_def_property_ui_text(prop, "Mesh Drag Direction", "Click-drag direction style for lasso select"); prop = RNA_def_property(srna, "box_direction_upright", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "box_direction_upright", 0); @@ -3904,6 +3904,103 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply"); RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3); + /* UI prop helper, so you can use a heading without a real property or operator on the same line */ + prop = RNA_def_property(srna, "ui_prop", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ui_prop", 0); + RNA_def_property_ui_text(prop, "UI Prop", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* X-Ray header button */ + prop = RNA_def_property(srna, "xray_button", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "xray_button", 0); + RNA_def_property_ui_text( + prop, "X-Ray Button", "Show button for X-Ray in viewport header"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* Auto X-Ray */ + prop = RNA_def_property(srna, "auto_xray", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray", "Transparent scene display during drag select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "auto_xray_button", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_button", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray Button", "Show button for automatic X-Ray in viewport header"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "auto_xray_reset", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_reset", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray Reset", "Helper that turns xray off for autoxray"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "auto_xray_object", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_object", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray Object", "Automatic X-Ray in object mode"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "auto_xray_edit", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_edit", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray Edit", "Automatic X-Ray in edit mode"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "auto_xray_box", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_box", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray Box", "Transparent scene display during box select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "auto_xray_lasso", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_lasso", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray Lasso", "Transparent scene display during lasso select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "auto_xray_circle", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "auto_xray_circle", 0); + RNA_def_property_ui_text(prop, "Auto X-Ray Circle", "Transparent scene display during circle select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* Select Through */ + prop = RNA_def_property(srna, "select_through", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_through", 0); + RNA_def_property_ui_text( + prop, "Select Through", "Select occluded objects and mesh elements with drag select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "select_through_button", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_through_button", 0); + RNA_def_property_ui_text( + prop, "Select Through Button", "Show button for select through in viewport header"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "select_through_object", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_through_object", 0); + RNA_def_property_ui_text(prop, "Select Through Object", "Select through in object mode"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "select_through_edit", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_through_edit", 0); + RNA_def_property_ui_text(prop, "Select Through Edit", "Select through in edit mode"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "select_through_box", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_through_box", 0); + RNA_def_property_ui_text( + prop, "Select Through Box", "Select occluded objects and mesh elements with box select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "select_through_lasso", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_through_lasso", 0); + RNA_def_property_ui_text(prop, + "Select Through Lasso", + "Select occluded objects and mesh elements with lasso select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "select_through_circle", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_through_circle", 0); + RNA_def_property_ui_text(prop, + "Select Through Circle", + "Select occluded objects and mesh elements with circle select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + /* Unified Paint Settings */ prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index a60c2be9703..1cf4be9348f 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5785,17 +5785,17 @@ static void rna_def_userdef_input(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - static const EnumPropertyItem drag_select_mesh_control_types[] = { - {USER_DRAG_SELECT_MESH_KEYMAP, - "USER_MESH_KEYMAP", - 0, - "Keymap", - "Use the keymap to control mesh selection style for box, lasso, and circle"}, - {USER_DRAG_SELECT_MESH_TOOLSETTING, - "USER_MESH_TOOLSETTING", + static const EnumPropertyItem drag_select_control_types[] = { + {USER_DRAG_SELECT_TOOLSETTING, + "USER_DRAG_TOOLSETTING", 0, "Toolsetting", - "Use toolsettings to control mesh selection style for box, lasso, and circle"}, + "Use toolsettings to control selection options for box, lasso, and circle select"}, + {USER_DRAG_SELECT_KEYMAP, + "USER_DRAG_KEYMAP", + 0, + "Keymap", + "Use the keymap to control selection options for box, lasso, and circle selection"}, {0, NULL, 0, NULL, NULL}, }; @@ -5910,11 +5910,11 @@ static void rna_def_userdef_input(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Keymap Drag Directions", "Style of click-drag direction the keymap will use"); - prop = RNA_def_property(srna, "drag_select_mesh_control", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, drag_select_mesh_control_types); + prop = RNA_def_property(srna, "drag_select_control", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, drag_select_control_types); RNA_def_property_ui_text(prop, - "Mesh Drag Select Control", - "Use either the keymap or toolsettings to control edge and face selection style " + "Drag Select Control", + "Use either the keymap or toolsettings to control selection options " "for box, lasso, and circle select"); prop = RNA_def_property(srna, "use_numeric_input_advanced", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index 03cc653811f..3c8a6900c4b 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -273,7 +273,7 @@ int WM_event_drag_direction(const wmEvent *event, ToolSettings *ts) bool left_right = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT; bool up_down = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_UP_DOWN; - bool drag_select_toolsetting = U.drag_select_mesh_control & USER_DRAG_SELECT_MESH_TOOLSETTING; + bool drag_select_toolsetting = U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING; int theta = left_right ? round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) : up_down ? diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index ae8c446bd87..d9ecd122b19 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -29,6 +29,7 @@ #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_view3d.h" #include "UI_interface.h" @@ -85,6 +86,18 @@ static void gesture_modal_state_to_operator(wmOperator *op, int modal_state) } } +static void gesture_toggle_xray(bContext *C) +{ + wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_toggle_xray", true); + ToolSettings *ts = CTX_data_tool_settings(C); + BLI_assert(ot); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL); + WM_operator_properties_free(&ptr); + ts->auto_xray_reset ^= true; +} + static int UNUSED_FUNCTION(gesture_modal_state_from_operator)(wmOperator *op) { PropertyRNA *prop; @@ -163,9 +176,33 @@ static bool gesture_box_apply(bContext *C, wmOperator *op) int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + View3D *v3d = CTX_wm_view3d(C); + Object *obedit = CTX_data_edit_object(C); + ToolSettings *ts = CTX_data_tool_settings(C); const ARegion *region = CTX_wm_region(C); const bool wait_for_input = !WM_event_is_mouse_drag_or_press(event) && RNA_boolean_get(op->ptr, "wait_for_input"); + + bool auto_xray = false; + if (U.drag_select_control & USER_DRAG_SELECT_KEYMAP) { + const int auto_xray_int = RNA_enum_get(op->ptr, "auto_xray"); + auto_xray = obedit ? auto_xray_int > 2 : auto_xray_int == 2 || auto_xray_int == 8; + } + else { + auto_xray = ts->auto_xray && ts->auto_xray_box ? + obedit ? ts->auto_xray_edit : ts->auto_xray_object : + false; + } + + if (ts->auto_xray_reset) { + ts->auto_xray_reset ^= true; + } + + if (v3d && auto_xray) { + if (!XRAY_FLAG_ENABLED(v3d)) { + gesture_toggle_xray(C); + } + } if (wait_for_input) { op->customdata = WM_gesture_new(win, region, event, WM_GESTURE_CROSS_RECT); @@ -190,8 +227,11 @@ int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event) int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + View3D *v3d = CTX_wm_view3d(C); wmGesture *gesture = op->customdata; rcti *rect = gesture->customdata; + Object *obedit = CTX_data_edit_object(C); + ToolSettings *ts = CTX_data_tool_settings(C); if (event->type == EVT_MODAL_MAP) { switch (event->val) { @@ -214,13 +254,22 @@ int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event) gesture->modal_state = event->val; } if (gesture_box_apply(C, op)) { + if (ts->auto_xray_reset) { + gesture_toggle_xray(C); + } gesture_modal_end(C, op); return OPERATOR_FINISHED; } + if (ts->auto_xray_reset) { + gesture_toggle_xray(C); + } gesture_modal_end(C, op); return OPERATOR_CANCELLED; } case GESTURE_MODAL_CANCEL: { + if (ts->auto_xray_reset) { + gesture_toggle_xray(C); + } gesture_modal_end(C, op); return OPERATOR_CANCELLED; } @@ -286,8 +335,31 @@ static void gesture_circle_apply(bContext *C, wmOperator *op); int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + View3D *v3d = CTX_wm_view3d(C); const bool wait_for_input = !WM_event_is_mouse_drag_or_press(event) && RNA_boolean_get(op->ptr, "wait_for_input"); + Object *obedit = CTX_data_edit_object(C); + ToolSettings *ts = win->scene->toolsettings; + bool auto_xray = false; + if (U.drag_select_control & USER_DRAG_SELECT_KEYMAP) { + const int auto_xray_int = RNA_enum_get(op->ptr, "auto_xray"); + auto_xray = obedit ? auto_xray_int > 2 : auto_xray_int == 2 || auto_xray_int == 8; + } + else { + auto_xray = ts->auto_xray && ts->auto_xray_circle ? + obedit ? ts->auto_xray_edit : ts->auto_xray_object : + false; + } + + if (ts->auto_xray_reset) { + ts->auto_xray_reset ^= true; + } + + if (v3d && auto_xray) { + if (!XRAY_FLAG_ENABLED(v3d)) { + gesture_toggle_xray(C); + } + } op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_CIRCLE); wmGesture *gesture = op->customdata; @@ -345,11 +417,14 @@ static void gesture_circle_apply(bContext *C, wmOperator *op) int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + View3D *v3d = CTX_wm_view3d(C); wmGesture *gesture = op->customdata; rcti *rect = gesture->customdata; - if (event->type == MOUSEMOVE) { + Object *obedit = CTX_data_edit_object(C); + ToolSettings *ts = win->scene->toolsettings; + if (event->type == MOUSEMOVE) { rect->xmin = event->xy[0] - gesture->winrct.xmin; rect->ymin = event->xy[1] - gesture->winrct.ymin; @@ -415,6 +490,9 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event) } if (is_finished) { + if (ts->auto_xray_reset) { + gesture_toggle_xray(C); + } gesture_modal_end(C, op); return OPERATOR_FINISHED; /* use finish or we don't get an undo */ } @@ -477,7 +555,31 @@ void WM_OT_circle_gesture(wmOperatorType *ot) int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + View3D *v3d = CTX_wm_view3d(C); PropertyRNA *prop; + Object *obedit = CTX_data_edit_object(C); + ToolSettings *ts = win->scene->toolsettings; + + bool auto_xray = false; + if (U.drag_select_control & USER_DRAG_SELECT_KEYMAP) { + const int auto_xray_int = RNA_enum_get(op->ptr, "auto_xray"); + auto_xray = obedit ? auto_xray_int > 2 : auto_xray_int == 2 || auto_xray_int == 8; + } + else { + auto_xray = ts->auto_xray && ts->auto_xray_lasso ? + obedit ? ts->auto_xray_edit : ts->auto_xray_object : + false; + } + + if (ts->auto_xray_reset) { + ts->auto_xray_reset ^= true; + } + + if (v3d && auto_xray) { + if (!XRAY_FLAG_ENABLED(v3d)) { + gesture_toggle_xray(C); + } + } op->customdata = WM_gesture_new(win, CTX_wm_region(C), event, WM_GESTURE_LASSO); @@ -517,6 +619,10 @@ static int gesture_lasso_apply(bContext *C, wmOperator *op) int retval = OPERATOR_FINISHED; wmGesture *gesture = op->customdata; PointerRNA itemptr; + View3D *v3d = CTX_wm_view3d(C); + Object *obedit = CTX_data_edit_object(C); + wmWindow *win = CTX_wm_window(C); + ToolSettings *ts = win->scene->toolsettings; float loc[2]; int i; const short *lasso = gesture->customdata; @@ -538,12 +644,20 @@ static int gesture_lasso_apply(bContext *C, wmOperator *op) OPERATOR_RETVAL_CHECK(retval); } + if (ts->auto_xray_reset) { + gesture_toggle_xray(C); + } + return retval; } int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmGesture *gesture = op->customdata; + View3D *v3d = CTX_wm_view3d(C); + Object *obedit = CTX_data_edit_object(C); + wmWindow *win = CTX_wm_window(C); + ToolSettings *ts = win->scene->toolsettings; if (event->type == EVT_MODAL_MAP) { switch (event->val) { @@ -597,6 +711,9 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event) break; } case EVT_ESCKEY: { + if (ts->auto_xray_reset) { + gesture_toggle_xray(C); + } gesture_modal_end(C, op); return OPERATOR_CANCELLED; } diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index 5ff12a9c250..9086441c99b 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -456,12 +456,44 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem auto_xray_items[] = { + {AUTO_XRAY_DISABLE, "AUTO_XRAY_DISABLE", 0, "Disable", "Disable Automatic X-Ray"}, + {AUTO_XRAY_OBJECT, + "AUTO_XRAY_OBJECT", + 0, + "Object", + "Enable X-Ray during box select in object mode"}, + {AUTO_XRAY_EDIT, "AUTO_XRAY_EDIT", 0, "Edit", "Enable X-Ray during box select in edit mode"}, + {AUTO_XRAY_BOTH, + "AUTO_XRAY_BOTH", + 0, + "Both", + "Enable X-Ray during box select in object and edit mode"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem select_through_items[] = { + {SELECT_THROUGH_OBJECT, "SELECT_THROUGH_OBJECT", 0, "Object", "Select occluded objects"}, + {SELECT_THROUGH_EDIT, "SELECT_THROUGH_EDIT", 0, "Edit", "Select occluded mesh elements"}, + {SELECT_THROUGH_BOTH, + "SELECT_THROUGH_BOTH", + 0, + "Both", + "Select occluded objects and mesh elements"}, + {SELECT_THROUGH_DISABLE, "SELECT_THROUGH_DISABLE", 0, "Disable", "Disable Select Through"}, + {0, NULL, 0, NULL, NULL}, + }; + WM_operator_properties_border(ot); prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "auto_xray", auto_xray_items, 0, "Automatic X-Ray", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "select_through", select_through_items, 0, "Select Through", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); if (deselect) { prop = RNA_def_boolean( @@ -614,10 +646,49 @@ void WM_operator_properties_gesture_lasso(wmOperatorType *ot) "Select edges that are fully inside the selection area"}, {0, NULL, 0, NULL, NULL}, }; + + static const EnumPropertyItem auto_xray_items[] = { + {AUTO_XRAY_DISABLE, "AUTO_XRAY_DISABLE", 0, "Disable", "Disable Automatic X-Ray"}, + {AUTO_XRAY_OBJECT, + "AUTO_XRAY_OBJECT", + 0, + "Object", + "Enable X-Ray during lasso select in object mode"}, + {AUTO_XRAY_EDIT, + "AUTO_XRAY_EDIT", + 0, + "Edit", + "Enable X-Ray during lasso select in edit mode"}, + {AUTO_XRAY_BOTH, + "AUTO_XRAY_BOTH", + 0, + "Both", + "Enable X-Ray during lasso select in object and edit mode"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem select_through_items[] = { + {SELECT_THROUGH_OBJECT, "SELECT_THROUGH_OBJECT", 0, "Object", "Select occluded objects"}, + {SELECT_THROUGH_EDIT, "SELECT_THROUGH_EDIT", 0, "Edit", "Select occluded mesh elements"}, + {SELECT_THROUGH_BOTH, + "SELECT_THROUGH_BOTH", + 0, + "Both", + "Select occluded objects and mesh elements"}, + {SELECT_THROUGH_DISABLE, "SELECT_THROUGH_DISABLE", 0, "Disable", "Disable Select Through"}, + {0, NULL, 0, NULL, NULL}, + }; + + WM_operator_properties_border(ot); + prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "auto_xray", auto_xray_items, 0, "Automatic X-Ray", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "select_through", select_through_items, 0, "Select Through", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } @@ -695,6 +766,42 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem auto_xray_items[] = { + {AUTO_XRAY_DISABLE, "AUTO_XRAY_DISABLE", 0, "Disable", "Disable Automatic X-Ray"}, + {AUTO_XRAY_OBJECT, + "AUTO_XRAY_OBJECT", + 0, + "Object", + "Enable X-Ray during circle select in object mode"}, + {AUTO_XRAY_EDIT, "AUTO_XRAY_EDIT", 0, "Edit", "Enable X-Ray during circle select in edit mode"}, + {AUTO_XRAY_BOTH, + "AUTO_XRAY_BOTH", + 0, + "Both", + "Enable X-Ray during circle select in object and edit mode"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem select_through_items[] = { + {SELECT_THROUGH_OBJECT, + "SELECT_THROUGH_OBJECT", + 0, + "Object", + "Select occluded objects"}, + {SELECT_THROUGH_EDIT, + "SELECT_THROUGH_EDIT", + 0, + "Edit", + "Select occluded mesh elements"}, + {SELECT_THROUGH_BOTH, + "SELECT_THROUGH_BOTH", + 0, + "Both", + "Select occluded objects and mesh elements"}, + {SELECT_THROUGH_DISABLE, "SELECT_THROUGH_DISABLE", 0, "Disable", "Disable Select Through"}, + {0, NULL, 0, NULL, NULL}, + }; + prop = RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); @@ -708,6 +815,10 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "auto_xray", auto_xray_items, 0, "Automatic X-Ray", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "select_through", select_through_items, 0, "Select Through", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } void WM_operator_properties_mouse_select(wmOperatorType *ot) -- 2.30.2 From d7565873f9082785eec2085d5816e90f41104837 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Wed, 5 Apr 2023 02:22:50 -0700 Subject: [PATCH 05/20] cleanup view3d_select --- .../editors/space_view3d/view3d_select.cc | 419 +++++++++--------- 1 file changed, 216 insertions(+), 203 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index e45a7492dc1..1ad7ed98aee 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -287,6 +287,189 @@ struct CircleSelectUserData { bool is_changed; }; +int edbm_select_style(ToolSettings *ts, int style[2], const bool box, const bool lasso, wmOperator *op) +{ + if (U.drag_select_control & USER_DRAG_SELECT_KEYMAP) { + style[0] = RNA_enum_get(op->ptr, "edge_type"); + style[1] = RNA_enum_get(op->ptr, "face_type"); + } + else { + if (box) { + if (ts->box_drag_direction > 1) { + if (ts->box_drag_direction == 2) { + if (ts->box_direction_upright) { + style[0] = ts->box_edge_right; + style[1] = ts->box_face_right; + } + else { + style[0] = ts->box_edge_left; + style[1] = ts->box_face_left; + } + } + else if (ts->box_direction_upright) { + style[0] = ts->box_edge_up; + style[1] = ts->box_face_up; + } + else { + style[0] = ts->box_edge_down; + style[1] = ts->box_face_down; + } + } + else { + style[0] = ts->box_edge; + style[1] = ts->box_face; + } + } + else if (lasso) { + if (ts->lasso_drag_direction > 1) { + if (ts->lasso_drag_direction == 2) { + if (ts->lasso_direction_upright) { + style[0] = ts->lasso_edge_right; + style[1] = ts->lasso_face_right; + } + else { + style[0] = ts->lasso_edge_left; + style[1] = ts->lasso_face_left; + } + } + else if (ts->lasso_direction_upright) { + style[0] = ts->lasso_edge_up; + style[1] = ts->lasso_face_up; + } + else { + style[0] = ts->lasso_edge_down; + style[1] = ts->lasso_face_down; + } + } + else { + style[0] = ts->lasso_edge; + style[1] = ts->lasso_face; + } + } + else { + style[0] = ts->circle_edge; + style[1] = ts->circle_face; + } + } + return style[2]; +} + +bool edbm_circle_enclose_edge(BMEdge *eed, struct CircleSelectUserData *data) +{ + BMVert *eve; + BMIter iter; + bool enclose_edge = false; + BM_ITER_ELEM (eve, &iter, eed, BM_VERTS_OF_EDGE) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose_edge = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; + if (!enclose_edge) { + break; + } + } + return enclose_edge; +} + +bool edbm_circle_enclose_face(ViewContext *vc, BMFace *efa, struct CircleSelectUserData *data) +{ + BMVert *eve; + BMIter iter; + bool enclose_face = false; + + BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose_face = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; + if (!enclose_face) { + break; + } + } + return enclose_face; +} + +bool edbm_center_face(ViewContext *vc, + BMFace *efa, + const rcti *rect, + struct LassoSelectUserData *lassoData, + struct CircleSelectUserData *circleData) +{ + BMVert *eve; + BMIter iter; + rctf rectf; + float centerv3[3] = {0.0f, 0.0f, 0.0f}; + float centerv2[2] = {0.0f, 0.0f}; + bool center_face = false; + + if (rect != NULL) { + BLI_rctf_rcti_copy(&rectf, rect); + } + + /* tri */ + if (efa->len == 3) { + float tri_vco[3][3] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + int tri_index = 0; + BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { + tri_vco[tri_index][0] = eve->co[0]; + tri_vco[tri_index][1] = eve->co[1]; + tri_vco[tri_index][2] = eve->co[2]; + tri_index++; + } + float triv1[3] = {tri_vco[0][0], tri_vco[0][1], tri_vco[0][2]}; + float triv2[3] = {tri_vco[1][0], tri_vco[1][1], tri_vco[1][2]}; + float triv3[3] = {tri_vco[2][0], tri_vco[2][1], tri_vco[2][2]}; + mid_v3_v3v3v3(centerv3, triv1, triv2, triv3); + } + /* quad */ + else if (efa->len == 4) { + float quad_vco[4][3] = { + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; + int quad_index = 0; + BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { + quad_vco[quad_index][0] = eve->co[0]; + quad_vco[quad_index][1] = eve->co[1]; + quad_vco[quad_index][2] = eve->co[2]; + quad_index++; + } + float quadv1[3] = {quad_vco[0][0], quad_vco[0][1], quad_vco[0][2]}; + float quadv2[3] = {quad_vco[1][0], quad_vco[1][1], quad_vco[1][2]}; + float quadv3[3] = {quad_vco[2][0], quad_vco[2][1], quad_vco[2][2]}; + float quadv4[3] = {quad_vco[3][0], quad_vco[3][1], quad_vco[3][2]}; + mid_v3_v3v3v3v3(centerv3, quadv1, quadv2, quadv3, quadv4); + } + /* ngon */ + else { + const float w = 1.0f / (float)efa->len; + BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { + madd_v3_v3fl(centerv3, eve->co, w); + } + } + ED_view3d_project_float_object( + vc->region, centerv3, centerv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + + /* lasso center */ + if (lassoData != NULL) { + center_face = BLI_rctf_isect_pt_v(&rectf, centerv2) && + BLI_lasso_is_point_inside(lassoData->mcoords, + lassoData->mcoords_len, + centerv2[0], + centerv2[1], + IS_CLIPPED); + } + /* circle center */ + else if (circleData != NULL) { + center_face = (len_squared_v2v2(circleData->mval_fl, centerv2) <= circleData->radius_squared); + } + /* box center */ + else { + center_face = BLI_rctf_isect_pt_v(&rectf, centerv2); + } + return center_face; +} + static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, @@ -345,18 +528,9 @@ static bool edbm_backbuf_check_and_select_edges(void *userData, const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); bool enclose_edge = true; - /* enclose edge */ - if (style == 4 && is_inside) { - BM_ITER_ELEM (eve, &viter, eed, BM_VERTS_OF_EDGE) { - float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; - float vertv2[2] = {0.0f, 0.0f}; - ED_view3d_project_float_object( - data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - enclose_edge = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; - if (!enclose_edge) { - break; - } - } + + if (data->edge_style == 4 && is_inside) { + enclose_edge = edbm_circle_enclose_edge(eed, data); } const int sel_op_result = ED_select_op_action_deselected( @@ -379,8 +553,8 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, const eSelectOp sel_op, const rcti *rect, const int face_style, - void *lassoData, - void *circleData) + void *ldata, + void *cdata) { BMIter iter, viter; BMFace *efa; @@ -389,11 +563,11 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, const BLI_bitmap *select_bitmap = esel->select_bitmap; rctf rectf; - LassoSelectUserData *ldata = static_cast(lassoData); - CircleSelectUserData *cdata = static_cast(circleData); + LassoSelectUserData *lassoData = static_cast(ldata); + CircleSelectUserData *circleData = static_cast(cdata); uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE); uint vindex = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX); - int style = face_style; + if (rect != NULL) { BLI_rctf_rcti_copy(&rectf, rect); } @@ -409,92 +583,22 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); bool enclose_face = true; bool center_face = true; - if (style > 2 && is_inside) { - /* enclose face */ - if (style == 4) { - BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { - /* circle enclose */ - if (cdata != NULL) { - float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; - float vertv2[2] = {0.0f, 0.0f}; - ED_view3d_project_float_object( - vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - enclose_face = len_squared_v2v2(cdata->mval_fl, vertv2) <= cdata->radius_squared; + if (face_style > 2 && is_inside) { + if (face_style == 4) { + if (circleData != NULL) { + enclose_face = edbm_circle_enclose_face(vc, efa, circleData); + } + else { + BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { + enclose_face = BLI_BITMAP_TEST_BOOL(select_bitmap, vindex + BM_elem_index_get(eve)); if (!enclose_face) { break; } } - /* box and lasso enclose */ - else { - if (!BLI_BITMAP_TEST_BOOL(select_bitmap, vindex + BM_elem_index_get(eve))) { - enclose_face = false; - break; - } - } } } - /* center face */ else { - float centerv3[3] = {0.0f, 0.0f, 0.0f}; - float centerv2[2] = {0.0f, 0.0f}; - /* tri */ - if (efa->len == 3) { - float tri_vco[3][3] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - int tri_index = 0; - BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { - tri_vco[tri_index][0] = eve->co[0]; - tri_vco[tri_index][1] = eve->co[1]; - tri_vco[tri_index][2] = eve->co[2]; - tri_index++; - } - float triv1[3] = {tri_vco[0][0], tri_vco[0][1], tri_vco[0][2]}; - float triv2[3] = {tri_vco[1][0], tri_vco[1][1], tri_vco[1][2]}; - float triv3[3] = {tri_vco[2][0], tri_vco[2][1], tri_vco[2][2]}; - mid_v3_v3v3v3(centerv3, triv1, triv2, triv3); - } - /* quad */ - else if (efa->len == 4) { - float quad_vco[4][3] = { - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; - int quad_index = 0; - BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { - quad_vco[quad_index][0] = eve->co[0]; - quad_vco[quad_index][1] = eve->co[1]; - quad_vco[quad_index][2] = eve->co[2]; - quad_index++; - } - float quadv1[3] = {quad_vco[0][0], quad_vco[0][1], quad_vco[0][2]}; - float quadv2[3] = {quad_vco[1][0], quad_vco[1][1], quad_vco[1][2]}; - float quadv3[3] = {quad_vco[2][0], quad_vco[2][1], quad_vco[2][2]}; - float quadv4[3] = {quad_vco[3][0], quad_vco[3][1], quad_vco[3][2]}; - mid_v3_v3v3v3v3(centerv3, quadv1, quadv2, quadv3, quadv4); - } - /* ngon */ - else { - const float w = 1.0f / (float)efa->len; - BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { - madd_v3_v3fl(centerv3, eve->co, w); - } - } - ED_view3d_project_float_object( - vc->region, centerv3, centerv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - /* lasso center */ - if (lassoData != NULL) { - center_face = BLI_rctf_isect_pt_v(&rectf, centerv2) && - BLI_lasso_is_point_inside(ldata->mcoords, - ldata->mcoords_len, - centerv2[0], - centerv2[1], - IS_CLIPPED); - } - /* circle center */ - else if (circleData != NULL) { - center_face = (len_squared_v2v2(cdata->mval_fl, centerv2) <= cdata->radius_squared); - } - /* box center */ - else { - center_face = BLI_rctf_isect_pt_v(&rectf, centerv2); - } + center_face = edbm_center_face(vc, efa, rect, lassoData, circleData); } } @@ -1223,46 +1327,17 @@ static bool do_lasso_select_mesh(ViewContext *vc, LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; rcti rect; + int select_style[2] = {0, 0}; /* set editmesh */ vc->em = BKE_editmesh_from_object(vc->obedit); BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - int edge_style, face_style; - if (U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING) { - if (ts->lasso_drag_direction > 1) { - if (ts->lasso_drag_direction == 2) { - if (ts->lasso_direction_upright) { - edge_style = ts->lasso_edge_right; - face_style = ts->lasso_face_right; - } - else { - edge_style = ts->lasso_edge_left; - face_style = ts->lasso_face_left; - } - } - else if (ts->lasso_direction_upright) { - edge_style = ts->lasso_edge_up; - face_style = ts->lasso_face_up; - } - else { - edge_style = ts->lasso_edge_down; - face_style = ts->lasso_face_down; - } - } - else { - edge_style = ts->lasso_edge; - face_style = ts->lasso_face; - } - } - else { - edge_style = RNA_enum_get(op->ptr, "edge_type"); - face_style = RNA_enum_get(op->ptr, "face_type"); - } + edbm_select_style(ts, select_style, false, true, op); view3d_userdata_lassoselect_init( - &data, vc, &rect, mcoords, mcoords_len, sel_op, edge_style, face_style); + &data, vc, &rect, mcoords, mcoords_len, sel_op, select_style[0], select_style[1]); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (vc->em->bm->totvertsel) { @@ -4071,40 +4146,11 @@ static bool do_mesh_box_select(ViewContext *vc, { BoxSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; + int select_style[2] = {0, 0}; - int edge_style, face_style; - if (U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING) { - if (ts->box_drag_direction > 1) { - if (ts->box_drag_direction == 2) { - if (ts->box_direction_upright) { - edge_style = ts->box_edge_right; - face_style = ts->box_face_right; - } - else { - edge_style = ts->box_edge_left; - face_style = ts->box_face_left; - } - } - else if (ts->box_direction_upright) { - edge_style = ts->box_edge_up; - face_style = ts->box_face_up; - } - else { - edge_style = ts->box_edge_down; - face_style = ts->box_face_down; - } - } - else { - edge_style = ts->box_edge; - face_style = ts->box_face; - } - } - else { - edge_style = RNA_enum_get(op->ptr, "edge_type"); - face_style = RNA_enum_get(op->ptr, "face_type"); - } + edbm_select_style(ts, select_style, true, false, op); - view3d_userdata_boxselect_init(&data, vc, rect, sel_op, edge_style, face_style); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op, select_style[0], select_style[1]); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (vc->em->bm->totvertsel) { @@ -4713,24 +4759,11 @@ static void mesh_circle_doSelectEdge(void *userData, int /*index*/) { CircleSelectUserData *data = static_cast(userData); - const int style = data->edge_style; - BMVert *eve; - BMIter iter; - + + bool enclose_edge = true; if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) { - bool enclose_edge = true; - /* enclose edge */ - if (style == 4) { - BM_ITER_ELEM (eve, &iter, eed, BM_VERTS_OF_EDGE) { - float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; - float vertv2[2] = {0.0f, 0.0f}; - ED_view3d_project_float_object( - data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - enclose_edge = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; - if (!enclose_edge) { - break; - } - } + if (data->edge_style == 4) { + enclose_edge = edbm_circle_enclose_edge(eed, data); } if (enclose_edge) { @@ -4748,15 +4781,13 @@ static void mesh_circle_doSelectFace(void *userData, bool *face_hit) { CircleSelectUserData *data = static_cast(userData); - BMIter iter; - BMVert *eve; - int style = data->face_style; if (!BLI_rctf_isect_circle(screen_rect, data->mval_fl, data->radius)) { return; } bool inside = false; + bool enclose_face = true; for (int i = 0; i < total_count; i++) { int a = i; @@ -4773,19 +4804,8 @@ static void mesh_circle_doSelectFace(void *userData, *face_hit = inside; - bool enclose_face = true; - /* enclose face */ - if (style == 4 && inside) { - BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { - float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; - float vertv2[2] = {0.0f, 0.0f}; - ED_view3d_project_float_object( - data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - enclose_face = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; - if (!enclose_face) { - break; - } - } + if (data->face_style == 4 && inside) { + enclose_face = edbm_circle_enclose_face(data->vc, efa, data); } if (inside && enclose_face) { @@ -4816,6 +4836,7 @@ static bool mesh_circle_select(ViewContext *vc, { ToolSettings *ts = vc->scene->toolsettings; CircleSelectUserData data; + int select_style[2] = {0, 0}; vc->em = BKE_editmesh_from_object(vc->obedit); bool changed = false; @@ -4832,17 +4853,9 @@ static bool mesh_circle_select(ViewContext *vc, ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ - int edge_style, face_style; - if (U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING) { - edge_style = ts->circle_edge; - face_style = ts->circle_face; - } - else { - edge_style = RNA_enum_get(op->ptr, "edge_type"); - face_style = RNA_enum_get(op->ptr, "face_type"); - } + edbm_select_style(ts, select_style, false, false, op); - view3d_userdata_circleselect_init(&data, vc, select, mval, rad, edge_style, face_style); + view3d_userdata_circleselect_init(&data, vc, select, mval, rad, select_style[0], select_style[1]); const int select_through_int = RNA_enum_get(op->ptr, "select_through"); const bool select_through = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? -- 2.30.2 From 02b3cdf50356c6f918af0cf15bb7e506db67f1e8 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Wed, 5 Apr 2023 06:23:53 -0700 Subject: [PATCH 06/20] add viewport-facing select --- scripts/startup/bl_ui/space_view3d_toolbar.py | 34 ++ .../blenloader/intern/versioning_defaults.cc | 6 + source/blender/editors/include/ED_transform.h | 5 +- .../editors/space_view3d/view3d_navigate.c | 2 +- .../editors/space_view3d/view3d_select.cc | 476 +++++++++++++++--- .../transform/transform_orientations.c | 120 ++++- source/blender/makesdna/DNA_scene_defaults.h | 6 + source/blender/makesdna/DNA_scene_types.h | 43 +- source/blender/makesrna/intern/rna_scene.c | 143 ++++++ 9 files changed, 738 insertions(+), 97 deletions(-) diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index 059c9e9255c..c9f0ed3ed9c 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -277,6 +277,39 @@ class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel): col.prop(tool_settings, "double_threshold", text="Threshold") +class VIEW3D_PT_tools_meshedit_options_viewport_facing_select(View3DPanel, Panel): + bl_category = "Tool" + bl_context = ".mesh_edit" # dot on purpose (access from topbar) + bl_label = "Viewport Facing Select" + bl_parent_id = "VIEW3D_PT_tools_meshedit_options" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return context.active_object + + def draw_header(self, context): + tool_settings = context.tool_settings + + self.layout.prop(tool_settings, "viewport_facing_select", text="", toggle=False) + + def draw(self, context): + layout = self.layout + + tool_settings = context.tool_settings + + layout.use_property_split = True + layout.use_property_decorate = False + + col = layout.column(align=True) + col.active = tool_settings.viewport_facing_select + col.prop(tool_settings, "viewport_facing_select_mode") + col.prop(tool_settings, "viewport_facing_select_threshold", text="Threshold") + col.prop(tool_settings, "viewport_facing_select_vert") + col.prop(tool_settings, "viewport_facing_select_edge") + col.prop(tool_settings, "viewport_facing_select_face") + + # ********** default tools for editmode_armature **************** @@ -2421,6 +2454,7 @@ classes = ( VIEW3D_PT_tools_object_options_transform, VIEW3D_PT_tools_meshedit_options, VIEW3D_PT_tools_meshedit_options_automerge, + VIEW3D_PT_tools_meshedit_options_viewport_facing_select, VIEW3D_PT_tools_armatureedit_options, VIEW3D_PT_tools_posemode_options, diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index cea068678cf..beb54e03346 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -412,6 +412,12 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) ts->select_through_box = true; ts->select_through_lasso = true; ts->select_through_circle = true; + + /* Viewport-Facing Select */ + ts->viewport_facing_select_mode = 1; + ts->viewport_facing_select_vert = 1; + ts->viewport_facing_select_edge = 1; + ts->viewport_facing_select_face = 1; } void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index d7fb108809f..b447630f98b 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -100,7 +100,10 @@ void ED_getTransformOrientationMatrix(const struct Scene *scene, struct Object *ob, struct Object *obedit, short around, - float r_orientation_mat[3][3]); + float r_orientation_mat[3][3], + struct BMVert *eve, + struct BMEdge *eed, + struct BMFace *efa); int BIF_countTransformOrientation(const struct bContext *C); diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c index 9f4710b28a0..b6c78c7bf72 100644 --- a/source/blender/editors/space_view3d/view3d_navigate.c +++ b/source/blender/editors/space_view3d/view3d_navigate.c @@ -1192,7 +1192,7 @@ static int view_axis_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); /* same as transform gizmo when normal is set */ ED_getTransformOrientationMatrix( - scene, view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat); + scene, view_layer, v3d, obact, obedit, V3D_AROUND_ACTIVE, twmat, NULL, NULL, NULL); align_quat = align_quat_buf; mat3_to_quat(align_quat, twmat); invert_qt_normalized(align_quat); diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 1ad7ed98aee..f304f177114 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -80,6 +80,7 @@ #include "ED_screen.h" #include "ED_sculpt.h" #include "ED_select_utils.h" +#include "ED_transform.h" #include "UI_interface.h" #include "UI_resources.h" @@ -248,6 +249,7 @@ struct BoxSelectUserData { eBezTriple_Flag select_flag; int edge_style; int face_style; + bool check_mesh_direction; /* runtime */ bool is_done; @@ -265,6 +267,7 @@ struct LassoSelectUserData { eBezTriple_Flag select_flag; int edge_style; int face_style; + bool check_mesh_direction; /* runtime */ int pass; @@ -282,11 +285,172 @@ struct CircleSelectUserData { eBezTriple_Flag select_flag; int edge_style; int face_style; + bool check_mesh_direction; /* runtime */ bool is_changed; }; +bool edbm_normal_facing_viewport(ViewContext *vc, + struct BMVert *eve, + struct BMEdge *eed, + struct BMFace *efa, + bool use_direction) +{ + ToolSettings *ts = vc->scene->toolsettings; + float meshmat[3][3]; + bool backface = false; + int direction = 0; + if (eve != NULL) { + ED_getTransformOrientationMatrix(vc->scene, + vc->view_layer, + vc->v3d, + vc->obact, + vc->obedit, + V3D_AROUND_ACTIVE, + meshmat, + eve, + NULL, + NULL); + direction = ts->viewport_facing_select_vert; + if (use_direction && (direction == 4 || direction == 8)) { + backface = true; + } + } + else if (eed != NULL) { + ED_getTransformOrientationMatrix(vc->scene, + vc->view_layer, + vc->v3d, + vc->obact, + vc->obedit, + V3D_AROUND_ACTIVE, + meshmat, + NULL, + eed, + NULL); + direction = ts->viewport_facing_select_edge; + if (use_direction && (direction == 4 || direction == 8)) { + backface = true; + } + } + else if (efa != NULL) { + ED_getTransformOrientationMatrix(vc->scene, + vc->view_layer, + vc->v3d, + vc->obact, + vc->obedit, + V3D_AROUND_ACTIVE, + meshmat, + NULL, + NULL, + efa); + direction = ts->viewport_facing_select_face; + if (use_direction && (direction == 4 || direction == 8)) { + backface = true; + } + } + normalize_m3(meshmat); + invert_m3(meshmat); + float meshcol3[3] = {0, 0, 0}; + meshcol3[0] = meshmat[0][2]; + meshcol3[1] = meshmat[1][2]; + meshcol3[2] = meshmat[2][2]; + float viewcol3[3] = {0, 0, 0}; + viewcol3[0] = vc->rv3d->viewmat[0][2]; + viewcol3[1] = vc->rv3d->viewmat[1][2]; + viewcol3[2] = vc->rv3d->viewmat[2][2]; + bool mesh_facing; + if (backface) { + mesh_facing = dot_v3v3(meshcol3, viewcol3) < -ts->viewport_facing_select_threshold; + } + else { + mesh_facing = dot_v3v3(meshcol3, viewcol3) > ts->viewport_facing_select_threshold; + } + return mesh_facing; +} + +bool edbm_facing_viewport_precheck(ToolSettings *ts, int style, bool xray) +{ + if (!ts->viewport_facing_select) { + return false; + } + const bool mode_match = xray ? ts->viewport_facing_select_mode == 1 || + ts->viewport_facing_select_mode == 4 : + ts->viewport_facing_select_mode < 4; + const bool check_mesh_facing = mode_match && style > 0 && style < 16; + return check_mesh_facing; +} + +bool edbm_facing_viewport(ViewContext *vc, BMVert *eve, BMEdge *eed, BMFace *efa, int style) +{ + BMIter iter; + bool mesh_facing = false; + if (eve != NULL) { + /* viewport-facing or rear-facing vert */ + mesh_facing = edbm_normal_facing_viewport(vc, eve, NULL, NULL, true); + if (!mesh_facing && eve->e && eve->e->l && (style == 2 || style == 8)) { + BM_ITER_ELEM (efa, &iter, eve, BM_FACES_OF_VERT) { + const bool eve_efa_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, false); + /* vert of a viewport-facing face */ + if (style == 2) { + if (eve_efa_facing) { + mesh_facing = true; + break; + } + } + /* vert of a rear-facing face */ + else if (!eve_efa_facing) { + mesh_facing = true; + break; + } + } + } + } + else if (eed != NULL) { + /* viewport-facing or rear-facing edge */ + mesh_facing = edbm_normal_facing_viewport(vc, NULL, eed, NULL, true); + if (!mesh_facing && eed->l && (style == 2 || style == 8)) { + BM_ITER_ELEM (efa, &iter, eed, BM_FACES_OF_EDGE) { + const bool eed_efa_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, false); + /* edge of a viewport-facing face */ + if (style == 2) { + if (eed_efa_facing) { + mesh_facing = true; + break; + } + } + /* edge of a rear-facing face */ + else if (!eed_efa_facing) { + mesh_facing = true; + break; + } + } + } + } + else if (efa != NULL) { + /* viewport-facing or rear-facing face */ + mesh_facing = edbm_normal_facing_viewport(vc, NULL, NULL, efa, true); + if (!mesh_facing && (style == 2 || style == 8)) { + BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { + const bool efa_eve_facing = edbm_normal_facing_viewport(vc, eve, NULL, NULL, false); + /* face has a viewport-facing vert */ + if (style == 2) { + if (efa_eve_facing) { + mesh_facing = true; + break; + } + } + /* face has a rear-facing vert */ + else if (!efa_eve_facing) { + mesh_facing = true; + break; + } + } + } + } + return mesh_facing; +} + int edbm_select_style(ToolSettings *ts, int style[2], const bool box, const bool lasso, wmOperator *op) { if (U.drag_select_control & USER_DRAG_SELECT_KEYMAP) { @@ -470,15 +634,21 @@ bool edbm_center_face(ViewContext *vc, return center_face; } -static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel, + + +static bool edbm_backbuf_check_and_select_verts(ViewContext *vc, + EditSelectBuf_Cache *esel, Depsgraph *depsgraph, Object *ob, BMEditMesh *em, const eSelectOp sel_op) { + ToolSettings *ts = vc->scene->toolsettings; BMVert *eve; BMIter iter; bool changed = false; + const int style = ts->viewport_facing_select_vert; + const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false); const BLI_bitmap *select_bitmap = esel->select_bitmap; uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX); @@ -491,7 +661,12 @@ static bool edbm_backbuf_check_and_select_verts(EditSelectBuf_Cache *esel, if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); - const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + bool mesh_facing = true; + if (is_inside && check_mesh_facing) { + mesh_facing = edbm_facing_viewport(vc, eve, NULL, NULL, style); + } + const int sel_op_result = ED_select_op_action_deselected( + sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_vert_select_set(em->bm, eve, sel_op_result); changed = true; @@ -510,11 +685,12 @@ static bool edbm_backbuf_check_and_select_edges(void *userData, const eSelectOp sel_op) { CircleSelectUserData *data = static_cast(userData); + ToolSettings *ts = data->vc->scene->toolsettings; BMEdge *eed; - BMVert *eve; - BMIter iter, viter; + BMIter iter; bool changed = false; - int style = data->edge_style; + const int style = ts->viewport_facing_select_edge; + const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false); const BLI_bitmap *select_bitmap = esel->select_bitmap; uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_EDGE); @@ -528,13 +704,18 @@ static bool edbm_backbuf_check_and_select_edges(void *userData, const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); bool enclose_edge = true; + bool mesh_facing = true; if (data->edge_style == 4 && is_inside) { enclose_edge = edbm_circle_enclose_edge(eed, data); } + if (check_mesh_facing && is_inside) { + mesh_facing = edbm_facing_viewport(data->vc, NULL, eed, NULL, style); + } + const int sel_op_result = ED_select_op_action_deselected( - sel_op, is_select, is_inside && enclose_edge); + sel_op, is_select, is_inside && enclose_edge && mesh_facing); if (sel_op_result != -1) { BM_edge_select_set(em->bm, eed, sel_op_result); changed = true; @@ -556,10 +737,13 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, void *ldata, void *cdata) { + ToolSettings *ts = vc->scene->toolsettings; BMIter iter, viter; BMFace *efa; BMVert *eve; bool changed = false; + const int style = ts->viewport_facing_select_face; + const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false); const BLI_bitmap *select_bitmap = esel->select_bitmap; rctf rectf; @@ -583,6 +767,8 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, const bool is_inside = BLI_BITMAP_TEST_BOOL(select_bitmap, index); bool enclose_face = true; bool center_face = true; + bool mesh_facing = true; + if (face_style > 2 && is_inside) { if (face_style == 4) { if (circleData != NULL) { @@ -602,8 +788,12 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, } } + if (check_mesh_facing && is_inside) { + mesh_facing = edbm_facing_viewport(vc, NULL, NULL, efa, style); + } + const int sel_op_result = ED_select_op_action_deselected( - sel_op, is_select, is_inside && enclose_face && center_face); + sel_op, is_select, is_inside && enclose_face && center_face && mesh_facing); if (sel_op_result != -1) { BM_face_select_set(em->bm, efa, sel_op_result); changed = true; @@ -704,6 +894,7 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->select_flag = (eBezTriple_Flag)SELECT; r_data->edge_style = edge_style; r_data->face_style = face_style; + r_data->check_mesh_direction = false; /* runtime */ r_data->pass = 0; @@ -1165,7 +1356,15 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && BLI_lasso_is_point_inside( data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + bool mesh_facing = true; + + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); data->is_changed = true; @@ -1186,6 +1385,7 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, user_data); LassoSelectUserData *data = data_for_edge->data; bool is_visible = true; + bool mesh_facing = true; if (data_for_edge->backbuf_offset) { uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1; is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx); @@ -1198,7 +1398,14 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) && BLI_lasso_is_point_inside( data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED)); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); data->is_done = true; @@ -1215,6 +1422,7 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, user_data); LassoSelectUserData *data = data_for_edge->data; bool is_visible = true; + bool mesh_facing = true; if (data_for_edge->backbuf_offset) { uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1; is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx); @@ -1227,7 +1435,14 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, UNPACK2(screen_co_b), IS_CLIPPED, false)); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); data->is_changed = true; @@ -1245,7 +1460,15 @@ static void do_lasso_select_mesh__doSelectFaceCenter(void *userData, (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && BLI_lasso_is_point_inside( data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + bool mesh_facing = true; + + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_face_select_set(data->vc->em->bm, efa, sel_op_result); data->is_changed = true; @@ -1259,7 +1482,6 @@ static void do_lasso_select_mesh__doSelectFace(void *user_data, rctf *screen_rect, bool *face_hit) { - LassoSelectUserData *data = static_cast(user_data); int style = data->face_style; @@ -1267,6 +1489,7 @@ static void do_lasso_select_mesh__doSelectFace(void *user_data, return; bool inside = false; + bool mesh_facing = true; for (int i = 0; i < total_count; i++) { int a = i; @@ -1309,7 +1532,13 @@ static void do_lasso_select_mesh__doSelectFace(void *user_data, *face_hit = inside; const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside); + + if (inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face); + } + + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside && mesh_facing); if (sel_op_result != -1) { BM_face_select_set(data->vc->em->bm, efa, sel_op_result); @@ -1379,9 +1608,12 @@ static bool do_lasso_select_mesh(ViewContext *vc, if (ts->selectmode & SCE_SELECT_VERTEX) { if (use_zbuf) { data.is_changed |= edbm_backbuf_check_and_select_verts( - esel, vc->depsgraph, vc->obedit, vc->em, sel_op); + vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op); } else { + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_vert, true); + mesh_foreachScreenVert( vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } @@ -1397,6 +1629,13 @@ static bool do_lasso_select_mesh(ViewContext *vc, const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB); + + data.check_mesh_direction = use_zbuf ? + edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_edge, false) : + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_edge, true); + /* Fully inside, hybrid and enclose edge */ if (data.edge_style != 2) { mesh_foreachScreenEdge_clip_bb_segment( @@ -1412,22 +1651,7 @@ static bool do_lasso_select_mesh(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_FACE) { - /* xray center and auto face with fallback for touch and enclose intersect */ - if (!use_zbuf && - (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op))) { - mesh_foreachScreenFaceCenter( - vc, do_lasso_select_mesh__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - } - /* xray touch and enclose face */ - else if (!use_zbuf) { - /* works for everything except intersect for some reason */ - mesh_foreachScreenFaceVerts(vc, - do_lasso_select_mesh__doSelectFace, - &data, - V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - } - /* near face */ - else { + if (use_zbuf) { data.is_changed |= edbm_backbuf_check_and_select_faces(vc, esel, vc->depsgraph, @@ -1439,6 +1663,23 @@ static bool do_lasso_select_mesh(ViewContext *vc, &data, NULL); } + else { + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_face, true); + + /* xray center and auto face with fallback for touch and enclose intersect */ + if (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op)) { + mesh_foreachScreenFaceCenter( + vc, do_lasso_select_mesh__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + } + /* xray touch and enclose face - doesn't work for intersect */ + else { + mesh_foreachScreenFaceVerts(vc, + do_lasso_select_mesh__doSelectFace, + &data, + V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + } + } } if (data.is_changed) { @@ -3771,6 +4012,7 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data, r_data->select_flag = (eBezTriple_Flag)SELECT; r_data->edge_style = edge_style; r_data->face_style = face_style; + r_data->check_mesh_direction = false; /* runtime */ r_data->is_done = false; @@ -4012,7 +4254,15 @@ static void do_mesh_box_select__doSelectVert(void *userData, BoxSelectUserData *data = static_cast(userData); const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + + bool mesh_facing = true; + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); data->is_changed = true; @@ -4033,6 +4283,7 @@ static void do_mesh_box_select__doSelectEdge_pass0( userData); BoxSelectUserData *data = data_for_edge->data; bool is_visible = true; + bool mesh_facing = true; if (data_for_edge->backbuf_offset) { uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1; is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx); @@ -4041,7 +4292,14 @@ static void do_mesh_box_select__doSelectEdge_pass0( const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); data->is_done = true; @@ -4058,6 +4316,7 @@ static void do_mesh_box_select__doSelectEdge_pass1( userData); BoxSelectUserData *data = data_for_edge->data; bool is_visible = true; + bool mesh_facing = true; if (data_for_edge->backbuf_offset) { uint bitmap_inedx = data_for_edge->backbuf_offset + index - 1; is_visible = BLI_BITMAP_TEST_BOOL(data_for_edge->esel->select_bitmap, bitmap_inedx); @@ -4065,7 +4324,14 @@ static void do_mesh_box_select__doSelectEdge_pass1( const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = (is_visible && edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); data->is_changed = true; @@ -4080,19 +4346,19 @@ static void do_mesh_box_select__doSelectFace(void *userData, bool *face_hit) { BoxSelectUserData *data = static_cast(userData); - int style = data->face_style; if (!BLI_rctf_isect(data->rect_fl, screen_rect, NULL)) return; bool inside = false; + bool mesh_facing = true; for (int i = 0; i < total_count; i++) { int a = i; int b = (i + 1) % total_count; /* enclose */ - if (style == 4) { + if (data->face_style == 4) { inside = edge_fully_inside_rect(data->rect_fl, screen_co[a], screen_co[b]); if (!inside) { break; @@ -4108,7 +4374,7 @@ static void do_mesh_box_select__doSelectFace(void *userData, } /* touch interior of face */ - if (style == 2 && !inside) { + if (data->face_style == 2 && !inside) { float point[2] = {data->rect_fl->xmax, data->rect_fl->ymax}; inside = isect_point_poly_v2(point, screen_co, total_count, true); } @@ -4116,7 +4382,13 @@ static void do_mesh_box_select__doSelectFace(void *userData, *face_hit = inside; const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside); + + if (inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face); + } + + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, inside && mesh_facing); if (sel_op_result != -1) { BM_face_select_set(data->vc->em->bm, efa, sel_op_result); @@ -4132,7 +4404,15 @@ static void do_mesh_box_select__doSelectFaceCenter(void *userData, BoxSelectUserData *data = static_cast(userData); const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); - const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + bool mesh_facing = true; + + if (is_inside && data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face); + } + + const int sel_op_result = ED_select_op_action_deselected( + data->sel_op, is_select, is_inside && mesh_facing); if (sel_op_result != -1) { BM_face_select_set(data->vc->em->bm, efa, sel_op_result); data->is_changed = true; @@ -4192,9 +4472,12 @@ static bool do_mesh_box_select(ViewContext *vc, if (ts->selectmode & SCE_SELECT_VERTEX) { if (use_zbuf) { data.is_changed |= edbm_backbuf_check_and_select_verts( - esel, vc->depsgraph, vc->obedit, vc->em, sel_op); + vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op); } else { + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_vert, true); + mesh_foreachScreenVert( vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } @@ -4211,6 +4494,12 @@ static bool do_mesh_box_select(ViewContext *vc, const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_NEAR | (use_zbuf ? (eV3DProjTest)0 : V3D_PROJ_TEST_CLIP_BB); + + data.check_mesh_direction = use_zbuf ? + edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_edge, false) : + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_edge, true); /* Fully inside, hybrid and enclose edge */ if (data.edge_style != 2) { mesh_foreachScreenEdge_clip_bb_segment( @@ -4226,25 +4515,27 @@ static bool do_mesh_box_select(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_FACE) { - /* xray center and auto face with fallback for touch and enclose intersect */ - if (!use_zbuf && - (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op))) { - mesh_foreachScreenFaceCenter( - vc, do_mesh_box_select__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - } - /* xray touch and enclose face */ - else if (!use_zbuf) { - /* works for everything except intersect for some reason */ - mesh_foreachScreenFaceVerts(vc, - do_mesh_box_select__doSelectFace, - &data, - V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - } - /* near face */ - else { + if (use_zbuf) { data.is_changed |= edbm_backbuf_check_and_select_faces( vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, rect, data.face_style, NULL, NULL); } + else { + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_face, true); + + /* xray center and auto face with fallback for touch and enclose intersect */ + if (data.face_style == 1 || data.face_style == 8 || SEL_OP_USE_OUTSIDE(sel_op)) { + mesh_foreachScreenFaceCenter( + vc, do_mesh_box_select__doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + } + /* xray touch and enclose face - doesn't work with intersect */ + else { + mesh_foreachScreenFaceVerts(vc, + do_mesh_box_select__doSelectFace, + &data, + V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + } + } } if (data.is_changed) { @@ -4735,6 +5026,7 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data, r_data->select_flag = (eBezTriple_Flag)SELECT; r_data->edge_style = edge_style; r_data->face_style = face_style; + r_data->check_mesh_direction = false; /* runtime */ r_data->is_changed = false; @@ -4748,8 +5040,16 @@ static void mesh_circle_doSelectVert(void *userData, CircleSelectUserData *data = static_cast(userData); if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { - BM_vert_select_set(data->vc->em->bm, eve, data->select); + bool mesh_facing = true; data->is_changed = true; + if (data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, eve, NULL, NULL, data->vc->scene->toolsettings->viewport_facing_select_vert); + } + if (mesh_facing) { + BM_vert_select_set(data->vc->em->bm, eve, data->select); + data->is_changed = true; + } } } static void mesh_circle_doSelectEdge(void *userData, @@ -4761,12 +5061,18 @@ static void mesh_circle_doSelectEdge(void *userData, CircleSelectUserData *data = static_cast(userData); bool enclose_edge = true; + bool mesh_facing = true; if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) { if (data->edge_style == 4) { enclose_edge = edbm_circle_enclose_edge(eed, data); } - if (enclose_edge) { + if (data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, eed, NULL, data->vc->scene->toolsettings->viewport_facing_select_edge); + } + + if (enclose_edge && mesh_facing) { BM_edge_select_set(data->vc->em->bm, eed, data->select); data->is_changed = true; } @@ -4788,6 +5094,7 @@ static void mesh_circle_doSelectFace(void *userData, bool inside = false; bool enclose_face = true; + bool mesh_facing = true; for (int i = 0; i < total_count; i++) { int a = i; @@ -4808,7 +5115,12 @@ static void mesh_circle_doSelectFace(void *userData, enclose_face = edbm_circle_enclose_face(data->vc, efa, data); } - if (inside && enclose_face) { + if (data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face); + } + + if (inside && enclose_face && mesh_facing) { BM_face_select_set(data->vc->em->bm, efa, data->select); data->is_changed = true; } @@ -4820,10 +5132,18 @@ static void mesh_circle_doSelectFaceCenter(void *userData, int /*index*/) { CircleSelectUserData *data = static_cast(userData); + bool mesh_facing = true; if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { - BM_face_select_set(data->vc->em->bm, efa, data->select); - data->is_changed = true; + if (data->check_mesh_direction) { + mesh_facing = edbm_facing_viewport( + data->vc, NULL, NULL, efa, data->vc->scene->toolsettings->viewport_facing_select_face); + } + + if (mesh_facing) { + BM_face_select_set(data->vc->em->bm, efa, data->select); + data->is_changed = true; + } } } @@ -4882,10 +5202,13 @@ static bool mesh_circle_select(ViewContext *vc, if (use_zbuf) { if (esel->select_bitmap != nullptr) { changed |= edbm_backbuf_check_and_select_verts( - esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); + vc, esel, vc->depsgraph, vc->obedit, vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } } else { + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_vert, true); + mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } } @@ -4898,6 +5221,9 @@ static bool mesh_circle_select(ViewContext *vc, } } else { + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_edge, true); + mesh_foreachScreenEdge_clip_bb_segment( vc, mesh_circle_doSelectEdge, @@ -4907,18 +5233,7 @@ static bool mesh_circle_select(ViewContext *vc, } if (ts->selectmode & SCE_SELECT_FACE) { - /* xray center and auto face */ - if (!use_zbuf && (data.face_style == 1 || data.face_style == 8)) { - mesh_foreachScreenFaceCenter( - vc, mesh_circle_doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - } - /* xray touch and enclose face */ - else if (!use_zbuf) { - mesh_foreachScreenFaceVerts( - vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - } - /* near face */ - else { + if (use_zbuf) { if (esel->select_bitmap != NULL) { changed |= edbm_backbuf_check_and_select_faces(vc, esel, @@ -4932,6 +5247,21 @@ static bool mesh_circle_select(ViewContext *vc, &data); } } + else { + data.check_mesh_direction = edbm_facing_viewport_precheck( + ts, ts->viewport_facing_select_face, true); + + /* xray center and auto face */ + if (data.face_style == 1 || data.face_style == 8) { + mesh_foreachScreenFaceCenter( + vc, mesh_circle_doSelectFaceCenter, &data, V3D_PROJ_TEST_CLIP_DEFAULT); + } + /* xray touch and enclose face */ + else { + mesh_foreachScreenFaceVerts( + vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + } + } } changed |= data.is_changed; diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 0cf9d5fa309..5a067f0f7f9 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -516,7 +516,8 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, } case V3D_ORIENT_NORMAL: { if (obedit || (ob && ob->mode & OB_MODE_POSE)) { - ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); + ED_getTransformOrientationMatrix( + scene, view_layer, v3d, ob, obedit, pivot_point, r_mat, NULL, NULL, NULL); break; } /* No break we define 'normal' as 'local' in Object mode. */ @@ -529,7 +530,8 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, * use the active pones axis for display #33575, this works as expected on a single * bone and users who select many bones will understand what's going on and what local * means when they start transforming. */ - ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat); + ED_getTransformOrientationMatrix( + scene, view_layer, v3d, ob, obedit, pivot_point, r_mat, NULL, NULL, NULL); } else { transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world)); @@ -752,13 +754,18 @@ int getTransformOrientation_ex(const Scene *scene, struct Object *obedit, float normal[3], float plane[3], - const short around) + const short around, + struct BMVert *eve, + struct BMEdge *eed, + struct BMFace *efa) { int result = ORIENTATION_NONE; const bool activeOnly = (around == V3D_AROUND_ACTIVE); - zero_v3(normal); - zero_v3(plane); + if (efa == NULL && eed == NULL) { + zero_v3(normal); + zero_v3(plane); + } if (obedit) { float imat[3][3], mat[3][3]; @@ -777,20 +784,72 @@ int getTransformOrientation_ex(const Scene *scene, float vec[3] = {0, 0, 0}; /* USE LAST SELECTED WITH ACTIVE */ - if (activeOnly && BM_select_history_active_get(em->bm, &ese)) { - BM_editselection_normal(&ese, normal); - BM_editselection_plane(&ese, plane); + if (efa != NULL || eed != NULL || eve != NULL || + activeOnly && BM_select_history_active_get(em->bm, &ese)) { + if (efa != NULL) { + copy_v3_v3(normal, efa->no); + BM_face_calc_tangent_auto(efa, plane); + result = ORIENTATION_FACE; + } + else if (eed != NULL) { + float eed_plane[3]; + float vec[3]; + add_v3_v3v3(normal, eed->v1->no, eed->v2->no); + sub_v3_v3v3(eed_plane, eed->v2->co, eed->v1->co); + cross_v3_v3v3(vec, normal, eed_plane); + cross_v3_v3v3(normal, eed_plane, vec); + normalize_v3(normal); - switch (ese.htype) { - case BM_VERT: - result = ORIENTATION_VERT; - break; - case BM_EDGE: - result = ORIENTATION_EDGE; - break; - case BM_FACE: - result = ORIENTATION_FACE; - break; + if (BM_edge_is_boundary(eed)) { + sub_v3_v3v3(plane, eed->l->v->co, eed->l->next->v->co); + } + else { + if (eed->v2->co[1] > eed->v1->co[1]) { + sub_v3_v3v3(plane, eed->v2->co, eed->v1->co); + } + else { + sub_v3_v3v3(plane, eed->v1->co, eed->v2->co); + } + } + normalize_v3(plane); + result = ORIENTATION_EDGE; + } + else if (eve != NULL) { + copy_v3_v3(normal, eve->no); + if (eve->e) { + float vert1v3[3] = {eve->e->v1->co[0], eve->e->v1->co[1], eve->e->v1->co[2]}; + float vert2v3[3] = {eve->e->v2->co[0], eve->e->v2->co[1], eve->e->v2->co[2]}; + sub_v3_v3v3(plane, vert2v3, vert1v3); + } + else { + if (eve->no[0] < 0.5f) { + vec[0] = 1.0f; + } + else if (eve->no[1] < 0.5f) { + vec[1] = 1.0f; + } + else { + vec[2] = 1.0f; + } + cross_v3_v3v3(plane, eve->no, vec); + } + normalize_v3(plane); + result = ORIENTATION_VERT; + } + else { + BM_editselection_normal(&ese, normal); + BM_editselection_plane(&ese, plane); + switch (ese.htype) { + case BM_VERT: + result = ORIENTATION_VERT; + break; + case BM_EDGE: + result = ORIENTATION_EDGE; + break; + case BM_FACE: + result = ORIENTATION_FACE; + break; + } } } else { @@ -1289,7 +1348,8 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3]) ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); - return getTransformOrientation_ex(scene, view_layer, v3d, obact, obedit, normal, plane, around); + return getTransformOrientation_ex( + scene, view_layer, v3d, obact, obedit, normal, plane, around, NULL, NULL, NULL); } void ED_getTransformOrientationMatrix(const Scene *scene, @@ -1298,14 +1358,32 @@ void ED_getTransformOrientationMatrix(const Scene *scene, Object *ob, Object *obedit, const short around, - float r_orientation_mat[3][3]) + float r_orientation_mat[3][3], + struct BMVert *eve, + struct BMEdge *eed, + struct BMFace *efa) { float normal[3] = {0.0, 0.0, 0.0}; float plane[3] = {0.0, 0.0, 0.0}; int type; - type = getTransformOrientation_ex(scene, view_layer, v3d, ob, obedit, normal, plane, around); + if (efa != NULL) { + type = getTransformOrientation_ex( + scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, NULL, efa); + } + else if (eed != NULL) { + type = getTransformOrientation_ex( + scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, eed, NULL); + } + else if (eve != NULL) { + type = getTransformOrientation_ex( + scene, view_layer, v3d, ob, obedit, normal, plane, around, eve, NULL, NULL); + } + else { + type = getTransformOrientation_ex( + scene, view_layer, v3d, ob, obedit, normal, plane, around, NULL, NULL, NULL); + } /* Fallback, when the plane can't be calculated. */ if (ORIENTATION_USE_PLANE(type) && is_zero_v3(plane)) { diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index 05c50e19a32..8932413264d 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -405,6 +405,12 @@ .select_through_box = true, \ .select_through_lasso = true, \ .select_through_circle = true, \ + \ + /* Viewport-Facing Select */ \ + .viewport_facing_select_mode = 1, \ + .viewport_facing_select_vert = 1, \ + .viewport_facing_select_edge = 1, \ + .viewport_facing_select_face = 1, \ } /* clang-format off */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index aa90e3dd7c8..95e4bd546b5 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1578,7 +1578,14 @@ typedef struct ToolSettings { char select_through_box; char select_through_lasso; char select_through_circle; - char _pad0[1]; + + /* Mesh Normal Direction Select */ + char viewport_facing_select; + char viewport_facing_select_mode; + float viewport_facing_select_threshold; + char viewport_facing_select_vert; + char viewport_facing_select_edge; + char viewport_facing_select_face; /* Annotations. */ /** Stroke placement settings - 3D View. */ @@ -2380,6 +2387,40 @@ typedef enum eSnapTransformMode { SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2), } eSnapTransformMode; +/** #ToolSettings.viewport_facing_mode */ +enum { + VIEWPORT_FACING_SELECT_BOTH = (1 << 0), + VIEWPORT_FACING_SELECT_NEAR = (1 << 1), + VIEWPORT_FACING_SELECT_XRAY = (1 << 2), +}; + +/** #ToolSettings.viewport_facing_select_vert */ +enum { + VIEWPORT_FACING_SELECT_FRONT_VERTS = (1 << 0), + VIEWPORT_FACING_SELECT_FRONT_VERTS_FACE = (1 << 1), + VIEWPORT_FACING_SELECT_REAR_VERTS = (1 << 2), + VIEWPORT_FACING_SELECT_REAR_VERTS_FACE = (1 << 3), + VIEWPORT_FACING_SELECT_ALL_VERTS = (1 << 4), +}; + +/** #ToolSettings.viewport_facing_select_edge */ +enum { + VIEWPORT_FACING_SELECT_FRONT_EDGES = (1 << 0), + VIEWPORT_FACING_SELECT_FRONT_EDGES_FACE = (1 << 1), + VIEWPORT_FACING_SELECT_REAR_EDGES = (1 << 2), + VIEWPORT_FACING_SELECT_REAR_EDGES_FACE = (1 << 3), + VIEWPORT_FACING_SELECT_ALL_EDGES = (1 << 4), +}; + +/** #ToolSettings.viewport_facing_select_face */ +enum { + VIEWPORT_FACING_SELECT_FRONT_FACES = (1 << 0), + VIEWPORT_FACING_SELECT_FRONT_FACES_VERT = (1 << 1), + VIEWPORT_FACING_SELECT_REAR_FACES = (1 << 2), + VIEWPORT_FACING_SELECT_REAR_FACES_VERT = (1 << 3), + VIEWPORT_FACING_SELECT_ALL_FACES = (1 << 4), +}; + /** #ToolSettings.face_select */ enum { FACE_AUTO = (1 << 0), diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index cd3e8671575..d63c86306e3 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3123,10 +3123,153 @@ static void rna_def_tool_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem viewport_facing_select_mode_items[] = { + {VIEWPORT_FACING_SELECT_BOTH, + "BOTH", + 0, + "Near and X-Ray", + "Use viewport-facing selection in near select and X-Ray"}, + {VIEWPORT_FACING_SELECT_NEAR, + "NEAR", + 0, + "Near", + "Use viewport-facing selection in near select"}, + {VIEWPORT_FACING_SELECT_XRAY, + "XRAY", + 0, + "X-Ray", + "Use viewport-facing selection in X-Ray"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem viewport_facing_select_vert_items[] = { + {VIEWPORT_FACING_SELECT_FRONT_VERTS, + "FRONT_VERTS", + 0, + "Front Verts", + "Select vertices with viewport-facing normals"}, + {VIEWPORT_FACING_SELECT_FRONT_VERTS_FACE, + "FRONT_VERTS_FACE", + 0, + "Verts of Front Face", + "Select vertices if they are part of a face that has a viewport-facing normal"}, + {VIEWPORT_FACING_SELECT_REAR_VERTS, + "REAR_VERTS", + 0, + "Rear Verts", + "Select vertices without viewport-facing normals"}, + {VIEWPORT_FACING_SELECT_REAR_VERTS_FACE, + "REAR_VERTS_FACE", + 0, + "Verts of Rear Face", + "Select vertices if they are part of a face that does not have a viewport-facing normal"}, + {VIEWPORT_FACING_SELECT_ALL_VERTS, + "ALL_VERTS", + 0, + "All Verts", + "Select vertices regarless of their normal direction"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem viewport_facing_select_edge_items[] = { + {VIEWPORT_FACING_SELECT_FRONT_EDGES, + "FRONT_EDGES", + 0, + "Front Edges", + "Select edges with viewport-facing normals"}, + {VIEWPORT_FACING_SELECT_FRONT_EDGES_FACE, + "FRONT_EDGES_FACE", + 0, + "Edges of Front Face", + "Select edges if they are part of a face that has a viewport-facing normal"}, + {VIEWPORT_FACING_SELECT_REAR_EDGES, + "REAR_EDGES", + 0, + "Rear Edges", + "Select edges without viewport-facing normals"}, + {VIEWPORT_FACING_SELECT_REAR_EDGES_FACE, + "REAR_EDGES_FACE", + 0, + "Edges of Rear Face", + "Select edges if they are part of a face that does not have a viewport-facing normal"}, + {VIEWPORT_FACING_SELECT_ALL_EDGES, + "ALL_EDGES", + 0, + "All Edges", + "Select edges regarless of their normal direction"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem viewport_facing_select_face_items[] = { + {VIEWPORT_FACING_SELECT_FRONT_FACES, + "FRONT_FACES", + 0, + "Front Faces", + "Select faces with viewport-facing normals"}, + {VIEWPORT_FACING_SELECT_FRONT_FACES_VERT, + "FRONT_FACES_VERT", + 0, + "Faces of Front Vert", + "Select faces if they have a vertex with a viewport-facing normal"}, + {VIEWPORT_FACING_SELECT_REAR_FACES, + "REAR_FACES", + 0, + "Rear Faces", + "Select faces without viewport-facing normals"}, + {VIEWPORT_FACING_SELECT_REAR_FACES_VERT, + "REAR_FACES_VERT", + 0, + "Faces of Rear Vert", + "Select faces if they have a vertex without a viewport-facing normal"}, + {VIEWPORT_FACING_SELECT_ALL_FACES, + "ALL_FACES", + 0, + "All Faces", + "Select faces regarless of their normal direction"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "ToolSettings", NULL); RNA_def_struct_path_func(srna, "rna_ToolSettings_path"); RNA_def_struct_ui_text(srna, "Tool Settings", ""); + /* Viewport-Facing Select */ + prop = RNA_def_property(srna, "viewport_facing_select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "viewport_facing_select", 0); + RNA_def_property_ui_text( + prop, + "Viewport Facing Select", + "Filter box, lasso, and circle selection of mesh elements based on the direction of their " + "normals compared to the viewport"); + + prop = RNA_def_property(srna, "viewport_facing_select_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_mode"); + RNA_def_property_enum_items(prop, viewport_facing_select_mode_items); + RNA_def_property_ui_text(prop, "Mode", "Which selection modes to use viewport-facing selection"); + + prop = RNA_def_property(srna, "viewport_facing_select_vert", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_vert"); + RNA_def_property_enum_items(prop, viewport_facing_select_vert_items); + RNA_def_property_ui_text(prop, "Vert", "Direction and mode for vertices"); + + prop = RNA_def_property(srna, "viewport_facing_select_edge", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_edge"); + RNA_def_property_enum_items(prop, viewport_facing_select_edge_items); + RNA_def_property_ui_text(prop, "Edge", "Direction and mode for edges"); + + prop = RNA_def_property(srna, "viewport_facing_select_face", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "viewport_facing_select_face"); + RNA_def_property_enum_items(prop, viewport_facing_select_face_items); + RNA_def_property_ui_text(prop, "Face", "Direction and mode for faces"); + + prop = RNA_def_property(srna, "viewport_facing_select_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 1.0f, 2); + RNA_def_property_ui_text( + prop, + "Threshold", + "How close the angles of the viewport and mesh element need to be for selection to occur"); + /* Mesh select settings. */ prop = RNA_def_property(srna, "box_drag_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mesh_drag_direction_items); -- 2.30.2 From 974a9c9634f5410a8dadd30b6c498181d70ecaf1 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Wed, 5 Apr 2023 21:54:21 -0700 Subject: [PATCH 07/20] combine edbm_circle_enclose functions --- .../editors/space_view3d/view3d_select.cc | 86 ++++++++----------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index f304f177114..9ef0a3a50e3 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -518,60 +518,51 @@ int edbm_select_style(ToolSettings *ts, int style[2], const bool box, const bool return style[2]; } -bool edbm_circle_enclose_edge(BMEdge *eed, struct CircleSelectUserData *data) +bool edbm_circle_enclose_mesh(BMEdge *eed, BMFace *efa, struct CircleSelectUserData *data) { BMVert *eve; BMIter iter; - bool enclose_edge = false; - BM_ITER_ELEM (eve, &iter, eed, BM_VERTS_OF_EDGE) { - float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; - float vertv2[2] = {0.0f, 0.0f}; - ED_view3d_project_float_object( - data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - enclose_edge = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; - if (!enclose_edge) { - break; + bool enclose = false; + + if (eed != NULL) { + BM_ITER_ELEM (eve, &iter, eed, BM_VERTS_OF_EDGE) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; + if (!enclose) { + break; + } } } - return enclose_edge; -} - -bool edbm_circle_enclose_face(ViewContext *vc, BMFace *efa, struct CircleSelectUserData *data) -{ - BMVert *eve; - BMIter iter; - bool enclose_face = false; - - BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { - float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; - float vertv2[2] = {0.0f, 0.0f}; - ED_view3d_project_float_object( - vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); - enclose_face = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; - if (!enclose_face) { - break; + else if (efa != NULL) { + BM_ITER_ELEM (eve, &iter, efa, BM_VERTS_OF_FACE) { + float vertv3[3] = {eve->co[0], eve->co[1], eve->co[2]}; + float vertv2[2] = {0.0f, 0.0f}; + ED_view3d_project_float_object( + data->vc->region, vertv3, vertv2, V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_BB); + enclose = len_squared_v2v2(data->mval_fl, vertv2) <= data->radius_squared; + if (!enclose) { + break; + } } } - return enclose_face; + return enclose; } bool edbm_center_face(ViewContext *vc, BMFace *efa, - const rcti *rect, + const rctf *rect, struct LassoSelectUserData *lassoData, struct CircleSelectUserData *circleData) { BMVert *eve; BMIter iter; - rctf rectf; float centerv3[3] = {0.0f, 0.0f, 0.0f}; float centerv2[2] = {0.0f, 0.0f}; bool center_face = false; - if (rect != NULL) { - BLI_rctf_rcti_copy(&rectf, rect); - } - /* tri */ if (efa->len == 3) { float tri_vco[3][3] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; @@ -616,7 +607,7 @@ bool edbm_center_face(ViewContext *vc, /* lasso center */ if (lassoData != NULL) { - center_face = BLI_rctf_isect_pt_v(&rectf, centerv2) && + center_face = BLI_rctf_isect_pt_v(rect, centerv2) && BLI_lasso_is_point_inside(lassoData->mcoords, lassoData->mcoords_len, centerv2[0], @@ -629,7 +620,7 @@ bool edbm_center_face(ViewContext *vc, } /* box center */ else { - center_face = BLI_rctf_isect_pt_v(&rectf, centerv2); + center_face = BLI_rctf_isect_pt_v(rect, centerv2); } return center_face; } @@ -707,7 +698,7 @@ static bool edbm_backbuf_check_and_select_edges(void *userData, bool mesh_facing = true; if (data->edge_style == 4 && is_inside) { - enclose_edge = edbm_circle_enclose_edge(eed, data); + enclose_edge = edbm_circle_enclose_mesh(eed, NULL, data); } if (check_mesh_facing && is_inside) { @@ -732,7 +723,7 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, Object *ob, BMEditMesh *em, const eSelectOp sel_op, - const rcti *rect, + const rctf *rect, const int face_style, void *ldata, void *cdata) @@ -744,17 +735,12 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, bool changed = false; const int style = ts->viewport_facing_select_face; const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false); - const BLI_bitmap *select_bitmap = esel->select_bitmap; - rctf rectf; LassoSelectUserData *lassoData = static_cast(ldata); CircleSelectUserData *circleData = static_cast(cdata); uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE); uint vindex = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX); - if (rect != NULL) { - BLI_rctf_rcti_copy(&rectf, rect); - } if (index == 0 || vindex == 0) { return false; } @@ -772,7 +758,7 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, if (face_style > 2 && is_inside) { if (face_style == 4) { if (circleData != NULL) { - enclose_face = edbm_circle_enclose_face(vc, efa, circleData); + enclose_face = edbm_circle_enclose_mesh(NULL, efa, circleData); } else { BM_ITER_ELEM (eve, &viter, efa, BM_VERTS_OF_FACE) { @@ -1652,13 +1638,15 @@ static bool do_lasso_select_mesh(ViewContext *vc, if (ts->selectmode & SCE_SELECT_FACE) { if (use_zbuf) { + rctf rectf; + BLI_rctf_rcti_copy(&rectf, &rect); data.is_changed |= edbm_backbuf_check_and_select_faces(vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, - &rect, + &rectf, data.face_style, &data, NULL); @@ -4516,8 +4504,10 @@ static bool do_mesh_box_select(ViewContext *vc, if (ts->selectmode & SCE_SELECT_FACE) { if (use_zbuf) { + rctf rectf; + BLI_rctf_rcti_copy(&rectf, rect); data.is_changed |= edbm_backbuf_check_and_select_faces( - vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, rect, data.face_style, NULL, NULL); + vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, &rectf, data.face_style, NULL, NULL); } else { data.check_mesh_direction = edbm_facing_viewport_precheck( @@ -5064,7 +5054,7 @@ static void mesh_circle_doSelectEdge(void *userData, bool mesh_facing = true; if (edge_inside_circle(data->mval_fl, data->radius, screen_co_a, screen_co_b)) { if (data->edge_style == 4) { - enclose_edge = edbm_circle_enclose_edge(eed, data); + enclose_edge = edbm_circle_enclose_mesh(eed, NULL, data); } if (data->check_mesh_direction) { @@ -5112,7 +5102,7 @@ static void mesh_circle_doSelectFace(void *userData, *face_hit = inside; if (data->face_style == 4 && inside) { - enclose_face = edbm_circle_enclose_face(data->vc, efa, data); + enclose_face = edbm_circle_enclose_mesh(NULL, efa, data); } if (data->check_mesh_direction) { -- 2.30.2 From ca2908e29284beddf541deb319d708eab16c3d81 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Wed, 5 Apr 2023 22:14:34 -0700 Subject: [PATCH 08/20] put rcti to rctf back in edbf_select_faces --- .../editors/space_view3d/view3d_select.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 9ef0a3a50e3..6d56445a1ea 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -723,7 +723,7 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, Object *ob, BMEditMesh *em, const eSelectOp sel_op, - const rctf *rect, + const rcti *rect, const int face_style, void *ldata, void *cdata) @@ -732,6 +732,7 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, BMIter iter, viter; BMFace *efa; BMVert *eve; + rctf rectf; bool changed = false; const int style = ts->viewport_facing_select_face; const bool check_mesh_facing = edbm_facing_viewport_precheck(ts, style, false); @@ -741,6 +742,10 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, uint index = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_FACE); uint vindex = DRW_select_buffer_context_offset_for_object_elem(depsgraph, ob, SCE_SELECT_VERTEX); + if (rect != NULL) { + BLI_rctf_rcti_copy(&rectf, rect); + } + if (index == 0 || vindex == 0) { return false; } @@ -770,7 +775,7 @@ static bool edbm_backbuf_check_and_select_faces(ViewContext *vc, } } else { - center_face = edbm_center_face(vc, efa, rect, lassoData, circleData); + center_face = edbm_center_face(vc, efa, &rectf, lassoData, circleData); } } @@ -1638,15 +1643,13 @@ static bool do_lasso_select_mesh(ViewContext *vc, if (ts->selectmode & SCE_SELECT_FACE) { if (use_zbuf) { - rctf rectf; - BLI_rctf_rcti_copy(&rectf, &rect); data.is_changed |= edbm_backbuf_check_and_select_faces(vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, - &rectf, + &rect, data.face_style, &data, NULL); @@ -4504,10 +4507,8 @@ static bool do_mesh_box_select(ViewContext *vc, if (ts->selectmode & SCE_SELECT_FACE) { if (use_zbuf) { - rctf rectf; - BLI_rctf_rcti_copy(&rectf, rect); data.is_changed |= edbm_backbuf_check_and_select_faces( - vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, &rectf, data.face_style, NULL, NULL); + vc, esel, vc->depsgraph, vc->obedit, vc->em, sel_op, rect, data.face_style, NULL, NULL); } else { data.check_mesh_direction = edbm_facing_viewport_precheck( -- 2.30.2 From 8d7c2efab1a6442355bd08b9551df5fa8009a373 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Thu, 6 Apr 2023 22:17:12 -0700 Subject: [PATCH 09/20] add origin select and repeat tool --- .../startup/bl_ui/space_toolsystem_toolbar.py | 8 +++ .../blenloader/intern/versioning_defaults.cc | 3 + source/blender/editors/screen/screen_ops.c | 56 +++++++++++++++++++ .../editors/space_view3d/view3d_select.cc | 46 ++++++++++----- source/blender/makesdna/DNA_scene_defaults.h | 3 + source/blender/makesdna/DNA_scene_types.h | 5 ++ source/blender/makesrna/intern/rna_scene.c | 13 +++++ source/blender/windowmanager/WM_api.h | 1 + .../windowmanager/intern/wm_event_system.cc | 5 ++ .../windowmanager/intern/wm_operator_props.c | 6 ++ 10 files changed, 131 insertions(+), 15 deletions(-) diff --git a/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/scripts/startup/bl_ui/space_toolsystem_toolbar.py index aa448aeca56..4ed0c4fd135 100644 --- a/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -390,6 +390,10 @@ class _defs_view3d_select: row = layout.row() row.use_property_split = False row.prop(props, "mode", text="", expand=True, icon_only=True) + + if _context.mode == 'OBJECT': + tool_settings = _context.tool_settings + layout.prop(tool_settings, "select_origin_box") return dict( idname="builtin.select_box", label="Select Box", @@ -424,6 +428,10 @@ class _defs_view3d_select: row.prop(props, "mode", text="", expand=True, icon_only=True) layout.prop(props, "radius") + if _context.mode == 'OBJECT': + tool_settings = _context.tool_settings + layout.prop(tool_settings, "select_origin_circle") + def draw_cursor(_context, tool, xy): from gpu_extras.presets import draw_circle_2d props = tool.operator_properties("view3d.select_circle") diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index beb54e03346..b324a516f10 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -418,6 +418,9 @@ static void blo_update_defaults_scene(Main *bmain, Scene *scene) ts->viewport_facing_select_vert = 1; ts->viewport_facing_select_edge = 1; ts->viewport_facing_select_face = 1; + + /* Object Origin Select */ + ts->select_origin_circle = true; } void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 80e5da43423..689275a4d79 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3847,6 +3847,61 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Repeat Tool Operator + * \{ */ + +static int repeat_tool_exec(bContext *C, wmOperator *UNUSED(op)) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmOperator *lastop = wm->operators.last; + + /* Seek last registered operator */ + while (lastop) { + if (lastop->type->flag & OPTYPE_REGISTER) { + if (STREQ(lastop->idname, "MESH_OT_delete") || STREQ(lastop->idname, "MESH_OT_select_all") || + STREQ(lastop->idname, "MESH_OT_select_mode") || + STREQ(lastop->idname, "OBJECT_OT_editmode_toggle") || + STREQ(lastop->idname, "OBJECT_OT_select_all") || + STREQ(lastop->idname, "TRANSFORM_OT_resize") || + STREQ(lastop->idname, "TRANSFORM_OT_rotate") || + STREQ(lastop->idname, "TRANSFORM_OT_trackball") || + STREQ(lastop->idname, "TRANSFORM_OT_translate")) { + lastop = lastop->prev; + } + else { + printf(lastop->idname, "\n"); + break; + } + } + else { + lastop = lastop->prev; + } + } + + if (lastop) { + WM_operator_free_all_after(wm, lastop); + WM_operator_repeat_tool(C, lastop); + } + + return OPERATOR_CANCELLED; +} + +static void SCREEN_OT_repeat_tool(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Repeat Tool"; + ot->description = "Repeat last tool"; + ot->idname = "SCREEN_OT_repeat_tool"; + + /* api callbacks */ + ot->exec = repeat_tool_exec; + + ot->poll = ED_operator_screenactive; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Redo Operator * \{ */ @@ -5679,6 +5734,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(SCREEN_OT_actionzone); WM_operatortype_append(SCREEN_OT_repeat_last); WM_operatortype_append(SCREEN_OT_repeat_history); + WM_operatortype_append(SCREEN_OT_repeat_tool); WM_operatortype_append(SCREEN_OT_redo_last); /* Screen tools. */ diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 6d56445a1ea..4737da23d0c 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -1206,13 +1206,15 @@ static bool do_lasso_select_objects(ViewContext *vc, } else { is_inside = base->object->id.tag & LIB_TAG_DOIT ? + ts->select_origin_circle ? (ED_view3d_project_float_global(vc->region, base->object->object_to_world[3], region_co, V3D_PROJ_TEST_CLIP_DEFAULT) == - V3D_PROJ_RET_OK) && - len_squared_v2v2(mval_fl, region_co) <= - circle_data[2] * circle_data[2] : + V3D_PROJ_RET_OK) ? + len_squared_v2v2(mval_fl, region_co) <= circle_data[2] * circle_data[2] : + false : + true : false; } @@ -4692,13 +4694,20 @@ static bool do_object_box_select( View3D *v3d = vc->v3d; int totobj = MAXPICKELEMS; /* XXX solve later */ ToolSettings *ts = vc->scene->toolsettings; + rctf rect_f_data; + rctf *rect_f = &rect_f_data; + BLI_rctf_rcti_copy(rect_f, rect); + float region_co[2]; /* Selection buffer has bones potentially too, so we add #MAXPICKELEMS. */ GPUSelectResult *buffer = static_cast( MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(GPUSelectResult), __func__)); const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); - const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool select_origin = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + RNA_boolean_get(op->ptr, "select_origin_box") : + ts->select_origin_box; + const bool select_through_int = RNA_enum_get(op->ptr, "select_through"); const bool select_through = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? select_through_int == 2 || select_through_int == 8 : ts->select_through && ts->select_through_object && @@ -4753,7 +4762,13 @@ static bool do_object_box_select( for (Base *base = static_cast(object_bases->first); base && hits; base = base->next) { if (BASE_SELECTABLE(v3d, base)) { const bool is_select = base->flag & BASE_SELECTED; - const bool is_inside = base->object->id.tag & LIB_TAG_DOIT; + const bool is_inside = base->object->id.tag & LIB_TAG_DOIT ? + select_origin ? + (ED_view3d_project_base(vc->region, base, region_co) == + V3D_PROJ_RET_OK) && + BLI_rctf_isect_pt_v(rect_f, region_co) : + true : + false; const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); @@ -5913,15 +5928,6 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) static_cast(RNA_enum_get(op->ptr, "mode")), WM_gesture_is_modal_first(gesture)); ED_view3d_viewcontext_init(C, &vc, depsgraph); - ToolSettings *ts = vc.scene->toolsettings; - const int select_through_int = RNA_enum_get(op->ptr, "select_through"); - const bool select_through_object = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? - select_through_int == 2 || select_through_int == 8 : - ts->select_through && ts->select_through_object && - ts->select_through_circle; - if (!select_through_object) { - BKE_object_update_select_id(CTX_data_main(C)); - } Object *obact = vc.obact; Object *obedit = vc.obedit; @@ -5967,7 +5973,16 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } else { - if (select_through_object) { + ToolSettings *ts = vc.scene->toolsettings; + const int select_through_int = RNA_enum_get(op->ptr, "select_through"); + const bool default_object_select = U.drag_select_control & USER_DRAG_SELECT_KEYMAP ? + RNA_boolean_get(op->ptr, "select_origin_circle") && + (select_through_int == 2 || + select_through_int == 8) : + ts->select_through && ts->select_through_object && + ts->select_through_circle && + ts->select_origin_circle; + if (default_object_select) { if (object_circle_select(&vc, sel_op, mval, float(radius))) { DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene); @@ -5976,6 +5991,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op) } } else { + BKE_object_update_select_id(CTX_data_main(C)); int circle_data[3] = {mval[0], mval[1], radius}; do_lasso_select_objects(&vc, NULL, NULL, sel_op, op, circle_data); } diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index 8932413264d..e97e7402d1a 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -411,6 +411,9 @@ .viewport_facing_select_vert = 1, \ .viewport_facing_select_edge = 1, \ .viewport_facing_select_face = 1, \ + \ + /* Object Origin Select */ \ + .select_origin_circle = true, \ } /* clang-format off */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 95e4bd546b5..1c19b564cc6 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1587,6 +1587,11 @@ typedef struct ToolSettings { char viewport_facing_select_edge; char viewport_facing_select_face; + /* object origin select */ + char select_origin_box; + char select_origin_circle; + char _pad0[6]; + /* Annotations. */ /** Stroke placement settings - 3D View. */ char annotate_v3d_align; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index d63c86306e3..91c390cd614 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4144,6 +4144,19 @@ static void rna_def_tool_settings(BlenderRNA *brna) "Select occluded objects and mesh elements with circle select"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + /* Object Origin Select */ + prop = RNA_def_property(srna, "select_origin_box", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_origin_box", 0); + RNA_def_property_ui_text( + prop, "Select Origin", "Select objects by their origin with box select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "select_origin_circle", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "select_origin_circle", 0); + RNA_def_property_ui_text( + prop, "Select Origin", "Select objects by their origin with circle select"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + /* Unified Paint Settings */ prop = RNA_def_property(srna, "unified_paint_settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index a48ef91e7f7..1a5f6359bdf 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -688,6 +688,7 @@ int WM_operator_call_notest(struct bContext *C, struct wmOperator *op); * Execute this operator again, put here so it can share above code */ int WM_operator_repeat(struct bContext *C, struct wmOperator *op); +int WM_operator_repeat_tool(struct bContext *C, struct wmOperator *op); int WM_operator_repeat_last(struct bContext *C, struct wmOperator *op); /** * \return true if #WM_operator_repeat can run. diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 5069685e7d9..72c750be060 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -1292,6 +1292,11 @@ int WM_operator_repeat(bContext *C, wmOperator *op) op->flag &= ~op_flag; return ret; } +int WM_operator_repeat_tool(bContext *C, wmOperator *op) +{ + const int ret = WM_operator_name_call_ptr(C, op->type, WM_OP_INVOKE_DEFAULT, NULL, NULL); + return ret; +} int WM_operator_repeat_last(bContext *C, wmOperator *op) { const int op_flag = OP_IS_REPEAT_LAST; diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index 9086441c99b..1004d953199 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -486,6 +486,9 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo WM_operator_properties_border(ot); + prop = RNA_def_boolean(ot->srna, "select_origin_box", false, "Select Object Origin", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); @@ -811,6 +814,9 @@ void WM_operator_properties_gesture_circle(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "select_origin_circle", true, "Select Object Origin", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "face_type", face_select_items, 0, "Face Select", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_enum(ot->srna, "edge_type", edge_select_items, 0, "Edge Select", ""); -- 2.30.2 From 5cab0f27d2816d13e88cd384e5b86e1fc2205b4b Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Fri, 7 Apr 2023 06:58:23 -0700 Subject: [PATCH 10/20] fix toolsetting drag direction detections --- source/blender/windowmanager/intern/wm_event_query.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index 3c8a6900c4b..c5c846affe2 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -273,7 +273,6 @@ int WM_event_drag_direction(const wmEvent *event, ToolSettings *ts) bool left_right = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_LEFT_RIGHT; bool up_down = U.click_drag_direction & USER_CLICK_DRAG_DIRECTION_UP_DOWN; - bool drag_select_toolsetting = U.drag_select_control & USER_DRAG_SELECT_TOOLSETTING; int theta = left_right ? round_fl_to_int(atan2f(0.0f, (float)delta[0]) / (float)M_PI) : up_down ? @@ -310,7 +309,7 @@ int WM_event_drag_direction(const wmEvent *event, ToolSettings *ts) } } - if (drag_select_toolsetting) { + if (U.drag_select_control < 1) { int box = ts->box_drag_direction; int lasso = ts->lasso_drag_direction; -- 2.30.2 From c7d3465f1f4d4a5bf7f4d46c2b241911bba778a3 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sat, 8 Apr 2023 02:24:43 -0700 Subject: [PATCH 11/20] a vulgar display of formatting abuse but it's the lesser of a dozen worse ideas --- scripts/startup/bl_ui/space_view3d_toolbar.py | 157 ++++++++++++++++-- source/blender/makesdna/DNA_scene_types.h | 5 +- source/blender/makesrna/intern/rna_scene.c | 19 ++- 3 files changed, 166 insertions(+), 15 deletions(-) diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index c9f0ed3ed9c..07340e0fc31 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -192,17 +192,55 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): row.prop(mesh, "use_mirror_topology") if bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': - from bl_ui.space_toolsystem_common import ToolSelectPanelHelper - _cls = ToolSelectPanelHelper._tool_class_from_space_type('VIEW_3D') - - if tool_settings.workspace_tool_type == 'FALLBACK': - tool = _cls._tool_get_by_id_active(context, _cls.tool_fallback_id)[0].idname - else: - tool = ToolSelectPanelHelper.tool_active_from_context(context).idname - - if tool == "builtin.select_box" or tool == "builtin.select_lasso" or tool == "builtin.select_circle": row = layout.row(align=True) - if tool == "builtin.select_box": + if tool_settings.show_box_options: + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, icon='DOWNARROW_HLT') + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + else: + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, icon='RIGHTARROW') + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") + if tool_settings.show_box_options: + row = layout.row(align=True) row.prop(tool_settings, "box_drag_direction") row = layout.row(align=True) if tool_settings.box_drag_direction == 'MESH_DIRECTION_ANY': @@ -221,7 +259,55 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): row = layout.row(align=True) row.prop(tool_settings, "box_face_up", text="Box Face", icon='TRIA_UP') row.prop(tool_settings, "box_face_down", text="", icon='TRIA_DOWN') - elif tool == "builtin.select_lasso": + row = layout.row(align=True) + if tool_settings.show_lasso_options: + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, icon='DOWNARROW_HLT') + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + else: + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, icon='RIGHTARROW') + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") + if tool_settings.show_lasso_options: + row = layout.row(align=True) row.prop(tool_settings, "lasso_drag_direction") row = layout.row(align=True) if tool_settings.lasso_drag_direction == 'MESH_DIRECTION_ANY': @@ -240,7 +326,54 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): row = layout.row(align=True) row.prop(tool_settings, "lasso_face_up", text="Lasso Face", icon='TRIA_UP') row.prop(tool_settings, "lasso_face_down", text="", icon='TRIA_DOWN') - elif tool == "builtin.select_circle": + row = layout.row(align=True) + if tool_settings.show_circle_options: + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, icon='DOWNARROW_HLT') + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + else: + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, icon='RIGHTARROW') + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") + if tool_settings.show_circle_options: row = layout.row(align=True) row.prop(tool_settings, "circle_edge") row = layout.row(align=True) diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 1c19b564cc6..88f1f3024e8 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1743,7 +1743,10 @@ typedef struct ToolSettings { char lasso_face_down; char circle_edge; char circle_face; - char _pad6[2]; + char show_box_options; + char show_lasso_options; + char show_circle_options; + char _pad6[7]; /** * Custom Curve Profile for bevel tool: diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 91c390cd614..98132b85dac 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3273,11 +3273,11 @@ static void rna_def_tool_settings(BlenderRNA *brna) /* Mesh select settings. */ prop = RNA_def_property(srna, "box_drag_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mesh_drag_direction_items); - RNA_def_property_ui_text(prop, "Mesh Drag Direction", "Click-drag direction style for box select"); + RNA_def_property_ui_text(prop, "Drag Direction", "Click-drag direction style for box select"); prop = RNA_def_property(srna, "lasso_drag_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, mesh_drag_direction_items); - RNA_def_property_ui_text(prop, "Mesh Drag Direction", "Click-drag direction style for lasso select"); + RNA_def_property_ui_text(prop, "Drag Direction", "Click-drag direction style for lasso select"); prop = RNA_def_property(srna, "box_direction_upright", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "box_direction_upright", 0); @@ -3287,6 +3287,21 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "lasso_direction_upright", 0); RNA_def_property_ui_text(prop, "Lasso Direction Helper", ""); + prop = RNA_def_property(srna, "show_box_options", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_box_options", 0); + RNA_def_property_ui_text( + prop, "Box Options", "Additional options for box selection of mesh elements"); + + prop = RNA_def_property(srna, "show_lasso_options", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_lasso_options", 0); + RNA_def_property_ui_text( + prop, "Lasso Options", "Additional options for lasso selection of mesh elements"); + + prop = RNA_def_property(srna, "show_circle_options", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "show_circle_options", 0); + RNA_def_property_ui_text( + prop, "Circle Options", "Additional options for circle selection of mesh elements"); + prop = RNA_def_property(srna, "box_edge", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); RNA_def_property_ui_text(prop, "Box Edge", "Box edge selection style"); -- 2.30.2 From 3a96a94ed90e29055ec942a0073bef6581352f3e Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sat, 8 Apr 2023 04:57:08 -0700 Subject: [PATCH 12/20] ok undo that last bit of ui abuse, this is good enough --- release/datafiles/userdef/userdef_default.c | 1 + .../startup/bl_ui/space_toolsystem_toolbar.py | 61 +++++- scripts/startup/bl_ui/space_userpref.py | 6 + scripts/startup/bl_ui/space_view3d_toolbar.py | 190 +----------------- .../blenloader/intern/versioning_userdef.c | 5 +- .../blender/editors/mesh/editmesh_select.cc | 33 +-- .../editors/space_view3d/view3d_select.cc | 7 +- source/blender/makesdna/DNA_userdef_types.h | 10 +- source/blender/makesrna/intern/rna_scene.c | 50 ++--- source/blender/makesrna/intern/rna_userdef.c | 15 ++ 10 files changed, 142 insertions(+), 236 deletions(-) diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index cbcd99d4b3f..794104af6f6 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -185,6 +185,7 @@ const UserDef U_default = { .render_display_type = USER_RENDER_DISPLAY_WINDOW, .filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW, .viewport_aa = 8, + .selection_radius = 75.0f, .walk_navigation = { diff --git a/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 4ed0c4fd135..e735b9f797b 100644 --- a/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -386,14 +386,37 @@ class _defs_view3d_select: @ToolDef.from_fn def box(): def draw_settings(_context, layout, tool): + tool_settings = _context.tool_settings props = tool.operator_properties("view3d.select_box") row = layout.row() row.use_property_split = False row.prop(props, "mode", text="", expand=True, icon_only=True) - if _context.mode == 'OBJECT': - tool_settings = _context.tool_settings + if _context.mode == 'OBJECT' and bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': layout.prop(tool_settings, "select_origin_box") + if _context.mode == 'EDIT_MESH' and bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': + layout.prop(tool_settings, "show_box_options", toggle=True) + if tool_settings.show_box_options: + row = layout.row(align=True) + row.prop(tool_settings, "box_drag_direction") + row = layout.row(align=True) + if tool_settings.box_drag_direction == 'MESH_DIRECTION_ANY': + row.prop(tool_settings, "box_edge") + row = layout.row(align=True) + row.prop(tool_settings, "box_face") + elif tool_settings.box_drag_direction == 'MESH_DIRECTION_LEFT_RIGHT': + row.prop(tool_settings, "box_edge_left", icon='TRIA_LEFT') + row.prop(tool_settings, "box_edge_right", text="", icon='TRIA_RIGHT') + row = layout.row(align=True) + row.prop(tool_settings, "box_face_left", icon='TRIA_LEFT') + row.prop(tool_settings, "box_face_right", text="", icon='TRIA_RIGHT') + else: + row.prop(tool_settings, "box_edge_up", icon='TRIA_UP') + row.prop(tool_settings, "box_edge_down", text="", icon='TRIA_DOWN') + row = layout.row(align=True) + row.prop(tool_settings, "box_face_up", icon='TRIA_UP') + row.prop(tool_settings, "box_face_down", text="", icon='TRIA_DOWN') + return dict( idname="builtin.select_box", label="Select Box", @@ -406,10 +429,33 @@ class _defs_view3d_select: @ToolDef.from_fn def lasso(): def draw_settings(_context, layout, tool): + tool_settings = _context.tool_settings props = tool.operator_properties("view3d.select_lasso") row = layout.row() row.use_property_split = False row.prop(props, "mode", text="", expand=True, icon_only=True) + if _context.mode == 'EDIT_MESH' and bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': + layout.prop(tool_settings, "show_lasso_options", toggle=True) + if tool_settings.show_lasso_options: + row = layout.row(align=True) + row.prop(tool_settings, "lasso_drag_direction") + row = layout.row(align=True) + if tool_settings.lasso_drag_direction == 'MESH_DIRECTION_ANY': + row.prop(tool_settings, "lasso_edge") + row = layout.row(align=True) + row.prop(tool_settings, "lasso_face") + elif tool_settings.lasso_drag_direction == 'MESH_DIRECTION_LEFT_RIGHT': + row.prop(tool_settings, "lasso_edge_left", icon='TRIA_LEFT') + row.prop(tool_settings, "lasso_edge_right", text="", icon='TRIA_RIGHT') + row = layout.row(align=True) + row.prop(tool_settings, "lasso_face_left", icon='TRIA_LEFT') + row.prop(tool_settings, "lasso_face_right", text="", icon='TRIA_RIGHT') + else: + row.prop(tool_settings, "lasso_edge_up", icon='TRIA_UP') + row.prop(tool_settings, "lasso_edge_down", text="", icon='TRIA_DOWN') + row = layout.row(align=True) + row.prop(tool_settings, "lasso_face_up", icon='TRIA_UP') + row.prop(tool_settings, "lasso_face_down", text="", icon='TRIA_DOWN') return dict( idname="builtin.select_lasso", label="Select Lasso", @@ -422,15 +468,22 @@ class _defs_view3d_select: @ToolDef.from_fn def circle(): def draw_settings(_context, layout, tool): + tool_settings = _context.tool_settings props = tool.operator_properties("view3d.select_circle") row = layout.row() row.use_property_split = False row.prop(props, "mode", text="", expand=True, icon_only=True) layout.prop(props, "radius") - if _context.mode == 'OBJECT': - tool_settings = _context.tool_settings + if _context.mode == 'OBJECT' and bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': layout.prop(tool_settings, "select_origin_circle") + if _context.mode == 'EDIT_MESH' and bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': + layout.prop(tool_settings, "show_circle_options", toggle=True) + if tool_settings.show_circle_options: + row = layout.row(align=True) + row.prop(tool_settings, "circle_edge") + row = layout.row(align=True) + row.prop(tool_settings, "circle_face") def draw_cursor(_context, tool, xy): from gpu_extras.presets import draw_circle_2d diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index d77ab7162cf..92b96e3d1f6 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -496,6 +496,12 @@ class USERPREF_PT_edit_misc(EditingPanel, CenterAlignMixIn, Panel): col = layout.column() col.prop(edit, "sculpt_paint_overlay_color", text="Sculpt Overlay Color") col.prop(edit, "node_margin", text="Node Auto-Offset Margin") + col.prop(edit, "adjustable_click_select") + colsub = col.column(align=True) + colsub.active = edit.adjustable_click_select + colsub.prop(edit, "select_unbiased") + colsub.prop(edit, "selection_radius") + # ----------------------------------------------------------------------------- diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index 07340e0fc31..29631c411e7 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -191,194 +191,6 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): row.active = ob.data.use_mirror_x or ob.data.use_mirror_y or ob.data.use_mirror_z row.prop(mesh, "use_mirror_topology") - if bpy.context.preferences.inputs.drag_select_control == 'USER_DRAG_TOOLSETTING': - row = layout.row(align=True) - if tool_settings.show_box_options: - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, icon='DOWNARROW_HLT') - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - else: - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, icon='RIGHTARROW') - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_box_options", toggle=True, emboss=False, text="") - if tool_settings.show_box_options: - row = layout.row(align=True) - row.prop(tool_settings, "box_drag_direction") - row = layout.row(align=True) - if tool_settings.box_drag_direction == 'MESH_DIRECTION_ANY': - row.prop(tool_settings, "box_edge") - row = layout.row(align=True) - row.prop(tool_settings, "box_face") - elif tool_settings.box_drag_direction == 'MESH_DIRECTION_LEFT_RIGHT': - row.prop(tool_settings, "box_edge_left", text="Box Edge", icon='TRIA_LEFT') - row.prop(tool_settings, "box_edge_right", text="", icon='TRIA_RIGHT') - row = layout.row(align=True) - row.prop(tool_settings, "box_face_left", text="Box Face", icon='TRIA_LEFT') - row.prop(tool_settings, "box_face_right", text="", icon='TRIA_RIGHT') - else: - row.prop(tool_settings, "box_edge_up", text="Box Edge", icon='TRIA_UP') - row.prop(tool_settings, "box_edge_down", text="", icon='TRIA_DOWN') - row = layout.row(align=True) - row.prop(tool_settings, "box_face_up", text="Box Face", icon='TRIA_UP') - row.prop(tool_settings, "box_face_down", text="", icon='TRIA_DOWN') - row = layout.row(align=True) - if tool_settings.show_lasso_options: - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, icon='DOWNARROW_HLT') - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - else: - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, icon='RIGHTARROW') - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_lasso_options", toggle=True, emboss=False, text="") - if tool_settings.show_lasso_options: - row = layout.row(align=True) - row.prop(tool_settings, "lasso_drag_direction") - row = layout.row(align=True) - if tool_settings.lasso_drag_direction == 'MESH_DIRECTION_ANY': - row.prop(tool_settings, "lasso_edge") - row = layout.row(align=True) - row.prop(tool_settings, "lasso_face") - elif tool_settings.lasso_drag_direction == 'MESH_DIRECTION_LEFT_RIGHT': - row.prop(tool_settings, "lasso_edge_left", text="Lasso Edge", icon='TRIA_LEFT') - row.prop(tool_settings, "lasso_edge_right", text="", icon='TRIA_RIGHT') - row = layout.row(align=True) - row.prop(tool_settings, "lasso_face_left", text="Lasso Face", icon='TRIA_LEFT') - row.prop(tool_settings, "lasso_face_right", text="", icon='TRIA_RIGHT') - else: - row.prop(tool_settings, "lasso_edge_up", text="Lasso Edge", icon='TRIA_UP') - row.prop(tool_settings, "lasso_edge_down", text="", icon='TRIA_DOWN') - row = layout.row(align=True) - row.prop(tool_settings, "lasso_face_up", text="Lasso Face", icon='TRIA_UP') - row.prop(tool_settings, "lasso_face_down", text="", icon='TRIA_DOWN') - row = layout.row(align=True) - if tool_settings.show_circle_options: - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, icon='DOWNARROW_HLT') - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - else: - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, icon='RIGHTARROW') - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - row.prop(tool_settings, "show_circle_options", toggle=True, emboss=False, text="") - if tool_settings.show_circle_options: - row = layout.row(align=True) - row.prop(tool_settings, "circle_edge") - row = layout.row(align=True) - row.prop(tool_settings, "circle_face") - class VIEW3D_PT_tools_meshedit_options_automerge(View3DPanel, Panel): bl_category = "Tool" @@ -434,7 +246,7 @@ class VIEW3D_PT_tools_meshedit_options_viewport_facing_select(View3DPanel, Panel layout.use_property_split = True layout.use_property_decorate = False - col = layout.column(align=True) + col = layout.column() col.active = tool_settings.viewport_facing_select col.prop(tool_settings, "viewport_facing_select_mode") col.prop(tool_settings, "viewport_facing_select_threshold", text="Threshold") diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 4b2acfa7205..bdb327fc5f3 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -434,9 +434,8 @@ void blo_do_versions_userdef(UserDef *userdef) if (!USER_VERSION_ATLEAST(278, 6)) { /* Clear preference flags for re-use. */ - userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_UNUSED_2 | USER_FLAG_UNUSED_3 | - USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | USER_FLAG_UNUSED_9 | - USER_DEVELOPER_UI); + userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | + USER_FLAG_UNUSED_9 | USER_DEVELOPER_UI); userdef->uiflag &= ~(USER_HEADER_BOTTOM); userdef->transopts &= ~(USER_TR_UNUSED_2 | USER_TR_UNUSED_3 | USER_TR_UNUSED_4 | USER_TR_UNUSED_6 | USER_TR_UNUSED_7); diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc index 5f03a1686dc..c8ec4ab78c2 100644 --- a/source/blender/editors/mesh/editmesh_select.cc +++ b/source/blender/editors/mesh/editmesh_select.cc @@ -233,7 +233,8 @@ static void findnearestvert__doClosest(void *userData, dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); - if (data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT && U.flag & USER_SELECT_UNBIASED) && + data->use_select_bias && BM_elem_flag_test(eve, BM_ELEM_SELECT)) { dist_test_bias += FIND_NEAR_SELECT_BIAS; } @@ -438,7 +439,8 @@ static void find_nearest_edge__doClosest( dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); - if (data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT && U.flag & USER_SELECT_UNBIASED) && + data->use_select_bias && BM_elem_flag_test(eed, BM_ELEM_SELECT)) { dist_test_bias += FIND_NEAR_SELECT_BIAS; } @@ -670,7 +672,8 @@ static void findnearestface__doClosest(void *userData, dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); - if (data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT && U.flag & USER_SELECT_UNBIASED) && + data->use_select_bias && BM_elem_flag_test(efa, BM_ELEM_SELECT)) { dist_test_bias += FIND_NEAR_SELECT_BIAS; } @@ -706,27 +709,26 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, uint base_index = 0; if (!XRAY_FLAG_ENABLED(vc->v3d)) { - float dist_test; + float dist_test = 0.0f; uint index; BMFace *efa; + uint dist_px_manhattan_test = 0; { - uint dist_px_manhattan_test = 0; - if (*dist_px_manhattan_p != 0.0f && (use_zbuf_single_px == false)) { - dist_px_manhattan_test = uint( - ED_view3d_backbuf_sample_size_clamp(vc->region, *dist_px_manhattan_p)); + if (U.flag & USER_ADJUSTABLE_CLICK_SELECT || + *dist_px_manhattan_p != 0.0f && (use_zbuf_single_px == false)) { + dist_px_manhattan_test = (uint)ED_view3d_backbuf_sample_size_clamp(vc->region, + *dist_px_manhattan_p); } DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_FACE); - if (dist_px_manhattan_test == 0) { + if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT) && dist_px_manhattan_test == 0) { index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, vc->mval); - dist_test = 0.0f; } else { index = DRW_select_buffer_find_nearest_to_point( vc->depsgraph, vc->region, vc->v3d, vc->mval, 1, UINT_MAX, &dist_px_manhattan_test); - dist_test = dist_px_manhattan_test; } if (index) { @@ -760,7 +762,14 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, /* end exception */ if (efa) { - if (dist_test < *dist_px_manhattan_p) { + if (U.flag & USER_ADJUSTABLE_CLICK_SELECT && dist_px_manhattan_test < *dist_px_manhattan_p) { + if (r_base_index) { + *r_base_index = base_index; + } + *dist_px_manhattan_p = dist_px_manhattan_test; + return efa; + } + else if (!(U.flag & USER_ADJUSTABLE_CLICK_SELECT) && dist_test < *dist_px_manhattan_p) { if (r_base_index) { *r_base_index = base_index; } diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 4737da23d0c..0036b8269c6 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -104,7 +104,12 @@ float ED_view3d_select_dist_px(void) { - return 75.0f * U.pixelsize; + if (U.flag & USER_ADJUSTABLE_CLICK_SELECT) { + return U.selection_radius * U.pixelsize; + } + else { + return 75.0f * U.pixelsize; + } } void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index cd8640e0b91..da9904b3ae4 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -904,6 +904,12 @@ typedef struct UserDef { char drag_threshold; char move_threshold; + /** Adjustable selection radius */ + float selection_radius; + char adjustable_click_select; + char select_unbiased; + char _pad9[2]; + char font_path_ui[1024]; char font_path_ui_mono[1024]; @@ -1006,8 +1012,8 @@ typedef enum eUserPref_SpaceData_Flag { typedef enum eUserPref_Flag { USER_AUTOSAVE = (1 << 0), USER_FLAG_NUMINPUT_ADVANCED = (1 << 1), - USER_FLAG_UNUSED_2 = (1 << 2), /* cleared */ - USER_FLAG_UNUSED_3 = (1 << 3), /* cleared */ + USER_ADJUSTABLE_CLICK_SELECT = (1 << 2), + USER_SELECT_UNBIASED = (1 << 3), USER_FLAG_UNUSED_4 = (1 << 4), /* cleared */ USER_TRACKBALL = (1 << 5), USER_FLAG_UNUSED_6 = (1 << 6), /* cleared */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 98132b85dac..7085dcd6c74 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3290,105 +3290,105 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "show_box_options", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "show_box_options", 0); RNA_def_property_ui_text( - prop, "Box Options", "Additional options for box selection of mesh elements"); + prop, "Mesh Options", "Additional options for box selection of mesh elements"); prop = RNA_def_property(srna, "show_lasso_options", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "show_lasso_options", 0); RNA_def_property_ui_text( - prop, "Lasso Options", "Additional options for lasso selection of mesh elements"); + prop, "Mesh Options", "Additional options for lasso selection of mesh elements"); prop = RNA_def_property(srna, "show_circle_options", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "show_circle_options", 0); RNA_def_property_ui_text( - prop, "Circle Options", "Additional options for circle selection of mesh elements"); + prop, "Mesh Options", "Additional options for circle selection of mesh elements"); prop = RNA_def_property(srna, "box_edge", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Box Edge", "Box edge selection style"); + RNA_def_property_ui_text(prop, "Edge", "Box edge selection style"); prop = RNA_def_property(srna, "box_edge_left", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Box Edge Left", "Box edge selection style when dragging left"); + RNA_def_property_ui_text(prop, "Edge", "Box edge selection style when dragging left"); prop = RNA_def_property(srna, "box_edge_right", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Box Edge Right", "Box edge selection style when dragging right"); + RNA_def_property_ui_text(prop, "Edge", "Box edge selection style when dragging right"); prop = RNA_def_property(srna, "box_edge_up", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Box Edge Up", "Box edge selection style when dragging up"); + RNA_def_property_ui_text(prop, "Edge", "Box edge selection style when dragging up"); prop = RNA_def_property(srna, "box_edge_down", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Box Edge Down", "Box edge selection style when dragging down"); + RNA_def_property_ui_text(prop, "Edge", "Box edge selection style when dragging down"); prop = RNA_def_property(srna, "box_face", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Box Face", "Box face selection style"); + RNA_def_property_ui_text(prop, "Face", "Box face selection style"); prop = RNA_def_property(srna, "box_face_left", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Box Face Left", "Box face selection style when dragging left"); + RNA_def_property_ui_text(prop, "Face", "Box face selection style when dragging left"); prop = RNA_def_property(srna, "box_face_right", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Box Face Right", "Box face selection style when dragging right"); + RNA_def_property_ui_text(prop, "Face", "Box face selection style when dragging right"); prop = RNA_def_property(srna, "box_face_up", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Box Face Up", "Box face selection style when dragging up"); + RNA_def_property_ui_text(prop, "Face", "Box face selection style when dragging up"); prop = RNA_def_property(srna, "box_face_down", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Box Face Down", "Box face selection style when dragging down"); + RNA_def_property_ui_text(prop, "Face", "Box face selection style when dragging down"); prop = RNA_def_property(srna, "lasso_edge", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Lasso Edge", "Lasso edge selection style"); + RNA_def_property_ui_text(prop, "Edge", "Lasso edge selection style"); prop = RNA_def_property(srna, "lasso_edge_left", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Lasso Edge Left", "Lasso edge selection style when dragging left"); + RNA_def_property_ui_text(prop, "Edge", "Lasso edge selection style when dragging left"); prop = RNA_def_property(srna, "lasso_edge_right", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Lasso Edge Right", "Lasso edge selection style when dragging right"); + RNA_def_property_ui_text(prop, "Edge", "Lasso edge selection style when dragging right"); prop = RNA_def_property(srna, "lasso_edge_up", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Lasso Edge Up", "Lasso edge selection style when dragging up"); + RNA_def_property_ui_text(prop, "Edge", "Lasso edge selection style when dragging up"); prop = RNA_def_property(srna, "lasso_edge_down", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_select_items); - RNA_def_property_ui_text(prop, "Lasso Edge Down", "Lasso edge selection style when dragging down"); + RNA_def_property_ui_text(prop, "Edge", "Lasso edge selection style when dragging down"); prop = RNA_def_property(srna, "lasso_face", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Lasso Face", "Lasso face selection style"); + RNA_def_property_ui_text(prop, "Face", "Lasso face selection style"); prop = RNA_def_property(srna, "lasso_face_left", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Lasso Face Left", "Lasso face selection style when dragging left"); + RNA_def_property_ui_text(prop, "Face", "Lasso face selection style when dragging left"); prop = RNA_def_property(srna, "lasso_face_right", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Lasso Face Right", "Lasso face selection style when dragging right"); + RNA_def_property_ui_text(prop, "Face", "Lasso face selection style when dragging right"); prop = RNA_def_property(srna, "lasso_face_up", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Lasso Face Up", "Lasso face selection style when dragging up"); + RNA_def_property_ui_text(prop, "Face", "Lasso face selection style when dragging up"); prop = RNA_def_property(srna, "lasso_face_down", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Lasso Face Down", "Lasso face selection style when dragging down"); + RNA_def_property_ui_text(prop, "Face", "Lasso face selection style when dragging down"); prop = RNA_def_property(srna, "circle_edge", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, edge_circle_select_items); - RNA_def_property_ui_text(prop, "Circle Edge", "Circle edge selection style"); + RNA_def_property_ui_text(prop, "Edge", "Circle edge selection style"); prop = RNA_def_property(srna, "circle_face", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, face_select_items); - RNA_def_property_ui_text(prop, "Circle Face", "Circle face selection style"); + RNA_def_property_ui_text(prop, "Face", "Circle face selection style"); prop = RNA_def_property(srna, "sculpt", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Sculpt"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 1cf4be9348f..5687f054bd4 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5310,6 +5310,21 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop, "Auto-offset Margin", "Minimum distance between nodes for Auto-offsetting nodes"); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "adjustable_click_select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ADJUSTABLE_CLICK_SELECT); + RNA_def_property_ui_text( + prop, "Adjustable Click-Select", "Use additional options for single-click select"); + + prop = RNA_def_property(srna, "select_unbiased", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SELECT_UNBIASED); + RNA_def_property_ui_text( + prop, "Select Unbiased", "Click-select will not favor unselected mesh elements"); + + prop = RNA_def_property(srna, "selection_radius", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_range(prop, 0.1f, 150.0f); + RNA_def_property_ui_range(prop, 0.1f, 150.0f, 0.01f, 2); + RNA_def_property_ui_text(prop, "Radius", "Size of single-click selection radius"); + /* cursor */ prop = RNA_def_property(srna, "use_cursor_lock_adjust", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCK_CURSOR_ADJUST); -- 2.30.2 From e234aaa6fabdfa54df380ebbf8030ae88dea4bd6 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sat, 8 Apr 2023 06:20:44 -0700 Subject: [PATCH 13/20] combine shading header --- scripts/startup/bl_ui/space_view3d.py | 20 +++++++++++++++++++- source/blender/makesdna/DNA_scene_types.h | 5 ++++- source/blender/makesrna/intern/rna_scene.c | 8 +++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index c4cf6e040de..0fe90c6bf8b 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -949,7 +949,18 @@ class VIEW3D_HT_header(Header): row.popover(panel="VIEW3D_PT_xray", text="") row = layout.row(align=True) - row.prop(shading, "type", text="", expand=True) + if tool_settings.shrink_shading_header: + if shading.type == 'SOLID': + shadicon = 'SHADING_SOLID' + elif shading.type == 'MATERIAL': + shadicon = 'SHADING_TEXTURE' + elif shading.type == 'RENDERED': + shadicon = 'SHADING_RENDERED' + else: + shadicon = 'SHADING_WIRE' + row.operator("view3d.toggle_xray", text="", icon=shadicon, depress=draw_depressed) + else: + row.prop(shading, "type", text="", expand=True) sub = row.row(align=True) # TODO, currently render shading type ignores mesh two-side, until it's supported # show the shading popover which shows double-sided option. @@ -5929,6 +5940,12 @@ class VIEW3D_PT_shading(Panel): def draw(self, _context): layout = self.layout layout.label(text="Viewport Shading") + tool_settings = _context.tool_settings + shading = VIEW3D_PT_shading.get_shading(_context) + + layout.prop(tool_settings, "shrink_shading_header") + if tool_settings.shrink_shading_header: + layout.prop(shading, "type", text = '', expand=True) class VIEW3D_PT_shading_lighting(Panel): @@ -5941,6 +5958,7 @@ class VIEW3D_PT_shading_lighting(Panel): def poll(cls, context): shading = VIEW3D_PT_shading.get_shading(context) engine = context.scene.render.engine + return shading.type in {'SOLID', 'MATERIAL'} or engine == 'BLENDER_EEVEE' and shading.type == 'RENDERED' def draw(self, context): diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 88f1f3024e8..4396d1ba9b7 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1746,7 +1746,10 @@ typedef struct ToolSettings { char show_box_options; char show_lasso_options; char show_circle_options; - char _pad6[7]; + + /* Combine shading and xray header buttons */ + char shrink_shading_header; + char _pad6[6]; /** * Custom Curve Profile for bevel tool: diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 7085dcd6c74..76b52a8abe6 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4062,12 +4062,18 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Normal Vector", "Normal Vector used to copy, add or multiply"); RNA_def_property_ui_range(prop, -10000.0, 10000.0, 1, 3); - /* UI prop helper, so you can use a heading without a real property or operator on the same line */ + /* UI prop helper, might help with formatting and using headings on a blank line, unused for now */ prop = RNA_def_property(srna, "ui_prop", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "ui_prop", 0); RNA_def_property_ui_text(prop, "UI Prop", ""); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + /* Shrink Shading Header */ + prop = RNA_def_property(srna, "shrink_shading_header", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "shrink_shading_header", 0); + RNA_def_property_ui_text( + prop, "Shrink Header", "Combine the four Shading Header buttons into one button that also toggles X-Ray"); + /* X-Ray header button */ prop = RNA_def_property(srna, "xray_button", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "xray_button", 0); -- 2.30.2 From 039cb0055599930b9d998233af727a4f8a9366ed Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sat, 8 Apr 2023 06:22:10 -0700 Subject: [PATCH 14/20] fix an extra line insert --- scripts/startup/bl_ui/space_view3d.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 0fe90c6bf8b..f25f392e360 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -5958,7 +5958,6 @@ class VIEW3D_PT_shading_lighting(Panel): def poll(cls, context): shading = VIEW3D_PT_shading.get_shading(context) engine = context.scene.render.engine - return shading.type in {'SOLID', 'MATERIAL'} or engine == 'BLENDER_EEVEE' and shading.type == 'RENDERED' def draw(self, context): -- 2.30.2 From 0e448998fe0649dfa4c5702e2df5ecf3e292cbf5 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sat, 8 Apr 2023 17:40:44 -0700 Subject: [PATCH 15/20] text = '' to text="" --- scripts/startup/bl_ui/space_view3d.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index f25f392e360..0a3d13bd7d8 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -5945,7 +5945,7 @@ class VIEW3D_PT_shading(Panel): layout.prop(tool_settings, "shrink_shading_header") if tool_settings.shrink_shading_header: - layout.prop(shading, "type", text = '', expand=True) + layout.prop(shading, "type", text="", expand=True) class VIEW3D_PT_shading_lighting(Panel): -- 2.30.2 From 78f2652042c363e3254e9028e48fb773552a0188 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sun, 9 Apr 2023 03:03:30 -0700 Subject: [PATCH 16/20] add frame selected and zoom speed options to keymap --- .../editors/space_view3d/view3d_navigate.c | 42 +++++++++++++++---- .../editors/space_view3d/view3d_navigate.h | 2 + .../space_view3d/view3d_navigate_zoom.c | 10 +++-- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c index b6c78c7bf72..809000be817 100644 --- a/source/blender/editors/space_view3d/view3d_navigate.c +++ b/source/blender/editors/space_view3d/view3d_navigate.c @@ -99,6 +99,26 @@ void view3d_operator_properties_common(wmOperatorType *ot, const enum eV3D_OpPro if (flag & V3D_OP_PROP_USE_MOUSE_INIT) { WM_operator_properties_use_cursor_init(ot); } + + if (flag & V3D_OP_PROP_FRAME_SELECTED_DISTANCE) { + PropertyRNA *prop; + prop = RNA_def_int(ot->srna, + "frame_selected_distance", + 0, + 0, + 1000, + "Camera Offset", + "Distance to put camera from selected", + 0, + 1000); + + } + + if (flag & V3D_OP_PROP_ZOOM_SPEED) { + PropertyRNA *prop; + prop = RNA_def_float( + ot->srna, "zoom_speed", 1.2f, 1.001, 10, "Zoom Speed", "Speed to zoom camera", 1.001f, 10); + } } /** \} */ @@ -652,7 +672,8 @@ static void view3d_from_minmax(bContext *C, const float min[3], const float max[3], bool ok_dist, - const int smooth_viewtx) + const int smooth_viewtx, + const int view_dist) { RegionView3D *rv3d = region->regiondata; float afm[3]; @@ -695,7 +716,7 @@ static void view3d_from_minmax(bContext *C, v3d, region, depsgraph, persp, true, (size / 2) * VIEW3D_MARGIN); if (rv3d->is_persp) { /* don't zoom closer than the near clipping plane */ - new_dist = max_ff(new_dist, v3d->clip_start * 1.5f); + new_dist = max_ff(new_dist, v3d->clip_start * 1.5f + view_dist); } } } @@ -741,7 +762,8 @@ static void view3d_from_minmax_multi(bContext *C, const float min[3], const float max[3], const bool ok_dist, - const int smooth_viewtx) + const int smooth_viewtx, + const int view_dist) { ScrArea *area = CTX_wm_area(C); ARegion *region; @@ -751,7 +773,7 @@ static void view3d_from_minmax_multi(bContext *C, /* when using all regions, don't jump out of camera view, * but _do_ allow locked cameras to be moved */ if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) { - view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx); + view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx, view_dist); } } } @@ -831,10 +853,10 @@ static int view3d_all_exec(bContext *C, wmOperator *op) ED_view3d_smooth_view_undo_begin(C, area); if (use_all_regions) { - view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx); + view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx, 0); } else { - view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx); + view3d_from_minmax(C, v3d, region, min, max, true, smooth_viewtx, 0); } ED_view3d_smooth_view_undo_end(C, area, op->type->name, false); @@ -893,6 +915,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) /* any one of the regions may be locked */ (use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA)); const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + const int view_dist = RNA_int_get(op->ptr, "frame_selected_distance"); INIT_MINMAX(min, max); if (is_face_map) { @@ -1007,10 +1030,10 @@ static int viewselected_exec(bContext *C, wmOperator *op) ED_view3d_smooth_view_undo_begin(C, area); if (use_all_regions) { - view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx); + view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx, view_dist); } else { - view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx); + view3d_from_minmax(C, v3d, region, min, max, ok_dist, smooth_viewtx, view_dist); } ED_view3d_smooth_view_undo_end(C, area, op->type->name, false); @@ -1033,7 +1056,8 @@ void VIEW3D_OT_view_selected(wmOperatorType *ot) ot->flag = 0; /* properties */ - view3d_operator_properties_common(ot, V3D_OP_PROP_USE_ALL_REGIONS); + view3d_operator_properties_common( + ot, V3D_OP_PROP_USE_ALL_REGIONS | V3D_OP_PROP_FRAME_SELECTED_DISTANCE); } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate.h b/source/blender/editors/space_view3d/view3d_navigate.h index 46dacbc606f..a641a3748fa 100644 --- a/source/blender/editors/space_view3d/view3d_navigate.h +++ b/source/blender/editors/space_view3d/view3d_navigate.h @@ -34,6 +34,8 @@ enum eV3D_OpPropFlag { V3D_OP_PROP_DELTA = (1 << 1), V3D_OP_PROP_USE_ALL_REGIONS = (1 << 2), V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3), + V3D_OP_PROP_FRAME_SELECTED_DISTANCE = (1 << 4), + V3D_OP_PROP_ZOOM_SPEED = (1 << 5), }; enum { diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom.c b/source/blender/editors/space_view3d/view3d_navigate_zoom.c index 51aab367959..a5f8341dd27 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_zoom.c +++ b/source/blender/editors/space_view3d/view3d_navigate_zoom.c @@ -506,9 +506,10 @@ static int viewzoom_exec(bContext *C, wmOperator *op) } ED_view3d_dist_range_get(v3d, dist_range); + const float zoom_speed = RNA_float_get(op->ptr, "zoom_speed"); if (delta < 0) { - const float step = 1.2f; + const float step = zoom_speed; if (use_cam_zoom) { view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy); } @@ -519,7 +520,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) } } else { - const float step = 1.0f / 1.2f; + const float step = 1.0f / zoom_speed; if (use_cam_zoom) { view_zoom_to_window_xy_camera(scene, depsgraph, v3d, region, step, zoom_xy); } @@ -631,8 +632,9 @@ void VIEW3D_OT_zoom(wmOperatorType *ot) ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY; /* properties */ - view3d_operator_properties_common( - ot, V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | V3D_OP_PROP_USE_MOUSE_INIT); + view3d_operator_properties_common(ot, + V3D_OP_PROP_DELTA | V3D_OP_PROP_MOUSE_CO | + V3D_OP_PROP_USE_MOUSE_INIT | V3D_OP_PROP_ZOOM_SPEED); } /** \} */ -- 2.30.2 From 5f0ae19709327d82aee8b73a6a35334daf5df126 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sun, 9 Apr 2023 06:05:31 -0700 Subject: [PATCH 17/20] two alternate cursors --- intern/ghost/GHOST_Types.h | 2 ++ intern/ghost/intern/GHOST_WindowWin32.cpp | 6 ++++++ release/windows/icons/winblender.rc | 2 ++ scripts/startup/bl_ui/space_userpref.py | 5 +++++ source/blender/blenloader/intern/versioning_userdef.c | 4 +--- source/blender/makesdna/DNA_userdef_types.h | 4 ++-- source/blender/makesrna/intern/rna_userdef.c | 10 ++++++++++ source/blender/windowmanager/intern/wm_cursors.c | 10 +++++++++- 8 files changed, 37 insertions(+), 6 deletions(-) diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index e950f9bc679..8e8ca667e5f 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -235,6 +235,8 @@ typedef enum { GHOST_kStandardCursorCrosshairA, GHOST_kStandardCursorCrosshairB, GHOST_kStandardCursorCrosshairC, + GHOST_kStandardCursorCrosshairD, + GHOST_kStandardCursorCrosshairE, GHOST_kStandardCursorPencil, GHOST_kStandardCursorUpArrow, GHOST_kStandardCursorDownArrow, diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 3e82f55c583..183af447f9b 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -772,6 +772,12 @@ HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const case GHOST_kStandardCursorCrosshairC: cursor = ::LoadImage(module, "crossC_cursor", IMAGE_CURSOR, cx, cy, flags); break; /* Minimal Crosshair C */ + case GHOST_kStandardCursorCrosshairD: + cursor = ::LoadImage(module, "crossD_cursor", IMAGE_CURSOR, cx, cy, flags); + break; /* Alternate Crosshair D */ + case GHOST_kStandardCursorCrosshairE: + cursor = ::LoadImage(module, "crossE_cursor", IMAGE_CURSOR, cx, cy, flags); + break; /* Large Crosshair E */ case GHOST_kStandardCursorBottomSide: case GHOST_kStandardCursorUpDown: cursor = ::LoadImage(module, "movens_cursor", IMAGE_CURSOR, cx, cy, flags); diff --git a/release/windows/icons/winblender.rc b/release/windows/icons/winblender.rc index a0dff81b711..fcd2a66b0cd 100644 --- a/release/windows/icons/winblender.rc +++ b/release/windows/icons/winblender.rc @@ -23,6 +23,8 @@ cross_cursor CURSOR "cursors/cross.cur" crossA_cursor CURSOR "cursors/crossa.cur" crossB_cursor CURSOR "cursors/crossb.cur" crossC_cursor CURSOR "cursors/crossc.cur" +crossD_cursor CURSOR "cursors/crossd.cur" +crossE_cursor CURSOR "cursors/crosse.cur" eraser_cursor CURSOR "cursors/eraser.cur" eyedropper_cursor CURSOR "cursors/eyedropper.cur" handopen_cursor CURSOR "cursors/handopen.cur" diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index 92b96e3d1f6..91d7410819f 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -501,6 +501,11 @@ class USERPREF_PT_edit_misc(EditingPanel, CenterAlignMixIn, Panel): colsub.active = edit.adjustable_click_select colsub.prop(edit, "select_unbiased") colsub.prop(edit, "selection_radius") + col = layout.column() + col.prop(edit, "alternate_cursor") + colsub = col.column(align=True) + colsub.active = edit.alternate_cursor + colsub.prop(edit, "alternate_cursor_large") diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index bdb327fc5f3..a4c765d9e61 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -434,7 +434,7 @@ void blo_do_versions_userdef(UserDef *userdef) if (!USER_VERSION_ATLEAST(278, 6)) { /* Clear preference flags for re-use. */ - userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | + userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_UNUSED_7 | USER_FLAG_UNUSED_9 | USER_DEVELOPER_UI); userdef->uiflag &= ~(USER_HEADER_BOTTOM); userdef->transopts &= ~(USER_TR_UNUSED_2 | USER_TR_UNUSED_3 | USER_TR_UNUSED_4 | @@ -524,8 +524,6 @@ void blo_do_versions_userdef(UserDef *userdef) copy_v3_fl3(userdef->light_ambient, 0.025000, 0.025000, 0.025000); - userdef->flag &= ~(USER_FLAG_UNUSED_4); - userdef->uiflag &= ~(USER_HEADER_FROM_PREF | USER_UIFLAG_UNUSED_12 | USER_UIFLAG_UNUSED_22); } diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index da9904b3ae4..1b45ea6fe42 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1014,9 +1014,9 @@ typedef enum eUserPref_Flag { USER_FLAG_NUMINPUT_ADVANCED = (1 << 1), USER_ADJUSTABLE_CLICK_SELECT = (1 << 2), USER_SELECT_UNBIASED = (1 << 3), - USER_FLAG_UNUSED_4 = (1 << 4), /* cleared */ + USER_ALTERNATE_CURSOR = (1 << 4), USER_TRACKBALL = (1 << 5), - USER_FLAG_UNUSED_6 = (1 << 6), /* cleared */ + USER_ALTERNATE_CURSOR_LARGE = (1 << 6), USER_FLAG_UNUSED_7 = (1 << 7), /* cleared */ USER_MAT_ON_OB = (1 << 8), USER_FLAG_UNUSED_9 = (1 << 9), /* cleared */ diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 5687f054bd4..5caead59308 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5337,6 +5337,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DEPTH_CURSOR); RNA_def_property_ui_text( prop, "Cursor Surface Project", "Use the surface depth for cursor placement"); + + prop = RNA_def_property(srna, "alternate_cursor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ALTERNATE_CURSOR); + RNA_def_property_ui_text(prop, "Alternate Cursor", "Alternate edit mode crosshair"); + + prop = RNA_def_property(srna, "alternate_cursor_large", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ALTERNATE_CURSOR_LARGE); + RNA_def_property_ui_text(prop, "Large Cursor", "Supersize the alternate edit mode crosshair"); } static void rna_def_userdef_system(BlenderRNA *brna) @@ -5932,6 +5940,8 @@ static void rna_def_userdef_input(BlenderRNA *brna) "Use either the keymap or toolsettings to control selection options " "for box, lasso, and circle select"); + + prop = RNA_def_property(srna, "use_numeric_input_advanced", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_FLAG_NUMINPUT_ADVANCED); RNA_def_property_ui_text(prop, diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index c9624d0e14e..2475e617fd0 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -50,7 +50,15 @@ static GHOST_TStandardCursor convert_to_ghost_standard_cursor(WMCursorType curs) return GHOST_kStandardCursorWait; case WM_CURSOR_EDIT: case WM_CURSOR_CROSS: - return GHOST_kStandardCursorCrosshair; + if (U.flag & USER_ALTERNATE_CURSOR && !(U.flag & USER_ALTERNATE_CURSOR_LARGE)) { + return GHOST_kStandardCursorCrosshairD; + } + else if (U.flag & USER_ALTERNATE_CURSOR && U.flag & USER_ALTERNATE_CURSOR_LARGE) { + return GHOST_kStandardCursorCrosshairE; + } + else { + return GHOST_kStandardCursorCrosshair; + } case WM_CURSOR_X_MOVE: return GHOST_kStandardCursorLeftRight; case WM_CURSOR_Y_MOVE: -- 2.30.2 From 0df7951a8fe09dd9994a2feec9400f1cd09398ac Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sun, 9 Apr 2023 06:07:41 -0700 Subject: [PATCH 18/20] remove empty lines --- source/blender/makesrna/intern/rna_userdef.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 5caead59308..3deda02181a 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5940,8 +5940,6 @@ static void rna_def_userdef_input(BlenderRNA *brna) "Use either the keymap or toolsettings to control selection options " "for box, lasso, and circle select"); - - prop = RNA_def_property(srna, "use_numeric_input_advanced", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_FLAG_NUMINPUT_ADVANCED); RNA_def_property_ui_text(prop, -- 2.30.2 From 7787aff6abbcb241bbae7fa13cb6fb05f04b8590 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sun, 9 Apr 2023 06:13:00 -0700 Subject: [PATCH 19/20] custom python operators stored in space_view3d.py --- scripts/startup/bl_ui/space_view3d.py | 93 +++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 0a3d13bd7d8..12e84045311 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -1077,6 +1077,99 @@ class ShowHideMenu: layout.operator("%s.hide" % self._operator_name, text="Hide Unselected").unselected = True +# Custom Operators +class VIEW3D_gizmo_tweak(bpy.types.Operator): + """tweak based on gizmo shown""" + bl_idname = "view3d.gizmo_tweak" + bl_label = "gizmo tweak" + + from bpy.props import StringProperty, BoolProperty + + tmode: StringProperty(name="Transform Mode") + release: BoolProperty(name="Confirm on Release") + + def modal(self, context, event): + if event.type == 'MOUSEMOVE': + bpy.ops.transform.transform( + 'INVOKE_DEFAULT', + mode=self.tmode, + release_confirm=self.release) + return {'FINISHED'} + + return {'RUNNING_MODAL'} + + def invoke(self, context, event): + if context.object: + if context.space_data.show_gizmo_object_translate==True: + self.tmode = 'TRANSLATION' + elif context.space_data.show_gizmo_object_rotate==True: + self.tmode = 'ROTATION' + elif context.space_data.show_gizmo_object_scale==True: + self.tmode = 'RESIZE' + else: self.tmode = 'TRANSLATION' + + context.window_manager.modal_handler_add(self) + return {'RUNNING_MODAL'} + else: + self.report({'WARNING'}, "No active object, could not finish") + return {'CANCELLED'} + +class VIEW3D_gizmo_move(bpy.types.Operator): + bl_idname = "view3d.gizmo_move" + bl_label = "gizmo move" + + def invoke(self, context, event): + areas = bpy.context.workspace.screens[0].areas + for area in areas: + for space in area.spaces: + if space.type == 'VIEW_3D': + space.show_gizmo_object_translate^= True + space.show_gizmo_object_rotate = False + space.show_gizmo_object_scale = False + return {'FINISHED'} + +class VIEW3D_gizmo_scale(bpy.types.Operator): + bl_idname = "view3d.gizmo_scale" + bl_label = "gizmo scale" + + def invoke(self, context, event): + areas = bpy.context.workspace.screens[0].areas + for area in areas: + for space in area.spaces: + if space.type == 'VIEW_3D': + space.show_gizmo_object_translate = False + space.show_gizmo_object_rotate = False + space.show_gizmo_object_scale ^= True + return {'FINISHED'} + +class VIEW3D_gizmo_rotate(bpy.types.Operator): + bl_idname = "view3d.gizmo_rotate" + bl_label = "gizmo rotate" + + def invoke(self, context, event): + areas = bpy.context.workspace.screens[0].areas + for area in areas: + for space in area.spaces: + if space.type == 'VIEW_3D': + space.show_gizmo_object_translate = False + space.show_gizmo_object_rotate ^= True + space.show_gizmo_object_scale = False + return {'FINISHED'} + +class VIEW3D_box_lasso(bpy.types.Operator): + bl_idname = "view3d.box_lasso" + bl_label = "box lasso" + + def invoke(self, context, event): + from bl_ui.space_toolsystem_common import ToolSelectPanelHelper + tool = ToolSelectPanelHelper.tool_active_from_context(context) + if tool.idname == "builtin.select_box": + bpy.ops.wm.tool_set_by_id(name="builtin.select_lasso") + else: + bpy.ops.wm.tool_set_by_id(name="builtin.select_box") + return {'FINISHED'} + + # Standard transforms which apply to all cases (mix-in class, not used directly). class VIEW3D_MT_transform_base: bl_label = "Transform" -- 2.30.2 From 3a6aa68b7b75dd3fc25d143f599e8f14700dc042 Mon Sep 17 00:00:00 2001 From: Lukas Sneyd Date: Sun, 9 Apr 2023 07:12:16 -0700 Subject: [PATCH 20/20] fix python operators --- scripts/startup/bl_ui/space_view3d.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 12e84045311..0f935ce00fc 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -8403,6 +8403,11 @@ classes = ( VIEW3D_MT_sculpt_gpencil_automasking_pie, VIEW3D_MT_wpaint_vgroup_lock_pie, VIEW3D_MT_sculpt_face_sets_edit_pie, + VIEW3D_gizmo_tweak, + VIEW3D_gizmo_move, + VIEW3D_gizmo_scale, + VIEW3D_gizmo_rotate, + VIEW3D_box_lasso, VIEW3D_MT_sculpt_curves, VIEW3D_PT_active_tool, VIEW3D_PT_active_tool_duplicate, -- 2.30.2