From 421411a9f3b16f1e59b726c1395cf46e59f457ff Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 5 Jun 2026 00:41:18 +0200 Subject: [PATCH] paint: select tool --- paint/sources/base.c | 63 +++++++++++++++++++++++++++++++ paint/sources/enums.h | 7 ++-- paint/sources/keymap.c | 1 + paint/sources/main.c | 6 ++- paint/sources/render/make_paint.c | 7 ++++ paint/sources/types.h | 8 ++++ paint/sources/uniforms.c | 3 ++ 7 files changed, 90 insertions(+), 5 deletions(-) diff --git a/paint/sources/base.c b/paint/sources/base.c index 0f0c82eb..b3c57f44 100644 --- a/paint/sources/base.c +++ b/paint/sources/base.c @@ -448,6 +448,19 @@ void base_render(void *_) { draw_end(); } + // Select tool rectangle mask + if (g_context->select_active || g_context->select_dragging) { + f32 x1 = g_context->select_x1 * sys_w() + sys_x(); + f32 y1 = g_context->select_y1 * sys_h() + sys_y(); + f32 x2 = g_context->select_x2 * sys_w() + sys_x(); + f32 y2 = g_context->select_y2 * sys_h() + sys_y(); + draw_begin(NULL, false, 0); + draw_set_color(g_context->select_dragging ? 0xffffffff : 0xaaffffff); + draw_rect(x1, y1, x2 - x1, y2 - y1, 1.0); + draw_set_color(0xffffffff); + draw_end(); + } + bool using_menu = ui_menu_show && mouse_y > ui_header_h; base_ui_enabled = !ui_box_show && !using_menu && ui->combo_selected_handle == NULL; @@ -860,6 +873,49 @@ void ui_base_update_ui() { g_context->brush_stencil_y += (old_h - new_h) / (float)base_h() / 2.0; } + // Select tool + if (g_context->tool == TOOL_TYPE_SELECT) { + if (base_ui_enabled && !base_is_dragging && !base_is_resizing) { + f32 mx = mouse_view_x(); + f32 my = mouse_view_y(); + bool in_viewport = mx < sys_w() && mx > 0 && my < sys_h() && my > 0; + + if (mouse_started("left") && in_viewport) { + g_context->select_dragging = true; + g_context->select_start_x = mx / (float)sys_w(); + g_context->select_start_y = my / (float)sys_h(); + g_context->select_x1 = g_context->select_start_x; + g_context->select_y1 = g_context->select_start_y; + g_context->select_x2 = g_context->select_start_x; + g_context->select_y2 = g_context->select_start_y; + } + + if (g_context->select_dragging && mouse_down("left")) { + f32 cx = math_max(0.0, math_min(1.0, mx / (float)sys_w())); + f32 cy = math_max(0.0, math_min(1.0, my / (float)sys_h())); + g_context->select_x1 = math_min(g_context->select_start_x, cx); + g_context->select_y1 = math_min(g_context->select_start_y, cy); + g_context->select_x2 = math_max(g_context->select_start_x, cx); + g_context->select_y2 = math_max(g_context->select_start_y, cy); + } + + if (g_context->select_dragging && mouse_released("left")) { + g_context->select_dragging = false; + f32 dx = math_abs(g_context->select_x2 - g_context->select_x1) * sys_w(); + f32 dy = math_abs(g_context->select_y2 - g_context->select_y1) * sys_h(); + bool was_active = g_context->select_active; + // Drag to enable, click to cancel + g_context->select_active = dx > 3 && dy > 3; + if (was_active != g_context->select_active) { + make_material_parse_paint_material(false); + } + } + } + } + else { + g_context->select_dragging = false; + } + bool set_clone_source = g_context->tool == TOOL_TYPE_CLONE && operator_shortcut(string("%s+%s", any_map_get(config_keymap, "set_clone_source"), any_map_get(config_keymap, "action_paint")), SHORTCUT_TYPE_DOWN); @@ -883,6 +939,10 @@ void ui_base_update_ui() { down = false; } + if (g_context->tool == TOOL_TYPE_SELECT) { + down = false; + } + if (down) { i32 mx = mouse_view_x(); i32 my = mouse_view_y(); @@ -1199,6 +1259,9 @@ void ui_base_update(void *_) { else if (operator_shortcut(any_map_get(config_keymap, "tool_cursor"), SHORTCUT_TYPE_STARTED)) { context_select_tool(TOOL_TYPE_CURSOR); } + else if (operator_shortcut(any_map_get(config_keymap, "tool_select"), SHORTCUT_TYPE_STARTED)) { + context_select_tool(TOOL_TYPE_SELECT); + } else if (operator_shortcut(any_map_get(config_keymap, "swap_brush_eraser"), SHORTCUT_TYPE_STARTED)) { context_select_tool(g_context->tool == TOOL_TYPE_BRUSH ? TOOL_TYPE_ERASER : TOOL_TYPE_BRUSH); } diff --git a/paint/sources/enums.h b/paint/sources/enums.h index 7fe35d49..d35c69d2 100644 --- a/paint/sources/enums.h +++ b/paint/sources/enums.h @@ -234,7 +234,8 @@ typedef enum { TOOL_TYPE_PICKER = 9, TOOL_TYPE_MATERIAL = 10, TOOL_TYPE_CURSOR = 11, - TOOL_TYPE_BAKE = 12, // Hidden, used by Bake Texture node + TOOL_TYPE_SELECT = 12, + TOOL_TYPE_BAKE = 13, // Hidden, used by Bake Texture node } tool_type_t; typedef enum { @@ -320,9 +321,9 @@ typedef enum { ICON_TEXT_PREVIEW = 18, ICON_PROPERTIES = 19, ICON_FOLDER_OPEN = 20, - ICON_EMPTY = 21, + ICON_BAKE = 21, ICON_SMUDGE = 22, - ICON_BAKE = 23, + ICON_SELECT = 23, ICON_MENU = 24, ICON_FILE_NEW = 25, ICON_FOLDER = 26, diff --git a/paint/sources/keymap.c b/paint/sources/keymap.c index 9073a049..860a8b49 100644 --- a/paint/sources/keymap.c +++ b/paint/sources/keymap.c @@ -100,6 +100,7 @@ any_map_t *keymap_get_default() { any_map_set(keymap, "tool_colorid", "c"); any_map_set(keymap, "tool_picker", "v"); any_map_set(keymap, "tool_cursor", "r"); + any_map_set(keymap, "tool_select", "m"); any_map_set(keymap, "tool_material", ""); any_map_set(keymap, "swap_brush_eraser", ""); return keymap; diff --git a/paint/sources/main.c b/paint/sources/main.c index 23b355cb..6890ba7f 100644 --- a/paint/sources/main.c +++ b/paint/sources/main.c @@ -313,8 +313,9 @@ void _kickstart() { _tr("Picker"), _tr("Material"), _tr("Cursor"), + _tr("Select"), }, - 12); + 13); gc_root(ui_toolbar_tool_names); ui_toolbar_tooltip_extras = any_array_create_from_raw( @@ -331,8 +332,9 @@ void _kickstart() { "", "", "", + "", }, - 12); + 13); gc_root(ui_toolbar_tooltip_extras); uniforms_ext_ortho_p = mat4_ortho(-0.5, 0.5, -0.5, 0.5, -0.5, 0.5); diff --git a/paint/sources/render/make_paint.c b/paint/sources/render/make_paint.c index 25402ab1..d109d58f 100644 --- a/paint/sources/render/make_paint.c +++ b/paint/sources/render/make_paint.c @@ -219,6 +219,13 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc node_shader_write_frag(kong, "bsp.x *= constants.aspect_ratio;"); node_shader_write_frag(kong, "bsp = bsp * 0.5 + 0.5;"); + // Select tool mask + if (g_context->select_active) { + node_shader_add_constant(kong, "select_mask: float4", "_select_mask"); + node_shader_write_frag(kong, "if (sp.x < constants.select_mask.x || sp.x > constants.select_mask.z || sp.y < constants.select_mask.y || sp.y > " + "constants.select_mask.w) { discard; }"); + } + node_shader_add_texture(kong, "gbufferD", NULL); kong->frag_out = "float4[4]"; diff --git a/paint/sources/types.h b/paint/sources/types.h index e737708f..9f6b00b4 100644 --- a/paint/sources/types.h +++ b/paint/sources/types.h @@ -295,6 +295,14 @@ typedef struct context { f32 decal_x; f32 decal_y; bool decal_camera_align; + bool select_active; // Select tool + bool select_dragging; + f32 select_start_x; + f32 select_start_y; + f32 select_x1; + f32 select_y1; + f32 select_x2; + f32 select_y2; bool write_icon_on_export; struct gpu_texture *text_tool_image; char *text_tool_text; diff --git a/paint/sources/uniforms.c b/paint/sources/uniforms.c index bdda2dfa..dcb0f6a9 100644 --- a/paint/sources/uniforms.c +++ b/paint/sources/uniforms.c @@ -279,6 +279,9 @@ vec4_t uniforms_ext_vec4_link(object_t *object, material_data_t *mat, char *link } return v; } + else if (string_equals(link, "_select_mask")) { + return (vec4_t){g_context->select_x1, g_context->select_y1, g_context->select_x2, g_context->select_y2}; + } return vec4_nan(); }