From 0790b0f406ec05c059a253b80c239952aca3cbd7 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Sat, 11 Jul 2026 17:42:26 +0200 Subject: [PATCH] paint: add viewport mask to picker tool --- paint/sources/context.c | 3 +- paint/sources/enums.h | 5 --- paint/sources/functions.h | 2 +- paint/sources/project.c | 7 ++-- paint/sources/render/make_discard.c | 24 +++++++---- paint/sources/render/make_mesh.c | 4 ++ paint/sources/render/make_paint.c | 6 +-- paint/sources/render/render_path_paint.c | 6 ++- paint/sources/types.h | 3 +- paint/sources/ui/ui_header.c | 53 ++++++++++++++---------- 10 files changed, 67 insertions(+), 46 deletions(-) diff --git a/paint/sources/context.c b/paint/sources/context.c index 5e514a83..d3ed8bbf 100644 --- a/paint/sources/context.c +++ b/paint/sources/context.c @@ -70,7 +70,8 @@ void context_init() { g_context->uvx_picked = 0.0; g_context->uvy_picked = 0.0; g_context->picker_select_material = false; - g_context->picker_mask = 0; + g_context->picker_paint_mask = false; + g_context->picker_viewport_mask = false; g_context->pick_pos_nor_tex = false; g_context->pick_object_id = false; g_context->posx_picked = 0.0; diff --git a/paint/sources/enums.h b/paint/sources/enums.h index df97cf34..74f05280 100644 --- a/paint/sources/enums.h +++ b/paint/sources/enums.h @@ -130,11 +130,6 @@ typedef enum { SCULPT_TYPE_GRAB = 1, } sculpt_type_t; -typedef enum { - PICKER_MASK_NONE = 0, - PICKER_MASK_MATERIAL = 1, -} picker_mask_t; - typedef enum { BLEND_TYPE_MIX = 0, BLEND_TYPE_DARKEN = 1, diff --git a/paint/sources/functions.h b/paint/sources/functions.h index d0748b16..2d3b7a57 100644 --- a/paint/sources/functions.h +++ b/paint/sources/functions.h @@ -610,7 +610,7 @@ void plugin_uv_unwrap_per_object_button(mesh_object_t *m void make_discard_color_id(node_shader_t *kong, char *tex_coord); void make_discard_face(node_shader_t *kong); void make_discard_uv_island(node_shader_t *kong); -void make_discard_material_id(node_shader_t *kong); +void make_discard_material_id(node_shader_t *kong, char *tex_coord); bool import_arm_is_old(buffer_t *b); project_t *import_arm_from_old(buffer_t *b); void nodes_brush_init(); diff --git a/paint/sources/project.c b/paint/sources/project.c index 96c44070..577381fa 100644 --- a/paint/sources/project.c +++ b/paint/sources/project.c @@ -203,9 +203,10 @@ void project_new(bool reset_layers) { } any_array_push(g_project->_->materials, slot_material_create(m, NULL)); - g_context->picker_mask = PICKER_MASK_NONE; - g_context->material = g_project->_->materials->buffer[0]; - ui_nodes_hwnd->redraws = 2; + g_context->picker_paint_mask = false; + g_context->picker_viewport_mask = false; + g_context->material = g_project->_->materials->buffer[0]; + ui_nodes_hwnd->redraws = 2; gc_unroot(ui_nodes_group_stack); ui_nodes_group_stack = any_array_create_from_raw((void *[]){}, 0); gc_root(ui_nodes_group_stack); diff --git a/paint/sources/render/make_discard.c b/paint/sources/render/make_discard.c index b7faf38a..69bc5f48 100644 --- a/paint/sources/render/make_discard.c +++ b/paint/sources/render/make_discard.c @@ -35,13 +35,21 @@ void make_discard_uv_island(node_shader_t *kong) { node_shader_write_frag(kong, "if (sample_lod(texuvislandmap, sampler_linear, input.tex_coord_pick, 0.0).r == 0.0) { discard; }"); } -void make_discard_material_id(node_shader_t *kong) { - kong->frag_wvpposition = true; - node_shader_write_frag( - kong, "var picker_sample_tc: float2 = float2(input.wvpposition.x / input.wvpposition.w, input.wvpposition.y / input.wvpposition.w) * 0.5 + 0.5;"); - node_shader_write_frag(kong, "picker_sample_tc.y = 1.0 - picker_sample_tc.y;"); +void make_discard_material_id(node_shader_t *kong, char *tex_coord) { + char *tc; + if (tex_coord == NULL) { + kong->frag_wvpposition = true; + node_shader_write_frag( + kong, "var picker_sample_tc: float2 = float2(input.wvpposition.x / input.wvpposition.w, input.wvpposition.y / input.wvpposition.w) * 0.5 + 0.5;"); + node_shader_write_frag(kong, "picker_sample_tc.y = 1.0 - picker_sample_tc.y;"); + tc = "picker_sample_tc"; + } + else { + tc = string("input.%s", tex_coord); + } node_shader_add_texture(kong, "texpaint_nor_undo", "_texpaint_nor_undo"); - i32 matid = g_context->materialid_picked / 255.0; - node_shader_write_frag(kong, - string("if (%s != sample_lod(texpaint_nor_undo, sampler_linear, picker_sample_tc, 0.0).a) { discard; }", i32_to_string(matid))); + node_shader_write_frag(kong, string("var picker_sample_a: float = sample_lod(texpaint_nor_undo, sampler_linear, %s, 0.0).a;", tc)); + // material_id * 3 + (0 - normal, 1 - emission, 2 - subsurface) + node_shader_write_frag(kong, "var picker_sample_id: float = floor(floor(picker_sample_a * 255.0 + 0.5) / 3.0);"); + node_shader_write_frag(kong, string("if (abs(picker_sample_id - %s) > 0.5) { discard; }", f32_to_string_with_zeros((f32)g_context->materialid_picked))); } diff --git a/paint/sources/render/make_mesh.c b/paint/sources/render/make_mesh.c index 68298e9f..624a116f 100644 --- a/paint/sources/render/make_mesh.c +++ b/paint/sources/render/make_mesh.c @@ -179,6 +179,10 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) { make_discard_color_id(kong, "tex_coord"); } + if (g_context->picker_viewport_mask && g_context->tool != TOOL_TYPE_PICKER) { + make_discard_material_id(kong, "tex_coord"); + } + if (g_context->tool == TOOL_TYPE_COLORID) { texture_count++; node_shader_add_texture(kong, "texcolorid", "_texcolorid"); diff --git a/paint/sources/render/make_paint.c b/paint/sources/render/make_paint.c index 0628ead2..0fb46e42 100644 --- a/paint/sources/render/make_paint.c +++ b/paint/sources/render/make_paint.c @@ -295,8 +295,8 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc } } - if (g_context->picker_mask == PICKER_MASK_MATERIAL) { - make_discard_material_id(kong); + if (g_context->picker_paint_mask) { + make_discard_material_id(kong, NULL); } make_texcoord_run(kong); @@ -484,7 +484,7 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_undo, sampler_linear, sample_tc, 0.0);"); f32 matid = g_context->material->id / 255.0; - if (g_context->picker_mask == PICKER_MASK_MATERIAL) { + if (g_context->picker_paint_mask) { matid = g_context->materialid_picked / 255.0; // Keep existing material id in place when mask is set } char *matid_string = parser_material_vec1(matid * 3.0); diff --git a/paint/sources/render/render_path_paint.c b/paint/sources/render/render_path_paint.c index 6ef74407..ae829d10 100644 --- a/paint/sources/render/render_path_paint.c +++ b/paint/sources/render/render_path_paint.c @@ -296,14 +296,16 @@ void render_path_paint_commands_paint(bool dilation) { g_context->picked_color->height = buffer_get_u8(c, i3) / 255.0; // Pick material - if (g_context->picker_select_material && g_context->color_picker_callback == NULL) { + if (g_context->color_picker_callback == NULL) { // matid % 3 == 0 - normal, 1 - emission, 2 - subsurface i32 id = buffer_get_u8(b, 3); i32 matid = math_floor((id - (id % 3)) / 3.0); for (i32 i = 0; i < g_project->_->materials->length; ++i) { slot_material_t *m = g_project->_->materials->buffer[i]; if (m->id == matid) { - context_set_material(m); + if (g_context->picker_select_material) { + context_set_material(m); + } g_context->materialid_picked = matid; break; } diff --git a/paint/sources/types.h b/paint/sources/types.h index ee195db4..2bda9434 100644 --- a/paint/sources/types.h +++ b/paint/sources/types.h @@ -281,7 +281,8 @@ typedef struct context { f32 uvx_picked; f32 uvy_picked; bool picker_select_material; - i32 picker_mask; + bool picker_paint_mask; + bool picker_viewport_mask; bool pick_pos_nor_tex; bool pick_object_id; f32 posx_picked; diff --git a/paint/sources/ui/ui_header.c b/paint/sources/ui/ui_header.c index d40fde08..1268c125 100644 --- a/paint/sources/ui/ui_header.c +++ b/paint/sources/ui/ui_header.c @@ -162,8 +162,9 @@ void ui_header_draw_tool_properties() { } g_ui->enabled = g_context->colorid_picked; if (ui_icon_button(tr("Clear"), ICON_ERASE, UI_ALIGN_CENTER)) { - g_context->colorid_picked = false; - ui_toolbar_handle->redraws = 1; + g_context->colorid_picked = false; + g_context->colorid_viewport_mask = false; + ui_toolbar_handle->redraws = 1; } g_ui->enabled = true; ui_text(tr("Color ID Map"), UI_ALIGN_LEFT, 0x00000000); @@ -199,6 +200,7 @@ void ui_header_draw_tool_properties() { g_ui->enabled = true; ui_handle_t *h_viewport_mask = ui_handle(__ID__); + h_viewport_mask->b = g_context->colorid_viewport_mask; g_context->colorid_viewport_mask = ui_check(h_viewport_mask, tr("Viewport Mask"), ""); if (h_viewport_mask->changed) { make_material_parse_mesh_material(); @@ -220,7 +222,7 @@ void ui_header_draw_tool_properties() { if (g_ui->is_hovered) { ui_tooltip(tr("Drag and drop picked color to swatches, materials, layers or to the node editor")); } - if (g_ui->is_hovered && g_ui->input_released) { + if (g_ui->is_hovered && g_ui->input_released && g_ui->combo_selected_handle == NULL) { gc_unroot(_ui_header_draw_tool_properties_h); _ui_header_draw_tool_properties_h = h_color; gc_root(_ui_header_draw_tool_properties_h); @@ -244,7 +246,7 @@ void ui_header_draw_tool_properties() { ui_handle_t *h_normal = ui_handle(__ID__); h_normal->color = g_context->picked_color->normal; ui_text("", 0, h_normal->color); - if (g_ui->is_hovered && g_ui->input_released) { + if (g_ui->is_hovered && g_ui->input_released && g_ui->combo_selected_handle == NULL) { gc_unroot(_ui_header_draw_tool_properties_h); _ui_header_draw_tool_properties_h = h_normal; gc_root(_ui_header_draw_tool_properties_h); @@ -278,18 +280,25 @@ void ui_header_draw_tool_properties() { h_select_mat->b = g_context->picker_select_material; g_context->picker_select_material = ui_check(h_select_mat, tr("Select Material"), ""); - string_array_t *picker_mask_combo = any_array_create_from_raw( - (void *[]){ - tr("None"), - tr("Material"), - }, - 2); + ui_handle_t *picker_paint_mask_handle = ui_handle(__ID__); + picker_paint_mask_handle->i = g_context->picker_paint_mask; + g_context->picker_paint_mask = ui_check(picker_paint_mask_handle, tr("Paint Mask"), ""); + if (picker_paint_mask_handle->changed) { + make_material_parse_paint_material(false); + } - ui_handle_t *picker_mask_handle = ui_handle(__ID__); - picker_mask_handle->i = g_context->picker_mask; - g_context->picker_mask = ui_combo(picker_mask_handle, picker_mask_combo, tr("Mask"), true, UI_ALIGN_LEFT, true); - if (picker_mask_handle->changed) { - make_material_parse_paint_material(true); + ui_handle_t *picker_viewport_mask_handle = ui_handle(__ID__); + picker_viewport_mask_handle->b = g_context->picker_viewport_mask; + g_context->picker_viewport_mask = ui_check(picker_viewport_mask_handle, tr("Viewport Mask"), ""); + if (picker_viewport_mask_handle->changed) { + make_material_parse_mesh_material(); + } + + if (ui_icon_button(tr("Clear"), ICON_ERASE, UI_ALIGN_CENTER)) { + g_context->picker_viewport_mask = false; + g_context->picker_paint_mask = false; + make_material_parse_mesh_material(); + make_material_parse_paint_material(false); } } else if (g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_ERASER || g_context->tool == TOOL_TYPE_FILL || @@ -431,13 +440,13 @@ void ui_header_draw_tool_properties() { } if (g_context->tool == TOOL_TYPE_BRUSH && g_config->workflow == WORKFLOW_SCULPT) { - ui_handle_t *sculpt_handle = ui_handle(__ID__); - string_array_t *mode_combo = any_array_create_from_raw( - (void *[]){ - tr("Draw"), - tr("Grab"), - }, - 2); + ui_handle_t *sculpt_handle = ui_handle(__ID__); + string_array_t *mode_combo = any_array_create_from_raw( + (void *[]){ + tr("Draw"), + tr("Grab"), + }, + 2); g_context->brush_sculpt = ui_combo(sculpt_handle, mode_combo, tr("Mode"), false, UI_ALIGN_LEFT, true); if (sculpt_handle->changed) { make_material_parse_paint_material(true);