From 36a9dc04bc477939473b73ff66d7b635b06d5212 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 21 Nov 2025 16:06:48 +0100 Subject: [PATCH 1/4] gltf import fixes --- paint/plugins/io_gltf/cgltf.c | 197 ++++++++++++++++------------------ 1 file changed, 91 insertions(+), 106 deletions(-) diff --git a/paint/plugins/io_gltf/cgltf.c b/paint/plugins/io_gltf/cgltf.c index 80aa485f..e0b53362 100644 --- a/paint/plugins/io_gltf/cgltf.c +++ b/paint/plugins/io_gltf/cgltf.c @@ -1,103 +1,71 @@ #define CGLTF_IMPLEMENTATION #include "cgltf.h" -#include #include "iron_array.h" #include "iron_obj.h" +#include -static bool has_next = false; -static int current_node = 0; -static float scale_pos = 1.0; - -uint32_t *io_gltf_read_u8_array(cgltf_accessor *a) { - cgltf_buffer_view *v = a->buffer_view; - uint8_t *ar = (uint8_t *) (v->buffer->data + v->offset); - uint32_t *res = malloc(sizeof(uint32_t) * v->size); - for (int i = 0; i < v->size; ++i) { - res[i] = ar[i]; - } - return res; -} - -uint32_t *io_gltf_read_u16_array(cgltf_accessor *a) { - cgltf_buffer_view *v = a->buffer_view; - uint16_t *ar = (uint16_t *) (v->buffer->data + v->offset); - uint32_t *res = malloc(sizeof(unsigned int) * v->size); - for (int i = 0; i < a->count; ++i) { - res[i] = ar[i]; - } - return res; -} - -uint32_t *io_gltf_read_u32_array(cgltf_accessor *a) { - cgltf_buffer_view *v = a->buffer_view; - uint32_t *ar = (uint32_t *) (v->buffer->data + v->offset); - return ar; -} - -float *io_gltf_read_f32_array(cgltf_accessor *a) { - cgltf_buffer_view *v = a->buffer_view; - float *ar = (float *) (v->buffer->data + v->offset); - return ar; -} +static bool has_next = false; +static int current_node = 0; +static float scale_pos = 1.0; void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, float *scale) { - cgltf_primitive *prim = NULL; - uint32_t *inda = NULL; + uint32_t *inda = NULL; for (int i = 0; i < mesh->primitives_count; ++i) { - prim = &mesh->primitives[0]; - + // TODO: handle all primitives + prim = &mesh->primitives[i]; cgltf_accessor *a = prim->indices; - int elem_size = a->buffer_view->size / a->count; - - inda = elem_size == 1 ? io_gltf_read_u8_array(a) - : elem_size == 2 ? io_gltf_read_u16_array(a) - : elem_size == 4 ? io_gltf_read_u32_array(a) : NULL; - - if (inda) { - break; + inda = malloc(sizeof(uint32_t) * a->count); + for (cgltf_size i = 0; i < a->count; ++i) { + inda[i] = cgltf_accessor_read_index(a, i); } } - if (!inda) { - // All of the primitives in the mesh don't have data + if (inda == NULL) { return; } - int index_count = prim->indices->count; - - int vertex_count = -1; - float *posa32 = NULL; - float *nora32 = NULL; - float *texa32 = NULL; + int index_count = prim->indices->count; + int vertex_count = -1; + float *posa32 = NULL; + float *nora32 = NULL; + float *texa32 = NULL; for (int i = 0; i < prim->attributes_count; ++i) { - cgltf_attribute* attrib = &prim->attributes[i]; + cgltf_attribute *attrib = &prim->attributes[i]; if (attrib->type == cgltf_attribute_type_position) { vertex_count = attrib->data->count; - posa32 = io_gltf_read_f32_array(attrib->data); + posa32 = malloc(sizeof(float) * attrib->data->count * 3); + for (cgltf_size i = 0; i < attrib->data->count; ++i) { + cgltf_accessor_read_float(attrib->data, i, posa32 + i * 3, 3); + } } else if (attrib->type == cgltf_attribute_type_normal) { - nora32 = io_gltf_read_f32_array(attrib->data); + nora32 = malloc(sizeof(float) * attrib->data->count * 3); + for (cgltf_size i = 0; i < attrib->data->count; ++i) { + cgltf_accessor_read_float(attrib->data, i, nora32 + i * 3, 3); + } } else if (attrib->type == cgltf_attribute_type_texcoord) { - texa32 = io_gltf_read_f32_array(attrib->data); + texa32 = malloc(sizeof(float) * attrib->data->count * 2); + for (cgltf_size i = 0; i < attrib->data->count; ++i) { + cgltf_accessor_read_float(attrib->data, i, texa32 + i * 2, 2); + } } } if (vertex_count == -1) { - // No vertex data position attributes found in primitive return; } float *m = to_world; for (int i = 0; i < vertex_count; ++i) { - float x = posa32[i * 3 + 0]; - float y = posa32[i * 3 + 1]; - float z = posa32[i * 3 + 2]; + float x = posa32[i * 3 + 0]; + float y = posa32[i * 3 + 1]; + float z = posa32[i * 3 + 2]; posa32[i * 3 + 0] = m[0] * x + m[4] * y + m[8] * z + m[12]; posa32[i * 3 + 1] = m[1] * x + m[5] * y + m[9] * z + m[13]; posa32[i * 3 + 2] = m[2] * x + m[6] * y + m[10] * z + m[14]; @@ -105,12 +73,21 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa if (nora32 != NULL) { for (int i = 0; i < vertex_count; ++i) { - float x = nora32[i * 3 + 0] / scale[0]; - float y = nora32[i * 3 + 1] / scale[1]; - float z = nora32[i * 3 + 2] / scale[2]; - nora32[i * 3 + 0] = m[0] * x + m[4] * y + m[8] * z; - nora32[i * 3 + 1] = m[1] * x + m[5] * y + m[9] * z; - nora32[i * 3 + 2] = m[2] * x + m[6] * y + m[10] * z; + float x = nora32[i * 3 + 0] / scale[0]; + float y = nora32[i * 3 + 1] / scale[1]; + float z = nora32[i * 3 + 2] / scale[2]; + float tx = m[0] * x + m[4] * y + m[8] * z; + float ty = m[1] * x + m[5] * y + m[9] * z; + float tz = m[2] * x + m[6] * y + m[10] * z; + float len = sqrtf(tx * tx + ty * ty + tz * tz); + if (len > 1e-6f) { + tx /= len; + ty /= len; + tz /= len; + } + nora32[i * 3 + 0] = tx; + nora32[i * 3 + 1] = ty; + nora32[i * 3 + 2] = tz; } } @@ -120,21 +97,25 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa float hz = 0.0; for (int i = 0; i < vertex_count; ++i) { float f = fabsf(posa32[i * 3]); - if (hx < f) hx = f; + if (hx < f) + hx = f; f = fabsf(posa32[i * 3 + 1]); - if (hy < f) hy = f; + if (hy < f) + hy = f; f = fabsf(posa32[i * 3 + 2]); - if (hz < f) hz = f; + if (hz < f) + hz = f; } float _scale_pos = fmax(hx, fmax(hy, hz)); - if (_scale_pos > scale_pos) scale_pos = _scale_pos; + if (_scale_pos > scale_pos) + scale_pos = _scale_pos; float inv = 1 / scale_pos; // Pack into 16bit short *posa = malloc(sizeof(short) * vertex_count * 4); for (int i = 0; i < vertex_count; ++i) { - posa[i * 4 ] = posa32[i * 3 ] * 32767 * inv; + posa[i * 4] = posa32[i * 3] * 32767 * inv; posa[i * 4 + 1] = posa32[i * 3 + 1] * 32767 * inv; posa[i * 4 + 2] = posa32[i * 3 + 2] * 32767 * inv; } @@ -142,7 +123,7 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa short *nora = malloc(sizeof(short) * vertex_count * 2); if (nora32 != NULL) { for (int i = 0; i < vertex_count; ++i) { - nora[i * 2 ] = nora32[i * 3 ] * 32767; + nora[i * 2] = nora32[i * 3] * 32767; nora[i * 2 + 1] = nora32[i * 3 + 1] * 32767; posa[i * 4 + 3] = nora32[i * 3 + 2] * 32767; } @@ -150,18 +131,28 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa else { // Calc normals for (int i = 0; i < index_count / 3; ++i) { - int i1 = inda[i * 3 ]; - int i2 = inda[i * 3 + 1]; - int i3 = inda[i * 3 + 2]; - float vax = posa32[i1 * 3]; float vay = posa32[i1 * 3 + 1]; float vaz = posa32[i1 * 3 + 2]; - float vbx = posa32[i2 * 3]; float vby = posa32[i2 * 3 + 1]; float vbz = posa32[i2 * 3 + 2]; - float vcx = posa32[i3 * 3]; float vcy = posa32[i3 * 3 + 1]; float vcz = posa32[i3 * 3 + 2]; - float cbx = vcx - vbx; float cby = vcy - vby; float cbz = vcz - vbz; - float abx = vax - vbx; float aby = vay - vby; float abz = vaz - vbz; + int i1 = inda[i * 3]; + int i2 = inda[i * 3 + 1]; + int i3 = inda[i * 3 + 2]; + float vax = posa32[i1 * 3]; + float vay = posa32[i1 * 3 + 1]; + float vaz = posa32[i1 * 3 + 2]; + float vbx = posa32[i2 * 3]; + float vby = posa32[i2 * 3 + 1]; + float vbz = posa32[i2 * 3 + 2]; + float vcx = posa32[i3 * 3]; + float vcy = posa32[i3 * 3 + 1]; + float vcz = posa32[i3 * 3 + 2]; + float cbx = vcx - vbx; + float cby = vcy - vby; + float cbz = vcz - vbz; + float abx = vax - vbx; + float aby = vay - vby; + float abz = vaz - vbz; float x = cbx, y = cby, z = cbz; - cbx = y * abz - z * aby; - cby = z * abx - x * abz; - cbz = x * aby - y * abx; + cbx = y * abz - z * aby; + cby = z * abx - x * abz; + cbz = x * aby - y * abx; float n = sqrt(cbx * cbx + cby * cby + cbz * cbz); if (n > 0.0) { float inv_n = 1.0 / n; @@ -169,13 +160,13 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa cby *= inv_n; cbz *= inv_n; } - nora[i1 * 2 ] = (int)(cbx * 32767); + nora[i1 * 2] = (int)(cbx * 32767); nora[i1 * 2 + 1] = (int)(cby * 32767); posa[i1 * 4 + 3] = (int)(cbz * 32767); - nora[i2 * 2 ] = (int)(cbx * 32767); + nora[i2 * 2] = (int)(cbx * 32767); nora[i2 * 2 + 1] = (int)(cby * 32767); posa[i2 * 4 + 3] = (int)(cbz * 32767); - nora[i3 * 2 ] = (int)(cbx * 32767); + nora[i3 * 2] = (int)(cbx * 32767); nora[i3 * 2 + 1] = (int)(cby * 32767); posa[i3 * 4 + 3] = (int)(cbz * 32767); } @@ -185,29 +176,26 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa if (texa32 != NULL) { texa = malloc(sizeof(short) * vertex_count * 2); for (int i = 0; i < vertex_count; ++i) { - texa[i * 2 ] = texa32[i * 2 ] * 32767; + texa[i * 2] = texa32[i * 2] * 32767; texa[i * 2 + 1] = texa32[i * 2 + 1] * 32767; } } - raw->posa = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->posa = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->posa->buffer = posa; raw->posa->length = raw->posa->capacity = vertex_count * 4; - raw->nora = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->nora = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->nora->buffer = nora; raw->nora->length = raw->nora->capacity = vertex_count * 2; if (texa != NULL) { - raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); raw->texa->buffer = texa; raw->texa->length = raw->texa->capacity = vertex_count * 2; } - else { - raw->texa = NULL; - } - raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); + raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); raw->inda->buffer = inda; raw->inda->length = raw->inda->capacity = index_count; @@ -217,8 +205,8 @@ void io_gltf_parse_mesh(raw_mesh_t *raw, cgltf_mesh *mesh, float *to_world, floa void *io_gltf_parse(char *buf, size_t size, const char *path) { cgltf_options options = {0}; - cgltf_data *data = NULL; - cgltf_result result = cgltf_parse(&options, buf, size, &data); + cgltf_data *data = NULL; + cgltf_result result = cgltf_parse(&options, buf, size, &data); if (result != cgltf_result_success) { return NULL; } @@ -232,17 +220,14 @@ void *io_gltf_parse(char *buf, size_t size, const char *path) { raw->name = malloc(strlen(n->name) + 1); strcpy(raw->name, n->name); float m[16]; - cgltf_node_transform_world(n, &m); - float scale[3]; - scale[0] = 1; - scale[1] = 1; - scale[2] = 1; + cgltf_node_transform_world(n, m); + float scale[3] = {1.0f, 1.0f, 1.0f}; if (n->has_scale) { scale[0] = n->scale[0]; scale[1] = n->scale[1]; scale[2] = n->scale[2]; } - io_gltf_parse_mesh(raw, n->mesh, &m, &scale); + io_gltf_parse_mesh(raw, n->mesh, m, scale); break; } } From 5a3ad739c6a88daaab5e8c93d15be03bc3c2c31d Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 21 Nov 2025 16:08:17 +0100 Subject: [PATCH 2/4] Prevent negative basecolor --- paint/sources/make_mesh.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/paint/sources/make_mesh.ts b/paint/sources/make_mesh.ts index 1a231a88..bfeb0dff 100644 --- a/paint/sources/make_mesh.ts +++ b/paint/sources/make_mesh.ts @@ -379,6 +379,7 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): node_shader_conte if (context_raw.viewport_mode == viewport_mode_t.LIT || context_raw.viewport_mode == viewport_mode_t.PATH_TRACE) { node_shader_write_frag(kong, "basecol = pow3(basecol, float3(2.2, 2.2, 2.2));"); + node_shader_write_frag(kong, "basecol = max3(basecol, float3(0.0, 0.0, 0.0));"); if (context_raw.viewport_shader != null) { node_shader_write_frag(kong, "var output_color: float3;"); From 8af2e7d325e42336665c2c1a2ee9504b0e7bb4c4 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 21 Nov 2025 18:42:36 +0100 Subject: [PATCH 3/4] Path handling fixes --- paint/sources/neural_nodes/neural_node.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paint/sources/neural_nodes/neural_node.ts b/paint/sources/neural_nodes/neural_node.ts index 06b68b4d..32d6001f 100644 --- a/paint/sources/neural_nodes/neural_node.ts +++ b/paint/sources/neural_nodes/neural_node.ts @@ -107,11 +107,11 @@ function neural_node_download(url: string) { // todo if (ends_with(url, "sd_vulkan")) { let bin: string = neural_node_dir() + "/sd_vulkan"; - iron_sys_command("chmod +x '" + bin + "'"); + iron_sys_command("chmod +x \"" + bin + "\""); } else if (ends_with(url, "sd_cpu")) { let bin: string = neural_node_dir() + "/sd_cpu"; - iron_sys_command("chmod +x '" + bin + "'"); + iron_sys_command("chmod +x \"" + bin + "\""); } /// end }); From 641aaaf90c23f5cc664d6b72f86f7787e6191730 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 21 Nov 2025 18:44:05 +0100 Subject: [PATCH 4/4] More windows path handling fixes --- base/sources/iron.h | 2 +- paint/sources/import_blend_mesh.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/base/sources/iron.h b/base/sources/iron.h index 0a3f0985..19faa7fb 100644 --- a/base/sources/iron.h +++ b/base/sources/iron.h @@ -1305,7 +1305,7 @@ i32 iron_sys_command(string_t *cmd) { wchar_t comspec[MAX_PATH]; GetEnvironmentVariableW(L"ComSpec", comspec, MAX_PATH); wchar_t cmdline[2048]; - swprintf(cmdline, 2048, L"\"%s\" /c %s", comspec, wstr); + swprintf(cmdline, 2048, L"\"%s\" /c \"%s\"", comspec, wstr); STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); diff --git a/paint/sources/import_blend_mesh.ts b/paint/sources/import_blend_mesh.ts index 4b87331f..bdafa9c4 100644 --- a/paint/sources/import_blend_mesh.ts +++ b/paint/sources/import_blend_mesh.ts @@ -43,7 +43,11 @@ import bpy;\ bpy.ops.wm.obj_export(filepath='" + bpy_folder + string_replace_all(save, "\\", "/") + "',export_triangulated_mesh=True,export_materials=False,check_existing=False)"; + /// if arm_windows + let bl: string = "\"" + string_replace_all(config_raw.blender, "/", "\\") + "\""; + /// else let bl: string = string_replace_all(config_raw.blender, " ", "\\ "); + /// end iron_sys_command(bl + " \"" + path + "\" -b --python-expr \"" + py + "\""); import_obj_run(save, replace_existing); }