plugin_api.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. #include "plugin_api.h"
  2. #include "iron_armpack.h"
  3. #include "iron_array.h"
  4. #include "iron_map.h"
  5. #include "iron_mat4.h"
  6. #include "iron_obj.h"
  7. #include "iron_ui.h"
  8. #include "iron_ui_nodes.h"
  9. #include "iron_vec4.h"
  10. void plugin_embed();
  11. // ██╗ ██╗██████╗
  12. // ██║ ██║██╔══██╗
  13. // ██║ ██║██████╔╝
  14. // ██║ ██║██╔══██╗
  15. // ███████╗██║██████╔╝
  16. // ╚══════╝╚═╝╚═════╝
  17. const char *lib = "\
  18. function buffer_to_string(b) {\
  19. let str = \"\";\
  20. let u8a = new Uint8Array(b);\
  21. for (let i = 0; i < u8a.length; ++i) {\
  22. str += String.fromCharCode(u8a[i]);\
  23. }\
  24. return str;\
  25. }\
  26. \
  27. function string_to_buffer(str) {\
  28. let u8a = new Uint8Array(str.length);\
  29. for (let i = 0; i < str.length; ++i) {\
  30. u8a[i] = str.charCodeAt(i);\
  31. }\
  32. return u8a.buffer;\
  33. }\
  34. \
  35. let pos = 0;\
  36. let k_type = \"\";\
  37. \
  38. function armpack_decode(b) {\
  39. pos = 0;\
  40. return read(new DataView(b));\
  41. }\
  42. \
  43. function read_u8(v) {\
  44. let i = v.getUint8(pos);\
  45. pos++;\
  46. return i;\
  47. }\
  48. \
  49. function read_i16(v) {\
  50. let i = v.getInt16(pos, true);\
  51. pos += 2;\
  52. return i;\
  53. }\
  54. \
  55. function read_i32(v) {\
  56. let i = v.getInt32(pos, true);\
  57. pos += 4;\
  58. return i;\
  59. }\
  60. \
  61. function read_u32(v) {\
  62. let i = v.getUint32(pos, true);\
  63. pos += 4;\
  64. return i;\
  65. }\
  66. \
  67. function read_f32(v) {\
  68. let f = v.getFloat32(pos, true);\
  69. pos += 4;\
  70. return f;\
  71. }\
  72. \
  73. function read_string(v, len) {\
  74. let s = \"\";\
  75. for (let i = 0; i < len; ++i) {\
  76. s += String.fromCharCode(read_u8(v));\
  77. }\
  78. return s;\
  79. }\
  80. \
  81. function read(v) {\
  82. let b = read_u8(v);\
  83. switch (b) {\
  84. case 0xc0: return null;\
  85. case 0xc2: return false;\
  86. case 0xc3: return true;\
  87. case 0xca: { k_type = \"__f32\"; return read_f32(v); }\
  88. case 0xd2: return read_i32(v);\
  89. case 0xdb: return read_string(v, read_u32(v));\
  90. case 0xdd: return read_array(v, read_i32(v));\
  91. case 0xdf: return read_map(v, read_i32(v));\
  92. }\
  93. return 0;\
  94. }\
  95. \
  96. function read_array(v, length) {\
  97. let b = read_u8(v);\
  98. \
  99. if (b == 0xca) { /* Typed f32 */ \
  100. let a = new Array(length);\
  101. for (let x = 0; x < length; ++x) a[x] = read_f32(v);\
  102. k_type = \"__f32\";\
  103. return a;\
  104. }\
  105. else if (b == 0xd2) { /* Typed i32 */ \
  106. let a = new Array(length);\
  107. for (let x = 0; x < length; ++x) a[x] = read_i32(v);\
  108. k_type = \"__i32\";\
  109. return a;\
  110. }\
  111. else if (b == 0xd1) { /* Typed i16 */ \
  112. let a = new Array(length);\
  113. for (let x = 0; x < length; ++x) a[x] = read_i16(v);\
  114. k_type = \"__i16\";\
  115. return a;\
  116. }\
  117. else if (b == 0xc4) { /* Typed u8 */ \
  118. let a = new Array(length);\
  119. for (let x = 0; x < length; ++x) a[x] = read_u8(v);\
  120. k_type = \"__u8\";\
  121. return a;\
  122. }\
  123. else { /* Dynamic type-value */ \
  124. pos--;\
  125. let a = new Array(length);\
  126. for (let x = 0; x < length; ++x) a[x] = read(v);\
  127. return a;\
  128. }\
  129. }\
  130. \
  131. function read_map(v, length) {\
  132. let out = {};\
  133. for (let n = 0; n < length; ++n) {\
  134. let k = read(v);\
  135. k_type = \"\";\
  136. let val = read(v);\
  137. k += k_type;\
  138. k_type = \"\";\
  139. out[k] = val;\
  140. }\
  141. return out;\
  142. }\
  143. \
  144. function armpack_encode(d) {\
  145. pos = 0;\
  146. write_dummy(d);\
  147. let b = new ArrayBuffer(pos);\
  148. let v = new DataView(b);\
  149. pos = 0;\
  150. write(v, d);\
  151. return b;\
  152. }\
  153. \
  154. function write_u8(v, i) {\
  155. v.setUint8(pos, i);\
  156. pos += 1;\
  157. }\
  158. \
  159. function write_i16(v, i) {\
  160. v.setInt16(pos, i, true);\
  161. pos += 2;\
  162. }\
  163. \
  164. function write_i32(v, i) {\
  165. v.setInt32(pos, i, true);\
  166. pos += 4;\
  167. }\
  168. \
  169. function write_f32(v, f) {\
  170. v.setFloat32(pos, f, true);\
  171. pos += 4;\
  172. }\
  173. \
  174. function write_string(v, str) {\
  175. for (let i = 0; i < str.length; ++i) {\
  176. write_u8(v, str.charCodeAt(i));\
  177. }\
  178. }\
  179. \
  180. function write(v, d) {\
  181. if (d == null) {\
  182. write_u8(v, 0xc0);\
  183. }\
  184. else if (typeof d == \"boolean\") {\
  185. write_u8(v, d ? 0xc3 : 0xc2);\
  186. }\
  187. else if (typeof d == \"number\") {\
  188. if (Number.isInteger(d) && k_type != \"__f32\") {\
  189. write_u8(v, 0xd2);\
  190. write_i32(v, d);\
  191. }\
  192. else {\
  193. write_u8(v, 0xca);\
  194. write_f32(v, d);\
  195. }\
  196. }\
  197. else if (typeof d == \"string\") {\
  198. write_u8(v, 0xdb);\
  199. write_i32(v, d.length);\
  200. write_string(v, d);\
  201. }\
  202. else if (Array.isArray(d)) {\
  203. write_u8(v, 0xdd);\
  204. write_i32(v, d.length);\
  205. if (k_type == \"__u8\") {\
  206. write_u8(v, 0xc4);\
  207. for (let i = 0; i < d.length; ++i) {\
  208. write_u8(v, d[i]);\
  209. }\
  210. }\
  211. else if (k_type == \"__i16\") {\
  212. write_u8(v, 0xd1);\
  213. for (let i = 0; i < d.length; ++i) {\
  214. write_i16(v, d[i]);\
  215. }\
  216. }\
  217. else if (k_type == \"__f32\") {\
  218. write_u8(v, 0xca);\
  219. for (let i = 0; i < d.length; ++i) {\
  220. write_f32(v, d[i]);\
  221. }\
  222. }\
  223. else if (k_type == \"__i32\") {\
  224. write_u8(v, 0xd2);\
  225. for (let i = 0; i < d.length; ++i) {\
  226. write_i32(v, d[i]);\
  227. }\
  228. }\
  229. else {\
  230. for (let i = 0; i < d.length; ++i) {\
  231. write(v, d[i]);\
  232. }\
  233. }\
  234. }\
  235. else {\
  236. write_object(v, d);\
  237. }\
  238. }\
  239. \
  240. function write_object(v, d) {\
  241. let f = Object.keys(d);\
  242. write_u8(v, 0xdf);\
  243. write_i32(v, f.length);\
  244. for (let i = 0; i < f.length; ++i) {\
  245. let k = f[i];\
  246. \
  247. k_type = \"\";\
  248. if (k.endsWith(\"__f32\")) {\
  249. k_type = \"__f32\";\
  250. }\
  251. else if (k.endsWith(\"__i32\")) {\
  252. k_type = \"__i32\";\
  253. }\
  254. else if (k.endsWith(\"__i16\")) {\
  255. k_type = \"__i16\";\
  256. }\
  257. else if (k.endsWith(\"__u8\")) {\
  258. k_type = \"__u8\";\
  259. }\
  260. \
  261. write_u8(v, 0xdb);\
  262. write_i32(v, k.length - k_type.length);\
  263. \
  264. write_string(v, k.substring(0, k.length - k_type.length));\
  265. write(v, d[k]);\
  266. k_type = \"\";\
  267. }\
  268. }\
  269. \
  270. function write_dummy(d) {\
  271. if (d == null) {\
  272. pos += 1;\
  273. }\
  274. else if (typeof d == \"boolean\") {\
  275. pos += 1;\
  276. }\
  277. else if (typeof d == \"number\") {\
  278. pos += 1;\
  279. pos += 4;\
  280. }\
  281. else if (typeof d == \"string\") {\
  282. pos += 1;\
  283. pos += 4;\
  284. pos += d.length;\
  285. }\
  286. else if (Array.isArray(d)) {\
  287. pos += 1;\
  288. pos += 4;\
  289. if (k_type == \"__u8\") {\
  290. pos += 1;\
  291. for (let i = 0; i < d.length; ++i) {\
  292. pos += 1;\
  293. }\
  294. }\
  295. else if (k_type == \"__i16\") {\
  296. pos += 1;\
  297. for (let i = 0; i < d.length; ++i) {\
  298. pos += 2;\
  299. }\
  300. }\
  301. else if (k_type == \"__f32\") {\
  302. pos += 1;\
  303. for (let i = 0; i < d.length; ++i) {\
  304. pos += 4;\
  305. }\
  306. }\
  307. else if (k_type == \"__i32\") {\
  308. pos += 1;\
  309. for (let i = 0; i < d.length; ++i) {\
  310. pos += 4;\
  311. }\
  312. }\
  313. else {\
  314. for (let i = 0; i < d.length; ++i) {\
  315. write_dummy(d[i]);\
  316. }\
  317. }\
  318. }\
  319. else {\
  320. write_object_dummy(d);\
  321. }\
  322. }\
  323. \
  324. function write_object_dummy(d) {\
  325. let f = Object.keys(d);\
  326. pos += 1;\
  327. pos += 4;\
  328. for (let i = 0; i < f.length; ++i) {\
  329. let k = f[i];\
  330. pos += 1;\
  331. pos += 4;\
  332. \
  333. k_type = \"\";\
  334. if (k.endsWith(\"__f32\")) {\
  335. k_type = \"__f32\";\
  336. }\
  337. else if (k.endsWith(\"__i32\")) {\
  338. k_type = \"__i32\";\
  339. }\
  340. else if (k.endsWith(\"__i16\")) {\
  341. k_type = \"__i16\";\
  342. }\
  343. else if (k.endsWith(\"__u8\")) {\
  344. k_type = \"__u8\";\
  345. }\
  346. \
  347. pos += k.length - k_type.length;\
  348. write_dummy(d[k]);\
  349. k_type = \"\";\
  350. }\
  351. }\
  352. \
  353. globalThis.armpack_encode = armpack_encode;\
  354. globalThis.armpack_decode = armpack_decode;\
  355. globalThis.string_to_buffer = string_to_buffer;\
  356. globalThis.buffer_to_string = buffer_to_string;\
  357. ";
  358. // ██████╗ ██╗███╗ ██╗██████╗ ██╗███╗ ██╗ ██████╗ ███████╗
  359. // ██╔══██╗██║████╗ ██║██╔══██╗██║████╗ ██║██╔════╝ ██╔════╝
  360. // ██████╔╝██║██╔██╗ ██║██║ ██║██║██╔██╗ ██║██║ ███╗███████╗
  361. // ██╔══██╗██║██║╚██╗██║██║ ██║██║██║╚██╗██║██║ ██║╚════██║
  362. // ██████╔╝██║██║ ╚████║██████╔╝██║██║ ╚████║╚██████╔╝███████║
  363. // ╚═════╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝
  364. any_array_t *plugin_gc;
  365. void gc_root(void *ptr);
  366. void gc_run();
  367. // These could be auto-generated by alang
  368. VOID_FN(gc_run)
  369. void *data_get_blob(char *s);
  370. FN(data_get_blob) {
  371. char *s = (char *)JS_ToCString(ctx, argv[0]);
  372. buffer_t *b = data_get_blob(s);
  373. JSValue val = JS_NewArrayBuffer(ctx, b->buffer, b->length, NULL, NULL, 0);
  374. return val;
  375. }
  376. void *data_delete_blob(char *s);
  377. FN(data_delete_blob) {
  378. char *s = (char *)JS_ToCString(ctx, argv[0]);
  379. data_delete_blob(s);
  380. return JS_UNDEFINED;
  381. }
  382. void *iron_file_save_bytes(char *s, buffer_t *b, int l);
  383. FN(iron_file_save_bytes) {
  384. char *to = (char *)JS_ToCString(ctx, argv[0]);
  385. size_t len;
  386. void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]);
  387. buffer_t b = {.buffer = ab, .length = len, .capacity = len};
  388. iron_file_save_bytes(to, &b, len);
  389. return JS_UNDEFINED;
  390. }
  391. void *gpu_create_texture_from_bytes(void *p, int w, int h, int format);
  392. FN(gpu_create_texture_from_bytes) {
  393. size_t len;
  394. void *ab = JS_GetArrayBuffer(ctx, &len, argv[0]);
  395. buffer_t b = {.buffer = ab, .length = len, .capacity = len};
  396. int64_t w;
  397. JS_ToInt64(ctx, &w, argv[1]);
  398. int64_t h;
  399. JS_ToInt64(ctx, &h, argv[2]);
  400. int64_t format = 0;
  401. if (argc > 3) {
  402. JS_ToInt64(ctx, &format, argv[3]);
  403. }
  404. uint64_t result = (uint64_t)gpu_create_texture_from_bytes(&b, w, h, format);
  405. return JS_NewBigUint64(ctx, result);
  406. }
  407. FN(ui_handle_create) {
  408. uint64_t result = (uint64_t)ui_handle_create();
  409. any_array_push(plugin_gc, (void *)result);
  410. return JS_NewBigUint64(ctx, result);
  411. }
  412. FN(ui_handle_set_value) {
  413. uint64_t p;
  414. JS_ToBigUint64(ctx, &p, argv[0]);
  415. ui_handle_t *h = (ui_handle_t *)p;
  416. double d;
  417. JS_ToFloat64(ctx, &d, argv[1]);
  418. h->f = d;
  419. return JS_UNDEFINED;
  420. }
  421. FN(ui_handle_get_value) {
  422. uint64_t p;
  423. JS_ToBigUint64(ctx, &p, argv[0]);
  424. ui_handle_t *h = (ui_handle_t *)p;
  425. return JS_NewFloat64(ctx, h->f);
  426. }
  427. FN(ui_panel) {
  428. uint64_t p;
  429. JS_ToBigUint64(ctx, &p, argv[0]);
  430. char *s = (char *)JS_ToCString(ctx, argv[1]);
  431. bool result = ui_panel((void *)p, s, false, false);
  432. return JS_NewBool(ctx, result);
  433. }
  434. FN(ui_button) {
  435. char *s = (char *)JS_ToCString(ctx, argv[0]);
  436. bool result = ui_button(s, UI_ALIGN_CENTER, "");
  437. return JS_NewBool(ctx, result);
  438. }
  439. FN(ui_text) {
  440. char *s = (char *)JS_ToCString(ctx, argv[0]);
  441. ui_text(s, UI_ALIGN_LEFT, 0);
  442. return JS_UNDEFINED;
  443. }
  444. FN(ui_text_input) {
  445. uint64_t p;
  446. JS_ToBigUint64(ctx, &p, argv[0]);
  447. char *s = (char *)JS_ToCString(ctx, argv[1]);
  448. ui_text_input((void *)p, s, UI_ALIGN_LEFT, true, false);
  449. return JS_UNDEFINED;
  450. }
  451. FN(ui_slider) {
  452. uint64_t p;
  453. JS_ToBigUint64(ctx, &p, argv[0]);
  454. char *s = (char *)JS_ToCString(ctx, argv[1]);
  455. double from = 0.0;
  456. double to = 1.0;
  457. bool filled = true;
  458. double prec = 100.0;
  459. if (argc > 2) {
  460. JS_ToFloat64(ctx, &from, argv[2]);
  461. }
  462. if (argc > 3) {
  463. JS_ToFloat64(ctx, &to, argv[3]);
  464. }
  465. if (argc > 4) {
  466. filled = JS_ToBool(ctx, argv[4]);
  467. }
  468. if (argc > 5) {
  469. JS_ToFloat64(ctx, &prec, argv[5]);
  470. }
  471. ui_slider((void *)p, s, from, to, filled, prec, true, UI_ALIGN_LEFT, true);
  472. return JS_UNDEFINED;
  473. }
  474. FN(ui_check) {
  475. uint64_t p;
  476. JS_ToBigUint64(ctx, &p, argv[0]);
  477. char *s = (char *)JS_ToCString(ctx, argv[1]);
  478. ui_check((void *)p, s, "");
  479. return JS_UNDEFINED;
  480. }
  481. FN(ui_radio) {
  482. uint64_t p;
  483. JS_ToBigUint64(ctx, &p, argv[0]);
  484. int32_t pos;
  485. JS_ToInt32(ctx, &pos, argv[1]);
  486. char *s = (char *)JS_ToCString(ctx, argv[2]);
  487. ui_radio((void *)p, pos, s, "");
  488. return JS_UNDEFINED;
  489. }
  490. FN(ui_row) {
  491. JSValue val_len = JS_GetPropertyStr(ctx, argv[0], "length");
  492. int len;
  493. JS_ToInt32(ctx, &len, val_len);
  494. f32_array_t *ratios = f32_array_create(len);
  495. for (int i = 0; i < len; ++i) {
  496. JSValue val = JS_GetPropertyUint32(ctx, argv[0], i);
  497. double f;
  498. JS_ToFloat64(ctx, &f, val);
  499. ratios->buffer[i] = f;
  500. }
  501. ui_row(ratios);
  502. return JS_UNDEFINED;
  503. }
  504. FN(ui_combo) {
  505. uint64_t p;
  506. JS_ToBigUint64(ctx, &p, argv[0]);
  507. JSValue val_len = JS_GetPropertyStr(ctx, argv[1], "length");
  508. int len;
  509. JS_ToInt32(ctx, &len, val_len);
  510. char_ptr_array_t *texts = any_array_create(len);
  511. for (int i = 0; i < len; ++i) {
  512. JSValue val = JS_GetPropertyUint32(ctx, argv[1], i);
  513. char *s = (char *)JS_ToCString(ctx, val);
  514. texts->buffer[i] = s;
  515. }
  516. char *label = (char *)JS_ToCString(ctx, argv[2]);
  517. ui_combo((void *)p, texts, label, true, UI_ALIGN_LEFT, true);
  518. return JS_UNDEFINED;
  519. }
  520. FN(plugin_api_make_raw_mesh) {
  521. raw_mesh_t *mesh = calloc(sizeof(raw_mesh_t), 1);
  522. mesh->name = (char *)JS_ToCString(ctx, argv[0]);
  523. size_t len;
  524. void *ab = JS_GetArrayBuffer(ctx, &len, argv[1]);
  525. mesh->posa = malloc(sizeof(i16_array_t));
  526. mesh->posa->buffer = malloc(len);
  527. memcpy(mesh->posa->buffer, ab, len);
  528. mesh->posa->length = len / 2;
  529. ab = JS_GetArrayBuffer(ctx, &len, argv[2]);
  530. mesh->nora = malloc(sizeof(i16_array_t));
  531. mesh->nora->buffer = malloc(len);
  532. memcpy(mesh->nora->buffer, ab, len);
  533. mesh->nora->length = len / 2;
  534. ab = JS_GetArrayBuffer(ctx, &len, argv[3]);
  535. mesh->inda = malloc(sizeof(u32_array_t));
  536. mesh->inda->buffer = malloc(len);
  537. memcpy(mesh->inda->buffer, ab, len);
  538. mesh->inda->length = len / 4;
  539. double d;
  540. JS_ToFloat64(ctx, &d, argv[4]);
  541. mesh->scale_pos = d;
  542. mesh->scale_tex = 1.0;
  543. return JS_NewBigUint64(ctx, (uint64_t)mesh);
  544. }
  545. void transform_rotate(void *raw, vec4_t axis, float f);
  546. FN(transform_rotate) {
  547. uint64_t p;
  548. JS_ToBigUint64(ctx, &p, argv[0]);
  549. vec4_t axis;
  550. axis.x = 0.0;
  551. axis.y = 0.0;
  552. axis.z = 1.0;
  553. double d;
  554. JS_ToFloat64(ctx, &d, argv[1]);
  555. transform_rotate((void *)p, axis, d);
  556. return JS_UNDEFINED;
  557. }
  558. void plugin_api_init() {
  559. JSValue global_obj = JS_GetGlobalObject(js_ctx);
  560. js_eval(lib);
  561. plugin_gc = any_array_create(0);
  562. gc_root(plugin_gc);
  563. BIND(gc_run, 0);
  564. BIND(data_get_blob, 1);
  565. BIND(data_delete_blob, 1);
  566. BIND(iron_file_save_bytes, 3);
  567. BIND(gpu_create_texture_from_bytes, 4);
  568. BIND(ui_handle_create, 0);
  569. BIND(ui_handle_set_value, 2);
  570. BIND(ui_handle_get_value, 1);
  571. BIND(ui_panel, 2);
  572. BIND(ui_button, 1);
  573. BIND(ui_text, 1);
  574. BIND(ui_text_input, 2);
  575. BIND(ui_slider, 5);
  576. BIND(ui_check, 2);
  577. BIND(ui_radio, 3);
  578. BIND(ui_row, 1);
  579. BIND(ui_combo, 3);
  580. BIND(plugin_api_make_raw_mesh, 5);
  581. BIND(transform_rotate, 3);
  582. plugin_embed();
  583. JS_FreeValue(js_ctx, global_obj);
  584. }