From 5d93d4c86a0b422b270bf5fecf3a354ffdd8173a Mon Sep 17 00:00:00 2001 From: luboslenco Date: Thu, 28 May 2026 17:55:23 +0200 Subject: [PATCH] paint: sculpt layer fixes --- paint/sources/functions.h | 4 +- paint/sources/import_mesh.c | 1 + paint/sources/make_depth.c | 13 ++++ paint/sources/make_mesh.c | 18 +++-- paint/sources/make_paint.c | 44 +++++++++++- paint/sources/make_sculpt.c | 113 +++++++++++++++++++++++------- paint/sources/render_path_paint.c | 15 +++- paint/sources/slot_layer.c | 4 +- paint/sources/uniforms.c | 4 ++ 9 files changed, 176 insertions(+), 40 deletions(-) diff --git a/paint/sources/functions.h b/paint/sources/functions.h index 8c607142..f2983b7c 100644 --- a/paint/sources/functions.h +++ b/paint/sources/functions.h @@ -602,8 +602,8 @@ void render_path_raytrace_init(); void render_path_raytrace_raytrace_init(char *shader_name, bool build); void render_path_raytrace_draw(bool use_live_layer); node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context_t *matcon); -void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t *l); -void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, slot_layer_t *l); +void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t_array_t *sculpt_layers, i32_array_t *sculpt_indices); +void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, gpu_texture_t *target); void sculpt_init_sculpt_texture(slot_layer_t *l, mesh_data_t *md); void sculpt_init(); void sculpt_layers_create_sculpt_layer(); diff --git a/paint/sources/import_mesh.c b/paint/sources/import_mesh.c index bf891e25..b22ec292 100644 --- a/paint/sources/import_mesh.c +++ b/paint/sources/import_mesh.c @@ -110,6 +110,7 @@ void import_mesh_finish_import(void *_) { render_path_raytrace_ready = false; g_context->paint_body = NULL; tab_meshes_reset_preview_map(); + base_update_workflow(); if (import_mesh_needs_unwrap) { import_mesh_needs_unwrap = false; diff --git a/paint/sources/make_depth.c b/paint/sources/make_depth.c index a5a3084c..03c5829b 100644 --- a/paint/sources/make_depth.c +++ b/paint/sources/make_depth.c @@ -60,6 +60,19 @@ node_shader_context_t *make_depth_run(material_t *data, material_context_t *matc node_shader_write_vert(kong, "output.pos = constants.VP * float4(output.wposition.xyz, 1.0);"); + // { + // slot_layer_t_array_t *sculpt_layers = any_array_create_from_raw((void *[]){}, 0); + // i32_array_t *sculpt_indices = i32_array_create(0); + // for (i32 i = 0; i < project_layers->length; ++i) { + // slot_layer_t *l = project_layers->buffer[i]; + // if (l->texpaint_sculpt != NULL && slot_layer_is_visible(l)) { + // any_array_push(sculpt_layers, l); + // i32_array_push(sculpt_indices, i); + // } + // } + // sculpt_make_mesh_run(kong, sculpt_layers, sculpt_indices); + // } + con_depth->data->color_writes_red = u8_array_create_from_raw( (u8[]){ false, diff --git a/paint/sources/make_mesh.c b/paint/sources/make_mesh.c index 224e1ee9..867ed83a 100644 --- a/paint/sources/make_mesh.c +++ b/paint/sources/make_mesh.c @@ -162,11 +162,17 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) { kong->frag_n = true; node_shader_add_function(kong, str_pack_float_int16); - for (i32 i = 0; i < project_layers->length; ++i) { - slot_layer_t *l = project_layers->buffer[i]; - if (l->texpaint_sculpt != NULL) { - sculpt_make_mesh_run(kong, l); + { + slot_layer_t_array_t *sculpt_layers = any_array_create_from_raw((void *[]){}, 0); + i32_array_t *sculpt_indices = i32_array_create(0); + for (i32 i = 0; i < project_layers->length; ++i) { + slot_layer_t *l = project_layers->buffer[i]; + if (l->texpaint_sculpt != NULL && slot_layer_is_visible(l)) { + any_array_push(sculpt_layers, l); + i32_array_push(sculpt_indices, i); + } } + sculpt_make_mesh_run(kong, sculpt_layers, sculpt_indices); } if (g_context->colorid_viewport_mask && g_context->tool != TOOL_TYPE_COLORID) { @@ -371,8 +377,8 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) { node_shader_write_frag(kong, "basecol = texpaint_sample.rgb * texpaint_opac;"); } else { - node_shader_write_frag(kong, string("basecol = %s;", - make_material_blend_mode(kong, slot_layer_get_blending(l), "basecol", "texpaint_sample.rgb", "texpaint_opac"))); + node_shader_write_frag(kong, string("basecol = %s;", make_material_blend_mode(kong, slot_layer_get_blending(l), "basecol", + "texpaint_sample.rgb", "texpaint_opac"))); } } diff --git a/paint/sources/make_paint.c b/paint/sources/make_paint.c index 6e544240..ebfacc69 100644 --- a/paint/sources/make_paint.c +++ b/paint/sources/make_paint.c @@ -584,8 +584,48 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc } parser_material_finalize(con_paint); - parser_material_triplanar = false; - parser_material_sample_keep_aspect = false; + parser_material_triplanar = false; + parser_material_sample_keep_aspect = false; + + { + slot_layer_t_array_t *sculpt_layers = any_array_create_from_raw((void *[]){}, 0); + i32_array_t *sculpt_indices = i32_array_create(0); + for (i32 i = 0; i < project_layers->length; ++i) { + slot_layer_t *l = project_layers->buffer[i]; + if (l->texpaint_sculpt != NULL && slot_layer_is_visible(l)) { + any_array_push(sculpt_layers, l); + i32_array_push(sculpt_indices, i); + } + } + i32 scount = sculpt_layers->length; + if (scount > 0) { + i32 idx0 = sculpt_indices->buffer[0]; + node_shader_add_constant(kong, string("texpaint_sculpt_size%d: float2", idx0), string("_size(_texpaint_sculpt%d)", idx0)); + for (i32 i = 0; i < scount; ++i) { + i32 idx = sculpt_indices->buffer[i]; + node_shader_add_texture(kong, string("texpaint_sculpt%d", idx), string("_texpaint_sculpt%d", idx)); + } + if (scount > 1) { + node_shader_add_texture(kong, "texpaint_sculpt_base", "_texpaint_sculpt_base"); + } + + node_shader_write_attrib_vert(kong, string("var sculpt_uv_paint: uint2 = uint2(uint(float(vertex_id()) %% constants.texpaint_sculpt_size%d.x), " + "uint(float(vertex_id()) / constants.texpaint_sculpt_size%d.y));", + idx0, idx0)); + + node_shader_write_attrib_vert(kong, string("var sculpt_pos_paint: float4 = texpaint_sculpt%d[sculpt_uv_paint];", idx0)); + for (i32 i = 1; i < scount; ++i) { + i32 idx = sculpt_indices->buffer[i]; + node_shader_write_attrib_vert( + kong, string("sculpt_pos_paint = sculpt_pos_paint + texpaint_sculpt%d[sculpt_uv_paint] - texpaint_sculpt_base[sculpt_uv_paint];", idx)); + } + node_shader_write_attrib_vert(kong, "output.ndc = constants.WVP * float4(sculpt_pos_paint.xyz, 1.0);"); + if (kong->frag_wposition) { + node_shader_write_attrib_vert(kong, "output.wposition = (constants.W * float4(sculpt_pos_paint.xyz, 1.0)).xyz;"); + } + } + } + con_paint->data->shader_from_source = true; gpu_create_shaders_from_kong(node_shader_get(kong), &con_paint->data->vertex_shader, &con_paint->data->fragment_shader, &con_paint->data->_->vertex_shader_size, &con_paint->data->_->fragment_shader_size); diff --git a/paint/sources/make_sculpt.c b/paint/sources/make_sculpt.c index d6200acd..2feb8e3b 100644 --- a/paint/sources/make_sculpt.c +++ b/paint/sources/make_sculpt.c @@ -1,7 +1,7 @@ #include "global.h" -void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, slot_layer_t *l) { +void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, gpu_texture_t *target) { buffer_t *b = buffer_create(config_get_texture_res_x() * config_get_texture_res_y() * 4 * 4); for (i32 i = 0; i < math_floor(mesh->index_array->length); ++i) { i32 index = mesh->index_array->buffer[i]; @@ -24,7 +24,7 @@ void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, slot_layer_t *l) { } gpu_texture_t *imgmesh = gpu_create_texture_from_bytes(b, config_get_texture_res_x(), config_get_texture_res_y(), GPU_TEXTURE_FORMAT_RGBA128); - draw_begin(l->texpaint_sculpt, false, 0); + draw_begin(target, false, 0); draw_set_pipeline(pipes_copy128); draw_scaled_image(imgmesh, 0, 0, config_get_texture_res_x(), config_get_texture_res_y()); draw_set_pipeline(NULL); @@ -211,38 +211,73 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context return con_paint; } -void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t *l) { +void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t_array_t *sculpt_layers, i32_array_t *sculpt_indices) { + i32 count = sculpt_layers->length; + if (count == 0) { + return; + } + + i32 idx0 = sculpt_indices->buffer[0]; + node_shader_add_constant(kong, "WVP: float4x4", "_world_view_proj_matrix"); - i32 lid = array_index_of(project_layers, l); - node_shader_add_texture(kong, "texpaint_sculpt", string("_texpaint_sculpt%s", i32_to_string(lid))); - node_shader_add_constant(kong, "texpaint_sculpt_size: float2", string("_size(_texpaint_sculpt%s)", i32_to_string(lid))); - // node_shader_write_vert(kong, "var meshpos: float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(vertex_id() % constants.texpaint_sculpt_size.x, - // vertex_id() / constants.texpaint_sculpt_size.y), 0.0).xyz;"); - node_shader_write_vert(kong, "var meshpos: float4 = texpaint_sculpt[uint2(uint(float(vertex_id()) % constants.texpaint_sculpt_size.x), " - "uint(float(vertex_id()) / constants.texpaint_sculpt_size.y))];"); - // + input.pos.xyz * 0.000001 - node_shader_write_vert(kong, "output.pos = constants.WVP * float4(meshpos.xyz, 1.0);"); - kong->frag_n = false; node_shader_add_constant(kong, "N: float3x3", "_normal_matrix"); node_shader_add_out(kong, "wnormal: float3"); + kong->frag_n = false; + + node_shader_add_constant(kong, string("texpaint_sculpt_size%d: float2", idx0), string("_size(_texpaint_sculpt%d)", idx0)); + + for (i32 i = 0; i < count; ++i) { + i32 idx = sculpt_indices->buffer[i]; + node_shader_add_texture(kong, string("texpaint_sculpt%d", idx), string("_texpaint_sculpt%d", idx)); + } + + if (count > 1) { + node_shader_add_texture(kong, "texpaint_sculpt_base", "_texpaint_sculpt_base"); + } + + // Position + node_shader_write_vert(kong, string("var sculpt_uv: uint2 = uint2(uint(float(vertex_id()) %% constants.texpaint_sculpt_size%d.x), " + "uint(float(vertex_id()) / constants.texpaint_sculpt_size%d.y));", + idx0, idx0)); + node_shader_write_vert(kong, string("var texpaint_sculpt_sample: float4 = texpaint_sculpt%d[sculpt_uv];", idx0)); + node_shader_write_vert(kong, "var sculpt_pos: float3 = texpaint_sculpt_sample.xyz;"); + for (i32 i = 1; i < count; ++i) { + i32 idx = sculpt_indices->buffer[i]; + node_shader_write_vert(kong, string("var texpaint_sculpt_sample_%d: float4 = texpaint_sculpt%d[sculpt_uv];", idx, idx)); + node_shader_write_vert(kong, string("var texpaint_sculpt_base_sample_%d: float4 = texpaint_sculpt_base[sculpt_uv];", idx)); + node_shader_write_vert(kong, string("sculpt_pos = sculpt_pos + texpaint_sculpt_sample_%d.xyz - texpaint_sculpt_base_sample_%d.xyz;", idx, idx)); + } + node_shader_write_vert(kong, "output.pos = constants.WVP * float4(sculpt_pos, 1.0);"); + + // Normal node_shader_write_attrib_vert(kong, "var base_vertex0: float = float(vertex_id()) - (float(vertex_id()) % float(3));"); node_shader_write_attrib_vert(kong, "var base_vertex1: float = base_vertex0 + 1.0;"); node_shader_write_attrib_vert(kong, "var base_vertex2: float = base_vertex0 + 2.0;"); - // node_shader_write_attrib_vert(kong, "var meshpos0: float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(base_vertex0 % - // constants.texpaint_sculpt_size.x, base_vertex0 / constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_attrib_vert(kong, "var meshpos1: - // float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(base_vertex1 % constants.texpaint_sculpt_size.x, base_vertex1 / - // constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_attrib_vert(kong, "var meshpos2: float3 = sample_lod(texpaint_sculpt, sampler_linear, - // uint2(base_vertex2 % constants.texpaint_sculpt_size.x, base_vertex2 / constants.texpaint_sculpt_size.y), 0.0).xyz;"); - node_shader_write_attrib_vert(kong, "var meshpos0: float4 = texpaint_sculpt[uint2(uint(base_vertex0 % constants.texpaint_sculpt_size.x), uint(base_vertex0 " - "/ constants.texpaint_sculpt_size.y))];"); - node_shader_write_attrib_vert(kong, "var meshpos1: float4 = texpaint_sculpt[uint2(uint(base_vertex1 % constants.texpaint_sculpt_size.x), uint(base_vertex1 " - "/ constants.texpaint_sculpt_size.y))];"); - node_shader_write_attrib_vert(kong, "var meshpos2: float4 = texpaint_sculpt[uint2(uint(base_vertex2 % constants.texpaint_sculpt_size.x), uint(base_vertex2 " - "/ constants.texpaint_sculpt_size.y))];"); + node_shader_write_attrib_vert( + kong, + string("var uv0: uint2 = uint2(uint(base_vertex0 %% constants.texpaint_sculpt_size%d.x), uint(base_vertex0 / constants.texpaint_sculpt_size%d.y));", + idx0, idx0)); + node_shader_write_attrib_vert( + kong, + string("var uv1: uint2 = uint2(uint(base_vertex1 %% constants.texpaint_sculpt_size%d.x), uint(base_vertex1 / constants.texpaint_sculpt_size%d.y));", + idx0, idx0)); + node_shader_write_attrib_vert( + kong, + string("var uv2: uint2 = uint2(uint(base_vertex2 %% constants.texpaint_sculpt_size%d.x), uint(base_vertex2 / constants.texpaint_sculpt_size%d.y));", + idx0, idx0)); + + node_shader_write_attrib_vert(kong, string("var meshpos0: float4 = texpaint_sculpt%d[uv0];", idx0)); + node_shader_write_attrib_vert(kong, string("var meshpos1: float4 = texpaint_sculpt%d[uv1];", idx0)); + node_shader_write_attrib_vert(kong, string("var meshpos2: float4 = texpaint_sculpt%d[uv2];", idx0)); + for (i32 i = 1; i < count; ++i) { + i32 idx = sculpt_indices->buffer[i]; + node_shader_write_attrib_vert(kong, string("meshpos0 = meshpos0 + texpaint_sculpt%d[uv0] - texpaint_sculpt_base[uv0];", idx)); + node_shader_write_attrib_vert(kong, string("meshpos1 = meshpos1 + texpaint_sculpt%d[uv1] - texpaint_sculpt_base[uv1];", idx)); + node_shader_write_attrib_vert(kong, string("meshpos2 = meshpos2 + texpaint_sculpt%d[uv2] - texpaint_sculpt_base[uv2];", idx)); + } node_shader_write_attrib_vert(kong, "var meshnor: float3 = normalize(cross(meshpos2.xyz - meshpos1.xyz, meshpos0.xyz - meshpos1.xyz));"); node_shader_write_attrib_vert(kong, "output.wnormal = constants.N * meshnor;"); - node_shader_write_attrib_frag(kong, "var n: float3 = normalize(input.wnormal);"); } @@ -256,7 +291,29 @@ void sculpt_init_sculpt_texture(slot_layer_t *l, mesh_data_t *md) { t->format = "RGBA128"; l->texpaint_sculpt = render_path_create_render_target(t)->_image; } - sculpt_import_mesh_pack_to_texture(md, l); + sculpt_import_mesh_pack_to_texture(md, l->texpaint_sculpt); + + i32 sculpt_layer_count = 0; + for (i32 i = 0; i < project_layers->length; ++i) { + if (project_layers->buffer[i]->texpaint_sculpt != NULL) { + sculpt_layer_count++; + } + } + + if (any_map_get(render_path_render_targets, "texpaint_sculpt_base") == NULL) { + render_target_t *t = render_target_create(); + t->name = "texpaint_sculpt_base"; + t->width = config_get_texture_res_x(); + t->height = config_get_texture_res_y(); + t->format = "RGBA128"; + render_path_create_render_target(t); + } + + if (sculpt_layer_count == 1) { + render_path_set_target("texpaint_sculpt_base", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); + render_path_bind_target(string("texpaint_sculpt%s", i32_to_string(id)), "tex"); + render_path_draw_shader("Scene/copy_pass/copyRGBA128_pass"); + } } void sculpt_init() { @@ -296,6 +353,10 @@ void sculpt_init() { md = mesh_data_create(raw); mesh_object_set_data(g_context->paint_object, md); + if (g_context->merged_object != NULL) { + util_mesh_merge(NULL); + } + make_material_parse_paint_material(true); make_material_parse_mesh_material(); diff --git a/paint/sources/render_path_paint.c b/paint/sources/render_path_paint.c index 1ed70346..b9588970 100644 --- a/paint/sources/render_path_paint.c +++ b/paint/sources/render_path_paint.c @@ -433,6 +433,17 @@ void render_path_paint_commands_paint(bool dilation) { if (read_tc) { render_path_bind_target("gbuffer2", "gbuffer2"); } + i32 sculpt_layer_count = 0; + for (i32 i = 0; i < project_layers->length; ++i) { + slot_layer_t *sl = project_layers->buffer[i]; + if (sl->texpaint_sculpt != NULL && slot_layer_is_visible(sl)) { + render_path_bind_target(string("texpaint_sculpt%d", sl->id), string("texpaint_sculpt%d", sl->id)); + sculpt_layer_count++; + } + } + if (sculpt_layer_count > 1) { + render_path_bind_target("texpaint_sculpt_base", "texpaint_sculpt_base"); + } object_t *bullet = scene_get_child(".Bullet"); bool bullet_vis = bullet != NULL && bullet->visible; if (bullet != NULL) { @@ -703,8 +714,8 @@ void render_path_paint_commands_cursor() { return; } - f32 mx = g_context->paint_vec.x; - f32 my = 1.0 - g_context->paint_vec.y; + f32 mx = g_context->paint_vec.x; + f32 my = 1.0 - g_context->paint_vec.y; f32 brush_nodes_radius = 1.0; // g_context->brush_nodes_radius; // Prevent cursor jumping constantly if randomness is used in brush nodes if (context_is_decal() && !g_context->paint2d) { diff --git a/paint/sources/slot_layer.c b/paint/sources/slot_layer.c index 662029b0..e4377483 100644 --- a/paint/sources/slot_layer.c +++ b/paint/sources/slot_layer.c @@ -1168,7 +1168,7 @@ void layers_update_fill_layers() { if (l->texpaint_sculpt != NULL) { i32 tid = l->id; i32 hid = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1; - sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, l); + sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, l->texpaint_sculpt); render_path_set_target(string("texpaint_sculpt_undo%d", hid), NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target(string("texpaint_sculpt%d", tid), "tex"); render_path_draw_shader("Scene/copy_pass/copyRGBA128_pass"); @@ -1248,7 +1248,7 @@ void layers_update_fill_layer(bool parse_paint) { if (g_context->layer->texpaint_sculpt != NULL) { i32 tid = g_context->layer->id; i32 hid = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1; - sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, g_context->layer); + sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, g_context->layer->texpaint_sculpt); render_path_set_target(string("texpaint_sculpt_undo%d", hid), NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target(string("texpaint_sculpt%d", tid), "tex"); render_path_draw_shader("Scene/copy_pass/copyRGBA128_pass"); diff --git a/paint/sources/uniforms.c b/paint/sources/uniforms.c index b365e2ad..10d79785 100644 --- a/paint/sources/uniforms.c +++ b/paint/sources/uniforms.c @@ -381,6 +381,10 @@ gpu_texture_t *uniforms_ext_tex_link(object_t *object, material_data_t *mat, cha i32 tid = parse_int(substring(link, string_length(link) - 1, string_length(link))); return tid < project_layers->length ? project_layers->buffer[tid]->texpaint_pack : NULL; } + if (string_equals(link, "_texpaint_sculpt_base")) { + render_target_t *rt = any_map_get(render_path_render_targets, "texpaint_sculpt_base"); + return rt != NULL ? rt->_image : NULL; + } if (starts_with(link, "_texpaint_sculpt")) { i32 tid = parse_int(substring(link, string_length(link) - 1, string_length(link))); return tid < project_layers->length ? project_layers->buffer[tid]->texpaint_sculpt : NULL;