diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index f3e4c82090e..3723e6b61bf 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -6400,6 +6400,16 @@ def km_3d_view_tool_sculpt_line_mask(params): ]}, ) +def km_3d_view_tool_sculpt_line_project(params): + return ( + "3D View Tool: Sculpt, Line Project", + {"space_type": 'VIEW_3D', "region_type": 'WINDOW'}, + {"items": [ + ("sculpt.project_line_gesture", {"type": params.tool_tweak, "value": 'ANY'}, + None), + ]}, + ) + def km_3d_view_tool_sculpt_mesh_filter(params): return ( "3D View Tool: Sculpt, Mesh Filter", @@ -7005,6 +7015,7 @@ def generate_keymaps(params=None): km_3d_view_tool_sculpt_box_trim(params), km_3d_view_tool_sculpt_lasso_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), km_3d_view_tool_sculpt_cloth_filter(params), km_3d_view_tool_sculpt_color_filter(params), diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 3f7a3604741..744726af5d1 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1324,6 +1324,16 @@ class _defs_sculpt: keymap=(), ) + @ToolDef.from_fn + def project_line(): + return dict( + idname="builtin.line_project", + label="Line Project", + icon="ops.sculpt.line_project", + widget=None, + keymap=(), + ) + @ToolDef.from_fn def mesh_filter(): def draw_settings(_context, layout, tool): @@ -2702,6 +2712,13 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel): context.preferences.experimental.use_tools_missing_icons) else () ), + lambda context: ( + (_defs_sculpt.project_line,) + if context is None or ( + context.preferences.view.show_developer_ui and + context.preferences.experimental.use_tools_missing_icons) + else () + ), None, _defs_sculpt.mesh_filter, _defs_sculpt.cloth_filter, diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 0f2ebdd28aa..c483d0273ff 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1171,6 +1171,95 @@ static void sculpt_trim_gesture_operator_properties(wmOperatorType *ot) NULL); } +/* Project Gesture Operation. */ + +typedef struct SculptGestureProjectOperation { + SculptGestureOperation operation; +} SculptGestureProjectOperation; + +static void sculpt_gesture_project_begin(bContext *C, SculptGestureContext *sgcontext) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + BKE_sculpt_update_object_for_edit(depsgraph, sgcontext->vc.obact, false, false, false); +} + +static void project_line_gesture_apply_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptGestureContext *sgcontext = userdata; + + PBVHNode *node = sgcontext->nodes[i]; + PBVHVertexIter vd; + bool any_updated = false; + + SCULPT_undo_push_node(sgcontext->vc.obact, node, SCULPT_UNDO_COORDS); + + BKE_pbvh_vertex_iter_begin(sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + if (!sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { + continue; + } + + float projected_pos[3]; + closest_to_plane_v3(projected_pos, sgcontext->line.plane, vd.co); + + float disp[3]; + sub_v3_v3v3(disp, projected_pos, vd.co); + const float mask = vd.mask ? *vd.mask : 0.0f; + mul_v3_fl(disp, 1.0f - mask); + if (is_zero_v3(disp)) { + continue; + } + add_v3_v3(vd.co, disp); + any_updated = true; + } + BKE_pbvh_vertex_iter_end; + + if (any_updated) { + BKE_pbvh_node_mark_update(node); + } +} + +static void sculpt_gesture_project_apply_for_symmetry_pass(bContext *UNUSED(C), + SculptGestureContext *sgcontext) +{ + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, sgcontext->totnode); + + switch (sgcontext->shape_type) { + case SCULPT_GESTURE_SHAPE_LINE: + BLI_task_parallel_range( + 0, sgcontext->totnode, sgcontext, project_line_gesture_apply_task_cb, &settings); + break; + case SCULPT_GESTURE_SHAPE_LASSO: + case SCULPT_GESTURE_SHAPE_BOX: + /* Gesture shape projection not implemented yet. */ + BLI_assert(false); + break; + } +} + +static void sculpt_gesture_project_end(bContext *C, SculptGestureContext *sgcontext) +{ + SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS); + SCULPT_flush_update_done(C, sgcontext->vc.obact, SCULPT_UPDATE_COORDS); +} + +static void sculpt_gesture_init_project_properties(SculptGestureContext *sgcontext, + wmOperator *UNUSED(op)) +{ + sgcontext->operation = MEM_callocN(sizeof(SculptGestureFaceSetOperation), "Project Operation"); + + SculptGestureProjectOperation *project_operation = (SculptGestureProjectOperation *) + sgcontext->operation; + + project_operation->operation.sculpt_gesture_begin = sculpt_gesture_project_begin; + project_operation->operation.sculpt_gesture_apply_for_symmetry_pass = + sculpt_gesture_project_apply_for_symmetry_pass; + project_operation->operation.sculpt_gesture_end = sculpt_gesture_project_end; +} + static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op) { SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op); @@ -1270,6 +1359,18 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int project_gesture_line_exec(bContext *C, wmOperator *op) +{ + SculptGestureContext *sgcontext = sculpt_gesture_init_from_line(C, op); + if (!sgcontext) { + return OPERATOR_CANCELLED; + } + sculpt_gesture_init_project_properties(sgcontext, op); + sculpt_gesture_apply(C, sgcontext); + sculpt_gesture_context_free(sgcontext); + return OPERATOR_FINISHED; +} + void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot) { ot->name = "Mask Lasso Gesture"; @@ -1408,3 +1509,22 @@ void SCULPT_OT_trim_box_gesture(wmOperatorType *ot) sculpt_trim_gesture_operator_properties(ot); } + +void SCULPT_OT_project_line_gesture(wmOperatorType *ot) +{ + ot->name = "Project Line Gesture"; + ot->idname = "SCULPT_OT_project_line_gesture"; + ot->description = "Project the geometry onto a plane defined by a line"; + + ot->invoke = WM_gesture_straightline_invoke; + ot->modal = WM_gesture_straightline_oneshot_modal; + ot->exec = project_gesture_line_exec; + + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER; + + /* Properties. */ + WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT); + sculpt_gesture_operator_properties(ot); +} diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c70c0f7cd54..12dbdc686ec 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -9175,6 +9175,7 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_face_set_box_gesture); WM_operatortype_append(SCULPT_OT_trim_box_gesture); WM_operatortype_append(SCULPT_OT_trim_lasso_gesture); + WM_operatortype_append(SCULPT_OT_project_line_gesture); WM_operatortype_append(SCULPT_OT_sample_color); WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 71d6eb844e9..b846e009369 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1064,6 +1064,8 @@ void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot); void SCULPT_OT_trim_lasso_gesture(struct wmOperatorType *ot); void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot); +void SCULPT_OT_project_line_gesture(struct wmOperatorType *ot); + /* Face Sets. */ void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot); void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 0e4bb1cc33a..9592a0bfd35 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -3905,6 +3905,7 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "SCULPT_OT_face_set_box_gesture"); WM_modalkeymap_assign(keymap, "SCULPT_OT_trim_box_gesture"); WM_modalkeymap_assign(keymap, "PAINT_OT_mask_line_gesture"); + WM_modalkeymap_assign(keymap, "SCULPT_OT_project_line_gesture"); WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border"); WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border"); WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");