paint: add viewport mask to picker tool

This commit is contained in:
luboslenco
2026-07-11 17:42:26 +02:00
parent a0e13782bf
commit 0790b0f406
10 changed files with 67 additions and 46 deletions
+2 -1
View File
@@ -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;
-5
View File
@@ -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,
+1 -1
View File
@@ -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();
+4 -3
View File
@@ -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);
+16 -8
View File
@@ -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)));
}
+4
View File
@@ -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");
+3 -3
View File
@@ -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);
+4 -2
View File
@@ -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;
}
+2 -1
View File
@@ -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;
+31 -22
View File
@@ -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);