export_arm.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. function export_arm_run_mesh(path: string, paint_objects: mesh_object_t[]) {
  2. let mesh_datas: mesh_data_t[] = [];
  3. for (let i: i32 = 0; i < paint_objects.length; ++i) {
  4. let p: mesh_object_t = paint_objects[i];
  5. array_push(mesh_datas, p.data);
  6. }
  7. let raw: scene_t = { mesh_datas: mesh_datas };
  8. let b: buffer_t = armpack_encode(raw);
  9. if (!ends_with(path, ".arm")) {
  10. path += ".arm";
  11. }
  12. krom_file_save_bytes(path, b, buffer_size(b) + 1);
  13. }
  14. function export_arm_run_project() {
  15. ///if (is_paint || is_sculpt)
  16. let mnodes: zui_node_canvas_t[] = [];
  17. for (let i: i32 = 0; i < project_materials.length; ++i) {
  18. let m: slot_material_t = project_materials[i];
  19. let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas));
  20. for (let i: i32 = 0; i < c.nodes.length; ++i) {
  21. let n: zui_node_t = c.nodes[i];
  22. export_arm_export_node(n);
  23. }
  24. array_push(mnodes, c);
  25. }
  26. let bnodes: zui_node_canvas_t[] = [];
  27. for (let i: i32 = 0; i < project_brushes.length; ++i) {
  28. let b: slot_brush_t = project_brushes[i];
  29. array_push(bnodes, b.canvas);
  30. }
  31. ///end
  32. ///if is_lab
  33. let c: zui_node_canvas_t = json_parse(json_stringify(project_canvas));
  34. for (let i: i32 = 0; i < c.nodes.length; ++i) {
  35. let n: zui_node_t = c.nodes[i];
  36. export_arm_export_node(n);
  37. }
  38. ///end
  39. let mgroups: zui_node_canvas_t[] = null;
  40. if (project_material_groups.length > 0) {
  41. mgroups = [];
  42. for (let i: i32 = 0; i < project_material_groups.length; ++i) {
  43. let g: node_group_t = project_material_groups[i];
  44. let c: zui_node_canvas_t = json_parse(json_stringify(g.canvas));
  45. for (let i: i32 = 0; i < c.nodes.length; ++i) {
  46. let n: zui_node_t = c.nodes[i];
  47. export_arm_export_node(n);
  48. }
  49. array_push(mgroups, c);
  50. }
  51. }
  52. ///if (is_paint || is_sculpt)
  53. let md: mesh_data_t[] = [];
  54. for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
  55. let p: mesh_object_t = project_paint_objects[i];
  56. array_push(md, p.data);
  57. }
  58. ///end
  59. ///if is_lab
  60. let md: mesh_data_t = project_paint_objects[0].data;
  61. ///end
  62. let texture_files: string[] = export_arm_assets_to_files(project_filepath, project_assets);
  63. ///if (is_paint || is_sculpt)
  64. let font_files: string[] = export_arm_fonts_to_files(project_filepath, project_fonts);
  65. let mesh_files: string[] = export_arm_meshes_to_files(project_filepath);
  66. let bits_pos: i32 = base_bits_handle.position;
  67. let bpp: i32 = bits_pos == texture_bits_t.BITS8 ? 8 : bits_pos == texture_bits_t.BITS16 ? 16 : 32;
  68. let ld: layer_data_t[] = [];
  69. for (let i: i32 = 0; i < project_layers.length; ++i) {
  70. let l: slot_layer_t = project_layers[i];
  71. array_push(ld, {
  72. name: l.name,
  73. res: l.texpaint != null ? l.texpaint.width : project_layers[0].texpaint.width,
  74. bpp: bpp,
  75. texpaint: l.texpaint != null ? lz4_encode(image_get_pixels(l.texpaint)) : null,
  76. uv_scale: l.scale,
  77. uv_rot: l.angle,
  78. uv_type: l.uv_type,
  79. decal_mat: l.uv_type == uv_type_t.PROJECT ? mat4_to_f32_array(l.decal_mat) : null,
  80. opacity_mask: l.mask_opacity,
  81. fill_layer: l.fill_layer != null ? array_index_of(project_materials, l.fill_layer) : -1,
  82. object_mask: l.object_mask,
  83. blending: l.blending,
  84. parent: l.parent != null ? array_index_of(project_layers, l.parent) : -1,
  85. visible: l.visible,
  86. ///if is_paint
  87. texpaint_nor: l.texpaint_nor != null ? lz4_encode(image_get_pixels(l.texpaint_nor)) : null,
  88. texpaint_pack: l.texpaint_pack != null ? lz4_encode(image_get_pixels(l.texpaint_pack)) : null,
  89. paint_base: l.paint_base,
  90. paint_opac: l.paint_opac,
  91. paint_occ: l.paint_occ,
  92. paint_rough: l.paint_rough,
  93. paint_met: l.paint_met,
  94. paint_nor: l.paint_nor,
  95. paint_nor_blend: l.paint_nor_blend,
  96. paint_height: l.paint_height,
  97. paint_height_blend: l.paint_height_blend,
  98. paint_emis: l.paint_emis,
  99. paint_subs: l.paint_subs
  100. ///end
  101. });
  102. }
  103. ///end
  104. let packed_assets: packed_asset_t[] = (project_raw.packed_assets == null || project_raw.packed_assets.length == 0) ? null : project_raw.packed_assets;
  105. ///if krom_ios
  106. let same_drive: bool = false;
  107. ///else
  108. let same_drive: bool = project_raw.envmap != null ? char_at(project_filepath, 0) == char_at(project_raw.envmap, 0) : true;
  109. ///end
  110. project_raw = {
  111. version: manifest_version,
  112. material_groups: mgroups,
  113. assets: texture_files,
  114. packed_assets: packed_assets,
  115. swatches: project_raw.swatches,
  116. envmap: project_raw.envmap != null ? (same_drive ? path_to_relative(project_filepath, project_raw.envmap) : project_raw.envmap) : null,
  117. envmap_strength: scene_world.strength,
  118. camera_world: mat4_to_f32_array(scene_camera.base.transform.local),
  119. camera_origin: export_arm_vec3f32(camera_origins[0]),
  120. camera_fov: scene_camera.data.fov,
  121. ///if (is_paint || is_sculpt)
  122. mesh_datas: md,
  123. material_nodes: mnodes,
  124. brush_nodes: bnodes,
  125. layer_datas: ld,
  126. font_assets: font_files,
  127. mesh_assets: mesh_files,
  128. ///end
  129. ///if is_paint
  130. atlas_objects: project_atlas_objects,
  131. atlas_names: project_atlas_names,
  132. ///end
  133. ///if is_lab
  134. mesh_data: md,
  135. material: c,
  136. ///end
  137. ///if (krom_metal || krom_vulkan)
  138. is_bgra: true
  139. ///else
  140. is_bgra: false
  141. ///end
  142. };
  143. ///if (krom_android || krom_ios)
  144. let tex: image_t = map_get(render_path_render_targets, context_raw.render_mode == render_mode_t.FORWARD ? "buf" : "tex")._image;
  145. let mesh_icon: image_t = image_create_render_target(256, 256);
  146. let r: f32 = app_w() / app_h();
  147. g2_begin(mesh_icon);
  148. ///if krom_opengl
  149. g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 256, 256 * r, -256);
  150. ///else
  151. g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 0, 256 * r, 256);
  152. ///end
  153. g2_end();
  154. ///if krom_metal
  155. // Flush command list
  156. g2_begin(mesh_icon);
  157. g2_end();
  158. ///end
  159. let mesh_icon_pixels: buffer_t = image_get_pixels(mesh_icon);
  160. let u8a: u8_array_t = u8_array_create_from_buffer(mesh_icon_pixels);
  161. for (let i: i32 = 0; i < 256 * 256 * 4; ++i) {
  162. u8a[i] = math_floor(math_pow(u8a[i] / 255, 1.0 / 2.2) * 255);
  163. }
  164. ///if (krom_metal || krom_vulkan)
  165. export_arm_bgra_swap(mesh_icon_pixels);
  166. ///end
  167. app_notify_on_next_frame(function () {
  168. image_unload(mesh_icon);
  169. });
  170. // raw.mesh_icons =
  171. // ///if (krom_metal || krom_vulkan)
  172. // [encode(bgraSwap(mesh_icon_pixels)];
  173. // ///else
  174. // [encode(mesh_icon_pixels)];
  175. // ///end
  176. krom_write_png(substring(project_filepath, 0, project_filepath.length - 4) + "_icon.png", mesh_icon_pixels, 256, 256, 0);
  177. ///end
  178. ///if (is_paint || is_sculpt)
  179. let is_packed: bool = ends_with(project_filepath, "_packed_.arm");
  180. if (is_packed) { // Pack textures
  181. export_arm_pack_assets(project_raw, project_assets);
  182. }
  183. ///end
  184. let buffer: buffer_t = armpack_encode(project_raw);
  185. krom_file_save_bytes(project_filepath, buffer, buffer_size(buffer) + 1);
  186. // Save to recent
  187. ///if krom_ios
  188. let recent_path: string = substring(project_filepath, string_last_index_of(project_filepath, "/") + 1, project_filepath.length);
  189. ///else
  190. let recent_path: string = project_filepath;
  191. ///end
  192. let recent: string[] = config_raw.recent_projects;
  193. array_remove(recent, recent_path);
  194. recent.unshift(recent_path);
  195. config_save();
  196. console_info(tr("Project saved"));
  197. }
  198. function export_arm_texture_node_name(): string {
  199. ///if (is_paint || is_sculpt)
  200. return "TEX_IMAGE";
  201. ///else
  202. return "ImageTextureNode";
  203. ///end
  204. }
  205. function export_arm_export_node(n: zui_node_t, assets: asset_t[] = null) {
  206. if (n.type == export_arm_texture_node_name()) {
  207. let index: i32 = n.buttons[0].default_value[0];
  208. n.buttons[0].data = u8_array_create_from_string(base_enum_texts(n.type)[index]);
  209. if (assets != null) {
  210. let asset: asset_t = project_assets[index];
  211. if (array_index_of(assets, asset) == -1) {
  212. array_push(assets, asset);
  213. }
  214. }
  215. }
  216. // Pack colors
  217. if (n.color > 0) {
  218. n.color -= 4294967296;
  219. }
  220. for (let i: i32 = 0; i < n.inputs.length; ++i) {
  221. let inp: zui_node_socket_t = n.inputs[i];
  222. if (inp.color > 0) {
  223. inp.color -= 4294967296;
  224. }
  225. }
  226. for (let i: i32 = 0; i < n.outputs.length; ++i) {
  227. let out: zui_node_socket_t = n.outputs[i];
  228. if (out.color > 0) {
  229. out.color -= 4294967296;
  230. }
  231. }
  232. }
  233. ///if (is_paint || is_sculpt)
  234. function export_arm_run_material(path: string) {
  235. if (!ends_with(path, ".arm")) path += ".arm";
  236. let mnodes: zui_node_canvas_t[] = [];
  237. let mgroups: zui_node_canvas_t[] = null;
  238. let m: slot_material_t = context_raw.material;
  239. let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas));
  240. let assets: asset_t[] = [];
  241. if (ui_nodes_has_group(c)) {
  242. mgroups = [];
  243. ui_nodes_traverse_group(mgroups, c);
  244. for (let i: i32 = 0; i < mgroups.length; ++i) {
  245. let gc: zui_node_canvas_t = mgroups[i];
  246. for (let i: i32 = 0; i < gc.nodes.length; ++i) {
  247. let n: zui_node_t = gc.nodes[i];
  248. export_arm_export_node(n, assets);
  249. }
  250. }
  251. }
  252. for (let i: i32 = 0; i < c.nodes.length; ++i) {
  253. let n: zui_node_t = c.nodes[i];
  254. export_arm_export_node(n, assets);
  255. }
  256. array_push(mnodes, c);
  257. let texture_files: string[] = export_arm_assets_to_files(path, assets);
  258. let is_cloud: bool = ends_with(path, "_cloud_.arm");
  259. if (is_cloud) {
  260. path = string_replace_all(path, "_cloud_", "");
  261. }
  262. let packed_assets: packed_asset_t[] = null;
  263. if (!context_raw.pack_assets_on_export) {
  264. packed_assets = export_arm_get_packed_assets(path, texture_files);
  265. }
  266. let micons: buffer_t[] = null;
  267. if (!is_cloud) {
  268. ///if (krom_metal || krom_vulkan)
  269. micons = [lz4_encode(export_arm_bgra_swap(image_get_pixels(m.image)))];
  270. ///else
  271. micons = [lz4_encode(image_get_pixels(m.image))];
  272. ///end
  273. }
  274. let raw: project_format_t = {
  275. version: manifest_version,
  276. material_nodes: mnodes,
  277. material_groups: mgroups,
  278. material_icons: micons,
  279. assets: texture_files,
  280. packed_assets: packed_assets
  281. };
  282. if (context_raw.write_icon_on_export) { // Separate icon files
  283. krom_write_png(substring(path, 0, path.length - 4) + "_icon.png", image_get_pixels(m.image), m.image.width, m.image.height, 0);
  284. if (is_cloud) {
  285. krom_write_jpg(substring(path, 0, path.length - 4) + "_icon.jpg", image_get_pixels(m.image), m.image.width, m.image.height, 0, 50);
  286. }
  287. }
  288. if (context_raw.pack_assets_on_export) { // Pack textures
  289. export_arm_pack_assets(raw, assets);
  290. }
  291. let buffer: buffer_t = armpack_encode(raw);
  292. krom_file_save_bytes(path, buffer, buffer_size(buffer) + 1);
  293. }
  294. ///end
  295. ///if (krom_metal || krom_vulkan)
  296. function export_arm_bgra_swap(buffer: buffer_t) {
  297. let view: buffer_view_t = buffer_view_create(buffer);
  298. for (let i: i32 = 0; i < math_floor(buffer_size(buffer) / 4); ++i) {
  299. let r: i32 = buffer_view_get_u8(view, i * 4);
  300. buffer_view_set_u8(view, i * 4, buffer_view_get_u8(view, i * 4 + 2));
  301. buffer_view_set_u8(view, i * 4 + 2, r);
  302. }
  303. return buffer;
  304. }
  305. ///end
  306. ///if (is_paint || is_sculpt)
  307. function export_arm_run_brush(path: string) {
  308. if (!ends_with(path, ".arm")) {
  309. path += ".arm";
  310. }
  311. let bnodes: zui_node_canvas_t[] = [];
  312. let b: slot_brush_t = context_raw.brush;
  313. let c: zui_node_canvas_t = json_parse(json_stringify(b.canvas));
  314. let assets: asset_t[] = [];
  315. for (let i: i32 = 0; i < c.nodes.length; ++i) {
  316. let n: zui_node_t = c.nodes[i];
  317. export_arm_export_node(n, assets);
  318. }
  319. array_push(bnodes, c);
  320. let texture_files: string[] = export_arm_assets_to_files(path, assets);
  321. let is_cloud: bool = ends_with(path, "_cloud_.arm");
  322. if (is_cloud) {
  323. path = string_replace_all(path, "_cloud_", "");
  324. }
  325. let packed_assets: packed_asset_t[] = null;
  326. if (!context_raw.pack_assets_on_export) {
  327. packed_assets = export_arm_get_packed_assets(path, texture_files);
  328. }
  329. let bicons: buffer_t[] = null;
  330. if (!is_cloud) {
  331. ///if (krom_metal || krom_vulkan)
  332. bicons = [lz4_encode(export_arm_bgra_swap(image_get_pixels(b.image)))];
  333. ///else
  334. bicons = [lz4_encode(image_get_pixels(b.image))];
  335. ///end
  336. }
  337. let raw: project_format_t = {
  338. version: manifest_version,
  339. brush_nodes: bnodes,
  340. brush_icons: bicons,
  341. assets: texture_files,
  342. packed_assets: packed_assets
  343. };
  344. if (context_raw.write_icon_on_export) { // Separate icon file
  345. krom_write_png(substring(path, 0, path.length - 4) + "_icon.png", image_get_pixels(b.image), b.image.width, b.image.height, 0);
  346. }
  347. if (context_raw.pack_assets_on_export) { // Pack textures
  348. export_arm_pack_assets(raw, assets);
  349. }
  350. let buffer: buffer_t = armpack_encode(raw);
  351. krom_file_save_bytes(path, buffer, buffer_size(buffer) + 1);
  352. }
  353. ///end
  354. function export_arm_assets_to_files(project_path: string, assets: asset_t[]): string[] {
  355. let texture_files: string[] = [];
  356. for (let i: i32 = 0; i < assets.length; ++i) {
  357. let a: asset_t = assets[i];
  358. ///if krom_ios
  359. let same_drive: bool = false;
  360. ///else
  361. let same_drive: bool = char_at(project_path, 0) == char_at(a.file, 0);
  362. ///end
  363. // Convert image path from absolute to relative
  364. if (same_drive) {
  365. array_push(texture_files, path_to_relative(project_path, a.file));
  366. }
  367. else {
  368. array_push(texture_files, a.file);
  369. }
  370. }
  371. return texture_files;
  372. }
  373. ///if (is_paint || is_sculpt)
  374. function export_arm_meshes_to_files(project_path: string): string[] {
  375. let mesh_files: string[] = [];
  376. for (let i: i32 = 0; i < project_mesh_assets.length; ++i) {
  377. let file: string = project_mesh_assets[i];
  378. ///if krom_ios
  379. let same_drive: bool = false;
  380. ///else
  381. let same_drive: bool = char_at(project_path, 0) == char_at(file, 0);
  382. ///end
  383. // Convert mesh path from absolute to relative
  384. if (same_drive) {
  385. array_push(mesh_files, path_to_relative(project_path, file));
  386. }
  387. else {
  388. array_push(mesh_files, file);
  389. }
  390. }
  391. return mesh_files;
  392. }
  393. function export_arm_fonts_to_files(project_path: string, fonts: slot_font_t[]): string[] {
  394. let font_files: string[] = [];
  395. for (let i = 1; i <fonts.length; ++i) {
  396. let f: slot_font_t = fonts[i];
  397. ///if krom_ios
  398. let same_drive: bool = false;
  399. ///else
  400. let same_drive: bool = char_at(project_path, 0) == char_at(f.file, 0);
  401. ///end
  402. // Convert font path from absolute to relative
  403. if (same_drive) {
  404. array_push(font_files, path_to_relative(project_path, f.file));
  405. }
  406. else {
  407. array_push(font_files, f.file);
  408. }
  409. }
  410. return font_files;
  411. }
  412. ///end
  413. function export_arm_get_packed_assets(project_path: string, texture_files: string[]): packed_asset_t[] {
  414. let packed_assets: packed_asset_t[] = null;
  415. if (project_raw.packed_assets != null) {
  416. for (let i: i32 = 0; i < project_raw.packed_assets.length; ++i) {
  417. let pa: packed_asset_t = project_raw.packed_assets[i];
  418. ///if krom_ios
  419. let same_drive: bool = false;
  420. ///else
  421. let same_drive: bool = char_at(project_path, 0) == char_at(pa.name, 0);
  422. ///end
  423. // Convert path from absolute to relative
  424. pa.name = same_drive ? path_to_relative(project_path, pa.name) : pa.name;
  425. for (let i: i32 = 0; i < texture_files.length; ++i) {
  426. let tf: string = texture_files[i];
  427. if (pa.name == tf) {
  428. if (packed_assets == null) {
  429. packed_assets = [];
  430. }
  431. array_push(packed_assets, pa);
  432. break;
  433. }
  434. }
  435. }
  436. }
  437. return packed_assets;
  438. }
  439. function export_arm_pack_assets(raw: project_format_t, assets: asset_t[]) {
  440. if (raw.packed_assets == null) {
  441. raw.packed_assets = [];
  442. }
  443. let temp_images: image_t[] = [];
  444. for (let i: i32 = 0; i < assets.length; ++i) {
  445. if (!project_packed_asset_exists(raw.packed_assets, assets[i].file)) {
  446. let image: image_t = project_get_image(assets[i]);
  447. let temp: image_t = image_create_render_target(image.width, image.height);
  448. g2_begin(temp);
  449. g2_draw_image(image, 0, 0);
  450. g2_end();
  451. array_push(temp_images, temp);
  452. array_push(raw.packed_assets, {
  453. name: assets[i].file,
  454. bytes: ends_with(assets[i].file, ".jpg") ?
  455. krom_encode_jpg(image_get_pixels(temp), temp.width, temp.height, 0, 80) :
  456. krom_encode_png(image_get_pixels(temp), temp.width, temp.height, 0)
  457. });
  458. }
  459. }
  460. app_notify_on_next_frame(function (temp_images: image_t[]) {
  461. for (let i: i32 = 0; i < temp_images.length; ++i) {
  462. let image: image_t = temp_images[i];
  463. image_unload(image);
  464. }
  465. }, temp_images);
  466. }
  467. function export_arm_run_swatches(path: string) {
  468. if (!ends_with(path, ".arm")) {
  469. path += ".arm";
  470. }
  471. let raw: any = {
  472. version: manifest_version,
  473. swatches: project_raw.swatches
  474. };
  475. let buffer: buffer_t = armpack_encode(raw);
  476. krom_file_save_bytes(path, buffer, buffer_size(buffer) + 1);
  477. }
  478. function export_arm_vec3f32(v: vec4_t): f32_array_t {
  479. let res: f32_array_t = f32_array_create(3);
  480. res[0] = v.x;
  481. res[1] = v.y;
  482. res[2] = v.z;
  483. return res;
  484. }