paint: fix mask opacity handling

This commit is contained in:
luboslenco
2026-05-19 13:39:57 +02:00
parent 4a6cb56859
commit f14ab07bfc
6 changed files with 41 additions and 102 deletions
+7 -12
View File
@@ -219,19 +219,14 @@ void export_texture_run_layers(char *path, slot_layer_t_array_t *layers, char *o
gpu_texture_t *mask = empty;
slot_layer_t_array_t *l1masks = slot_layer_get_masks(l1, true);
if (l1masks != NULL && !bake_material) {
if (l1masks->length > 1) {
layers_make_temp_mask_img();
draw_begin(pipes_temp_mask_image, true, 0x00000000);
draw_end();
slot_layer_t *l1 = GC_ALLOC_INIT(slot_layer_t, {.texpaint = pipes_temp_mask_image});
for (i32 i = 0; i < l1masks->length; ++i) {
layers_merge_layer(l1, l1masks->buffer[i], false);
}
mask = pipes_temp_mask_image;
}
else {
mask = l1masks->buffer[0]->texpaint;
layers_make_temp_mask_img();
draw_begin(pipes_temp_mask_image, true, 0xffffffff);
draw_end();
slot_layer_t *l1 = GC_ALLOC_INIT(slot_layer_t, {.texpaint = pipes_temp_mask_image});
for (i32 i = 0; i < l1masks->length; ++i) {
layers_merge_layer(l1, l1masks->buffer[i], false);
}
mask = pipes_temp_mask_image;
}
if (l1->paint_base) {
-1
View File
@@ -480,7 +480,6 @@ void make_material_restore_paint_material();
parse_node_preview_result_t *make_material_parse_node_preview_material(ui_node_t *node, ui_node_canvas_t *group, ui_node_t_array_t *parents);
void make_material_parse_brush();
char *make_material_blend_mode(node_shader_t *kong, i32 blending, char *cola, char *colb, char *opac);
char *make_material_blend_mode_mask(node_shader_t *kong, i32 blending, char *cola, char *colb, char *opac);
f32 make_material_get_displace_strength();
void ui_viewnodes_init();
void ui_viewnodes_on_node_remove(ui_node_t *n);
+4 -59
View File
@@ -1,10 +1,10 @@
#include "global.h"
shader_context_t *make_material_default_scon = NULL;
material_context_t *make_material_default_mcon = NULL;
static shader_context_t *make_material_saved_scon = NULL;
static material_context_t *make_material_saved_mcon = NULL;
shader_context_t *make_material_default_scon = NULL;
material_context_t *make_material_default_mcon = NULL;
static shader_context_t *make_material_saved_scon = NULL;
static material_context_t *make_material_saved_mcon = NULL;
bool make_material_get_mout() {
for (i32 i = 0; i < g_context->material->canvas->nodes->length; ++i) {
@@ -512,61 +512,6 @@ char *make_material_blend_mode(node_shader_t *kong, i32 blending, char *cola, ch
}
}
char *make_material_blend_mode_mask(node_shader_t *kong, i32 blending, char *cola, char *colb, char *opac) {
if (blending == BLEND_TYPE_MIX) {
return string("lerp(%s, %s, %s)", cola, colb, opac);
}
else if (blending == BLEND_TYPE_DARKEN) {
return string("lerp(%s, min(%s, %s), %s)", cola, cola, colb, opac);
}
else if (blending == BLEND_TYPE_MULTIPLY) {
return string("lerp(%s, %s * %s, %s)", cola, cola, colb, opac);
}
else if (blending == BLEND_TYPE_BURN) {
return string("lerp(%s, 1.0 - (1.0 - %s) / %s, %s)", cola, cola, colb, opac);
}
else if (blending == BLEND_TYPE_LIGHTEN) {
return string("max(%s, %s * %s)", cola, colb, opac);
}
else if (blending == BLEND_TYPE_SCREEN) {
return string("(1.0 - ((1.0 - %s) + %s * (1.0 - %s)) * (1.0 - %s))", opac, opac, colb, cola);
}
else if (blending == BLEND_TYPE_DODGE) {
return string("lerp(%s, %s / (1.0 - %s), %s)", cola, cola, colb, opac);
}
else if (blending == BLEND_TYPE_ADD) {
return string("lerp(%s, %s + %s, %s)", cola, cola, colb, opac);
}
else if (blending == BLEND_TYPE_OVERLAY) {
// return "lerp(" + cola + ", " + cola + " < 0.5 ? 2.0 * " + cola + " * " + colb + " : 1.0 - 2.0 * (1.0 - " + cola + ") * (1.0 - " + colb + "), " + opac
// + ")";
char *res = string("%s_res", string_replace_all(cola, ".", "_"));
node_shader_write_frag(kong, string("var %s: float;", res));
node_shader_write_frag(kong, string("if (%s < 0.5) { %s = 2.0 * %s * %s; } else { %s = 1.0 - 2.0 * (1.0 - %s) * (1.0 - %s); }", cola, res, cola, colb,
res, cola, colb));
return string("lerp(%s, %s, %s)", cola, res, opac);
}
else if (blending == BLEND_TYPE_SOFT_LIGHT) {
return string("((1.0 - %s) * %s + %s * ((1.0 - %s) * %s * %s + %s * (1.0 - (1.0 - %s) * (1.0 - %s))))", opac, cola, opac, cola, colb, cola, cola, colb,
cola);
}
else if (blending == BLEND_TYPE_LINEAR_LIGHT) {
return string("(%s + %s * (2.0 * (%s - 0.5)))", cola, opac, colb);
}
else if (blending == BLEND_TYPE_DIFFERENCE) {
return string("lerp(%s, abs(%s - %s), %s)", cola, cola, colb, opac);
}
else if (blending == BLEND_TYPE_SUBTRACT) {
return string("lerp(%s, %s - %s, %s)", cola, cola, colb, opac);
}
else if (blending == BLEND_TYPE_DIVIDE) {
return string("(1.0 - %s) * %s + %s * %s / %s", opac, cola, opac, cola, colb);
}
else { // BlendHue, BlendSaturation, BlendColor, BlendValue
return string("lerp(%s, %s, %s)", cola, colb, opac);
}
}
f32 make_material_get_displace_strength() {
vec4_t sc = context_main_object()->base->transform->scale;
return g_config->displace_strength * 0.1 * sc.x;
+7 -10
View File
@@ -341,7 +341,7 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) {
}
if (has_visible) {
char *texpaint_mask = string("texpaint_mask%s", i32_to_string(l->id));
node_shader_write_frag(kong, string("var %s: float = 0.0;", texpaint_mask));
node_shader_write_frag(kong, string("var %s: float = 1.0;", texpaint_mask));
for (i32 i = 0; i < masks->length; ++i) {
slot_layer_t *m = masks->buffer[i];
if (!slot_layer_is_visible(m)) {
@@ -352,10 +352,9 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) {
node_shader_write_frag(kong, string("var texpaint_mask_sample%s: float = sample_lod(texpaint%s, sampler_linear, %s, 0.0).r;",
i32_to_string(m->id), i32_to_string(m->id), tex_coord));
f32 opac = slot_layer_get_opacity(m);
char *mask = make_material_blend_mode_mask(kong, m->blending, texpaint_mask, string("texpaint_mask_sample%s", i32_to_string(m->id)),
string("float(%s)", f32_to_string(opac)));
node_shader_write_frag(kong, string("%s = %s;", texpaint_mask, mask));
f32 opac = slot_layer_get_opacity(m);
node_shader_write_frag(kong, string("%s *= lerp(1.0, %s, float(%s));", texpaint_mask,
string("texpaint_mask_sample%s", i32_to_string(m->id)), f32_to_string(opac)));
node_shader_write_frag(kong, "}");
}
node_shader_write_frag(kong, string("texpaint_opac *= clamp(%s, 0.0, 1.0);", texpaint_mask));
@@ -632,7 +631,7 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) {
node_shader_write_frag(kong, string("var mask_view: float = sample_lod(texpaint%s, sampler_linear, tex_coord, 0.0).r;", i32_to_string(id)));
}
else {
node_shader_write_frag(kong, "var mask_view: float = 0.0;");
node_shader_write_frag(kong, "var mask_view: float = 1.0;");
for (i32 i = 0; i < slot_layer_get_masks(g_context->layer, true)->length; ++i) {
slot_layer_t *m = slot_layer_get_masks(g_context->layer, true)->buffer[i];
if (!slot_layer_is_visible(m)) {
@@ -640,10 +639,8 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) {
}
node_shader_write_frag(kong, string("var mask_sample%s: float = sample_lod(texpaint_view_mask%s, sampler_linear, tex_coord, 0.0).r;",
i32_to_string(m->id), i32_to_string(m->id)));
f32 opac = slot_layer_get_opacity(m);
char *mask = make_material_blend_mode_mask(kong, m->blending, "mask_view", string("mask_sample%s", i32_to_string(m->id)),
string("float(%s)", f32_to_string(opac)));
node_shader_write_frag(kong, string("mask_view = %s;", mask));
f32 opac = slot_layer_get_opacity(m);
node_shader_write_frag(kong, string("mask_view *= lerp(1.0, mask_sample%s, float(%s));", i32_to_string(m->id), f32_to_string(opac)));
}
}
node_shader_write_frag(kong, "output[1] = float4(mask_view, mask_view, mask_view, 1.0);");
+21 -15
View File
@@ -99,7 +99,7 @@ slot_layer_t *slot_layer_create(char *ext, layer_slot_type_t type, slot_layer_t
i32 id = (raw->id + 1);
raw->name = string("Mask %d", id);
char *format = "RGBA32"; // Full bits for undo support, R8 is used
raw->blending = BLEND_TYPE_ADD;
raw->blending = BLEND_TYPE_MIX;
{
render_target_t *t = render_target_create();
@@ -1696,7 +1696,18 @@ void layers_merge_layer(slot_layer_t *l0, slot_layer_t *l1, bool use_mask) {
// for (let i: i32 = 1; i < l1masks.length - 1; ++i) {
// merge_layer(l1masks[i + 1], l1masks[i]);
// }
mask = l1masks->buffer[0]->texpaint;
layers_make_temp_mask_img();
_gpu_begin(pipes_temp_mask_image, NULL, NULL, GPU_CLEAR_NONE, 0, 0.0);
gpu_set_pipeline(pipes_merge_mask);
gpu_set_texture(pipes_tex0_merge_mask, l1masks->buffer[0]->texpaint);
gpu_set_texture(pipes_texa_merge_mask, empty);
gpu_set_float(pipes_opac_merge_mask, l1masks->buffer[0]->mask_opacity);
gpu_set_int(pipes_blending_merge_mask, BLEND_TYPE_MIX);
gpu_set_vertex_buffer(const_data_screen_aligned_vb);
gpu_set_index_buffer(const_data_screen_aligned_ib);
gpu_draw();
gpu_end();
mask = pipes_temp_mask_image;
}
if (slot_layer_is_mask(l1)) {
@@ -1705,7 +1716,7 @@ void layers_merge_layer(slot_layer_t *l0, slot_layer_t *l1, bool use_mask) {
gpu_set_texture(pipes_tex0_merge_mask, l1->texpaint);
gpu_set_texture(pipes_texa_merge_mask, layers_temp_image);
gpu_set_float(pipes_opac_merge_mask, slot_layer_get_opacity(l1));
gpu_set_int(pipes_blending_merge_mask, l1->blending);
gpu_set_int(pipes_blending_merge_mask, BLEND_TYPE_MIX);
gpu_set_vertex_buffer(const_data_screen_aligned_vb);
gpu_set_index_buffer(const_data_screen_aligned_ib);
gpu_draw();
@@ -1814,19 +1825,14 @@ slot_layer_t *layers_flatten(bool height_to_normal, slot_layer_t_array_t *layers
gpu_texture_t *mask = empty;
slot_layer_t_array_t *l1masks = slot_layer_get_masks(l1, true);
if (l1masks != NULL) {
if (l1masks->length > 1) {
layers_make_temp_mask_img();
draw_begin(pipes_temp_mask_image, GPU_CLEAR_COLOR, 0x00000000);
draw_end();
slot_layer_t *l1 = GC_ALLOC_INIT(slot_layer_t, {.texpaint = pipes_temp_mask_image});
for (i32 i = 0; i < l1masks->length; ++i) {
layers_merge_layer(l1, l1masks->buffer[i], false);
}
mask = pipes_temp_mask_image;
}
else {
mask = l1masks->buffer[0]->texpaint;
layers_make_temp_mask_img();
draw_begin(pipes_temp_mask_image, GPU_CLEAR_COLOR, 0xffffffff);
draw_end();
slot_layer_t *l1 = GC_ALLOC_INIT(slot_layer_t, {.texpaint = pipes_temp_mask_image});
for (i32 i = 0; i < l1masks->length; ++i) {
layers_merge_layer(l1, l1masks->buffer[i], false);
}
mask = pipes_temp_mask_image;
}
if (l1->paint_base) {
+2 -5
View File
@@ -447,13 +447,10 @@ void tab_layers_draw_layer_slot_full(slot_layer_t *l, i32 i) {
}
// Blending combo
if (!slot_layer_is_group(l)) {
if (!slot_layer_is_group(l) && !slot_layer_is_mask(l)) {
ui->_x = uix + uiw * 0.60;
ui->_y = uiy;
ui->_w = uiw * 0.30;
if (slot_layer_is_mask(l)) {
ui->_y += center;
}
tab_layers_combo_blending(l, false);
}
@@ -641,7 +638,7 @@ void tab_layers_draw_layer_context_menu_draw() {
ui_menu_keep_open = true;
}
if (!slot_layer_is_group(l)) {
if (!slot_layer_is_group(l) && !slot_layer_is_mask(l)) {
if (tab_layers_combo_blending(l, true)->changed) {
ui_menu_keep_open = true;
}