export_arm.ts 16 KB

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