From 0ec15f2b9ca4097cde2d98f9492a73838d0ae753 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Sat, 24 Aug 2024 11:17:02 +0200 Subject: [PATCH] Plugins work --- armorpaint/assets/plugins/import_fbx.js | 57 +- armorpaint/assets/plugins/import_gltf_glb.js | 54 +- armorpaint/assets/plugins/import_stl.js | 36 +- armorpaint/assets/plugins/import_svg.js | 40 +- armorpaint/assets/plugins/import_usdc.js | 49 +- armorpaint/plugins/project.js | 4 + armorpaint/plugins/sources/io_fbx/io_fbx.c | 164 ++---- armorpaint/plugins/sources/io_gltf/cgltf.c | 169 +++--- armorpaint/plugins/sources/io_svg/nanosvg.c | 50 +- armorpaint/plugins/sources/io_usd/io_usd.cc | 91 ++-- armorpaint/plugins/sources/plugins.c | 34 +- base/assets/plugins/autosave.js | 15 +- base/assets/plugins/import_tiff.js | 22 +- base/assets/plugins/import_txt.js | 27 +- base/sources/import_mesh.ts | 17 +- base/sources/import_texture.ts | 9 +- base/sources/path.ts | 8 +- base/sources/plugin.ts | 4 + base/sources/plugin_api.c | 518 ++++++++++++------- 19 files changed, 634 insertions(+), 734 deletions(-) diff --git a/armorpaint/assets/plugins/import_fbx.js b/armorpaint/assets/plugins/import_fbx.js index d4566d7e..4e1b7c75 100644 --- a/armorpaint/assets/plugins/import_fbx.js +++ b/armorpaint/assets/plugins/import_fbx.js @@ -1,53 +1,12 @@ -let a = Krom_import_fbx; -class R { - get buffer() { return Krom_import_fbx._buffer(); } -} -let r = new R(); - -// import_fbx.js -let import_fbx = function(path) { - data_get_blob(path); - let buf_off = a._init(b.byteLength); //// Allocate r.buffer - let buf = new Uint8Array(r.buffer, buf_off, b.byteLength); - let bbuf = new Uint8Array(b); - for (let i = 0; i < b.byteLength; ++i) { - buf[i] = bbuf[i]; - } - a._parse(); - let vertex_count = a._get_vertex_count(); - let index_count = a._get_index_count(); - let inda = new Uint32Array(r.buffer, a._get_indices(), index_count); - let posa = new Int16Array(r.buffer, a._get_positions(), vertex_count * 4); - let nora = new Int16Array(r.buffer, a._get_normals(), vertex_count * 2); - let texa = a._get_uvs() > 0 ? new Int16Array(r.buffer, a._get_uvs(), vertex_count * 2) : null; - let cola = a._get_colors() > 0 ? new Int16Array(r.buffer, a._get_colors(), vertex_count * 3) : null; - - // a._destroy(); //// Destroys r.buffer - // data_delete_blob(path); - - // Use .slice() for now as the next mesh will overwrite buffer data corrupting the old vertex data - return { - name: a._get_name(), - posa: posa.slice(), - nora: nora.slice(), - texa: texa != null ? texa.slice() : null, - cola: cola != null ? cola.slice() : null, - inda: inda.slice(), - scale_pos: a._get_scale_pos(), - scale_tex: 1.0, - transform: a._get_transform(), - has_next: a._has_next() - }; +function import_fbx(path) { + let b = data_get_blob(path); + data_delete_blob(path); + return io_fbx_parse(b); } let plugin = plugin_create(); -let formats = path_mesh_formats; -let importers = path_mesh_mporters; -formats.push("fbx"); -importers.set("fbx", import_fbx); - -plugin.delete = function() { - formats.splice(formats.indexOf("fbx"), 1); - importers.delete("fbx"); -}; +path_mesh_importers_set("fbx", import_fbx); +plugin_notify_on_delete(plugin, function() { + path_mesh_importers_delete("fbx"); +}); diff --git a/armorpaint/assets/plugins/import_gltf_glb.js b/armorpaint/assets/plugins/import_gltf_glb.js index 99f09d4d..13904caf 100644 --- a/armorpaint/assets/plugins/import_gltf_glb.js +++ b/armorpaint/assets/plugins/import_gltf_glb.js @@ -1,52 +1,14 @@ -let a = Krom_import_gltf; -class R { - get buffer() { return Krom_import_gltf._buffer(); } -} -let r = new R(); - -// import_gltf_glb.js -let import_gltf_glb = function(path) { +function import_gltf_glb(path) { let b = data_get_blob(path); - let buf_off = a._init(b.byteLength); //// Allocate r.buffer - let buf = new Uint8Array(r.buffer, buf_off, b.byteLength); - let bbuf = new Uint8Array(b); - for (let i = 0; i < b.byteLength; ++i) { - buf[i] = bbuf[i]; - } - a._parse(); - let vertex_count = a._get_vertex_count(); - let index_count = a._get_index_count(); - let inda = new Uint32Array(r.buffer, a._get_indices(), index_count); - let posa = new Int16Array(r.buffer, a._get_positions(), vertex_count * 4); - let nora = new Int16Array(r.buffer, a._get_normals(), vertex_count * 2); - let uvs = a._get_uvs(); - let texa = uvs == 0 ? null : new Int16Array(r.buffer, uvs, vertex_count * 2); - let name = path.split("\\").pop().split("/").pop().split(".").shift(); - return { - name: name, - posa: posa, - nora: nora, - texa: texa, - inda: inda, - scale_pos: a._get_scale_pos(), - scale_tex: 1.0 - }; - // a._destroy(); //// Destroys r.buffer data_delete_blob(path); + return io_gltf_parse(b); } let plugin = plugin_create(); -let formats = path_mesh_formats; -let importers = path_mesh_importers; -formats.push("gltf"); -formats.push("glb"); -importers.set("gltf", import_gltf_glb); -importers.set("glb", import_gltf_glb); - -plugin.delete = function() { - formats.splice(formats.indexOf("gltf"), 1); - formats.splice(formats.indexOf("glb"), 1); - importers.delete("gltf"); - importers.delete("glb"); -}; +path_mesh_importers_set("gltf", import_gltf_glb); +path_mesh_importers_set("glb", import_gltf_glb); +plugin_notify_on_delete(plugin, function() { + path_mesh_importers_delete("gltf"); + path_mesh_importers_delete("glb"); +}); diff --git a/armorpaint/assets/plugins/import_stl.js b/armorpaint/assets/plugins/import_stl.js index 77ce27af..d9d87407 100644 --- a/armorpaint/assets/plugins/import_stl.js +++ b/armorpaint/assets/plugins/import_stl.js @@ -1,33 +1,29 @@ let pos = 0; -let read_i16 = function(view) { +function read_i16(view) { let i = view.getInt16(pos, true); pos += 2; return i; } -let read_i32 = function(view) { +function read_i32(view) { let i = view.getInt32(pos, true); pos += 4; return i; } -let read_f32 = function(view) { +function read_f32(view) { let f = view.getFloat32(pos, true); pos += 4; return f; } -let import_stl = function(path, done) { +function import_stl(path) { let b = data_get_blob(path); let view = new DataView(b); pos = 0; - // let header = input.read(80); - pos += 80; - // if (header.getString(0, 5) == "solid") { - // return; // ascii not supported - // } + pos += 80; // header let faces = read_i32(view); let pos_temp = new Float32Array(faces * 9); let nor_temp = new Float32Array(faces * 3); @@ -74,23 +70,11 @@ let import_stl = function(path, done) { data_delete_blob(path); let name = path.split("\\").pop().split("/").pop().split(".").shift(); - return { - name: name, - posa: posa, - nora: nora, - inda: inda, - scale_pos: scale_pos, - scale_tex: 1.0 - }; + return plugin_api_make_raw_mesh(name, posa.buffer, nora.buffer, inda.buffer, scale_pos); } let plugin = plugin_create(); -let formats = path_mesh_formats; -let importers = path_mesh_importers; -formats.push("stl"); -importers.set("stl", import_stl); - -plugin.delete = function() { - formats.splice(formats.indexOf("stl"), 1); - importers.delete("stl"); -}; +path_mesh_importers_set("stl", import_stl); +plugin_notify_on_delete(plugin, function() { + path_mesh_importers_delete("stl"); +}); diff --git a/armorpaint/assets/plugins/import_svg.js b/armorpaint/assets/plugins/import_svg.js index 09d48963..ae15de38 100644 --- a/armorpaint/assets/plugins/import_svg.js +++ b/armorpaint/assets/plugins/import_svg.js @@ -1,40 +1,12 @@ -let a = Krom_import_svg; -class R { - get buffer() { return Krom_import_svg._buffer(); } -} -let r = new R(); - -// import_svg.js -let import_svg = function(path) { +function import_svg(path) { let b = data_get_blob(path); - let buf_off = a._init(b.byteLength + 1); //// Allocate r.buffer - let buf = new Uint8Array(r.buffer, buf_off, b.byteLength + 1); - let bbuf = new Uint8Array(b); - for (let i = 0; i < b.byteLength; ++i) { - buf[i] = bbuf[i]; - } - buf[b.byteLength] = 0; - - a._parse(); - let w = a._get_pixels_w(); - let h = a._get_pixels_h(); - let pixels = r.buffer.slice(a._get_pixels(), a._get_pixels() + w * h * 4); - let image = image_from_bytes(pixels, w, h); - - // a._destroy(); //// Destroys r.buffer data_delete_blob(path); - - return image; + return io_svg_parse(b); } let plugin = plugin_create(); -let formats = path_texture_formats; -let importers = path_texture_importers; -formats.push("svg"); -importers.set("svg", import_svg); - -plugin.delete = function() { - formats.splice(formats.indexOf("svg"), 1); - importers.delete("svg"); -}; +path_texture_importers_set("svg", import_svg); +plugin_notify_on_delete(plugin, function() { + path_texture_importers_delete("svg"); +}); diff --git a/armorpaint/assets/plugins/import_usdc.js b/armorpaint/assets/plugins/import_usdc.js index 545fa890..c4fb99a3 100644 --- a/armorpaint/assets/plugins/import_usdc.js +++ b/armorpaint/assets/plugins/import_usdc.js @@ -1,49 +1,12 @@ -let a = Krom_import_usdc; -class R { - get buffer() { return Krom_import_usdc._buffer(); } -} -let r = new R(); - -// import_usdc.js -let import_usdc = function(path) { +function import_usd(path) { let b = data_get_blob(path); - let buf_off = a._init(b.byteLength); //// Allocate r.buffer - let buf = new Uint8Array(r.buffer, buf_off, b.byteLength); - let bbuf = new Uint8Array(b); - for (let i = 0; i < b.byteLength; ++i) { - buf[i] = bbuf[i]; - } - a._parse(); - let vertex_count = a._get_vertex_count(); - let index_count = a._get_index_count(); - let inda = new Uint32Array(r.buffer, a._get_indices(), index_count); - let posa = new Int16Array(r.buffer, a._get_positions(), vertex_count * 4); - let nora = new Int16Array(r.buffer, a._get_normals(), vertex_count * 2); - let texa = new Int16Array(r.buffer, a._get_uvs(), vertex_count * 2); - let name = path.split("\\").pop().split("/").pop().split(".").shift(); - - // a._destroy(); //// Destroys r.buffer data_delete_blob(path); - - return { - name: name, - posa: posa, - nora: nora, - texa: texa, - inda: inda, - scale_pos: a._get_scale_pos(), - scale_tex: 1.0 - }; + return io_usd_parse(b); } let plugin = plugin_create(); -let formats = path_mesh_formats; -let importers = path_mesh_importers; -formats.push("usdc"); -importers.set("usdc", import_usdc); - -plugin.delete = function() { - formats.splice(formats.indexOf("usdc"), 1); - importers.delete("usdc"); -}; +path_mesh_importers_set("usdc", import_usd); +plugin_notify_on_delete(plugin, function() { + path_mesh_importers_delete("usdc"); +}); diff --git a/armorpaint/plugins/project.js b/armorpaint/plugins/project.js index 4471a17d..462c1bc6 100644 --- a/armorpaint/plugins/project.js +++ b/armorpaint/plugins/project.js @@ -2,6 +2,10 @@ let project = new Project("plugins"); project.addFile("sources/plugins.c"); project.addFile("sources/proc_xatlas/**"); +project.addFile("sources/io_svg/**"); +project.addFile("sources/io_usd/**"); +project.addFile("sources/io_gltf/**"); +project.addFile("sources/io_fbx/**"); project.addDefine("TINYUSDZ_NO_STB_IMAGE_IMPLEMENTATION"); diff --git a/armorpaint/plugins/sources/io_fbx/io_fbx.c b/armorpaint/plugins/sources/io_fbx/io_fbx.c index 3024111e..6b770e9b 100644 --- a/armorpaint/plugins/sources/io_fbx/io_fbx.c +++ b/armorpaint/plugins/sources/io_fbx/io_fbx.c @@ -1,49 +1,16 @@ #include "ufbx/ufbx.h" #include #include +#include "iron_array.h" +#include "io_obj.h" -static uint8_t *buffer = NULL; -static uint32_t bufferLength = 0; -static int bufOff; /* Pointer to fbx file data */ -static size_t size; /* Size of the file data */ - -static int index_count; -static int vertex_count; -static int indaOff; -static int posaOff; -static int noraOff; -static int texaOff; -static int colaOff; -static float scale_pos; -static char name[128]; -static float transform[16]; static bool has_next = false; -static int current_node; +static int current_node = 0; +static float scale_pos = 1.0; -uint8_t *io_fbx_getBuffer() { return buffer; } -uint32_t io_fbx_getBufferLength() { return bufferLength; } - -static int allocate(int size) { - size += size % 4; // Byte align - bufferLength += size; - buffer = buffer == NULL ? (uint8_t *)malloc(bufferLength) : (uint8_t *)realloc(buffer, bufferLength); - return bufferLength - size; -} - -int io_fbx_init(int bufSize) { - if (!has_next) { - current_node = 0; - scale_pos = 0; - } - - size = bufSize; - bufOff = allocate(sizeof(uint8_t) * bufSize); - return bufOff; -} - -void io_fbx_parse_mesh(ufbx_mesh *mesh) { +void io_fbx_parse_mesh(raw_mesh_t *raw, ufbx_mesh *mesh, ufbx_matrix *to_world, ufbx_matrix *to_world_unscaled) { uint32_t indices_size = mesh->max_face_triangles * 3; - uint32_t *indices = (uint32_t *)malloc(sizeof(uint32_t) * mesh->max_face_triangles * 3); + uint32_t *indices = (uint32_t *)malloc(sizeof(uint32_t) * indices_size); bool has_tex = mesh->vertex_uv.exists; bool has_col = mesh->vertex_color.exists; @@ -64,13 +31,15 @@ void io_fbx_parse_mesh(ufbx_mesh *mesh) { for (uint32_t v_ix = 0; v_ix < num_triangles * 3; v_ix++) { uint32_t a = indices[v_ix]; - posa32[pi++] = ufbx_get_vertex_vec3(&mesh->vertex_position, a).x; - posa32[pi++] = ufbx_get_vertex_vec3(&mesh->vertex_position, a).y; - posa32[pi++] = ufbx_get_vertex_vec3(&mesh->vertex_position, a).z; + ufbx_vec3 v = ufbx_transform_position(to_world, ufbx_get_vertex_vec3(&mesh->vertex_position, a)); + posa32[pi++] = v.x; + posa32[pi++] = v.y; + posa32[pi++] = v.z; - nora32[ni++] = ufbx_get_vertex_vec3(&mesh->vertex_normal, a).x; - nora32[ni++] = ufbx_get_vertex_vec3(&mesh->vertex_normal, a).y; - nora32[ni++] = ufbx_get_vertex_vec3(&mesh->vertex_normal, a).z; + v = ufbx_transform_direction(to_world_unscaled, ufbx_get_vertex_vec3(&mesh->vertex_normal, a)); + nora32[ni++] = v.x; + nora32[ni++] = v.y; + nora32[ni++] = v.z; if (has_tex) { texa32[ti++] = ufbx_get_vertex_vec2(&mesh->vertex_uv, a).x; @@ -87,11 +56,10 @@ void io_fbx_parse_mesh(ufbx_mesh *mesh) { free(indices); - vertex_count = pi / 3; - index_count = vertex_count; + int vertex_count = pi / 3; + int index_count = vertex_count; - indaOff = allocate(sizeof(uint32_t) * index_count); - uint32_t *inda = (uint32_t *)&buffer[indaOff]; + uint32_t *inda = malloc(sizeof(uint32_t) * index_count); for (int i = 0; i < index_count; ++i) { inda[i] = i; } @@ -113,16 +81,14 @@ void io_fbx_parse_mesh(ufbx_mesh *mesh) { float inv = 1 / scale_pos; // Pack into 16bit - posaOff = allocate(sizeof(short) * vertex_count * 4); - short *posa = (short *)&buffer[posaOff]; + 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 + 1] = posa32[i * 3 + 1] * 32767 * inv; posa[i * 4 + 2] = posa32[i * 3 + 2] * 32767 * inv; } - noraOff = allocate(sizeof(short) * vertex_count * 2); - short *nora = (short *)&buffer[noraOff]; + 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; @@ -134,20 +100,19 @@ void io_fbx_parse_mesh(ufbx_mesh *mesh) { free(posa32); + short *texa = NULL; if (texa32 != NULL) { - texaOff = allocate(sizeof(short) * vertex_count * 2); - short *texa = (short *)&buffer[texaOff]; + 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 + 1] = (1.0 - texa32[i * 2 + 1]) * 32767; } free(texa32); } - else texaOff = 0; + short *cola = NULL; if (cola32 != NULL) { - colaOff = allocate(sizeof(short) * vertex_count * 3); - short *cola = (short *)&buffer[colaOff]; + short *cola = malloc(sizeof(short) * vertex_count * 3); for (int i = 0; i < vertex_count; ++i) { cola[i * 3 ] = cola32[i * 3 ] * 32767; cola[i * 3 + 1] = cola32[i * 3 + 1] * 32767; @@ -155,46 +120,38 @@ void io_fbx_parse_mesh(ufbx_mesh *mesh) { } free(cola32); } - else colaOff = 0; + + 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->buffer = nora; + raw->nora->length = raw->nora->capacity = vertex_count * 2; + + raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->texa->buffer = texa; + raw->texa->length = raw->texa->capacity = vertex_count * 2; + + raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); + raw->inda->buffer = inda; + raw->inda->length = raw->inda->capacity = index_count; + + raw->scale_pos = scale_pos; + raw->scale_tex = 1.0; } -void io_fbx_parse() { - void *buf = &buffer[bufOff]; +void *io_fbx_parse(char *buf, size_t size) { ufbx_load_opts opts = { .generate_missing_normals = true }; ufbx_scene *scene = ufbx_load_memory(buf, size, &opts, NULL); + raw_mesh_t *raw = (raw_mesh_t *)calloc(sizeof(raw_mesh_t), 1); - for (size_t i = current_node; i < scene->nodes.count; ++i) { - current_node = i; - ufbx_node *n = scene->nodes.data[i]; + for (; current_node < scene->nodes.count; ++current_node) { + ufbx_node *n = scene->nodes.data[current_node]; if (n->mesh != NULL) { - strcpy(name, n->name.data); - // transform[0] = n->local_transform.translation.x; - // transform[1] = n->local_transform.translation.y; - // transform[2] = n->local_transform.translation.z; - // transform[3] = n->local_transform.scale.x; - // transform[4] = n->local_transform.scale.y; - // transform[5] = n->local_transform.scale.z; - // transform[6] = n->local_transform.rotation.x; - // transform[7] = n->local_transform.rotation.y; - // transform[8] = n->local_transform.rotation.z; - // transform[9] = n->local_transform.rotation.w; - transform[0] = n->unscaled_node_to_world.m00; - transform[1] = n->unscaled_node_to_world.m01; - transform[2] = n->unscaled_node_to_world.m02; - transform[3] = n->unscaled_node_to_world.m03; - transform[4] = n->unscaled_node_to_world.m10; - transform[5] = n->unscaled_node_to_world.m11; - transform[6] = n->unscaled_node_to_world.m12; - transform[7] = n->unscaled_node_to_world.m13; - transform[8] = n->unscaled_node_to_world.m20; - transform[9] = n->unscaled_node_to_world.m21; - transform[10] = n->unscaled_node_to_world.m22; - transform[11] = n->unscaled_node_to_world.m23; - transform[12] = 0.0; - transform[13] = 0.0; - transform[14] = 0.0; - transform[15] = 1.0; - io_fbx_parse_mesh(n->mesh); + raw->name = malloc(strlen(n->name.data) + 1); + strcpy(raw->name, n->name.data); + io_fbx_parse_mesh(raw, n->mesh, &n->node_to_world, &n->unscaled_node_to_world); break; } } @@ -208,21 +165,12 @@ void io_fbx_parse() { break; } } -} -void io_fbx_destroy() { - free(buffer); - buffer = NULL; -} + if (!has_next) { + current_node = 0; + } -int io_fbx_get_index_count() { return index_count; } -int io_fbx_get_vertex_count() { return vertex_count; } -float io_fbx_get_scale_pos() { return scale_pos; } -int io_fbx_get_indices() { return indaOff; } -int io_fbx_get_positions() { return posaOff; } -int io_fbx_get_normals() { return noraOff; } -int io_fbx_get_uvs() { return texaOff; } -int io_fbx_get_colors() { return colaOff; } -char *io_fbx_get_name() { return &name[0]; } -float *io_fbx_get_transform() { return &transform[0]; } -int io_fbx_has_next() { return has_next; } + raw->has_next = has_next; + + return raw; +} diff --git a/armorpaint/plugins/sources/io_gltf/cgltf.c b/armorpaint/plugins/sources/io_gltf/cgltf.c index b74b4897..bab283cc 100644 --- a/armorpaint/plugins/sources/io_gltf/cgltf.c +++ b/armorpaint/plugins/sources/io_gltf/cgltf.c @@ -1,88 +1,49 @@ -// cgltf bridge for armorpaint #define CGLTF_IMPLEMENTATION #include "cgltf.h" #include +#include "iron_array.h" +#include "io_obj.h" -static uint8_t *buffer = NULL; -static uint32_t bufferLength = 0; -static int bufOff; /* Pointer to glb or gltf file data */ -static size_t size; /* Size of the file data */ - -static cgltf_data *data = NULL; - -static int index_count; -static int vertex_count; -static int indaOff = 0; -static int posaOff = 0; -static int noraOff = 0; -static int texaOff = 0; -static float scale_pos; - -uint8_t *io_gltf_getBuffer() { return buffer; } -uint32_t io_gltf_getBufferLength() { return bufferLength; } - -static int allocate(int size) { - size += size % 4; // Byte align - bufferLength += size; - buffer = buffer == NULL ? (uint8_t *)malloc(bufferLength) : (uint8_t *)realloc(buffer, bufferLength); - return bufferLength - size; -} - -int io_gltf_read_u8_array(cgltf_accessor *a) { +uint32_t *io_gltf_read_u8_array(cgltf_accessor *a) { cgltf_buffer_view *v = a->buffer_view; unsigned char *ar = (unsigned char *)v->buffer->data + v->offset; - int resOff = allocate(sizeof(unsigned int) * v->size); - unsigned int *res = (unsigned int *)&buffer[resOff]; + uint32_t *res = malloc(sizeof(unsigned int) * v->size); for (int i = 0; i < v->size; ++i) { res[i] = ar[i]; } - return resOff; -} - -int io_gltf_read_u16_array(cgltf_accessor *a) { - cgltf_buffer_view *v = a->buffer_view; - unsigned short *ar = (unsigned short *)v->buffer->data + v->offset / 2; - int resOff = allocate(sizeof(unsigned int) * v->size / 2); - unsigned int *res = (unsigned int *)&buffer[resOff]; - for (int i = 0; i < v->size / 2; ++i) { - res[i] = ar[i]; - } - return resOff; -} - -int io_gltf_read_u32_array(cgltf_accessor *a) { - cgltf_buffer_view *v = a->buffer_view; - unsigned int *ar = (unsigned int *)v->buffer->data + v->offset / 4; - int resOff = allocate(sizeof(unsigned int) * v->size / 4); - unsigned int *res = (unsigned int *)&buffer[resOff]; - for (int i = 0; i < v->size / 4; ++i) { - res[i] = ar[i]; - } - return resOff; -} - -float *io_gltf_read_f32_array_malloc(cgltf_accessor *a) { - cgltf_buffer_view *v = a->buffer_view; - float *ar = (float *)v->buffer->data + v->offset / 4; - float *res = (float *)malloc(sizeof(float) * v->size / 4); - for (int i = 0; i < v->size / 4; ++i) { - res[i] = ar[i]; - } return res; } -int io_gltf_init(int bufSize) { - size = bufSize; - bufOff = allocate(sizeof(char) * bufSize); - return bufOff; +uint32_t *io_gltf_read_u16_array(cgltf_accessor *a) { + cgltf_buffer_view *v = a->buffer_view; + unsigned short *ar = (unsigned short *)v->buffer->data + v->offset / 2; + uint32_t *res = malloc(sizeof(unsigned int) * v->size); + for (int i = 0; i < v->size / 2; ++i) { + res[i] = ar[i]; + } + return res; } -void io_gltf_parse() { +uint32_t *io_gltf_read_u32_array(cgltf_accessor *a) { + cgltf_buffer_view *v = a->buffer_view; + unsigned int *ar = (unsigned int *)v->buffer->data + v->offset / 4; + 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 / 4; + return ar; +} + +void *io_gltf_parse(char *buf, size_t size) { cgltf_options options = {0}; - char *buf = (char *)&buffer[bufOff]; + cgltf_data *data = NULL; cgltf_result result = cgltf_parse(&options, buf, size, &data); - if (result != cgltf_result_success) { return; } + if (result != cgltf_result_success) { + return NULL; + } cgltf_load_buffers(&options, data, NULL); cgltf_mesh *mesh = &data->meshes[0]; @@ -90,10 +51,10 @@ void io_gltf_parse() { cgltf_accessor *a = prim->indices; int elem_size = a->buffer_view->size / a->count; - index_count = a->count; - indaOff = elem_size == 1 ? io_gltf_read_u8_array(a) : - elem_size == 2 ? io_gltf_read_u16_array(a) : - io_gltf_read_u32_array(a); + int index_count = a->count; + uint32_t *inda = elem_size == 1 ? io_gltf_read_u8_array(a) : + elem_size == 2 ? io_gltf_read_u16_array(a) : + io_gltf_read_u32_array(a); float *posa32 = NULL; float *nora32 = NULL; @@ -101,17 +62,17 @@ void io_gltf_parse() { for (int i = 0; i < prim->attributes_count; ++i) { cgltf_attribute* attrib = &prim->attributes[i]; if (attrib->type == cgltf_attribute_type_position) { - posa32 = io_gltf_read_f32_array_malloc(attrib->data); + posa32 = io_gltf_read_f32_array(attrib->data); } else if (attrib->type == cgltf_attribute_type_normal) { - nora32 = io_gltf_read_f32_array_malloc(attrib->data); + nora32 = io_gltf_read_f32_array(attrib->data); } else if (attrib->type == cgltf_attribute_type_texcoord) { - texa32 = io_gltf_read_f32_array_malloc(attrib->data); + texa32 = io_gltf_read_f32_array(attrib->data); } } - vertex_count = prim->attributes[0].data->count; // Assume VEC3 position + int vertex_count = prim->attributes[0].data->count; // Assume VEC3 position // Pack positions to (-1, 1) range float hx = 0.0; @@ -125,31 +86,27 @@ void io_gltf_parse() { f = fabsf(posa32[i * 3 + 2]); if (hz < f) hz = f; } - scale_pos = fmax(hx, fmax(hy, hz)); + float scale_pos = fmax(hx, fmax(hy, hz)); float inv = 1 / scale_pos; // Pack into 16bit - posaOff = allocate(sizeof(short) * vertex_count * 4); - short *posa = (short *)&buffer[posaOff]; + 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 + 1] = posa32[i * 3 + 1] * 32767 * inv; posa[i * 4 + 2] = posa32[i * 3 + 2] * 32767 * inv; } - noraOff = allocate(sizeof(short) * vertex_count * 2); - short *nora = (short *)&buffer[noraOff]; + 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 + 1] = nora32[i * 3 + 1] * 32767; posa[i * 4 + 3] = nora32[i * 3 + 2] * 32767; } - free(nora32); } else { // Calc normals - int *inda = (int *)&buffer[indaOff]; for (int i = 0; i < index_count / 3; ++i) { int i1 = inda[i * 3 ]; int i2 = inda[i * 3 + 1]; @@ -182,29 +139,41 @@ void io_gltf_parse() { } } - free(posa32); - + short *texa = NULL; if (texa32 != NULL) { - texaOff = allocate(sizeof(short) * vertex_count * 2); - short *texa = (short *)&buffer[texaOff]; + 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 + 1] = texa32[i * 2 + 1] * 32767; } - free(texa32); } -} -void io_gltf_destroy() { cgltf_free(data); - free(buffer); - buffer = NULL; -} -int io_gltf_get_index_count() { return index_count; } -int io_gltf_get_vertex_count() { return vertex_count; } -float io_gltf_get_scale_pos() { return scale_pos; } -int io_gltf_get_indices() { return indaOff; } -int io_gltf_get_positions() { return posaOff; } -int io_gltf_get_normals() { return noraOff; } -int io_gltf_get_uvs() { return texaOff; } + raw_mesh_t *raw = (raw_mesh_t *)calloc(sizeof(raw_mesh_t), 1); + + // raw->name = (char *)malloc(strlen(mesh->name) + 1); + // strcpy(raw->name, mesh->name); + raw->name = ""; + + 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->buffer = nora; + raw->nora->length = raw->nora->capacity = vertex_count * 2; + + raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->texa->buffer = texa; + raw->texa->length = raw->texa->capacity = vertex_count * 2; + + raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); + raw->inda->buffer = inda; + raw->inda->length = raw->inda->capacity = index_count; + + raw->scale_pos = scale_pos; + raw->scale_tex = 1.0; + + return raw; +} diff --git a/armorpaint/plugins/sources/io_svg/nanosvg.c b/armorpaint/plugins/sources/io_svg/nanosvg.c index 5d43df80..0ed48f5c 100644 --- a/armorpaint/plugins/sources/io_svg/nanosvg.c +++ b/armorpaint/plugins/sources/io_svg/nanosvg.c @@ -1,56 +1,28 @@ -// nanosvg bridge for armorpaint #include #include #include #include -// #define NANOSVG_ALL_COLOR_KEYWORDS #define NANOSVG_IMPLEMENTATION #include "nanosvg.h" #define NANOSVGRAST_IMPLEMENTATION #include "nanosvgrast.h" -static uint8_t *buffer = NULL; -static uint32_t bufferLength = 0; -static int bufOff; /* Pointer to null terminated svg string input */ -static int pixelsOff; /* Rasterized pixel output */ -static int w; -static int h; +#include "iron_array.h" +void *image_from_bytes(void *buffer, int width, int height, int format); -uint8_t *io_svg_getBuffer() { return buffer; } -uint32_t io_svg_getBufferLength() { return bufferLength; } - -static int allocate(int size) { - size += size % 4; // Byte align - bufferLength += size; - buffer = buffer == NULL ? (uint8_t *)malloc(bufferLength) : (uint8_t *)realloc(buffer, bufferLength); - return bufferLength - size; -} - -int io_svg_init(int buf_size) { - bufOff = allocate(sizeof(char) * buf_size); - return bufOff; -} - -void io_svg_parse() { - char *buf = (char *)&buffer[bufOff]; +void *io_svg_parse(char *buf) { NSVGimage *image = nsvgParse(buf, "px", 96.0f); - w = (int)image->width; - h = (int)image->height; - pixelsOff = allocate(sizeof(unsigned char) * w * h * 4); - unsigned char *pixels = &buffer[pixelsOff]; - struct NSVGrasterizer *rast; - rast = nsvgCreateRasterizer(); + int w = (int)image->width; + int h = (int)image->height; + unsigned char *pixels = malloc(w * h * 4); + struct NSVGrasterizer *rast = nsvgCreateRasterizer(); nsvgRasterize(rast, image, 0, 0, 1, pixels, w, h, w * 4); nsvgDelete(image); nsvgDeleteRasterizer(rast); -} -int io_svg_get_pixels() { return pixelsOff; } -int io_svg_get_pixels_w() { return w; } -int io_svg_get_pixels_h() { return h; } - -void io_svg_destroy() { - free(buffer); - buffer = NULL; + buffer_t *b = malloc(sizeof(buffer_t)); + b->buffer = pixels; + b->length = b->capacity = w * h * 4; + return image_from_bytes(b, w, h, 0); } diff --git a/armorpaint/plugins/sources/io_usd/io_usd.cc b/armorpaint/plugins/sources/io_usd/io_usd.cc index bb0f06ce..b4a10c99 100644 --- a/armorpaint/plugins/sources/io_usd/io_usd.cc +++ b/armorpaint/plugins/sources/io_usd/io_usd.cc @@ -1,41 +1,13 @@ #include -#include "tinyusdz/tinyusdz.hh" #include +#include "tinyusdz/tinyusdz.hh" +#include "io_obj.h" +#include "iron_array.h" -static uint8_t *buffer = NULL; -static uint32_t bufferLength = 0; -static int bufOff; /* Pointer to usdc file data */ -static size_t size; /* Size of the file data */ - -static int index_count; -static int vertex_count; -static int indaOff; -static int posaOff; -static int noraOff; -static int texaOff; -static float scale_pos; - -extern "C" uint8_t *io_usd_getBuffer() { return buffer; } -extern "C" uint32_t io_usd_getBufferLength() { return bufferLength; } - -static int allocate(int size) { - size += size % 4; // Byte align - bufferLength += size; - buffer = buffer == NULL ? (uint8_t *)malloc(bufferLength) : (uint8_t *)realloc(buffer, bufferLength); - return bufferLength - size; -} - -extern "C" int io_usd_init(int bufSize) { - size = bufSize; - bufOff = allocate(sizeof(uint8_t) * bufSize); - return bufOff; -} - -extern "C" void io_usd_parse() { +extern "C" void *io_usd_parse(uint8_t *buf, size_t size) { tinyusdz::Scene scene; std::string warn; std::string err; - uint8_t *buf = &buffer[bufOff]; tinyusdz::LoadUSDCFromMemory(buf, size, &scene, &warn, &err); tinyusdz::GeomMesh mesh = scene.geom_meshes[0]; @@ -111,8 +83,8 @@ extern "C" void io_usd_parse() { face_offset += f_count; } - vertex_count = dst_facevarying_indices.size(); - index_count = dst_facevarying_indices.size(); + int vertex_count = dst_facevarying_indices.size(); + int index_count = dst_facevarying_indices.size(); // Pack positions to (-1, 1) range float hx = 0.0; @@ -126,21 +98,17 @@ extern "C" void io_usd_parse() { f = fabsf(vertices[i * 3 + 2]); if (hz < f) hz = f; } - scale_pos = fmax(hx, fmax(hy, hz)); + float scale_pos = fmax(hx, fmax(hy, hz)); float inv = 1 / scale_pos; // Pack into 16bit - indaOff = allocate(sizeof(unsigned int) * index_count); - unsigned int *inda = (unsigned int *)&buffer[indaOff]; + uint32_t *inda = (uint32_t *)malloc(sizeof(uint32_t) * index_count); for (int i = 0; i < index_count; ++i) { inda[i] = i; } - posaOff = allocate(sizeof(short) * vertex_count * 4); - noraOff = allocate(sizeof(short) * vertex_count * 2); - texaOff = allocate(sizeof(short) * vertex_count * 2); - short *posa = (short *)&buffer[posaOff]; - short *nora = (short *)&buffer[noraOff]; - short *texa = (short *)&buffer[texaOff]; + int16_t *posa = (int16_t *)malloc(sizeof(int16_t) * vertex_count * 4); + int16_t *nora = (int16_t *)malloc(sizeof(int16_t) * vertex_count * 2); + int16_t *texa = (int16_t *)malloc(sizeof(int16_t) * vertex_count * 2); for (int i = 0; i < vertex_count; ++i) { posa[i * 4 ] = vertices[dst_facevarying_indices[i] * 3 ] * 32767 * inv; @@ -152,17 +120,30 @@ extern "C" void io_usd_parse() { texa[i * 2 ] = dst_facevarying_texcoords[i * 2 ] * 32767; texa[i * 2 + 1] = (1.0 - dst_facevarying_texcoords[i * 2 + 1]) * 32767; } -} -extern "C" void io_usd_destroy() { - free(buffer); - buffer = NULL; -} + raw_mesh_t *raw = (raw_mesh_t *)calloc(sizeof(raw_mesh_t), 1); -extern "C" int io_usd_get_index_count() { return index_count; } -extern "C" int io_usd_get_vertex_count() { return vertex_count; } -extern "C" float io_usd_get_scale_pos() { return scale_pos; } -extern "C" int io_usd_get_indices() { return indaOff; } -extern "C" int io_usd_get_positions() { return posaOff; } -extern "C" int io_usd_get_normals() { return noraOff; } -extern "C" int io_usd_get_uvs() { return texaOff; } + raw->name = (char *)malloc(mesh.name.length() + 1); + strcpy(raw->name, mesh.name.c_str()); + + 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->buffer = nora; + raw->nora->length = raw->nora->capacity = vertex_count * 2; + + raw->texa = (i16_array_t *)malloc(sizeof(i16_array_t)); + raw->texa->buffer = texa; + raw->texa->length = raw->texa->capacity = vertex_count * 2; + + raw->inda = (u32_array_t *)malloc(sizeof(u32_array_t)); + raw->inda->buffer = inda; + raw->inda->length = raw->inda->capacity = vertex_count * 2; + + raw->scale_pos = scale_pos; + raw->scale_tex = 1.0; + + return raw; +} diff --git a/armorpaint/plugins/sources/plugins.c b/armorpaint/plugins/sources/plugins.c index 51b2f224..7d13cfd9 100644 --- a/armorpaint/plugins/sources/plugins.c +++ b/armorpaint/plugins/sources/plugins.c @@ -4,15 +4,47 @@ void proc_xatlas_unwrap(void *mesh); FN(proc_xatlas_unwrap) { int64_t mesh; - JS_ToInt64(ctx, &mesh, argv[0]); + JS_ToInt64(ctx, &mesh, argv[0]); proc_xatlas_unwrap((void *)mesh); return JS_UNDEFINED; } +void *io_svg_parse(char *buf); +FN(io_svg_parse) { + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[0]); + return JS_NewInt64(ctx, (int64_t)io_svg_parse(ab)); +} + +void *io_usd_parse(char *buf, size_t size); +FN(io_usd_parse) { + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[0]); + return JS_NewInt64(ctx, (int64_t)io_usd_parse(ab, len)); +} + +void *io_gltf_parse(char *buf, size_t size); +FN(io_gltf_parse) { + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[0]); + return JS_NewInt64(ctx, (int64_t)io_gltf_parse(ab, len)); +} + +void *io_fbx_parse(char *buf, size_t size); +FN(io_fbx_parse) { + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[0]); + return JS_NewInt64(ctx, (int64_t)io_fbx_parse(ab, len)); +} + void plugin_embed() { JSValue global_obj = JS_GetGlobalObject(js_ctx); BIND(proc_xatlas_unwrap, 1); + BIND(io_svg_parse, 1); + BIND(io_usd_parse, 1); + BIND(io_gltf_parse, 1); + BIND(io_fbx_parse, 1); JS_FreeValue(js_ctx, global_obj); } diff --git a/base/assets/plugins/autosave.js b/base/assets/plugins/autosave.js index 2f736367..ddc16528 100644 --- a/base/assets/plugins/autosave.js +++ b/base/assets/plugins/autosave.js @@ -2,22 +2,23 @@ let plugin = plugin_create(); let h1 = zui_handle_create(); -let h2 = zui_handle_create({value: 5}); +let h2 = zui_handle_create(); +zui_handle_set_value(h2, 5.0); let timer = 0.0; -plugin.draw_ui = function(ui) { +plugin_notify_on_ui(plugin, function() { if (zui_panel(h1, "Auto Save")) { zui_slider(h2, "min", 1, 15, false, 1); } -} +}); -plugin.update = function() { - if (project_filepath == "") { +plugin_notify_on_update(plugin, function() { + if (project_filepath_get() == "") { return; } timer += 1 / 60; - if (timer >= h2.value * 60) { + if (timer >= zui_handle_get_value(h2) * 60) { timer = 0.0; project_save(); } -} +}); diff --git a/base/assets/plugins/import_tiff.js b/base/assets/plugins/import_tiff.js index be82f091..70caf50b 100644 --- a/base/assets/plugins/import_tiff.js +++ b/base/assets/plugins/import_tiff.js @@ -3,8 +3,7 @@ // https://github.com/photopea/UTIF.js var UTIF={},pako=null;function log(){console.log(arguments)}!function(x,A){function r(r,e){this.message=r,this.g=e}function e(r){this.message="JPEG error: "+r}function t(){this.M=null,this.B=-1}function U(r,e){for(var t,i,n=0,a=[],o=16;0>--I&1;if(255===(A=t[i++])){var r=t[i++];if(r){if(220===r&&E){i+=2;var e=t[i++]<<8|t[i++];if(0>>(I=7)}function u(r){for(;;){if("number"==typeof(r=r[d()]))return r;if("object"!==(void 0===r?"undefined":L(r)))throw new C("invalid huffman sequence")}}function l(r){for(var e=0;0>=4,0==n){if(i<15){B=l(i)+(1<>=4,0===t)M=n<15?(B=l(n)+(1<>=4,0==n){if(i<15)break;t+=16}else t+=i,r.a[e+J[t]]=c(n),t++}},F=0,G=1===k?r[0].c*r[0].l:y*n.O;F>10,s[u]=l,s[u+1]=l,s[u+2]=l,s[u+3]=l,s[u+4]=l,s[u+5]=l,s[u+6]=l,s[u+7]=l;else{c*=h[u+1],v*=h[u+2],g*=h[u+3],_*=h[u+4],w*=h[u+5];var m=5793*l+128>>8,E=5793*_+128>>8,y=v,U=b*=h[u+6];E=(m=m+E+1>>1)-E,l=3784*y+1567*U+128>>8,y=1567*y-3784*U+128>>8,w=(_=(_=2896*(c-(p*=h[u+7]))+128>>8)+(w<<=4)+1>>1)-w,g=(p=(p=2896*(c+p)+128>>8)+(g<<=4)+1>>1)-g,U=(m=m+(U=l)+1>>1)-U,y=(E=E+y+1>>1)-y,l=2276*_+3406*p+2048>>12,_=3406*_-2276*p+2048>>12,p=l,l=799*g+4017*w+2048>>12,g=4017*g-799*w+2048>>12,w=l,s[u]=m+p,s[u+7]=m-p,s[u+1]=E+w,s[u+6]=E-w,s[u+2]=y+g,s[u+5]=y-g,s[u+3]=U+_,s[u+4]=U-_}}for(h=0;h<8;++h)l=s[h],0==((c=s[h+8])|(v=s[h+16])|(g=s[h+24])|(_=s[h+32])|(w=s[h+40])|(b=s[h+48])|(p=s[h+56]))?(l=(l=5793*l+8192>>14)<-2040?0:2024<=l?255:l+2056>>4,d[f+h]=l,d[f+h+8]=l,d[f+h+16]=l,d[f+h+24]=l,d[f+h+32]=l,d[f+h+40]=l,d[f+h+48]=l,d[f+h+56]=l):(m=5793*l+2048>>12,E=5793*_+2048>>12,l=3784*(y=v)+1567*(U=b)+2048>>12,y=1567*y-3784*U+2048>>12,U=l,w=(_=(_=2896*(c-p)+2048>>12)+w+1>>1)-w,g=(p=(p=2896*(c+p)+2048>>12)+g+1>>1)-g,l=2276*_+3406*p+2048>>12,_=3406*_-2276*p+2048>>12,p=l,l=799*g+4017*w+2048>>12,g=4017*g-799*w+2048>>12,c=(E=(E=(m=4112+(m+E+1>>1))-E)+y+1>>1)+(w=l),b=E-w,w=(y=E-y)-g,l=(l=(m=m+U+1>>1)+p)<16?0:4080<=l?255:l>>4,c=c<16?0:4080<=c?255:c>>4,v=(v=y+g)<16?0:4080<=v?255:v>>4,g=(g=(U=m-U)+_)<16?0:4080<=g?255:g>>4,_=(_=U-_)<16?0:4080<=_?255:_>>4,w=w<16?0:4080<=w?255:w>>4,b=b<16?0:4080<=b?255:b>>4,p=(p=m-p)<16?0:4080<=p?255:p>>4,d[f+h]=l,d[f+h+8]=c,d[f+h+16]=v,d[f+h+24]=g,d[f+h+32]=_,d[f+h+40]=w,d[f+h+48]=b,d[f+h+56]=p)}return e.a}function P(r,e,t){var i=2=n)return null;o=r[i]<<8|r[i+1]}return{f:a.toString(16),F:o,offset:i}}var J,L,C,O,m;function E(r,e,t,i,n){for(var a=0;a>4)for(c=0;c<64;c++)_[v=J[c]]=e[a++];else{if(1!=g>>4)throw new C("DQT - invalid table spec");for(c=0;c<64;c++)_[v=J[c]]=r()}i[15&g]=_}break;case 65472:case 65473:case 65474:if(w)throw new C("Only single frame JPEGs supported");r();var w={};for(w.X=65473===l,w.S=65474===l,w.precision=e[a++],l=r(),w.g=n||l,w.v=r(),w.b=[],w.C={},c=e[a++],l=_=g=0;l>4,p=15&e[a+1];g>4?u:d)[15&g]=U(_,p)}break;case 65501:r();var m=r();break;case 65498:for(c=1==++f&&!n,r(),g=e[a++],v=[],l=0;l>4],E.o=d[15&_],v.push(E)}l=e[a++],g=e[a++],_=e[a++];try{var y=I(e,a,w,v,m,l,g,_>>4,15&_,c);a+=y}catch(r){if(r instanceof O)return(0,_util.warn)('Attempting to re-parse JPEG image using "scanLines" parameter found in DNL marker (0xFFDC) segment.'),this.parse(e,{N:r.g});throw r}break;case 65500:a+=4;break;case 65535:255!==e[a]&&a--;break;default:if(255===e[a-3]&&192<=e[a-2]&&e[a-2]<=254)a-=3;else{if(!(c=P(e,a-2))||!c.f)throw new C("unknown marker "+l.toString(16));(0,_util.warn)("JpegImage.parse - unexpected data, current marker is: "+c.f),a=c.offset}}l=r()}for(this.width=w.v,this.height=w.g,this.A=o,this.b=[],l=0;l>8)+a[n+1];return s},w:function(){return this.A?!!this.A.W:3===this.i?0!==this.B:1===this.B},I:function(r){for(var e,t,i,n=0,a=r.length;n>>3)]),null==d&&(d=e.t325);var u=new Uint8Array(e.height*(s>>>3)),l=0;if(null!=e.t322){for(var c=e.t322[0],v=e.t323[0],g=Math.floor((e.width+c-1)/c),_=Math.floor((e.height+v-1)/v),w=new Uint8Array(0|Math.ceil(c*v*a/8)),b=0;b<_;b++)for(var p=0;p>>3,_=r.t278?r.t278[0]:r.height,w=Math.ceil(c*v*r.width/8);if(16==c&&!r.isLE&&null==r.t33422)for(var b=0;b<_;b++)for(var p=f+b*w,m=1;m>>8&255}else if(3==v)for(h=3;h>>11,c=15&d>>>22,v=15&d>>>26,g=0;g<4&&128<>3))>>>(7&_)&127)<>>4,n[a+E+1]=y<<4|A>>>4,n[a+E+2]=A<<4|U>>>4}else{f+=8;var I,B,M,k=[t,0,0,0],D=new Uint16Array(32770),F=[3857,3856,3599,3342,3085,2828,2571,2314,2057,1800,1543,1286,1029,772,771,768,514,513],G=0,N=x.decode._ljpeg_diff;for(D[0]=15,I=E=0;E<18;E++)for(var S=32768>>>(F[E]>>>8),P=0;P>>4),0)<<1)<>>1)&1<>>3;r[i]|=t>>>16,r[1+i]|=t>>>8,r[2+i]|=t},x.decode._getbithuff=function(r,e,t,i){x.decode._get_byte;var n,a=e[0],o=e[1],f=e[2],s=e[3];if(0==t||f<0)return 0;for(;!s&&f>>32-t,i?(f-=i[n+1]>>>8,n=255&i[n+1]):f-=t,f<0)throw"e";return e[0]=a,e[1]=o,e[2]=f,e[3]=s,n},x.decode._make_decoder=function(r){var e,t,i,n,a,o=[];for(e=16;0!=e&&!r[e];e--);var f=17;for(o[0]=e,i=t=1;t<=e;t++)for(n=0;n>>8;else for(d=0;d>>8,n[a+(d<<1)+1]=255&v[d];else{if(14!=c&&12!=c)throw new Error("unsupported bit depth "+c);var _=16-c;for(d=0;d offset to first strip or tile");if(null==n){var y=0,U=[];U[y++]=255,U[y++]=216;var A=r.t519;if(null==A)throw new Error("JPEGQTables tag is missing");for(o=0;o>>8,U[y++]=255&B,U[y++]=o|s<<4,f=0;f<16;f++)U[y++]=e[t+I[o]+f];for(f=0;f>>8&255,U[y++]=255&r.height,U[y++]=r.width>>>8&255,U[y++]=255&r.width,1==(U[y++]=m))U[y++]=1,U[y++]=17,U[y++]=0;else for(o=0;o<3;o++)U[y++]=o+1,U[y++]=0!=o?17:(15&b)<<4|15&p,U[y++]=o;null!=E&&0!=E[0]&&(U[y++]=255,U[y++]=221,U[y++]=0,U[y++]=4,U[y++]=E[0]>>>8&255,U[y++]=255&E[0]),n=new Uint8Array(U)}var M=-1;for(o=0;o>>8&255,n[D++]=255&r.height,n[D++]=r.width>>>8&255,n[D++]=255&r.width,1==(n[D++]=m))n[D++]=1,n[D++]=17,n[D++]=0;else for(o=0;o<3;o++)n[D++]=o+1,n[D++]=0!=o?17:(15&b)<<4|15&p,n[D++]=o}if(255==e[d]&&218==e[d+1]){var F=e[d+2]<<8|e[d+3];for((a=new Uint8Array(2+F))[0]=e[d],a[1]=e[d+1],a[2]=e[d+2],a[3]=e[d+3],o=0;o>>8&255,s[d.sofPosition+6]=255&r.height,s[d.sofPosition+7]=r.width>>>8&255,s[d.sofPosition+8]=255&r.width,255==e[t]&&e[t+1]==SOS||(s.set(d.sosMarker,h),h+=sosMarker.length),c=0;c>>6,l=63&d;if(e++,3==u&&(h=15&l,i[s>>>1]|=h<<4*(1-s&1),s++),0==u)for(var c=0;c>>1]|=h<<4*(1-s&1),s++;if(2==u)for(c=0;c<2;c++){4!=(v=l>>>3*(1-c)&7)&&(h+=o[v],i[s>>>1]|=h<<4*(1-s&1),s++)}if(1==u)for(c=0;c<3;c++){var v;2!=(v=l>>>2*(2-c)&3)&&(h+=a[v],i[s>>>1]|=h<<4*(1-s&1),s++)}}},x.decode._dmap={1:0,"011":1,"000011":2,"0000011":3,"010":-1,"000010":-2,"0000010":-3},x.decode._lens=function(){function r(r,e,t,i){for(var n=0;n>>3>>3]>>>7-(7&s)&1),2==o&&(U=r[s>>>3]>>>(7&s)&1),s++,d+=U,"H"==m){if(null!=f._lens[b][d]){var A=f._lens[b][d];d="",h+=A,A<64&&(f._addNtimes(u,h,b),v+=h,b=1-b,(h=0)==--E&&(m=""))}}else"0001"==d&&(d="",f._addNtimes(u,w-v,b),v=w),"001"==d&&(d="",m="H",E=2),null!=f._dmap[d]&&(g=_+f._dmap[d],f._addNtimes(u,g-v,b),v=g,d="",b=1-b);u.length==a&&""==m&&(f._writeBits(u,i,8*n+p*y),p++,v=b=0,l=f._makeDiff(u),u=[])}},x.decode._findDiff=function(r,e,t){for(var i=0;i=e&&r[i+1]==t)return r[i]},x.decode._makeDiff=function(r){var e=[];1==r[0]&&e.push(0,1);for(var t=1;t>>3>>3]>>>7-(7&s)&1),2==o&&(A=r[s>>>3]>>>(7&s)&1),s++,d+=A,y){if(null!=f._lens[b][d]){var I=f._lens[b][d];d="",h+=I,I<64&&(f._addNtimes(u,h,b),b=1-b,h=0)}}else if("H"==m){if(null!=f._lens[b][d]){I=f._lens[b][d];d="",h+=I,I<64&&(f._addNtimes(u,h,b),v+=h,b=1-b,(h=0)==--E&&(m=""))}}else"0001"==d&&(d="",f._addNtimes(u,w-v,b),v=w),"001"==d&&(d="",m="H",E=2),null!=f._dmap[d]&&(g=_+f._dmap[d],f._addNtimes(u,g-v,b),v=g,d="",b=1-b);d.endsWith("000000000001")&&(0<=p&&f._writeBits(u,i,8*n+p*U),1==o&&(y=1==(r[s>>>3]>>>7-(7&s)&1)),2==o&&(y=1==(r[s>>>3]>>>(7&s)&1)),s++,null==f._decodeG3.allow2D&&(f._decodeG3.allow2D=y),f._decodeG3.allow2D||(y=!0,s--),d="",p++,v=b=0,l=f._makeDiff(u),u=[])}u.length==a&&f._writeBits(u,i,8*n+p*U)},x.decode._addNtimes=function(r,e,t){for(var i=0;i>>3]|=r[i]<<7-(t+i&7)},x.decode._decodeLZW=(m={},function(r,e,t,i){if(!m.c){for(var n=new Uint32Array(65535),a=new Uint16Array(65535),o=new Uint8Array(2e6),f=0;f<256;f++)n[o[f<<2]=f]=f<<2,a[f]=1;m.c=[n,a,o]}for(var s=m.c[0],h=m.c[1],d=(o=m.c[2],258),u=1032,l=9,c=e<<3,v=0,g=0;v=(r[c>>>3]<<16|r[c+8>>>3]<<8|r[c+16>>>3])>>24-(7&c)-l&(1<>>3]<<16|r[c+8>>>3]<<8|r[c+16>>>3])>>24-(7&c)-l&(1<>>----------------");for(var s=0;s>3)]>>7-(7&c)&1;o[v]=o[v+1]=o[v+2]=255*(1-g),o[v+3]=255}if(4==s)for(c=0;c>1)]>>4-4*(1&c)&15;o[v]=o[v+1]=o[v+2]=17*(15-g),o[v+3]=255}if(8==s)for(c=0;c>3)]>>7-(7&c)&1;o[v]=o[v+1]=o[v+2]=255*g,o[v+3]=255}if(2==s)for(c=0;c>2)]>>6-2*(3&c)&3;o[v]=o[v+1]=o[v+2]=85*g,o[v+3]=255}if(8==s)for(c=0;c>8,o[v+1]=b[256+p]>>8,o[v+2]=b[512+p]>>8,o[v+3]=255}}else if(5==f){var m=4<(_=r.t258?r.t258.length:4)?1:0;for(c=0;c>>1))+(1&M)];var k,D=a[k+2]-128,F=a[k+3]-128,G=U+((F>>2)+(F>>3)+(F>>5)),N=U-((D>>2)+(D>>4)+(D>>5))-((F>>1)+(F>>3)+(F>>4)+(F>>5)),S=U+(D+(D>>1)+(D>>2)+(D>>6));o[v]=Math.max(0,Math.min(255,G)),o[v+1]=Math.max(0,Math.min(255,N)),o[v+2]=Math.max(0,Math.min(255,S)),o[v+3]=255}}}else log("Unknown Photometric interpretation: "+f);return o},x._binBE={nextZero:function(r,e){for(;0!=r[e];)e++;return e},readUshort:function(r,e){return r[e]<<8|r[e+1]},readShort:function(r,e){var t=x._binBE.ui8;return t[0]=r[e+1],t[1]=r[e+0],x._binBE.i16[0]},readInt:function(r,e){var t=x._binBE.ui8;return t[0]=r[e+3],t[1]=r[e+2],t[2]=r[e+1],t[3]=r[e+0],x._binBE.i32[0]},readUint:function(r,e){var t=x._binBE.ui8;return t[0]=r[e+3],t[1]=r[e+2],t[2]=r[e+1],t[3]=r[e+0],x._binBE.ui32[0]},readASCII:function(r,e,t){for(var i="",n=0;n>8&255,r[e+1]=255&t},writeUint:function(r,e,t){r[e]=t>>24&255,r[e+1]=t>>16&255,r[e+2]=t>>8&255,r[e+3]=t>>0&255},writeASCII:function(r,e,t){for(var i=0;i>>8),this._=8),this.G>>>--this._&1},Z:function(r){var e=this._,t=this.G,i=Math.min(e,r);r-=i;for(var n=t>>>(e-=i)&(1<>>8),r-=i=Math.min(8,r),n<<=i,n|=t>>>(e=8-i)&(1<>>8),n=8),-1!=(i=r[(t=r[t+(a>>>--n&1)])+2]))return e._=n,e.G=a,e.N=o,i;return-1},n.prototype={$:function(r,e){this.Q=r.i(),this.F=r.l(),this.o=r.l();var t=this.O=r.i();this.L=[];for(var i=0;i>>4]}this.g=r.i(),r.t(r.N+e-(2+2*t))},D:function(r){var e=!1;if((t=r.l())===n.q)do{var t=r.l(),i=r.l()-2;switch(t){case n.m:this.$(r,i);break;case n.K:this.W(i);break;case n.V:this.p(r,i),e=!0;break;default:r.t(r.N+i)}}while(!e)},I:function(r,e){var t=o.B(e,r);if(16==t)return-32768;var i=r.Z(t);return 0==(i&1<>>1)),r[c]=v+a(t,s[h])}u+=e}}},n.m=65475,n.K=65476,n.q=65496,n.V=65498,function(r){var e=new n(r),t=new(8raw_mesh_t = map_get(path_mesh_importers, ext); - let mesh: raw_mesh_t = importer(path); + let importer: any = map_get(path_mesh_importers, ext); // JSValue -> (s: string)=>raw_mesh_t + let mesh: raw_mesh_t = js_pcall_str(importer, path); + if (mesh.name == "") { + mesh.name = path_base_name(path); + } + replace_existing ? import_mesh_make_mesh(mesh, path) : import_mesh_add_mesh(mesh); let has_next: bool = mesh.has_next; while (has_next) { - let mesh: raw_mesh_t = importer(path); + let mesh: raw_mesh_t = js_pcall_str(importer, path); + if (mesh.name == "") { + mesh.name = path_base_name(path); + } has_next = mesh.has_next; import_mesh_add_mesh(mesh); - - // let m: mat4_t = fromFloat32Array(mesh.transform); - // paintObjects[paintObjects.length - 1].transform.localOnly = true; - // paintObjects[paintObjects.length - 1].transform.setMatrix(m); } } diff --git a/base/sources/import_texture.ts b/base/sources/import_texture.ts index 26dd58f9..6e20ab0f 100644 --- a/base/sources/import_texture.ts +++ b/base/sources/import_texture.ts @@ -30,13 +30,16 @@ function import_texture_run(path: string, hdr_as_envmap: bool = true) { } let ext: string = substring(path, string_last_index_of(path, ".") + 1, path.length); - let importer: (s: string)=>image_t = map_get(path_texture_importers, ext); + let importer: any = map_get(path_texture_importers, ext); // JSValue -> (s: string)=>image_t let cached: bool = map_get(data_cached_images, path) != null; // Already loaded or pink texture for missing file + let image: image_t; if (importer == null || cached) { - importer = import_texture_default_importer; + image = import_texture_default_importer(path); + } + else { + image = js_pcall_str(importer, path); } - let image: image_t = importer(path); map_set(data_cached_images, path, image); let ar: string[] = string_split(path, path_sep); let name: string = ar[ar.length - 1]; diff --git a/base/sources/path.ts b/base/sources/path.ts index 998d4dbf..f5ff2164 100644 --- a/base/sources/path.ts +++ b/base/sources/path.ts @@ -14,8 +14,8 @@ let path_pwd: string = "echo $PWD"; let path_mesh_formats: string[] = ["obj", "blend"]; let path_texture_formats: string[] = ["jpg", "jpeg", "png", "tga", "bmp", "psd", "gif", "hdr", "k"]; -let path_mesh_importers: map_tany> = map_create(); -let path_texture_importers: map_timage_t> = map_create(); +let path_mesh_importers: map_t = map_create(); // JSValue -> (s: string)=>raw_mesh_t +let path_texture_importers: map_t = map_create(); // JSValue -> (s: string)=>image_t let path_base_color_ext: string[] = ["albedo", "alb", "basecol", "basecolor", "diffuse", "diff", "base", "bc", "d", "color", "col"]; let path_opacity_ext: string[] = ["opac", "opacity", "alpha"]; @@ -71,6 +71,10 @@ function path_base_dir(path: string): string { return substring(path, 0, string_last_index_of(path, path_sep) + 1); } +function path_base_name(path: string): string { + return substring(path, string_last_index_of(path, path_sep) + 1, string_last_index_of(path, ".")); +} + function path_working_dir(): string { if (path_working_dir_cache == null) { let cmd: string = path_pwd; diff --git a/base/sources/plugin.ts b/base/sources/plugin.ts index ebcfaa2a..d1faff40 100644 --- a/base/sources/plugin.ts +++ b/base/sources/plugin.ts @@ -37,6 +37,10 @@ function plugin_notify_on_ui(plugin: plugin_t, f: any): void { plugin.on_ui = f; } +function plugin_notify_on_update(plugin: plugin_t, f: any): void { + plugin.on_update = f; +} + function plugin_notify_on_delete(plugin: plugin_t, f: any): void { plugin.on_delete = f; } diff --git a/base/sources/plugin_api.c b/base/sources/plugin_api.c index a6a5c1ed..4770b009 100644 --- a/base/sources/plugin_api.c +++ b/base/sources/plugin_api.c @@ -5,6 +5,7 @@ #include "iron_array.h" #include "iron_map.h" #include "iron_armpack.h" +#include "io_obj.h" void plugin_embed(); @@ -369,300 +370,457 @@ VOID_FN_STR(console_log) VOID_FN_STR(console_info) PTR_FN(plugin_create) VOID_FN_PTR_CB(plugin_notify_on_ui) +VOID_FN_PTR_CB(plugin_notify_on_update) VOID_FN_PTR_CB(plugin_notify_on_delete) static JSObject *ui_files_cb; static void ui_files_done(char *path) { - JSValue path_val = JS_NewString(js_ctx, path); - JSValue argv[] = { path_val }; - js_call_arg(ui_files_cb, 1, argv); + JSValue path_val = JS_NewString(js_ctx, path); + JSValue argv[] = { path_val }; + js_call_arg(ui_files_cb, 1, argv); } void ui_files_show(char *s, bool b0, bool b1, void(*f)(char *)); FN(ui_files_show) { - char *filters = (char *)JS_ToCString(ctx, argv[0]); - bool is_save = JS_ToBool(ctx, argv[1]); - bool open_multiple = JS_ToBool(ctx, argv[2]); - ui_files_cb = malloc(sizeof(JSValue)); - JSValue dup = JS_DupValue(ctx, argv[3]); - memcpy(ui_files_cb, &dup, sizeof(JSValue)); - ui_files_show(filters, is_save, open_multiple, ui_files_done); - return JS_UNDEFINED; + char *filters = (char *)JS_ToCString(ctx, argv[0]); + bool is_save = JS_ToBool(ctx, argv[1]); + bool open_multiple = JS_ToBool(ctx, argv[2]); + ui_files_cb = malloc(sizeof(JSValue)); + JSValue dup = JS_DupValue(ctx, argv[3]); + memcpy(ui_files_cb, &dup, sizeof(JSValue)); + ui_files_show(filters, is_save, open_multiple, ui_files_done); + return JS_UNDEFINED; +} + +void ui_box_show_message(char *s0, char *s1, bool b); +extern bool ui_box_click_to_hide; +FN(ui_box_show_message) { + char *title = (char *)JS_ToCString(ctx, argv[0]); + char *message = (char *)JS_ToCString(ctx, argv[1]); + ui_box_show_message(title, message, true); + ui_box_click_to_hide = false; + return JS_UNDEFINED; } void *data_get_blob(char *s); FN(data_get_blob) { - char *s = (char *)JS_ToCString(ctx, argv[0]); - buffer_t *b = data_get_blob(s); - JSValue val = JS_NewArrayBuffer(ctx, b->buffer, b->length, NULL, NULL, 0); - return val; + char *s = (char *)JS_ToCString(ctx, argv[0]); + buffer_t *b = data_get_blob(s); + JSValue val = JS_NewArrayBuffer(ctx, b->buffer, b->length, NULL, NULL, 0); + return val; +} + +void *data_delete_blob(char *s); +FN(data_delete_blob) { + char *s = (char *)JS_ToCString(ctx, argv[0]); + data_delete_blob(s); + return JS_UNDEFINED; } void *krom_file_save_bytes(char *s, buffer_t *b, int l); FN(krom_file_save_bytes) { - char *to = (char *)JS_ToCString(ctx, argv[0]); - size_t len; - void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]); - buffer_t b = { .buffer = ab, .length = len, .capacity = len }; - krom_file_save_bytes(to, &b, len); - return JS_UNDEFINED; + char *to = (char *)JS_ToCString(ctx, argv[0]); + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]); + buffer_t b = { .buffer = ab, .length = len, .capacity = len }; + krom_file_save_bytes(to, &b, len); + return JS_UNDEFINED; } VOID_FN_CB(context_set_viewport_shader) void node_shader_add_uniform(void *p, char *s0, char *s1, bool b); FN(node_shader_add_uniform) { - int64_t p; - JS_ToInt64(ctx, &p, argv[0]); - char *s0 = (char *)JS_ToCString(ctx, argv[1]); - char *s1 = (char *)JS_ToCString(ctx, argv[2]); - node_shader_add_uniform((void *)p, s0, s1, false); - return JS_UNDEFINED; + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + char *s0 = (char *)JS_ToCString(ctx, argv[1]); + char *s1 = (char *)JS_ToCString(ctx, argv[2]); + node_shader_add_uniform((void *)p, s0, s1, false); + return JS_UNDEFINED; } VOID_FN_PTR_STR(node_shader_write) +void *image_from_bytes(void *p, int w, int h, int format); +FN(image_from_bytes) { + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[0]); + buffer_t b = { .buffer = ab, .length = len, .capacity = len }; + int64_t w; + JS_ToInt64(ctx, &w, argv[1]); + int64_t h; + JS_ToInt64(ctx, &h, argv[2]); + int64_t result = (int64_t)image_from_bytes(&b, w, h, 0); + return JS_NewInt64(ctx, result); +} + +extern char *project_filepath; +FN(project_filepath_get) { + return JS_NewString(ctx, project_filepath); +} + +void project_save(bool b); +FN(project_save) { + project_save(false); + return JS_UNDEFINED; +} + FN(zui_handle_create) { - int64_t result = (int64_t)zui_handle_create(); - return JS_NewInt64(ctx, result); + int64_t result = (int64_t)zui_handle_create(); + return JS_NewInt64(ctx, result); +} + +FN(zui_handle_set_value) { + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + zui_handle_t *h = (zui_handle_t *)p; + double d; + JS_ToFloat64(ctx, &d, argv[1]); + h->value = d; + return JS_UNDEFINED; +} + +FN(zui_handle_get_value) { + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + zui_handle_t *h = (zui_handle_t *)p; + return JS_NewFloat64(ctx, h->value); } FN(zui_panel) { - int64_t p; - JS_ToInt64(ctx, &p, argv[0]); - char *s = (char *)JS_ToCString(ctx, argv[1]); - bool result = zui_panel((void *)p, s, false, false); - return JS_NewBool(ctx, result); + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + char *s = (char *)JS_ToCString(ctx, argv[1]); + bool result = zui_panel((void *)p, s, false, false); + return JS_NewBool(ctx, result); } FN(zui_button) { - char *s = (char *)JS_ToCString(ctx, argv[0]); - bool result = zui_button(s, ZUI_ALIGN_CENTER, ""); - return JS_NewBool(ctx, result); + char *s = (char *)JS_ToCString(ctx, argv[0]); + bool result = zui_button(s, ZUI_ALIGN_CENTER, ""); + return JS_NewBool(ctx, result); } FN(zui_text) { - char *s = (char *)JS_ToCString(ctx, argv[0]); - zui_text(s, ZUI_ALIGN_LEFT, 0); - return JS_UNDEFINED; + char *s = (char *)JS_ToCString(ctx, argv[0]); + zui_text(s, ZUI_ALIGN_LEFT, 0); + return JS_UNDEFINED; } FN(zui_text_input) { - int64_t p; - JS_ToInt64(ctx, &p, argv[0]); - char *s = (char *)JS_ToCString(ctx, argv[1]); - zui_text_input((void *)p, s, ZUI_ALIGN_LEFT, true, false); - return JS_UNDEFINED; + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + char *s = (char *)JS_ToCString(ctx, argv[1]); + zui_text_input((void *)p, s, ZUI_ALIGN_LEFT, true, false); + return JS_UNDEFINED; } FN(zui_slider) { - int64_t p; - JS_ToInt64(ctx, &p, argv[0]); - char *s = (char *)JS_ToCString(ctx, argv[1]); - zui_slider((void *)p, s, 0, 1, true, 100, true, ZUI_ALIGN_LEFT, true); - return JS_UNDEFINED; + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + char *s = (char *)JS_ToCString(ctx, argv[1]); + double from = 0.0; + double to = 1.0; + bool filled = true; + double prec = 100.0; + if (argc > 2) { + JS_ToFloat64(ctx, &from, argv[2]); + } + if (argc > 3) { + JS_ToFloat64(ctx, &to, argv[3]); + } + if (argc > 4) { + filled = JS_ToBool(ctx, argv[4]); + } + if (argc > 5) { + JS_ToFloat64(ctx, &prec, argv[5]); + } + zui_slider((void *)p, s, from, to, filled, prec, true, ZUI_ALIGN_LEFT, true); + return JS_UNDEFINED; } FN(zui_check) { - int64_t p; - JS_ToInt64(ctx, &p, argv[0]); - char *s = (char *)JS_ToCString(ctx, argv[1]); - zui_check((void *)p, s, ""); - return JS_UNDEFINED; + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + char *s = (char *)JS_ToCString(ctx, argv[1]); + zui_check((void *)p, s, ""); + return JS_UNDEFINED; } FN(zui_radio) { - int64_t p; - JS_ToInt64(ctx, &p, argv[0]); - int32_t pos; - JS_ToInt32(ctx, &pos, argv[1]); - char *s = (char *)JS_ToCString(ctx, argv[2]); - zui_radio((void *)p, pos, s, ""); - return JS_UNDEFINED; + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); + int32_t pos; + JS_ToInt32(ctx, &pos, argv[1]); + char *s = (char *)JS_ToCString(ctx, argv[2]); + zui_radio((void *)p, pos, s, ""); + return JS_UNDEFINED; } FN(zui_row) { - JSValue val_len = JS_GetPropertyStr(ctx, argv[0], "length"); - int len; - JS_ToInt32(ctx, &len, val_len); - f32_array_t *ratios = f32_array_create(len); - for (int i = 0; i < len; ++i) { - JSValue val = JS_GetPropertyUint32(ctx, argv[0], i); - double f; - JS_ToFloat64(ctx, &f, val); - ratios->buffer[i] = f; - } - zui_row(ratios); - return JS_UNDEFINED; + JSValue val_len = JS_GetPropertyStr(ctx, argv[0], "length"); + int len; + JS_ToInt32(ctx, &len, val_len); + f32_array_t *ratios = f32_array_create(len); + for (int i = 0; i < len; ++i) { + JSValue val = JS_GetPropertyUint32(ctx, argv[0], i); + double f; + JS_ToFloat64(ctx, &f, val); + ratios->buffer[i] = f; + } + zui_row(ratios); + return JS_UNDEFINED; } FN(zui_combo) { - int64_t p; - JS_ToInt64(ctx, &p, argv[0]); + int64_t p; + JS_ToInt64(ctx, &p, argv[0]); - JSValue val_len = JS_GetPropertyStr(ctx, argv[1], "length"); - int len; - JS_ToInt32(ctx, &len, val_len); - char_ptr_array_t *texts = any_array_create(len); - for (int i = 0; i < len; ++i) { - JSValue val = JS_GetPropertyUint32(ctx, argv[1], i); - char *s = (char *)JS_ToCString(ctx, val); - texts->buffer[i] = s; - } + JSValue val_len = JS_GetPropertyStr(ctx, argv[1], "length"); + int len; + JS_ToInt32(ctx, &len, val_len); + char_ptr_array_t *texts = any_array_create(len); + for (int i = 0; i < len; ++i) { + JSValue val = JS_GetPropertyUint32(ctx, argv[1], i); + char *s = (char *)JS_ToCString(ctx, val); + texts->buffer[i] = s; + } - char *label = (char *)JS_ToCString(ctx, argv[2]); + char *label = (char *)JS_ToCString(ctx, argv[2]); - zui_combo((void *)p, texts, label, true, ZUI_ALIGN_LEFT, true); - return JS_UNDEFINED; + zui_combo((void *)p, texts, label, true, ZUI_ALIGN_LEFT, true); + return JS_UNDEFINED; } extern any_array_t *nodes_material_categories; extern any_array_t *nodes_material_list; FN(nodes_material_category_add) { - char *category_name = (char *)JS_ToCString(ctx, argv[0]); - any_array_push(nodes_material_categories, category_name); - size_t len; - void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]); - buffer_t b = { .buffer = ab, .length = len, .capacity = len }; - any_array_push(nodes_material_list, armpack_decode(&b)); - return JS_UNDEFINED; + char *category_name = (char *)JS_ToCString(ctx, argv[0]); + any_array_push(nodes_material_categories, category_name); + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]); + buffer_t b = { .buffer = ab, .length = len, .capacity = len }; + any_array_push(nodes_material_list, armpack_decode(&b)); + return JS_UNDEFINED; } FN(nodes_material_category_remove) { - char *category_name = (char *)JS_ToCString(ctx, argv[0]); - int i = array_index_of(nodes_material_categories, category_name); - array_splice(nodes_material_list, i, 1); + char *category_name = (char *)JS_ToCString(ctx, argv[0]); + int i = array_index_of(nodes_material_categories, category_name); + array_splice(nodes_material_list, i, 1); array_splice(nodes_material_categories, i, 1); - return JS_UNDEFINED; + return JS_UNDEFINED; } extern any_map_t *parser_material_custom_nodes; FN(parser_material_custom_nodes_set) { - char *node_type = (char *)JS_ToCString(ctx, argv[0]); - JSValue *p = malloc(sizeof(JSValue));\ - JSValue dup = JS_DupValue(ctx, argv[1]);\ - memcpy(p, &dup, sizeof(JSValue));\ - any_map_set(parser_material_custom_nodes, node_type, p); - return JS_UNDEFINED; + char *node_type = (char *)JS_ToCString(ctx, argv[0]); + JSValue *p = malloc(sizeof(JSValue));\ + JSValue dup = JS_DupValue(ctx, argv[1]);\ + memcpy(p, &dup, sizeof(JSValue));\ + any_map_set(parser_material_custom_nodes, node_type, p); + return JS_UNDEFINED; } FN(parser_material_custom_nodes_delete) { - char *node_type = (char *)JS_ToCString(ctx, argv[0]); - map_delete(parser_material_custom_nodes, node_type); - return JS_UNDEFINED; + char *node_type = (char *)JS_ToCString(ctx, argv[0]); + map_delete(parser_material_custom_nodes, node_type); + return JS_UNDEFINED; } extern void *parser_material_frag; FN(parser_material_frag_get) { - return JS_NewInt64(ctx, (int64_t)parser_material_frag); + return JS_NewInt64(ctx, (int64_t)parser_material_frag); } char *parser_material_parse_value_input(void *inp, bool vector_as_grayscale); FN(parser_material_parse_value_input) { - int64_t *node; - JS_ToInt64(ctx, &node, argv[0]); - int64_t i; - JS_ToInt64(ctx, &i, argv[1]); - char *s = parser_material_parse_value_input(((zui_node_t *)node)->inputs->buffer[i], false); - return JS_NewString(ctx, s); + int64_t *node; + JS_ToInt64(ctx, &node, argv[0]); + int64_t i; + JS_ToInt64(ctx, &i, argv[1]); + char *s = parser_material_parse_value_input(((zui_node_t *)node)->inputs->buffer[i], false); + return JS_NewString(ctx, s); } extern any_array_t *nodes_brush_categories; extern any_array_t *nodes_brush_list; FN(nodes_brush_category_add) { - char *category_name = (char *)JS_ToCString(ctx, argv[0]); - any_array_push(nodes_brush_categories, category_name); - size_t len; - void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]); - buffer_t b = { .buffer = ab, .length = len, .capacity = len }; - any_array_push(nodes_brush_list, armpack_decode(&b)); - return JS_UNDEFINED; + char *category_name = (char *)JS_ToCString(ctx, argv[0]); + any_array_push(nodes_brush_categories, category_name); + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]); + buffer_t b = { .buffer = ab, .length = len, .capacity = len }; + any_array_push(nodes_brush_list, armpack_decode(&b)); + return JS_UNDEFINED; } FN(nodes_brush_category_remove) { - char *category_name = (char *)JS_ToCString(ctx, argv[0]); - int i = array_index_of(nodes_brush_categories, category_name); - array_splice(nodes_brush_list, i, 1); + char *category_name = (char *)JS_ToCString(ctx, argv[0]); + int i = array_index_of(nodes_brush_categories, category_name); + array_splice(nodes_brush_list, i, 1); array_splice(nodes_brush_categories, i, 1); - return JS_UNDEFINED; + return JS_UNDEFINED; } extern any_map_t *parser_logic_custom_nodes; FN(parser_logic_custom_nodes_set) { - char *node_type = (char *)JS_ToCString(ctx, argv[0]); - JSValue *p = malloc(sizeof(JSValue));\ - JSValue dup = JS_DupValue(ctx, argv[1]);\ - memcpy(p, &dup, sizeof(JSValue));\ - any_map_set(parser_logic_custom_nodes, node_type, p); - return JS_UNDEFINED; + char *node_type = (char *)JS_ToCString(ctx, argv[0]); + JSValue *p = malloc(sizeof(JSValue));\ + JSValue dup = JS_DupValue(ctx, argv[1]);\ + memcpy(p, &dup, sizeof(JSValue));\ + any_map_set(parser_logic_custom_nodes, node_type, p); + return JS_UNDEFINED; } FN(parser_logic_custom_nodes_delete) { - char *node_type = (char *)JS_ToCString(ctx, argv[0]); - map_delete(parser_logic_custom_nodes, node_type); - return JS_UNDEFINED; + char *node_type = (char *)JS_ToCString(ctx, argv[0]); + map_delete(parser_logic_custom_nodes, node_type); + return JS_UNDEFINED; } extern any_map_t *util_mesh_unwrappers; FN(util_mesh_unwrappers_set) { - char *plugin_name = (char *)JS_ToCString(ctx, argv[0]); - JSValue *p = malloc(sizeof(JSValue));\ - JSValue dup = JS_DupValue(ctx, argv[1]);\ - memcpy(p, &dup, sizeof(JSValue));\ - any_map_set(util_mesh_unwrappers, plugin_name, p); - return JS_UNDEFINED; + char *plugin_name = (char *)JS_ToCString(ctx, argv[0]); + JSValue *p = malloc(sizeof(JSValue));\ + JSValue dup = JS_DupValue(ctx, argv[1]);\ + memcpy(p, &dup, sizeof(JSValue));\ + any_map_set(util_mesh_unwrappers, plugin_name, p); + return JS_UNDEFINED; } FN(util_mesh_unwrappers_delete) { - char *plugin_name = (char *)JS_ToCString(ctx, argv[0]); - map_delete(util_mesh_unwrappers, plugin_name); - return JS_UNDEFINED; + char *plugin_name = (char *)JS_ToCString(ctx, argv[0]); + map_delete(util_mesh_unwrappers, plugin_name); + return JS_UNDEFINED; +} + +extern any_map_t *path_mesh_importers; +extern char_ptr_array_t *path_mesh_formats; +FN(path_mesh_importers_set) { + char *format_name = (char *)JS_ToCString(ctx, argv[0]); + JSValue *p = malloc(sizeof(JSValue));\ + JSValue dup = JS_DupValue(ctx, argv[1]);\ + memcpy(p, &dup, sizeof(JSValue));\ + any_map_set(path_mesh_importers, format_name, p); + any_array_push(path_mesh_formats, format_name); + return JS_UNDEFINED; +} + +FN(path_mesh_importers_delete) { + char *format_name = (char *)JS_ToCString(ctx, argv[0]); + map_delete(path_mesh_importers, format_name); + array_splice(path_mesh_formats, char_ptr_array_index_of(path_mesh_formats, format_name), 1); + return JS_UNDEFINED; +} + +extern any_map_t *path_texture_importers; +extern char_ptr_array_t *path_texture_formats; +FN(path_texture_importers_set) { + char *format_name = (char *)JS_ToCString(ctx, argv[0]); + JSValue *p = malloc(sizeof(JSValue));\ + JSValue dup = JS_DupValue(ctx, argv[1]);\ + memcpy(p, &dup, sizeof(JSValue));\ + any_map_set(path_texture_importers, format_name, p); + any_array_push(path_texture_formats, format_name); + return JS_UNDEFINED; +} + +FN(path_texture_importers_delete) { + char *format_name = (char *)JS_ToCString(ctx, argv[0]); + map_delete(path_texture_importers, format_name); + array_splice(path_texture_formats, char_ptr_array_index_of(path_texture_formats, format_name), 1); + return JS_UNDEFINED; +} + +FN(plugin_api_make_raw_mesh) { + raw_mesh_t *mesh = calloc(sizeof(raw_mesh_t), 1); + mesh->name = (char *)JS_ToCString(ctx, argv[0]); + + size_t len; + void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]); + mesh->posa = malloc(sizeof(i16_array_t)); + mesh->posa->buffer = malloc(len); + memcpy(mesh->posa->buffer, ab, len); + mesh->posa->length = len / 2; + + ab = JS_GetArrayBuffer(ctx, &len, argv[2]); + mesh->nora = malloc(sizeof(i16_array_t)); + mesh->nora->buffer = malloc(len); + memcpy(mesh->nora->buffer, ab, len); + mesh->nora->length = len / 2; + + ab = JS_GetArrayBuffer(ctx, &len, argv[3]); + mesh->inda = malloc(sizeof(u32_array_t)); + mesh->inda->buffer = malloc(len); + memcpy(mesh->inda->buffer, ab, len); + mesh->inda->length = len / 4; + + double d; + JS_ToFloat64(ctx, &d, argv[4]); + mesh->scale_pos = d; + mesh->scale_tex = 1.0; + return JS_NewInt64(ctx, (int64_t)mesh); } void plugin_api_init() { - JSValue global_obj = JS_GetGlobalObject(js_ctx); + JSValue global_obj = JS_GetGlobalObject(js_ctx); - js_eval(lib); + js_eval(lib); - BIND(console_log, 1); - BIND(console_info, 1); - BIND(plugin_create, 0); - BIND(plugin_notify_on_ui, 2); - BIND(plugin_notify_on_delete, 2); - BIND(ui_files_show, 4); - BIND(data_get_blob, 1); - BIND(krom_file_save_bytes, 3); - BIND(context_set_viewport_shader, 1); - BIND(node_shader_add_uniform, 3); - BIND(node_shader_write, 2); + BIND(console_log, 1); + BIND(console_info, 1); + BIND(plugin_create, 0); + BIND(plugin_notify_on_ui, 2); + BIND(plugin_notify_on_update, 2); + BIND(plugin_notify_on_delete, 2); + BIND(ui_files_show, 4); + BIND(ui_box_show_message, 2); + BIND(data_get_blob, 1); + BIND(data_delete_blob, 1); + BIND(krom_file_save_bytes, 3); + BIND(context_set_viewport_shader, 1); + BIND(node_shader_add_uniform, 3); + BIND(node_shader_write, 2); + BIND(image_from_bytes, 3); + BIND(project_filepath_get, 0); + BIND(project_save, 0); - BIND(zui_handle_create, 0); - BIND(zui_panel, 2); - BIND(zui_button, 1); - BIND(zui_text, 1); - BIND(zui_text_input, 2); - BIND(zui_slider, 5); - BIND(zui_check, 2); - BIND(zui_radio, 3); - BIND(zui_row, 1); - BIND(zui_combo, 3); + BIND(zui_handle_create, 0); + BIND(zui_handle_set_value, 2); + BIND(zui_handle_get_value, 1); + BIND(zui_panel, 2); + BIND(zui_button, 1); + BIND(zui_text, 1); + BIND(zui_text_input, 2); + BIND(zui_slider, 5); + BIND(zui_check, 2); + BIND(zui_radio, 3); + BIND(zui_row, 1); + BIND(zui_combo, 3); - BIND(nodes_material_category_add, 2); - BIND(nodes_material_category_remove, 1); - BIND(parser_material_custom_nodes_set, 2); - BIND(parser_material_custom_nodes_delete, 1); - BIND(parser_material_frag_get, 0); - BIND(parser_material_parse_value_input, 2); + BIND(nodes_material_category_add, 2); + BIND(nodes_material_category_remove, 1); + BIND(parser_material_custom_nodes_set, 2); + BIND(parser_material_custom_nodes_delete, 1); + BIND(parser_material_frag_get, 0); + BIND(parser_material_parse_value_input, 2); - BIND(nodes_brush_category_add, 2); - BIND(nodes_brush_category_remove, 1); - BIND(parser_logic_custom_nodes_set, 2); - BIND(parser_logic_custom_nodes_delete, 1); + BIND(nodes_brush_category_add, 2); + BIND(nodes_brush_category_remove, 1); + BIND(parser_logic_custom_nodes_set, 2); + BIND(parser_logic_custom_nodes_delete, 1); - BIND(util_mesh_unwrappers_set, 2); - BIND(util_mesh_unwrappers_delete, 1); + BIND(util_mesh_unwrappers_set, 2); + BIND(util_mesh_unwrappers_delete, 1); + BIND(path_mesh_importers_set, 2); + BIND(path_mesh_importers_delete, 1); + BIND(path_texture_importers_set, 2); + BIND(path_texture_importers_delete, 1); + + BIND(plugin_api_make_raw_mesh, 5); plugin_embed(); - JS_FreeValue(js_ctx, global_obj); + JS_FreeValue(js_ctx, global_obj); }