From 3273dbbb641321c110b5b19563c77043c5a9ff6b Mon Sep 17 00:00:00 2001 From: luboslenco Date: Fri, 16 Aug 2024 11:44:07 +0200 Subject: [PATCH] Make converter plugin work --- armorpaint/assets/plugins/converter.js | 394 +++++++++++++++++++++---- base/sources/plugin_api.c | 11 + 2 files changed, 351 insertions(+), 54 deletions(-) diff --git a/armorpaint/assets/plugins/converter.js b/armorpaint/assets/plugins/converter.js index acc14c3d..e2865a16 100644 --- a/armorpaint/assets/plugins/converter.js +++ b/armorpaint/assets/plugins/converter.js @@ -9,68 +9,354 @@ plugin_notify_on_ui(plugin, function() { ui_files_show("arm", false, true, function(path) { let b = data_get_blob(path); let parsed = armpack_decode(b); - let out = sys_string_to_buffer(JSON.stringify(parsed, function(key, value) { - if (value.constructor.name === "Float32Array") { - let ar = Array.from(value); - ar.unshift(0); // Annotate array type - return ar; - } - else if (value.constructor.name === "Uint32Array") { - let ar = Array.from(value); - ar.unshift(1); - return ar; - } - else if (value.constructor.name === "Int16Array") { - let ar = Array.from(value); - ar.unshift(2); - return ar; - } - return value; - }, " ")); + let out = string_to_buffer(JSON.stringify(parsed, null, " ")); krom_file_save_bytes(path.substr(0, path.length - 3) + "json", out); }); } if (zui_button(".json to .arm")) { ui_files_show("json", false, true, function(path) { let b = data_get_blob(path); - let parsed = json_parse(sys_buffer_to_string(b)); - function iterate(d) { - for (const n of ReflectFields(d)) { - let v = ReflectField(d, n); - if (v.constructor.name === "Array") { - if (v[0].constructor.name === "Number") { - let ar = null; - if (v[0] === 0) { - ar = new Float32Array(v.length - 1); - } - else if (v[0] === 1) { - ar = new Uint32Array(v.length - 1); - } - else if (v[0] === 2) { - ar = new Int16Array(v.length - 1); - } - for (let i = 0; i < v.length - 1; ++i) { - ar[i] = v[i + 1]; - } - ReflectSetField(d, n, ar); - } - else { - for (const e of v) { - if (typeof e === 'object') { - iterate(e); - } - } - } - } - else if (typeof v === 'object') { - iterate(v); - } - } - } - iterate(parsed); + let parsed = JSON.parse(buffer_to_string(b)); let out = armpack_encode(parsed); - krom_file_save_bytes(path.substr(0, path.length - 4) + "arm", out, out.byteLength + 1); + krom_file_save_bytes(path.substr(0, path.length - 4) + "arm", out); }); } } }); + +function buffer_to_string(b) { + let str = ""; + let u8a = new Uint8Array(b); + for (let i = 0; i < u8a.length; ++i) { + str += String.fromCharCode(u8a[i]); + } + return str; +} + +function string_to_buffer(str) { + let u8a = new Uint8Array(str.length); + for (let i = 0; i < str.length; ++i) { + u8a[i] = str.charCodeAt(i); + } + return u8a.buffer; +} + +let pos = 0; +let k_type = ""; + +function armpack_decode(b) { + pos = 0; + return read(new DataView(b)); +} + +function read_u8(v) { + let i = v.getUint8(pos); + pos++; + return i; +} + +function read_i16(v) { + let i = v.getInt16(pos, true); + pos += 2; + return i; +} + +function read_i32(v) { + let i = v.getInt32(pos, true); + pos += 4; + return i; +} + +function read_u32(v) { + let i = v.getUint32(pos, true); + pos += 4; + return i; +} + +function read_f32(v) { + let f = v.getFloat32(pos, true); + pos += 4; + return f; +} + +function read_string(v, len) { + let s = ""; + for (let i = 0; i < len; ++i) { + s += String.fromCharCode(read_u8(v)); + } + return s; +} + +function read(v) { + let b = read_u8(v); + switch (b) { + case 0xc0: return null; + case 0xc2: return false; + case 0xc3: return true; + case 0xca: { k_type = "__f32"; return read_f32(v); } + case 0xd2: return read_i32(v); + case 0xdb: return read_string(v, read_u32(v)); + case 0xdd: return read_array(v, read_i32(v)); + case 0xdf: return read_map(v, read_i32(v)); + } + return 0; +} + +function read_array(v, length) { + let b = read_u8(v); + + if (b == 0xca) { // Typed f32 + let a = new Array(length); + for (let x = 0; x < length; ++x) a[x] = read_f32(v); + k_type = "__f32"; + return a; + } + else if (b == 0xd2) { // Typed i32 + let a = new Array(length); + for (let x = 0; x < length; ++x) a[x] = read_i32(v); + k_type = "__i32"; + return a; + } + else if (b == 0xd1) { // Typed i16 + let a = new Array(length); + for (let x = 0; x < length; ++x) a[x] = read_i16(v); + k_type = "__i16"; + return a; + } + else if (b == 0xc4) { // Typed u8 + let a = new Array(length); + for (let x = 0; x < length; ++x) a[x] = read_u8(v); + k_type = "__u8"; + return a; + } + else { // Dynamic type-value + pos--; + let a = new Array(length); + for (let x = 0; x < length; ++x) a[x] = read(v); + return a; + } +} + +function read_map(v, length) { + let out = {}; + for (let n = 0; n < length; ++n) { + let k = read(v); + k_type = ""; + let val = read(v); + k += k_type; + k_type = ""; + out[k] = val; + } + return out; +} + +function armpack_encode(d) { + pos = 0; + write_dummy(d); + console.log(pos); + let b = new ArrayBuffer(pos); + let v = new DataView(b); + pos = 0; + write(v, d); + console.log(b.byteLength); + return b; +} + +function write_u8(v, i) { + v.setUint8(pos, i); + pos += 1; +} + +function write_i16(v, i) { + v.setInt16(pos, i, true); + pos += 2; +} + +function write_i32(v, i) { + v.setInt32(pos, i, true); + pos += 4; +} + +function write_f32(v, f) { + v.setFloat32(pos, f, true); + pos += 4; +} + +function write_string(v, str) { + for (let i = 0; i < str.length; ++i) { + write_u8(v, str.charCodeAt(i)); + } +} + +function write(v, d) { + if (d == null) { + write_u8(v, 0xc0); + } + else if (typeof d == "boolean") { + write_u8(v, d ? 0xc3 : 0xc2); + } + else if (typeof d == "number") { + if (Number.isInteger(d) && k_type != "__f32") { + write_u8(v, 0xd2); + write_i32(v, d); + } + else { + write_u8(v, 0xca); + write_f32(v, d); + } + } + else if (typeof d == "string") { + write_u8(v, 0xdb); + write_i32(v, d.length); + write_string(v, d); + } + else if (Array.isArray(d)) { + write_u8(v, 0xdd); + write_i32(v, d.length); + if (k_type == "__u8") { + write_u8(v, 0xc4); + for (let i = 0; i < d.length; ++i) { + write_u8(v, d[i]); + } + } + else if (k_type == "__i16") { + write_u8(v, 0xd1); + for (let i = 0; i < d.length; ++i) { + write_i16(v, d[i]); + } + } + else if (k_type == "__f32") { + write_u8(v, 0xca); + for (let i = 0; i < d.length; ++i) { + write_f32(v, d[i]); + } + } + else if (k_type == "__i32") { + write_u8(v, 0xd2); + for (let i = 0; i < d.length; ++i) { + write_i32(v, d[i]); + } + } + else { + for (let i = 0; i < d.length; ++i) { + write(v, d[i]); + } + } + } + else { + write_object(v, d); + } +} + +function write_object(v, d) { + let f = Object.keys(d); + write_u8(v, 0xdf); + write_i32(v, f.length); + for (let i = 0; i < f.length; ++i) { + let k = f[i]; + + k_type = ""; + if (k.endsWith("__f32")) { + k_type = "__f32"; + } + else if (k.endsWith("__i32")) { + k_type = "__i32"; + } + else if (k.endsWith("__i16")) { + k_type = "__i16"; + } + else if (k.endsWith("__u8")) { + k_type = "__u8"; + } + + write_u8(v, 0xdb); + write_i32(v, k.length - k_type.length); + + write_string(v, k.substring(0, k.length - k_type.length)); + write(v, d[k]); + k_type = ""; + } +} + +function write_dummy(d) { + if (d == null) { + pos += 1; + } + else if (typeof d == "boolean") { + pos += 1; + } + else if (typeof d == "number") { + pos += 1; + pos += 4; + } + else if (typeof d == "string") { + pos += 1; + pos += 4; + pos += d.length; + } + else if (Array.isArray(d)) { + pos += 1; + pos += 4; + if (k_type == "__u8") { + pos += 1; + for (let i = 0; i < d.length; ++i) { + pos += 1; + } + } + else if (k_type == "__i16") { + pos += 1; + for (let i = 0; i < d.length; ++i) { + pos += 2; + } + } + else if (k_type == "__f32") { + pos += 1; + for (let i = 0; i < d.length; ++i) { + pos += 4; + } + } + else if (k_type == "__i32") { + pos += 1; + for (let i = 0; i < d.length; ++i) { + pos += 4; + } + } + else { + for (let i = 0; i < d.length; ++i) { + write_dummy(d[i]); + } + } + } + else { + write_object_dummy(d); + } +} + +function write_object_dummy(d) { + let f = Object.keys(d); + pos += 1; + pos += 4; + for (let i = 0; i < f.length; ++i) { + let k = f[i]; + pos += 1; + pos += 4; + + k_type = ""; + if (k.endsWith("__f32")) { + k_type = "__f32"; + } + else if (k.endsWith("__i32")) { + k_type = "__i32"; + } + else if (k.endsWith("__i16")) { + k_type = "__i16"; + } + else if (k.endsWith("__u8")) { + k_type = "__u8"; + } + + pos += k.length - k_type.length; + write_dummy(d[k]); + k_type = ""; + } +} diff --git a/base/sources/plugin_api.c b/base/sources/plugin_api.c index 9c177e05..565500cc 100644 --- a/base/sources/plugin_api.c +++ b/base/sources/plugin_api.c @@ -84,6 +84,16 @@ MAKE_FN(data_get_blob) { return val; } +void *krom_file_save_bytes(char *s, buffer_t *b, int l); +MAKE_FN(krom_file_save_bytes) { + char *to = (char *)JS_ToCString(ctx, argv[0]); + int64_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; +} + MAKE_FN(zui_handle_create) { int64_t result = (int64_t)zui_handle_create(); return JS_NewInt64(ctx, result); @@ -187,6 +197,7 @@ void plugin_api_init() { BIND_FN(plugin_notify_on_ui, 2); BIND_FN(ui_files_show, 4); BIND_FN(data_get_blob, 1); + BIND_FN(krom_file_save_bytes, 3); BIND_FN(zui_handle_create, 0); BIND_FN(zui_panel, 2);