diff --git a/paint/sources/functions.h b/paint/sources/functions.h index ed243b45..1b941499 100644 --- a/paint/sources/functions.h +++ b/paint/sources/functions.h @@ -678,7 +678,7 @@ void util_uv_cache_uv_map(); void util_uv_cache_triangle_map(); void util_uv_cache_dilate_map(); void util_uv_cache_uv_island_map(); -void util_texture_capture_output(gpu_texture_t *img, char *basename); +void util_texture_capture_output(gpu_texture_t *img, char *basename, bool bgra); 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); @@ -794,11 +794,8 @@ char *neural_node_dir(); void neural_node_download_models(string_array_t *models); void neural_node_models_init(); void edit_image_node_init(); -void tile_image_node_init(); void image_to_3d_mesh_node_init(); void image_to_3d_mesh_node_button(i32 node_id); -void image_to_normal_map_node_init(); -void image_to_depth_node_init(); void *tex_image_node_create(ui_node_t *raw, f32_array_t *args); void *random_node_create(ui_node_t *raw, f32_array_t *args); void *boolean_node_create(ui_node_t *raw, f32_array_t *args); diff --git a/paint/sources/main.c b/paint/sources/main.c index b72dc689..8e3f7fb7 100644 --- a/paint/sources/main.c +++ b/paint/sources/main.c @@ -104,8 +104,6 @@ #include "nodes_neural/edit_image_node.c" #include "nodes_neural/image_to_3d_mesh_node.c" -#include "nodes_neural/image_to_depth_node.c" -#include "nodes_neural/image_to_normal_map_node.c" #include "nodes_neural/image_to_pbr_node.c" #include "nodes_neural/inpaint_image_node.c" #include "nodes_neural/neural_node.c" @@ -115,7 +113,6 @@ #include "nodes_neural/text_to_image_node.c" #include "nodes_neural/text_to_text_node.c" #include "nodes_neural/texture_mesh_node.c" -#include "nodes_neural/tile_image_node.c" #include "nodes_neural/upscale_image_node.c" #include "render/make_bake.c" diff --git a/paint/sources/nodes_material.c b/paint/sources/nodes_material.c index fbd73b81..2b4111c9 100644 --- a/paint/sources/nodes_material.c +++ b/paint/sources/nodes_material.c @@ -90,8 +90,6 @@ void nodes_material_init() { #ifdef IRON_WINDOWS image_to_3d_mesh_node_init(); #endif - image_to_depth_node_init(); - image_to_normal_map_node_init(); image_to_pbr_node_init(); inpaint_image_node_init(); repeat_node_init(); @@ -100,7 +98,6 @@ void nodes_material_init() { if (g_config->experimental) { texture_mesh_node_init(); } - tile_image_node_init(); upscale_image_node_init(); #endif diff --git a/paint/sources/nodes_neural/edit_image_node.c b/paint/sources/nodes_neural/edit_image_node.c index ae4739d5..cc4d6099 100644 --- a/paint/sources/nodes_neural/edit_image_node.c +++ b/paint/sources/nodes_neural/edit_image_node.c @@ -1,7 +1,7 @@ #include "../global.h" -static string_array_t *edit_image_node_flux_klein_args(char *dir, char *prompt) { +static string_array_t *edit_image_node_flux_klein_args(char *dir) { string_array_t *argv = any_array_create_from_raw( (void *[]){ string("%s/%s", dir, neural_node_sd_bin()), @@ -11,33 +11,14 @@ static string_array_t *edit_image_node_flux_klein_args(char *dir, char *prompt) string("%s/taef2.safetensors", dir), "--llm", string("%s/Qwen3-4B-Q8_0.gguf", dir), - "--cfg-scale", - "1.0", - "--sampling-method", - "euler", - "--diffusion-fa", - "--offload-to-cpu", "--steps", "4", - "-s", - "-1", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), - "-r", - string("%s/input.png", dir), - "-p", - prompt, - "-o", - string("%s/output.png", dir), - NULL, }, - 28); + 9); return argv; } -static string_array_t *edit_image_node_qwen_args(char *dir, char *prompt) { +static string_array_t *edit_image_node_qwen_args(char *dir) { string_array_t *argv = any_array_create_from_raw( (void *[]){ string("%s/%s", dir, neural_node_sd_bin()), @@ -49,30 +30,11 @@ static string_array_t *edit_image_node_qwen_args(char *dir, char *prompt) { string("%s/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf", dir), "--llm_vision", string("%s/mmproj-F16.gguf", dir), - "--offload-to-cpu", - "--diffusion-fa", + "--qwen-image-zero-cond-t", "--steps", "30", - "-s", - "-1", - "--cfg-scale", - "2.5", - "--flow-shift", - "3", - "--qwen-image-zero-cond-t", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), - "-p", - prompt, - "-r", - string("%s/input.png", dir), - "-o", - string("%s/output.png", dir), - NULL, }, - 31); + 12); return argv; } @@ -82,10 +44,18 @@ void edit_image_node_button(i32 node_id) { char *node_name = parser_material_node_name(node, NULL); ui_handle_t *h = ui_handle(node_name); - string_array_t *models = any_array_create_from_raw((void *[]){"Qwen Image Edit", "FLUX 2 klein"}, 2); + string_array_t *models = any_array_create_from_raw((void *[]){"FLUX 2 klein", "Qwen Image Edit"}, 2); i32 model = ui_combo(ui_nest(h, 0), models, tr("Model"), false, UI_ALIGN_LEFT, true); char *prompt = ui_text_area(ui_nest(h, 1), UI_ALIGN_LEFT, true, tr("prompt"), true); - node->buttons->buffer[0]->height = string_split(prompt, "\n")->length + 2; + node->buttons->buffer[0]->height = string_split(prompt, "\n")->length + 4; + + ui_handle_t *hs = ui_nest(h, 2); + if (hs->init) { + hs->f = 1.0; + } + f32 strength = ui_slider(hs, tr("Strength"), 0.0, 1.0, true, 100.0, true, UI_ALIGN_LEFT, true); + + bool tiled = ui_check(ui_nest(h, 3), tr("Tiled"), ""); if (neural_node_button(node, models->buffer[model])) { ui_node_t *from_node = neural_from_node(node->inputs->buffer[0], 0); @@ -100,18 +70,37 @@ void edit_image_node_button(i32 node_id) { char *dir = neural_node_dir(); iron_write_png(string("%s%sinput.png", dir, PATH_SEP), input_buf, input->width, input->height, 0); - if (string_equals(prompt, "")) { - prompt = "."; - } - string_array_t *argv; if (model == 0) { - argv = edit_image_node_flux_klein_args(dir, prompt); + argv = edit_image_node_flux_klein_args(dir); } else { - argv = edit_image_node_qwen_args(dir, prompt); + argv = edit_image_node_qwen_args(dir); } + string_array_push(argv, "--cfg-scale"); + string_array_push(argv, "1.0"); + string_array_push(argv, "--diffusion-fa"); + string_array_push(argv, "--offload-to-cpu"); + string_array_push(argv, "--strength"); + string_array_push(argv, string("%f", strength)); + string_array_push(argv, "-s"); + string_array_push(argv, "-1"); + string_array_push(argv, "-W"); + string_array_push(argv, string("%d", g_config->neural_res)); + string_array_push(argv, "-H"); + string_array_push(argv, string("%d", g_config->neural_res)); + string_array_push(argv, "-p"); + string_array_push(argv, prompt); + string_array_push(argv, "-r"); + string_array_push(argv, string("%s/input.png", dir)); + string_array_push(argv, "-o"); + string_array_push(argv, string("%s/output.png", dir)); + if (tiled) { + string_array_push(argv, "--circular"); + } + string_array_push(argv, NULL); + iron_exec_async(argv->buffer[0], argv->buffer); sys_notify_on_update(neural_node_check_result, node); } diff --git a/paint/sources/nodes_neural/image_to_depth_node.c b/paint/sources/nodes_neural/image_to_depth_node.c deleted file mode 100644 index 3f823cae..00000000 --- a/paint/sources/nodes_neural/image_to_depth_node.c +++ /dev/null @@ -1,114 +0,0 @@ - -#include "../global.h" - -void image_to_depth_node_button(i32 node_id) { - ui_node_canvas_t *canvas = ui_nodes_get_canvas(true); - ui_node_t *node = ui_get_node(canvas->nodes, node_id); - char *node_name = parser_material_node_name(node, NULL); - ui_handle_t *h = ui_handle(node_name); - string_array_t *models = any_array_create_from_raw( - (void *[]){ - "Marigold", - }, - 1); - i32 model = ui_combo(ui_nest(h, 0), models, tr("Model"), false, UI_ALIGN_LEFT, true); - if (neural_node_button(node, models->buffer[model])) { - ui_node_t *from_node = neural_from_node(node->inputs->buffer[0], 0); - gpu_texture_t *input = ui_nodes_get_node_preview_image(from_node); - if (input != NULL) { - char *dir = neural_node_dir(); - -#ifdef IRON_BGRA - buffer_t *input_buf = buffer_bgra_swap(gpu_get_texture_pixels(input)); // Vulkan non-rt textures need a flip -#else - buffer_t *input_buf = gpu_get_texture_pixels(input); -#endif - iron_write_png(string("%s%sinput.png", dir, PATH_SEP), input_buf, input->width, input->height, 0); - - string_array_t *argv = any_array_create_from_raw( - (void *[]){ - string("%s/%s", dir, neural_node_sd_bin()), - "-m", - string("%s/marigold-depth-v1-1.q8_0.gguf", dir), - "--sampling-method", - "ddim_trailing", - "--steps", - "10", - "-s", - "-1", - "-W", - "768", - "-H", - "768", - "-p", - "_height", - "-i", - string("%s/input.png", dir), - "-o", - string("%s/output.png", dir), - NULL, - }, - 20); - iron_exec_async(argv->buffer[0], argv->buffer); - sys_notify_on_update(neural_node_check_result, node); - } - } -} - -void image_to_depth_node_init() { - - ui_node_t *image_to_depth_node_def = - GC_ALLOC_INIT(ui_node_t, {.id = 0, - .name = _tr("Image to Depth"), - .type = "NEURAL_IMAGE_TO_DEPTH", - .x = 0, - .y = 0, - .color = 0xff4982a0, - .inputs = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, - .node_id = 0, - .name = _tr("Color"), - .type = "RGBA", - .color = 0xffc7c729, - .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), - .min = 0.0, - .max = 1.0, - .precision = 100, - .display = 0}), - }, - 1), - .outputs = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, - .node_id = 0, - .name = _tr("Depth"), - .type = "VALUE", - .color = 0xffa1a1a1, - .default_value = f32_array_create_x(1.0), - .min = 0.0, - .max = 1.0, - .precision = 100, - .display = 0}), - }, - 1), - .buttons = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_button_t, {.name = "image_to_depth_node_button", - .type = "CUSTOM", - .output = -1, - .default_value = f32_array_create_x(0), - .data = NULL, - .min = 0.0, - .max = 1.0, - .precision = 100, - .height = 2}), - }, - 1), - .width = 0, - .flags = 0}); - - any_array_push(nodes_material_neural, image_to_depth_node_def); - any_map_set(parser_material_node_values, "NEURAL_IMAGE_TO_DEPTH", neural_node_value); - any_map_set(ui_nodes_custom_buttons, "image_to_depth_node_button", image_to_depth_node_button); -} diff --git a/paint/sources/nodes_neural/image_to_normal_map_node.c b/paint/sources/nodes_neural/image_to_normal_map_node.c deleted file mode 100644 index bf4def2f..00000000 --- a/paint/sources/nodes_neural/image_to_normal_map_node.c +++ /dev/null @@ -1,114 +0,0 @@ - -#include "../global.h" - -void image_to_normal_map_node_button(i32 node_id) { - ui_node_canvas_t *canvas = ui_nodes_get_canvas(true); - ui_node_t *node = ui_get_node(canvas->nodes, node_id); - char *node_name = parser_material_node_name(node, NULL); - ui_handle_t *h = ui_handle(node_name); - string_array_t *models = any_array_create_from_raw( - (void *[]){ - "Marigold", - }, - 1); - i32 model = ui_combo(ui_nest(h, 0), models, tr("Model"), false, UI_ALIGN_LEFT, true); - if (neural_node_button(node, models->buffer[model])) { - ui_node_t *from_node = neural_from_node(node->inputs->buffer[0], 0); - gpu_texture_t *input = ui_nodes_get_node_preview_image(from_node); - if (input != NULL) { - char *dir = neural_node_dir(); - -#ifdef IRON_BGRA - buffer_t *input_buf = buffer_bgra_swap(gpu_get_texture_pixels(input)); // Vulkan non-rt textures need a flip -#else - buffer_t *input_buf = gpu_get_texture_pixels(input); -#endif - iron_write_png(string("%s%sinput.png", dir, PATH_SEP), input_buf, input->width, input->height, 0); - - string_array_t *argv = any_array_create_from_raw( - (void *[]){ - string("%s/%s", dir, neural_node_sd_bin()), - "-m", - string("%s/marigold-normals-v1-1.q8_0.gguf", dir), - "--sampling-method", - "ddim_trailing", - "--steps", - "10", - "-s", - "-1", - "-W", - "768", - "-H", - "768", - "-p", - "_normals", - "-i", - string("%s/input.png", dir), - "-o", - string("%s/output.png", dir), - NULL, - }, - 20); - iron_exec_async(argv->buffer[0], argv->buffer); - sys_notify_on_update(neural_node_check_result, node); - } - } -} - -void image_to_normal_map_node_init() { - - ui_node_t *image_to_normal_map_node_def = - GC_ALLOC_INIT(ui_node_t, {.id = 0, - .name = _tr("Image to Normal Map"), - .type = "NEURAL_IMAGE_TO_NORMAL_MAP", - .x = 0, - .y = 0, - .color = 0xff4982a0, - .inputs = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, - .node_id = 0, - .name = _tr("Color"), - .type = "RGBA", - .color = 0xffc7c729, - .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), - .min = 0.0, - .max = 1.0, - .precision = 100, - .display = 0}), - }, - 1), - .outputs = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, - .node_id = 0, - .name = _tr("Normal Map"), - .type = "VECTOR", - .color = 0xffc7c729, - .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), - .min = 0.0, - .max = 1.0, - .precision = 100, - .display = 0}), - }, - 1), - .buttons = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_button_t, {.name = "image_to_normal_map_node_button", - .type = "CUSTOM", - .output = -1, - .default_value = f32_array_create_x(0), - .data = NULL, - .min = 0.0, - .max = 1.0, - .precision = 100, - .height = 2}), - }, - 1), - .width = 0, - .flags = 0}); - - any_array_push(nodes_material_neural, image_to_normal_map_node_def); - any_map_set(parser_material_node_vectors, "NEURAL_IMAGE_TO_NORMAL_MAP", neural_node_vector); - any_map_set(ui_nodes_custom_buttons, "image_to_normal_map_node_button", image_to_normal_map_node_button); -} diff --git a/paint/sources/nodes_neural/image_to_pbr_node.c b/paint/sources/nodes_neural/image_to_pbr_node.c index cd734548..f233260b 100644 --- a/paint/sources/nodes_neural/image_to_pbr_node.c +++ b/paint/sources/nodes_neural/image_to_pbr_node.c @@ -6,14 +6,13 @@ gpu_texture_t *image_to_pbr_node_result_normal = NULL; gpu_texture_t *image_to_pbr_node_result_occlusion = NULL; gpu_texture_t *image_to_pbr_node_result_height = NULL; gpu_texture_t *image_to_pbr_node_result_roughness = NULL; -gpu_texture_t *image_to_pbr_node_result_metallic = NULL; char *image_to_pbr_node_vector(ui_node_t *node, ui_node_socket_t *socket) { gpu_texture_t *result = NULL; if (socket == node->outputs->buffer[0]) { // base color result = image_to_pbr_node_result_base; } - else if (socket == node->outputs->buffer[4]) { // normal map + else if (socket == node->outputs->buffer[3]) { // normal map result = image_to_pbr_node_result_normal; } @@ -35,10 +34,7 @@ char *image_to_pbr_node_value(ui_node_t *node, ui_node_socket_t *socket) { else if (socket == node->outputs->buffer[2]) { // roughness result = image_to_pbr_node_result_roughness; } - else if (socket == node->outputs->buffer[3]) { // metallic - result = image_to_pbr_node_result_metallic; - } - else if (socket == node->outputs->buffer[5]) { // height + else if (socket == node->outputs->buffer[4]) { // height result = image_to_pbr_node_result_height; } @@ -220,17 +216,40 @@ void image_to_pbr_node_normals_done(gpu_texture_t *tex) { image_to_pbr_node_run_sd("marigold-depth-v1-1.q8_0.gguf", "_height", &image_to_pbr_node_height_done); } +void image_to_pbr_node_normals_only_done(gpu_texture_t *tex) { + gc_unroot(image_to_pbr_node_result_normal); + image_to_pbr_node_result_normal = tex; + gc_root(image_to_pbr_node_result_normal); +} + +void image_to_pbr_node_height_only_done(gpu_texture_t *tex) { + gc_unroot(image_to_pbr_node_result_height); + image_to_pbr_node_result_height = tex; + gc_root(image_to_pbr_node_result_height); +} + void image_to_pbr_node_button(i32 node_id) { ui_node_canvas_t *canvas = ui_nodes_get_canvas(true); ui_node_t *node = ui_get_node(canvas->nodes, node_id); char *node_name = parser_material_node_name(node, NULL); ui_handle_t *h = ui_handle(node_name); - string_array_t *models = any_array_create_from_raw( - (void *[]){ - "Marigold", - }, - 1); + + string_array_t *models = any_array_create_from_raw( + (void *[]){ + "Marigold", + }, + 1); i32 model = ui_combo(ui_nest(h, 0), models, tr("Model"), false, UI_ALIGN_LEFT, true); + + string_array_t *channels = any_array_create_from_raw( + (void *[]){ + "All", + "Normal Map", + "Height", + }, + 3); + i32 channel = ui_combo(ui_nest(h, 1), channels, tr("Channels"), false, UI_ALIGN_LEFT, true); + if (neural_node_button(node, models->buffer[model])) { ui_node_t *from_node = neural_from_node(node->inputs->buffer[0], 0); gpu_texture_t *input = ui_nodes_get_node_preview_image(from_node); @@ -244,7 +263,15 @@ void image_to_pbr_node_button(i32 node_id) { #endif iron_write_png(string("%s%sinput.png", dir, PATH_SEP), input_buf, input->width, input->height, 0); - image_to_pbr_node_run_sd("marigold-normals-v1-1.q8_0.gguf", "_normals", &image_to_pbr_node_normals_done); + if (channel == 1) { // Normal Map only + image_to_pbr_node_run_sd("marigold-normals-v1-1.q8_0.gguf", "_normals", &image_to_pbr_node_normals_only_done); + } + else if (channel == 2) { // Height only + image_to_pbr_node_run_sd("marigold-depth-v1-1.q8_0.gguf", "_height", &image_to_pbr_node_height_only_done); + } + else { // All + image_to_pbr_node_run_sd("marigold-normals-v1-1.q8_0.gguf", "_normals", &image_to_pbr_node_normals_done); + } } } } @@ -304,16 +331,6 @@ void image_to_pbr_node_init() { .max = 1.0, .precision = 100, .display = 0}), - GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, - .node_id = 0, - .name = _tr("Metallic"), - .type = "VALUE", - .color = 0xffa1a1a1, - .default_value = f32_array_create_x(0.0), - .min = 0.0, - .max = 1.0, - .precision = 100, - .display = 0}), GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, .node_id = 0, .name = _tr("Normal Map"), @@ -335,7 +352,7 @@ void image_to_pbr_node_init() { .precision = 100, .display = 0}), }, - 6), + 5), .buttons = any_array_create_from_raw( (void *[]){ GC_ALLOC_INIT(ui_node_button_t, {.name = "image_to_pbr_node_button", @@ -346,7 +363,7 @@ void image_to_pbr_node_init() { .min = 0.0, .max = 1.0, .precision = 100, - .height = 2}), + .height = 3}), }, 1), .width = 0, diff --git a/paint/sources/nodes_neural/inpaint_image_node.c b/paint/sources/nodes_neural/inpaint_image_node.c index d2ede25c..1f4d457a 100644 --- a/paint/sources/nodes_neural/inpaint_image_node.c +++ b/paint/sources/nodes_neural/inpaint_image_node.c @@ -1,6 +1,46 @@ #include "../global.h" +f32 inpaint_image_node_strength; +bool inpaint_image_node_tiled; + +static string_array_t *inpaint_image_node_flux_klein_args(char *dir) { + string_array_t *argv = any_array_create_from_raw( + (void *[]){ + string("%s/%s", dir, neural_node_sd_bin()), + "--diffusion-model", + string("%s/flux-2-klein-4b-Q8_0.gguf", dir), + "--taesd", + string("%s/taef2.safetensors", dir), + "--llm", + string("%s/Qwen3-4B-Q8_0.gguf", dir), + "--steps", + "4", + }, + 9); + return argv; +} + +static string_array_t *inpaint_image_node_qwen_args(char *dir) { + string_array_t *argv = any_array_create_from_raw( + (void *[]){ + string("%s/%s", dir, neural_node_sd_bin()), + "--diffusion-model", + string("%s/qwen-image-edit-2511-Q4_K_S.gguf", dir), + "--vae", + string("%s/Qwen_Image-VAE.safetensors", dir), + "--llm", + string("%s/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf", dir), + "--llm_vision", + string("%s/mmproj-F16.gguf", dir), + "--qwen-image-zero-cond-t", + "--steps", + "30", + }, + 12); + return argv; +} + void inpaint_image_node_button_on_next_frame(ui_node_t *node) { ui_node_t *from_node = neural_from_node(node->inputs->buffer[0], 0); ui_node_t *mask_node = neural_from_node(node->inputs->buffer[1], 1); @@ -13,6 +53,7 @@ void inpaint_image_node_button_on_next_frame(ui_node_t *node) { i32 model = ui_nest(h, 0)->i; char *dir = neural_node_dir(); + if (model == 0) { #ifdef IRON_BGRA buffer_t *input_buf = buffer_bgra_swap(gpu_get_texture_pixels(input)); // Vulkan non-rt textures need a flip @@ -50,77 +91,41 @@ void inpaint_image_node_button_on_next_frame(ui_node_t *node) { string_array_t *argv; if (model == 0) { - argv = any_array_create_from_raw( - (void *[]){ - string("%s/%s", dir, neural_node_sd_bin()), - "--diffusion-model", - string("%s/flux-2-klein-4b-Q8_0.gguf", dir), - "--taesd", - string("%s/taef2.safetensors", dir), - "--llm", - string("%s/Qwen3-4B-Q8_0.gguf", dir), - "--cfg-scale", - "0.0", - "--sampling-method", - "euler", - "--diffusion-fa", - "--offload-to-cpu", - "--steps", - "4", - "-s", - "-1", - "--strength", - "1", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), - "-p", - "", - "-i", - string("%s/input.png", dir), - "--mask", - string("%s/mask.png", dir), - "-o", - string("%s/output.png", dir), - NULL, - }, - 32); + argv = edit_image_node_flux_klein_args(dir); + string_array_push(argv, "-p"); + string_array_push(argv, ""); + string_array_push(argv, "-i"); + string_array_push(argv, string("%s/input.png", dir)); + string_array_push(argv, "--mask"); + string_array_push(argv, string("%s/mask.png", dir)); } else { - argv = any_array_create_from_raw( - (void *[]){ - string("%s/%s", dir, neural_node_sd_bin()), - "--diffusion-model", - string("%s/qwen-image-edit-2511-Q4_K_S.gguf", dir), - "--vae", - string("%s/Qwen_Image-VAE.safetensors", dir), - "--llm", - string("%s/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf", dir), - "--llm_vision", - string("%s/mmproj-F16.gguf", dir), - "--offload-to-cpu", - "--diffusion-fa", - "--qwen-image-zero-cond-t", - "--steps", - "50", - "-s", - "-1", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), - "-p", - "remove red area", - "-r", - string("%s/input.png", dir), - "-o", - string("%s/output.png", dir), - NULL, - }, - 27); + argv = edit_image_node_qwen_args(dir); + string_array_push(argv, "-p"); + string_array_push(argv, "remove red area"); + string_array_push(argv, "-r"); + string_array_push(argv, string("%s/input.png", dir)); } + string_array_push(argv, "--cfg-scale"); + string_array_push(argv, "1.0"); + string_array_push(argv, "--diffusion-fa"); + string_array_push(argv, "--offload-to-cpu"); + string_array_push(argv, "--strength"); + string_array_push(argv, string("%f", inpaint_image_node_strength)); + string_array_push(argv, "-s"); + string_array_push(argv, "-1"); + string_array_push(argv, "-W"); + string_array_push(argv, string("%d", g_config->neural_res)); + string_array_push(argv, "-H"); + string_array_push(argv, string("%d", g_config->neural_res)); + string_array_push(argv, "-o"); + string_array_push(argv, string("%s/output.png", dir)); + if (inpaint_image_node_tiled) { + string_array_push(argv, "--circular"); + } + string_array_push(argv, NULL); + iron_exec_async(argv->buffer[0], argv->buffer); sys_notify_on_update(neural_node_check_result, node); } @@ -131,14 +136,23 @@ void inpaint_image_node_button(i32 node_id) { ui_node_t *node = ui_get_node(canvas->nodes, node_id); char *node_name = parser_material_node_name(node, NULL); ui_handle_t *h = ui_handle(node_name); - string_array_t *models = any_array_create_from_raw( - (void *[]){ - "FLUX 2 klein", - "Qwen Image Edit", - }, - 2); + + string_array_t *models = any_array_create_from_raw( + (void *[]){ + "FLUX 2 klein", + "Qwen Image Edit", + }, + 2); i32 model = ui_combo(ui_nest(h, 0), models, tr("Model"), false, UI_ALIGN_LEFT, true); + ui_handle_t *hs = ui_nest(h, 1); + if (hs->init) { + hs->f = 1.0; + } + inpaint_image_node_strength = ui_slider(hs, tr("Strength"), 0.0, 1.0, true, 100.0, true, UI_ALIGN_LEFT, true); + + inpaint_image_node_tiled = ui_check(ui_nest(h, 2), tr("Tiled"), ""); + if (neural_node_button(node, models->buffer[model])) { sys_notify_on_next_frame(&inpaint_image_node_button_on_next_frame, node); } @@ -201,7 +215,7 @@ void inpaint_image_node_init() { .min = 0.0, .max = 1.0, .precision = 100, - .height = 2}), + .height = 4}), }, 1), .width = 0, diff --git a/paint/sources/nodes_neural/text_to_image_node.c b/paint/sources/nodes_neural/text_to_image_node.c index 71705316..0fc87a8f 100644 --- a/paint/sources/nodes_neural/text_to_image_node.c +++ b/paint/sources/nodes_neural/text_to_image_node.c @@ -11,27 +11,10 @@ string_array_t *text_to_image_node_flux_klein_args(char *dir, char *prompt) { string("%s/taef2.safetensors", dir), "--llm", string("%s/Qwen3-4B-Q8_0.gguf", dir), - "--cfg-scale", - "1.0", - "--sampling-method", - "euler", - "--diffusion-fa", - "--offload-to-cpu", "--steps", "4", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), - "-s", - "-1", - "-o", - string("%s/output.png", dir), - "-p", - string("'%s'", prompt), - NULL, }, - 26); + 9); return argv; } @@ -45,25 +28,10 @@ string_array_t *text_to_image_node_zimage_args(char *dir, char *prompt) { string("%s/ae.safetensors", dir), "--llm", string("%s/Qwen3-4B-Instruct-2507-Q4_K_S.gguf", dir), - "--diffusion-fa", - "--offload-to-cpu", - "--cfg-scale", - "1.0", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), "--steps", "40", - "-s", - "-1", - "-o", - string("%s/output.png", dir), - "-p", - string("'%s'", prompt), - NULL, }, - 24); + 9); return argv; } @@ -79,24 +47,10 @@ string_array_t *text_to_image_node_qwen_args(char *dir, char *prompt) { string("%s/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf", dir), "--llm_vision", string("%s/mmproj-F16.gguf", dir), - "--sampling-method", - "euler", - "--offload-to-cpu", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), "--steps", "20", - "-s", - "-1", - "-o", - string("%s/output.png", dir), - "-p", - string("'%s'", prompt), - NULL, }, - 25); + 11); return argv; } @@ -109,6 +63,7 @@ void text_to_image_node_run(ui_node_t *node, void (*callback)(ui_node_t *)) { if (prompt == NULL || string_equals(prompt, "")) { prompt = "."; } + string_array_t *argv; if (model == 0) { argv = text_to_image_node_flux_klein_args(dir, prompt); @@ -119,9 +74,26 @@ void text_to_image_node_run(ui_node_t *node, void (*callback)(ui_node_t *)) { else { argv = text_to_image_node_qwen_args(dir, prompt); } + + string_array_push(argv, "--cfg-scale"); + string_array_push(argv, "1.0"); + string_array_push(argv, "--diffusion-fa"); + string_array_push(argv, "--offload-to-cpu"); + string_array_push(argv, "-W"); + string_array_push(argv, string("%d", g_config->neural_res)); + string_array_push(argv, "-H"); + string_array_push(argv, string("%d", g_config->neural_res)); + string_array_push(argv, "-s"); + string_array_push(argv, "-1"); + string_array_push(argv, "-o"); + string_array_push(argv, string("%s/output.png", dir)); + string_array_push(argv, "-p"); + string_array_push(argv, string("'%s'", prompt)); if (node->buttons->buffer[1]->default_value->buffer[0] > 0.0) { - array_insert(argv, argv->length - 1, "--circular"); + string_array_push(argv, "--circular"); } + string_array_push(argv, NULL); + iron_exec_async(argv->buffer[0], argv->buffer); sys_notify_on_update(callback, node); } diff --git a/paint/sources/nodes_neural/tile_image_node.c b/paint/sources/nodes_neural/tile_image_node.c deleted file mode 100644 index 4ea52b02..00000000 --- a/paint/sources/nodes_neural/tile_image_node.c +++ /dev/null @@ -1,132 +0,0 @@ - -#include "../global.h" - -void tile_image_node_button_on_next_frame(ui_node_t *node) { - ui_node_t *from_node = neural_from_node(node->inputs->buffer[0], 0); - gpu_texture_t *input = ui_nodes_get_node_preview_image(from_node); - if (input != NULL) { - char *node_name = parser_material_node_name(node, NULL); - ui_handle_t *h = ui_handle(node_name); - i32 model = ui_nest(h, 0)->i; - char *dir = neural_node_dir(); - iron_write_png(string("%s%sinput.png", dir, PATH_SEP), gpu_get_texture_pixels(input), input->width, input->height, 0); - - string_array_t *argv; - if (model == 0) { - argv = any_array_create_from_raw( - (void *[]){ - string("%s/%s", dir, neural_node_sd_bin()), - "--diffusion-model", - string("%s/flux-2-klein-4b-Q8_0.gguf", dir), - "--vae", - // string("%s/full_encoder_small_decoder.safetensors", dir), - string("%s/flux_ae.safetensors", dir), - "--llm", - string("%s/Qwen3-4B-Q8_0.gguf", dir), - "--cfg-scale", - "1.0", - "--sampling-method", - "euler", - "--diffusion-fa", - "--offload-to-cpu", - "--steps", - "4", - "-s", - "-1", - "-W", - string("%d", g_config->neural_res), - "-H", - string("%d", g_config->neural_res), - "--circular", - "--strength", - "0.3", - "-p", - "", - "-i", - string("%s/input.png", dir), - "-o", - string("%s/output.png", dir), - NULL, - }, - 31); - } - - iron_exec_async(argv->buffer[0], argv->buffer); - sys_notify_on_update(neural_node_check_result, node); - } -} - -void tile_image_node_button(i32 node_id) { - ui_node_canvas_t *canvas = ui_nodes_get_canvas(true); - ui_node_t *node = ui_get_node(canvas->nodes, node_id); - char *node_name = parser_material_node_name(node, NULL); - ui_handle_t *h = ui_handle(node_name); - string_array_t *models = any_array_create_from_raw( - (void *[]){ - "FLUX 2 klein", - }, - 1); - i32 model = ui_combo(ui_nest(h, 0), models, tr("Model"), false, UI_ALIGN_LEFT, true); - - if (neural_node_button(node, models->buffer[model])) { - sys_notify_on_next_frame(&tile_image_node_button_on_next_frame, node); - } -} - -void tile_image_node_init() { - - ui_node_t *tile_image_node_def = - GC_ALLOC_INIT(ui_node_t, {.id = 0, - .name = _tr("Tile Image"), - .type = "NEURAL_TILE_IMAGE", - .x = 0, - .y = 0, - .color = 0xff4982a0, - .inputs = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, - .node_id = 0, - .name = _tr("Color"), - .type = "RGBA", - .color = 0xffc7c729, - .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), - .min = 0.0, - .max = 1.0, - .precision = 100, - .display = 0}), - }, - 1), - .outputs = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_socket_t, {.id = 0, - .node_id = 0, - .name = _tr("Color"), - .type = "RGBA", - .color = 0xffc7c729, - .default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0), - .min = 0.0, - .max = 1.0, - .precision = 100, - .display = 0}), - }, - 1), - .buttons = any_array_create_from_raw( - (void *[]){ - GC_ALLOC_INIT(ui_node_button_t, {.name = "tile_image_node_button", - .type = "CUSTOM", - .output = -1, - .default_value = f32_array_create_x(0), - .data = NULL, - .min = 0.0, - .max = 1.0, - .precision = 100, - .height = 2}), - }, - 1), - .width = 0, - .flags = 0}); - - any_array_push(nodes_material_neural, tile_image_node_def); - any_map_set(parser_material_node_vectors, "NEURAL_TILE_IMAGE", neural_node_vector); - any_map_set(ui_nodes_custom_buttons, "tile_image_node_button", tile_image_node_button); -}