diff --git a/base/sources/backends/android_net.c b/base/sources/backends/android_net.c index fe862ecd..521d23e2 100644 --- a/base/sources/backends/android_net.c +++ b/base/sources/backends/android_net.c @@ -39,3 +39,5 @@ void iron_net_request(const char *url_base, const char *url_path, const char *da void iron_net_update() { } + +volatile uint64_t iron_net_bytes_downloaded = 0; diff --git a/base/sources/backends/apple_net.m b/base/sources/backends/apple_net.m index 9bbf38c6..8994cc4c 100644 --- a/base/sources/backends/apple_net.m +++ b/base/sources/backends/apple_net.m @@ -42,3 +42,5 @@ void iron_net_request(const char *url_base, const char *url_path, const char *da void iron_net_update() { } + +volatile uint64_t iron_net_bytes_downloaded = 0; diff --git a/base/sources/backends/posix_net.c b/base/sources/backends/posix_net.c index ed2782b1..0fc62d63 100644 --- a/base/sources/backends/posix_net.c +++ b/base/sources/backends/posix_net.c @@ -72,3 +72,5 @@ void iron_net_request(const char *url_base, const char *url_path, const char *da void iron_net_update() { } + +volatile uint64_t iron_net_bytes_downloaded = 0; diff --git a/base/sources/backends/windows_net.c b/base/sources/backends/windows_net.c index 569a2084..767d97b1 100644 --- a/base/sources/backends/windows_net.c +++ b/base/sources/backends/windows_net.c @@ -27,6 +27,8 @@ typedef struct request { struct request *next; } request_t; +volatile uint64_t iron_net_bytes_downloaded = 0; + static BOOL initialized = FALSE; static request_t *pending_head = NULL; static request_t *pending_tail = NULL; @@ -106,6 +108,7 @@ static void CALLBACK iron_winhttp_callback(HINTERNET hInternet, DWORD_PTR dwCont if (ctx->hfile != INVALID_HANDLE_VALUE) { DWORD written; WriteFile(ctx->hfile, ctx->file_buffer, dwStatusInformationLength, &written, NULL); + iron_net_bytes_downloaded += dwStatusInformationLength; } else { ctx->return_data_index += dwStatusInformationLength; diff --git a/base/sources/iron_net.h b/base/sources/iron_net.h index 9ca94804..a1a2327e 100644 --- a/base/sources/iron_net.h +++ b/base/sources/iron_net.h @@ -9,5 +9,5 @@ typedef void (*iron_https_callback_t)(const char *body, void *callbackdata); void iron_net_request(const char *url_base, const char *url_path, const char *data, int port, int method, iron_https_callback_t callback, void *callbackdata, const char *dst_path); - void iron_net_update(); +extern volatile uint64_t iron_net_bytes_downloaded; diff --git a/paint/sources/box_preferences.ts b/paint/sources/box_preferences.ts index 57d2cd9b..ad22df15 100644 --- a/paint/sources/box_preferences.ts +++ b/paint/sources/box_preferences.ts @@ -10,6 +10,17 @@ let _box_preferences_f: string; let _box_preferences_h: ui_handle_t; let _box_preferences_i: i32; +type box_preferneces_model_t = { + name?: string; + memory?: string; + size?: string; + nodes?: string; + urls?: string[]; + web?: string; + license?: string; +}; +let box_preferences_models: box_preferneces_model_t[] = null; + function box_preferences_interface_tab() { if (box_preferences_locales == null) { box_preferences_locales = translator_get_supported_locales(); @@ -687,9 +698,87 @@ function box_preferences_keymap_tab() { } } -function box_preferences_neural_tab() { +function box_preferences_init_models() { + box_preferences_models = [ + { + name: "Stable Diffusion", + memory: "4GB", + size: "4.2GB", + nodes: "Inpaint Image, Outpaint Image, Text to Image, Tile Image, Vary Image", + urls: ["https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors"], + web: "https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5", + license: "openrail" + }, + { + name: "Qwen Image", + memory: "13GB", + size: "15.7GB", + nodes: "Text to Image", + urls: [ + "https://huggingface.co/QuantStack/Qwen-Image-GGUF/resolve/main/Qwen_Image-Q4_K_S.gguf", + "https://huggingface.co/QuantStack/Qwen-Image-GGUF/resolve/main/VAE/Qwen_Image-VAE.safetensors", + "https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf" + ], + web: "https://huggingface.co/QuantStack/Qwen-Image-GGUF", + license: "apache-2.0" + }, + { + name: "Qwen Image Edit", + memory: "13GB", + size: "17.0GB", + nodes: "Edit Image, Inpaint Image, Outpaint Image, Tile Image, Vary Image", + urls: [ + "https://huggingface.co/QuantStack/Qwen-Image-Edit-2509-GGUF/resolve/main/Qwen-Image-Edit-2509-Q4_K_S.gguf", + "https://huggingface.co/QuantStack/Qwen-Image-GGUF/resolve/main/VAE/Qwen_Image-VAE.safetensors", + "https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf", + "https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/mmproj-F16.gguf" + ], + web: "https://huggingface.co/QuantStack/Qwen-Image-Edit-2509-GGUF", + license: "apache-2.0" + }, + { + name: "Wan", + memory: "10GB", + size: "19.8GB", + nodes: "Text to Image", + urls: [ + "https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF/resolve/main/LowNoise/Wan2.2-T2V-A14B-LowNoise-Q4_K_S.gguf", + "https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF/resolve/main/HighNoise/Wan2.2-T2V-A14B-HighNoise-Q4_K_S.gguf", + "https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF/resolve/main/VAE/Wan2.1_VAE.safetensors", + "https://huggingface.co/city96/umt5-xxl-encoder-gguf/resolve/main/umt5-xxl-encoder-Q4_K_S.gguf" + ], + web: "https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF", + license: "apache-2.0" + }, + { + name: "Marigold", + memory: "6GB", + size: "9.6GB", + nodes: "Text to Image", + urls: [ + "https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-depth-v1-1.q8_0.gguf", + "https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-normals-v1-1.q8_0.gguf", + "https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-iid-appearance-v1-1.q8_0.gguf", + "https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-iid-lighting-v1-1.q8_0.gguf" + ], + web: "https://huggingface.co/armory3d/marigold-v1-1-gguf", + license: "openrail" + }, + { + name: "Real-ESRGAN", + memory: "1GB", + size: "0.06GB", + nodes: "Upscale Image", + urls: ["https://huggingface.co/armory3d/Real-ESRGAN/resolve/main/RealESRGAN_x4plus.pth"], + web: "https://huggingface.co/armory3d/Real-ESRGAN", + license: "bsd-3-clause" + } + ]; + // https://huggingface.co/webui/stable-diffusion-inpainting/resolve/main/sd-v1-5-inpainting.safetensors +} - ui_text(tr("All processing is done on device")); +function box_preferences_neural_tab() { + ui_text(tr("All processing is done locally on device")); let inference_handle: ui_handle_t = ui_handle(__ID__); if (inference_handle.init) { @@ -706,98 +795,72 @@ function box_preferences_neural_tab() { ui_text(tr("Models")); - if (ui_panel(ui_handle(__ID__), "Stable Diffusion")) { // (downloaded) - if (ui_text("source: https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5 (openrail)") == UI_STATE_RELEASED) { - iron_load_url("https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5"); - } - ui_text("gpu memory: 4GB"); - ui_text("nodes: Inpaint Image, Outpaint Image, Text to Image, Tile Image, Vary Image"); - if (ui_button(tr("Download (4.0GB)"))) { + if (box_preferences_models == null) { + box_preferences_init_models(); + } - if (file_read_directory(neural_node_dir())[0] == "") { - file_create_directory(neural_node_dir()); + for (let i: i32 = 0; i < box_preferences_models.length; ++i) { + box_preferences_model_panel(box_preferences_models[i]); + } +} + +function box_preferences_model_exists(file_name: string): bool { + return iron_file_exists(neural_node_dir() + path_sep + file_name); +} + +function box_preferences_file_name_from_url(url: string): string { + return substring(url, string_last_index_of(url, "/") + 1, url.length); +} + +function box_preferneces_model_url_from_name(name: string): string { + if (box_preferences_models == null) { + box_preferences_init_models(); + } + + for (let i: i32 = 0; i < box_preferences_models.length; ++i) { + if (box_preferences_models[i].name == name) { + return box_preferences_models[i].urls[0]; + } + } + return null; +} + +function box_preferences_model_panel(m: box_preferneces_model_t) { + if (ui_panel(ui_handle(m.name), m.name)) { + if (ui_text(tr("source") + ": " + m.web + " (" + m.license + ")") == UI_STATE_RELEASED) { + iron_load_url(m.web); + } + ui_text(tr("gpu memory") + ": " + m.memory); + ui_text(tr("nodes") + ": " + m.nodes); + + let url: string = m.urls[0]; + let file_name: string = box_preferences_file_name_from_url(url); + let found: bool = box_preferences_model_exists(file_name); + + if (neural_node_downloading > 0) { + ui.enabled = false; + + let u: u64 = iron_net_bytes_downloaded; + let i: i32 = (u / 1000000000) * 10; + let f: f32 = i / 10; + let downloaded: string = f + "GB"; + ui_box_hwnd.redraws = 2; + box_preferences_htab.redraws = 2; + iron_delay_idle_sleep(); + + ui_button(tr("Downloading") + "..." + "(" + downloaded + " / " + m.size + ")"); + ui.enabled = true; + } + else if (!found && ui_button(tr("Download") + " (" + m.size + ")")) { + neural_node_download_models(m.urls); + console_info(tr("Downloading")); + } + else if (found && ui_button(tr("Remove") + " (" + m.size + ")")) { + for (let i: i32 = 0; i < m.urls.length; ++i) { + let url: string = m.urls[i]; + let file_name: string = box_preferences_file_name_from_url(url); + iron_delete_file(neural_node_dir() + path_sep + file_name); } - - file_download_to("https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors", neural_node_dir() + path_sep + "v1-5-pruned-emaonly.safetensors", function(url: string) {}); - - // https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors - } - } - - // if (ui_panel(ui_handle(__ID__), "Stable Diffusion Inpaint")) { // (downloaded) - // ui_text("source: https://huggingface.co/webui/stable-diffusion-inpainting (openrail)"); - // ui_text("gpu memory: 4GB"); - // ui_text("nodes: Inpaint Image, Outpaint Image, Tile Image, Vary Image"); - // if (ui_button(tr("Download (4.0GB)"))) { - // // https://huggingface.co/webui/stable-diffusion-inpainting/resolve/main/sd-v1-5-inpainting.safetensors - // } - // } - - if (ui_panel(ui_handle(__ID__), "Qwen Image")) { // (downloaded) - if (ui_text("source: https://huggingface.co/QuantStack/Qwen-Image-GGUF (apache-2.0)") == UI_STATE_RELEASED) { - iron_load_url("https://huggingface.co/QuantStack/Qwen-Image-GGUF"); - } - ui_text("gpu memory: 13GB"); - ui_text("nodes: Text to Image"); - if (ui_button(tr("Download") + " (15.7GB)")) { - // https://huggingface.co/QuantStack/Qwen-Image-GGUF/resolve/main/Qwen_Image-Q4_K_S.gguf - // https://huggingface.co/QuantStack/Qwen-Image-GGUF/resolve/main/VAE/Qwen_Image-VAE.safetensors - // https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf - } - // if (ui_button(tr("Remove (15.7GB)"))) { - // } - } - - if (ui_panel(ui_handle(__ID__), "Qwen Image Edit")) { // (downloaded) - if (ui_text("source: https://huggingface.co/QuantStack/Qwen-Image-Edit-2509-GGUF (apache-2.0)") == UI_STATE_RELEASED) { - iron_load_url("https://huggingface.co/QuantStack/Qwen-Image-Edit-2509-GGUF"); - } - ui_text("gpu memory: 13GB"); - ui_text("nodes: Edit Image, Inpaint Image, Outpaint Image, Tile Image, Vary Image"); - if (ui_button(tr("Download (17.0GB)"))) { - // https://huggingface.co/QuantStack/Qwen-Image-Edit-2509-GGUF/resolve/main/Qwen-Image-Edit-2509-Q4_K_S.gguf - // https://huggingface.co/QuantStack/Qwen-Image-GGUF/resolve/main/VAE/Qwen_Image-VAE.safetensors - // https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/Qwen2.5-VL-7B-Instruct-Q4_K_S.gguf - // https://huggingface.co/unsloth/Qwen2.5-VL-7B-Instruct-GGUF/resolve/main/mmproj-F16.gguf - } - } - - if (ui_panel(ui_handle(__ID__), "Wan")) { // (downloaded) - if (ui_text("source: https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF (apache-2.0)") == UI_STATE_RELEASED) { - iron_load_url("https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF"); - } - ui_text("gpu memory: 10GB"); - ui_text("nodes: Text to Image"); - if (ui_button(tr("Download (19.8GB)"))) { - // https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF/resolve/main/LowNoise/Wan2.2-T2V-A14B-LowNoise-Q4_K_S.gguf - // https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF/resolve/main/HighNoise/Wan2.2-T2V-A14B-HighNoise-Q4_K_S.gguf - // https://huggingface.co/QuantStack/Wan2.2-T2V-A14B-GGUF/resolve/main/VAE/Wan2.1_VAE.safetensors - // https://huggingface.co/city96/umt5-xxl-encoder-gguf/resolve/main/umt5-xxl-encoder-Q4_K_S.gguf - } - } - - if (ui_panel(ui_handle(__ID__), "Marigold")) { // (downloaded) - if (ui_text("source: https://huggingface.co/armory3d/marigold-v1-1-gguf (openrail)") == UI_STATE_RELEASED) { - iron_load_url("https://huggingface.co/armory3d/marigold-v1-1-gguf"); - } - ui_text("gpu memory: 6GB"); - ui_text("nodes: Image to Depth, Image to Normal Map, Image to PBR"); - if (ui_button(tr("Download (9.6GB)"))) { - // https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-depth-v1-1.q8_0.gguf - // https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-normals-v1-1.q8_0.gguf - // https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-iid-appearance-v1-1.q8_0.gguf - // https://huggingface.co/armory3d/marigold-v1-1-gguf/resolve/main/marigold-iid-lighting-v1-1.q8_0.gguf - } - } - - if (ui_panel(ui_handle(__ID__), "RealESRGAN")) { // (downloaded) - if (ui_text("source: https://huggingface.co/armory3d/Real-ESRGAN (bsd-3-clause)") == UI_STATE_RELEASED) { - iron_load_url("https://huggingface.co/armory3d/Real-ESRGAN"); - } - ui_text("gpu memory: 1GB"); - ui_text("nodes: Upscale Image"); - if (ui_button(tr("Download (0.06GB)"))) { - // https://huggingface.co/armory3d/Real-ESRGAN/resolve/main/RealESRGAN_x4plus.pth } } } diff --git a/paint/sources/neural_nodes/edit_image_node.ts b/paint/sources/neural_nodes/edit_image_node.ts index 9619e6d3..ed7f0c04 100644 --- a/paint/sources/neural_nodes/edit_image_node.ts +++ b/paint/sources/neural_nodes/edit_image_node.ts @@ -17,7 +17,7 @@ function edit_image_node_button(node_id: i32) { let prompt: string = ui_text_area(ui_nest(h, 1), ui_align_t.LEFT, true, tr("prompt"), true); node.buttons[0].height = string_split(prompt, "\n").length + 2; - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); let input: gpu_texture_t = ui_nodes_get_node_preview_image(from_node); if (input != null) { diff --git a/paint/sources/neural_nodes/image_to_depth_node.ts b/paint/sources/neural_nodes/image_to_depth_node.ts index 3a4c75ca..f47aaa76 100644 --- a/paint/sources/neural_nodes/image_to_depth_node.ts +++ b/paint/sources/neural_nodes/image_to_depth_node.ts @@ -14,7 +14,7 @@ function image_to_depth_node_button(node_id: i32) { let models: string[] = [ "Marigold" ]; let model: i32 = ui_combo(ui_nest(h, 0), models, tr("Model")); - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); let input: gpu_texture_t = ui_nodes_get_node_preview_image(from_node); if (input != null) { diff --git a/paint/sources/neural_nodes/image_to_normal_map_node.ts b/paint/sources/neural_nodes/image_to_normal_map_node.ts index f84407b6..1f13e1ec 100644 --- a/paint/sources/neural_nodes/image_to_normal_map_node.ts +++ b/paint/sources/neural_nodes/image_to_normal_map_node.ts @@ -14,7 +14,7 @@ function image_to_normal_map_node_button(node_id: i32) { let models: string[] = [ "Marigold" ]; let model: i32 = ui_combo(ui_nest(h, 0), models, tr("Model")); - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); let input: gpu_texture_t = ui_nodes_get_node_preview_image(from_node); if (input != null) { diff --git a/paint/sources/neural_nodes/image_to_pbr_node.ts b/paint/sources/neural_nodes/image_to_pbr_node.ts index 5e810098..c76566f6 100644 --- a/paint/sources/neural_nodes/image_to_pbr_node.ts +++ b/paint/sources/neural_nodes/image_to_pbr_node.ts @@ -97,7 +97,7 @@ function image_to_pbr_node_button(node_id: i32) { let models: string[] = [ "Marigold" ]; let model: i32 = ui_combo(ui_nest(h, 0), models, tr("Model")); - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); let input: gpu_texture_t = ui_nodes_get_node_preview_image(from_node); if (input != null) { diff --git a/paint/sources/neural_nodes/inpaint_image_node.ts b/paint/sources/neural_nodes/inpaint_image_node.ts index bab4be9e..4302ced7 100644 --- a/paint/sources/neural_nodes/inpaint_image_node.ts +++ b/paint/sources/neural_nodes/inpaint_image_node.ts @@ -17,7 +17,7 @@ function inpaint_image_node_button(node_id: i32) { let prompt: string = ui_text_area(ui_nest(h, 1), ui_align_t.LEFT, true, tr("prompt"), true); node.buttons[0].height = string_split(prompt, "\n").length + 2; - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { sys_notify_on_next_frame(function(node: ui_node_t) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); diff --git a/paint/sources/neural_nodes/neural_node.ts b/paint/sources/neural_nodes/neural_node.ts index 12d23449..1ec0da04 100644 --- a/paint/sources/neural_nodes/neural_node.ts +++ b/paint/sources/neural_nodes/neural_node.ts @@ -3,31 +3,31 @@ let neural_node_results: map_t = map_create(); let neural_node_current: ui_node_t; function neural_node_vector(node: ui_node_t, socket: ui_node_socket_t): string { - let result: gpu_texture_t = map_get(neural_node_results, node.id); - if (result == null) { + let result: gpu_texture_t = map_get(neural_node_results, node.id); + if (result == null) { return "float3(0.0, 0.0, 0.0)"; } let tex_name: string = parser_material_node_name(node); map_set(data_cached_images, tex_name, result); - let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, tex_name); + let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, tex_name); let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space_t.AUTO); return texstore + ".rgb"; } function neural_node_value(node: ui_node_t, socket: ui_node_socket_t): string { - let result: gpu_texture_t = map_get(neural_node_results, node.id); - if (result == null) { + let result: gpu_texture_t = map_get(neural_node_results, node.id); + if (result == null) { return "0.0"; } let tex_name: string = parser_material_node_name(node); map_set(data_cached_images, tex_name, result); - let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, tex_name); + let tex: bind_tex_t = parser_material_make_bind_tex(tex_name, tex_name); let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space_t.AUTO); return texstore + ".r"; } function neural_from_node(inp: ui_node_socket_t, socket: i32): ui_node_t { - let result: ui_node_t = null; + let result: ui_node_t = null; let canvas: ui_node_canvas_t = ui_nodes_get_canvas(true); for (let i: i32 = 0; i < canvas.links.length; ++i) { let l: ui_node_link_t = canvas.links[i]; @@ -39,8 +39,10 @@ function neural_from_node(inp: ui_node_socket_t, socket: i32): ui_node_t { return result; } -function neural_node_button(node: ui_node_t): bool { - let found: bool = true; +function neural_node_button(node: ui_node_t, model: string): bool { + let url: string = box_preferneces_model_url_from_name(model); + let file_name: string = box_preferences_file_name_from_url(url); + let found: bool = box_preferences_model_exists(file_name); if (iron_exec_async_done == 0) { if (node != neural_node_current) { @@ -58,7 +60,7 @@ function neural_node_button(node: ui_node_t): bool { else if (found && ui_button(tr("Run"))) { return true; } - return false; + return false; } function neural_node_check_result(node: ui_node_t) { @@ -66,20 +68,56 @@ function neural_node_check_result(node: ui_node_t) { if (iron_exec_async_done == 1) { let file: string = neural_node_dir() + path_sep + "output.png"; if (iron_file_exists(file)) { - let result: gpu_texture_t = iron_load_texture(file); - map_set(neural_node_results, node.id, result); + let result: gpu_texture_t = iron_load_texture(file); + map_set(neural_node_results, node.id, result); } sys_remove_update(neural_node_check_result); } } function neural_node_dir(): string { - let dir: string; - if (path_is_protected()) { - dir = iron_internal_save_path() + "models"; - } - else { - dir = iron_internal_files_location() + path_sep + "models"; - } - return dir; + let dir: string; + if (path_is_protected()) { + dir = iron_internal_save_path() + "models"; + } + else { + dir = iron_internal_files_location() + path_sep + "models"; + } + return dir; +} + +let neural_node_downloading: i32 = 0; + +function neural_node_download(url: string) { + let file_name: string = substring(url, string_last_index_of(url, "/") + 1, url.length); + let file_path: string = neural_node_dir() + path_sep + file_name; + let found: bool = iron_file_exists(file_path); + if (found) { + return; + } + + neural_node_downloading++; + file_download_to(url, file_path, function (url: string) { neural_node_downloading--; }); +} + +function neural_node_download_models(models: string[]) { + if (file_read_directory(neural_node_dir())[0] == "") { + file_create_directory(neural_node_dir()); + } + + /// if arm_windows + neural_node_download("https://github.com/armory3d/armortools/raw/refs/heads/main/base/assets/bin/windows_x64/sd_cpu.exe"); + neural_node_download("https://github.com/armory3d/armortools/raw/refs/heads/main/base/assets/bin/windows_x64/sd_vulkan.exe"); + neural_node_download("https://github.com/armory3d/armortools/raw/refs/heads/main/base/assets/bin/windows_x64/sd_cuda.exe"); + /// elseif arm_linux + neural_node_download("https://github.com/armory3d/armortools/raw/refs/heads/main/base/assets/bin/linux_x64/sd_cpu"); + neural_node_download("https://github.com/armory3d/armortools/raw/refs/heads/main/base/assets/bin/linux_x64/sd_vulkan"); + /// else + neural_node_download("https://github.com/armory3d/armortools/raw/refs/heads/main/base/assets/bin/macos/sd_cpu"); + neural_node_download("https://github.com/armory3d/armortools/raw/refs/heads/main/base/assets/bin/macos/sd_vulkan"); + /// end + + for (let i: i32 = 0; i < models.length; ++i) { + neural_node_download(models[i]); + } } diff --git a/paint/sources/neural_nodes/outpaint_image_node.ts b/paint/sources/neural_nodes/outpaint_image_node.ts index 4c75fcc4..063b6278 100644 --- a/paint/sources/neural_nodes/outpaint_image_node.ts +++ b/paint/sources/neural_nodes/outpaint_image_node.ts @@ -17,7 +17,7 @@ function outpaint_image_node_button(node_id: i32) { let prompt: string = ui_text_area(ui_nest(h, 1), ui_align_t.LEFT, true, tr("prompt"), true); node.buttons[0].height = string_split(prompt, "\n").length + 2; - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { sys_notify_on_next_frame(function(node: ui_node_t) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); diff --git a/paint/sources/neural_nodes/text_to_image_node.ts b/paint/sources/neural_nodes/text_to_image_node.ts index 8406ceaa..3a0c940d 100644 --- a/paint/sources/neural_nodes/text_to_image_node.ts +++ b/paint/sources/neural_nodes/text_to_image_node.ts @@ -105,7 +105,7 @@ function text_to_image_node_button(node_id: i32) { let prompt: string = ui_text_area(ui_nest(h, 1), ui_align_t.LEFT, true, tr("prompt"), true); node.buttons[0].height = string_split(prompt, "\n").length + 2; - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { let dir: string = neural_node_dir(); if (prompt == "") { diff --git a/paint/sources/neural_nodes/tile_image_node.ts b/paint/sources/neural_nodes/tile_image_node.ts index 72d77012..a26c79d1 100644 --- a/paint/sources/neural_nodes/tile_image_node.ts +++ b/paint/sources/neural_nodes/tile_image_node.ts @@ -17,7 +17,7 @@ function tile_image_node_button(node_id: i32) { let prompt: string = ui_text_area(ui_nest(h, 1), ui_align_t.LEFT, true, tr("prompt"), true); node.buttons[0].height = string_split(prompt, "\n").length + 2; - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { sys_notify_on_next_frame(function(node: ui_node_t) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); diff --git a/paint/sources/neural_nodes/upscale_image_node.ts b/paint/sources/neural_nodes/upscale_image_node.ts index ff585d3d..5b307939 100644 --- a/paint/sources/neural_nodes/upscale_image_node.ts +++ b/paint/sources/neural_nodes/upscale_image_node.ts @@ -14,7 +14,7 @@ function upscale_image_node_button(node_id: i32) { let models: string[] = [ "RealESRGAN_X4" ]; let model: i32 = ui_combo(ui_nest(h, 0), models, tr("Model")); - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); let input: gpu_texture_t = ui_nodes_get_node_preview_image(from_node); if (input != null) { diff --git a/paint/sources/neural_nodes/vary_image_node.ts b/paint/sources/neural_nodes/vary_image_node.ts index 0b0179b7..c13af53b 100644 --- a/paint/sources/neural_nodes/vary_image_node.ts +++ b/paint/sources/neural_nodes/vary_image_node.ts @@ -17,7 +17,7 @@ function vary_image_node_button(node_id: i32) { let prompt: string = ui_text_area(ui_nest(h, 1), ui_align_t.LEFT, true, tr("prompt"), true); node.buttons[0].height = string_split(prompt, "\n").length + 2; - if (neural_node_button(node)) { + if (neural_node_button(node, models[model])) { sys_notify_on_next_frame(function(node: ui_node_t) { let from_node: ui_node_t = neural_from_node(node.inputs[0], 0); diff --git a/paint/sources/nodes_material.ts b/paint/sources/nodes_material.ts index 4fa5da6c..39c907fc 100644 --- a/paint/sources/nodes_material.ts +++ b/paint/sources/nodes_material.ts @@ -79,18 +79,16 @@ function nodes_material_init() { vector_math2_node_init(); nodes_material_neural = []; - if (config_raw.experimental) { - edit_image_node_init(); - image_to_depth_node_init(); - image_to_normal_map_node_init(); - image_to_pbr_node_init(); - inpaint_image_node_init(); - outpaint_image_node_init(); - text_to_image_node_init(); - tile_image_node_init(); - upscale_image_node_init(); - vary_image_node_init(); - } + edit_image_node_init(); + image_to_depth_node_init(); + image_to_normal_map_node_init(); + image_to_pbr_node_init(); + inpaint_image_node_init(); + outpaint_image_node_init(); + text_to_image_node_init(); + tile_image_node_init(); + upscale_image_node_init(); + vary_image_node_init(); nodes_material_group = []; group_node_init();