diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index 6cd1a281c0e..0da5ce0f274 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -8131,6 +8131,16 @@ def km_3d_view_tool_sculpt_lasso_trim(params): ) +def km_3d_view_tool_sculpt_line_trim(params): + return ( + "3D View Tool: Sculpt, Line Trim", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": [ + ("sculpt.trim_line_gesture", params.tool_maybe_tweak_event, None), + ]}, + ) + + def km_3d_view_tool_sculpt_line_mask(params): return ( "3D View Tool: Sculpt, Line Mask", @@ -9059,6 +9069,7 @@ def generate_keymaps(params=None): km_3d_view_tool_sculpt_lasso_face_set(params), km_3d_view_tool_sculpt_box_trim(params), km_3d_view_tool_sculpt_lasso_trim(params), + km_3d_view_tool_sculpt_line_trim(params), km_3d_view_tool_sculpt_line_mask(params), km_3d_view_tool_sculpt_line_project(params), km_3d_view_tool_sculpt_mesh_filter(params), diff --git a/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 10b30c0e925..6ba88ce096f 100644 --- a/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1579,6 +1579,23 @@ class _defs_sculpt: draw_settings=draw_settings, ) + @ToolDef.from_fn + def trim_line(): + def draw_settings(_context, layout, tool): + props = tool.operator_properties("sculpt.trim_line_gesture") + layout.prop(props, "trim_solver", expand=False) + layout.prop(props, "trim_orientation", expand=False) + layout.prop(props, "use_cursor_depth", expand=False) + layout.prop(props, "use_limit_to_segment", expand=False) + return dict( + idname="builtin.line_trim", + label="Line Trim", + icon="ops.sculpt.line_trim", + widget=None, + keymap=(), + draw_settings=draw_settings, + ) + @ToolDef.from_fn def project_line(): def draw_settings(_context, layout, tool): @@ -3410,6 +3427,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): ( _defs_sculpt.trim_box, _defs_sculpt.trim_lasso, + _defs_sculpt.trim_line, ), _defs_sculpt.project_line, None, diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 7fbc6c5e897..18ff478453e 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -3775,6 +3775,9 @@ class VIEW3D_MT_sculpt(Menu): props = layout.operator("sculpt.trim_lasso_gesture", text="Lasso Trim") props.trim_mode = 'DIFFERENCE' + props = layout.operator("sculpt.trim_line_gesture", text="Line Trim") + props.trim_mode = 'DIFFERENCE' + props = layout.operator("sculpt.trim_box_gesture", text="Box Add") props.trim_mode = 'JOIN' diff --git a/source/blender/editors/sculpt_paint/sculpt_gesture.cc b/source/blender/editors/sculpt_paint/sculpt_gesture.cc index bb9bbf8b59c..d668a44f740 100644 --- a/source/blender/editors/sculpt_paint/sculpt_gesture.cc +++ b/source/blender/editors/sculpt_paint/sculpt_gesture.cc @@ -235,6 +235,12 @@ std::unique_ptr init_from_line(bContext *C, wmOperator *op) line_points[1][0] = RNA_int_get(op->ptr, "xend"); line_points[1][1] = RNA_int_get(op->ptr, "yend"); + gesture_data->gesture_points.reinitialize(2); + gesture_data->gesture_points[0][0] = line_points[0][0]; + gesture_data->gesture_points[0][1] = line_points[0][1]; + gesture_data->gesture_points[1][0] = line_points[1][0]; + gesture_data->gesture_points[1][1] = line_points[1][1]; + gesture_data->line.flip = RNA_boolean_get(op->ptr, "flip"); float plane_points[4][3]; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index b23f914df94..5992f9d1404 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -1787,6 +1787,7 @@ void SCULPT_OT_project_line_gesture(wmOperatorType *ot); namespace blender::ed::sculpt_paint::trim { void SCULPT_OT_trim_lasso_gesture(wmOperatorType *ot); void SCULPT_OT_trim_box_gesture(wmOperatorType *ot); +void SCULPT_OT_trim_line_gesture(wmOperatorType *ot); } /** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.cc b/source/blender/editors/sculpt_paint/sculpt_ops.cc index 8a96b7a67a8..03cf3d84499 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/sculpt_ops.cc @@ -1321,6 +1321,7 @@ void ED_operatortypes_sculpt() WM_operatortype_append(face_set::SCULPT_OT_face_set_box_gesture); WM_operatortype_append(trim::SCULPT_OT_trim_box_gesture); WM_operatortype_append(trim::SCULPT_OT_trim_lasso_gesture); + WM_operatortype_append(trim::SCULPT_OT_trim_line_gesture); WM_operatortype_append(project::SCULPT_OT_project_line_gesture); WM_operatortype_append(SCULPT_OT_sample_color); diff --git a/source/blender/editors/sculpt_paint/sculpt_trim.cc b/source/blender/editors/sculpt_paint/sculpt_trim.cc index eb18cb36802..573a6e9b8df 100644 --- a/source/blender/editors/sculpt_paint/sculpt_trim.cc +++ b/source/blender/editors/sculpt_paint/sculpt_trim.cc @@ -10,6 +10,7 @@ #include "BLI_math_geom.h" #include "BLI_math_matrix.h" #include "BLI_math_vector.h" +#include "BLI_math_vector.hh" #include "BLI_polyfill_2d.h" #include "BKE_brush.hh" @@ -17,6 +18,7 @@ #include "BKE_layer.hh" #include "BKE_lib_id.hh" #include "BKE_mesh.hh" +#include "BKE_object.hh" #include "DNA_modifier_types.h" @@ -274,13 +276,63 @@ static void calculate_depth(gesture::GestureData &gesture_data, r_depth_back = depth_back; } +/* Calculates a scalar factor to use to ensure a drawn line gesture + * encompasses the entire object to be acted on. */ +static float calc_expand_factor(const gesture::GestureData &gesture_data) +{ + Object *object = gesture_data.vc.obact; + + rcti rect; + const Bounds bounds = *BKE_object_boundbox_get(object); + paint_convert_bb_to_rect( + &rect, bounds.min, bounds.max, gesture_data.vc.region, gesture_data.vc.rv3d, object); + + const float2 min_corner(rect.xmin, rect.ymin); + const float2 max_corner(rect.xmax, rect.ymax); + + /* Mutiply the screen space bounds by an arbitrary factor to ensure the created points are + * sufficiently far and enclose the mesh to be operated on. */ + return math::distance(min_corner, max_corner) * 2.0f; +} + +/* Converts a line gesture's points into usable screen points. */ +static Array gesture_to_screen_points(gesture::GestureData &gesture_data) +{ + if (gesture_data.shape_type != gesture::ShapeType::Line) { + return gesture_data.gesture_points; + } + + const float expand_factor = calc_expand_factor(gesture_data); + + float2 start(gesture_data.gesture_points[0]); + float2 end(gesture_data.gesture_points[1]); + + const float2 dir = math::normalize(end - start); + + if (!gesture_data.line.use_side_planes) { + end = end + dir * expand_factor; + start = start - dir * expand_factor; + } + + float2 perp(dir.y, -dir.x); + + if (gesture_data.line.flip) { + perp *= -1; + } + + const float2 parallel_start = start + perp * expand_factor; + const float2 parallel_end = end + perp * expand_factor; + + return {start, end, parallel_end, parallel_start}; +} + static void generate_geometry(gesture::GestureData &gesture_data) { TrimOperation *trim_operation = (TrimOperation *)gesture_data.operation; ViewContext *vc = &gesture_data.vc; ARegion *region = vc->region; - const Span screen_points = gesture_data.gesture_points; + const Array screen_points = gesture_to_screen_points(gesture_data); BLI_assert(screen_points.size() > 1); const int trim_totverts = screen_points.size() * 2; @@ -614,6 +666,11 @@ static void init_operation(gesture::GestureData &gesture_data, wmOperator &op) if (!trim_operation->initial_hit) { trim_operation->orientation = OrientationType::View; } + + if (gesture_data.shape_type == gesture::ShapeType::Line) { + /* Line gestures only support Difference, no extrusion. */ + trim_operation->mode = OperationType::Difference; + } } static void operator_properties(wmOperatorType *ot) @@ -773,6 +830,37 @@ static int gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *even return WM_gesture_lasso_invoke(C, op, event); } +static int gesture_line_exec(bContext *C, wmOperator *op) +{ + if (!can_exec(*C)) { + return OPERATOR_CANCELLED; + } + + std::unique_ptr gesture_data = gesture::init_from_line(C, op); + if (!gesture_data) { + return OPERATOR_CANCELLED; + } + + gesture_data->operation = reinterpret_cast( + MEM_cnew(__func__)); + + initialize_cursor_info(*C, *op, *gesture_data); + init_operation(*gesture_data, *op); + gesture::apply(*C, *gesture_data, *op); + return OPERATOR_FINISHED; +} + +static int gesture_line_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!can_invoke(*C)) { + return OPERATOR_CANCELLED; + } + + RNA_int_set_array(op->ptr, "location", event->mval); + + return WM_gesture_straightline_active_side_invoke(C, op, event); +} + void SCULPT_OT_trim_lasso_gesture(wmOperatorType *ot) { ot->name = "Trim Lasso Gesture"; @@ -814,4 +902,25 @@ void SCULPT_OT_trim_box_gesture(wmOperatorType *ot) operator_properties(ot); } + +void SCULPT_OT_trim_line_gesture(wmOperatorType *ot) +{ + ot->name = "Trim Line Gesture"; + ot->idname = "SCULPT_OT_trim_line_gesture"; + ot->description = "Trims the mesh divided by the line as you move the brush"; + + ot->invoke = gesture_line_invoke; + ot->modal = WM_gesture_straightline_oneshot_modal; + ot->exec = gesture_line_exec; + + ot->poll = SCULPT_mode_poll_view3d; + + ot->flag = OPTYPE_REGISTER; + + /* Properties. */ + WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT); + gesture::operator_properties(ot, gesture::ShapeType::Line); + + operator_properties(ot); +} } // namespace blender::ed::sculpt_paint::trim diff --git a/source/blender/windowmanager/intern/wm_operators.cc b/source/blender/windowmanager/intern/wm_operators.cc index 30bc77278b6..f86d8bc8c3c 100644 --- a/source/blender/windowmanager/intern/wm_operators.cc +++ b/source/blender/windowmanager/intern/wm_operators.cc @@ -4135,6 +4135,7 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "PAINT_OT_weight_gradient"); WM_modalkeymap_assign(keymap, "MESH_OT_bisect"); WM_modalkeymap_assign(keymap, "PAINT_OT_mask_line_gesture"); + WM_modalkeymap_assign(keymap, "SCULPT_OT_trim_line_gesture"); WM_modalkeymap_assign(keymap, "SCULPT_OT_project_line_gesture"); WM_modalkeymap_assign(keymap, "PAINT_OT_hide_show_line_gesture"); }