function export_arm_run_mesh(path: string, paint_objects: mesh_object_t[]) { let mesh_datas: mesh_data_t[] = []; for (let i: i32 = 0; i < paint_objects.length; ++i) { let p: mesh_object_t = paint_objects[i]; array_push(mesh_datas, p.data); } let raw: scene_t = { mesh_datas: mesh_datas }; let b: buffer_t = armpack_encode(raw); if (!ends_with(path, ".arm")) { path += ".arm"; } krom_file_save_bytes(path, b, buffer_size(b) + 1); } function export_arm_run_project() { ///if (is_paint || is_sculpt) let mnodes: zui_node_canvas_t[] = []; for (let i: i32 = 0; i < project_materials.length; ++i) { let m: slot_material_t = project_materials[i]; let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas)); for (let i: i32 = 0; i < c.nodes.length; ++i) { let n: zui_node_t = c.nodes[i]; export_arm_export_node(n); } array_push(mnodes, c); } let bnodes: zui_node_canvas_t[] = []; for (let i: i32 = 0; i < project_brushes.length; ++i) { let b: slot_brush_t = project_brushes[i]; array_push(bnodes, b.canvas); } ///end ///if is_lab let c: zui_node_canvas_t = json_parse(json_stringify(project_canvas)); for (let i: i32 = 0; i < c.nodes.length; ++i) { let n: zui_node_t = c.nodes[i]; export_arm_export_node(n); } ///end let mgroups: zui_node_canvas_t[] = null; if (project_material_groups.length > 0) { mgroups = []; for (let i: i32 = 0; i < project_material_groups.length; ++i) { let g: node_group_t = project_material_groups[i]; let c: zui_node_canvas_t = json_parse(json_stringify(g.canvas)); for (let i: i32 = 0; i < c.nodes.length; ++i) { let n: zui_node_t = c.nodes[i]; export_arm_export_node(n); } array_push(mgroups, c); } } ///if (is_paint || is_sculpt) let md: mesh_data_t[] = []; for (let i: i32 = 0; i < project_paint_objects.length; ++i) { let p: mesh_object_t = project_paint_objects[i]; array_push(md, p.data); } ///end ///if is_lab let md: mesh_data_t = project_paint_objects[0].data; ///end let texture_files: string[] = export_arm_assets_to_files(project_filepath, project_assets); ///if (is_paint || is_sculpt) let font_files: string[] = export_arm_fonts_to_files(project_filepath, project_fonts); let mesh_files: string[] = export_arm_meshes_to_files(project_filepath); let bits_pos: i32 = base_bits_handle.position; let bpp: i32 = bits_pos == texture_bits_t.BITS8 ? 8 : bits_pos == texture_bits_t.BITS16 ? 16 : 32; let ld: layer_data_t[] = []; for (let i: i32 = 0; i < project_layers.length; ++i) { let l: slot_layer_t = project_layers[i]; array_push(ld, { name: l.name, res: l.texpaint != null ? l.texpaint.width : project_layers[0].texpaint.width, bpp: bpp, texpaint: l.texpaint != null ? lz4_encode(image_get_pixels(l.texpaint)) : null, uv_scale: l.scale, uv_rot: l.angle, uv_type: l.uv_type, decal_mat: l.uv_type == uv_type_t.PROJECT ? mat4_to_f32_array(l.decal_mat) : null, opacity_mask: l.mask_opacity, fill_layer: l.fill_layer != null ? array_index_of(project_materials, l.fill_layer) : -1, object_mask: l.object_mask, blending: l.blending, parent: l.parent != null ? array_index_of(project_layers, l.parent) : -1, visible: l.visible, ///if is_paint texpaint_nor: l.texpaint_nor != null ? lz4_encode(image_get_pixels(l.texpaint_nor)) : null, texpaint_pack: l.texpaint_pack != null ? lz4_encode(image_get_pixels(l.texpaint_pack)) : null, paint_base: l.paint_base, paint_opac: l.paint_opac, paint_occ: l.paint_occ, paint_rough: l.paint_rough, paint_met: l.paint_met, paint_nor: l.paint_nor, paint_nor_blend: l.paint_nor_blend, paint_height: l.paint_height, paint_height_blend: l.paint_height_blend, paint_emis: l.paint_emis, paint_subs: l.paint_subs ///end }); } ///end let packed_assets: packed_asset_t[] = (project_raw.packed_assets == null || project_raw.packed_assets.length == 0) ? null : project_raw.packed_assets; ///if krom_ios let same_drive: bool = false; ///else let same_drive: bool = project_raw.envmap != null ? char_at(project_filepath, 0) == char_at(project_raw.envmap, 0) : true; ///end project_raw = { version: manifest_version, material_groups: mgroups, assets: texture_files, packed_assets: packed_assets, swatches: project_raw.swatches, envmap: project_raw.envmap != null ? (same_drive ? path_to_relative(project_filepath, project_raw.envmap) : project_raw.envmap) : null, envmap_strength: scene_world.strength, camera_world: mat4_to_f32_array(scene_camera.base.transform.local), camera_origin: export_arm_vec3f32(camera_origins[0]), camera_fov: scene_camera.data.fov, ///if (is_paint || is_sculpt) mesh_datas: md, material_nodes: mnodes, brush_nodes: bnodes, layer_datas: ld, font_assets: font_files, mesh_assets: mesh_files, ///end ///if is_paint atlas_objects: project_atlas_objects, atlas_names: project_atlas_names, ///end ///if is_lab mesh_data: md, material: c, ///end ///if (krom_metal || krom_vulkan) is_bgra: true ///else is_bgra: false ///end }; ///if (krom_android || krom_ios) let tex: image_t = map_get(render_path_render_targets, context_raw.render_mode == render_mode_t.FORWARD ? "buf" : "tex")._image; let mesh_icon: image_t = image_create_render_target(256, 256); let r: f32 = app_w() / app_h(); g2_begin(mesh_icon); ///if krom_opengl g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 256, 256 * r, -256); ///else g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 0, 256 * r, 256); ///end g2_end(); ///if krom_metal // Flush command list g2_begin(mesh_icon); g2_end(); ///end let mesh_icon_pixels: buffer_t = image_get_pixels(mesh_icon); let u8a: u8_array_t = u8_array_create_from_buffer(mesh_icon_pixels); for (let i: i32 = 0; i < 256 * 256 * 4; ++i) { u8a[i] = math_floor(math_pow(u8a[i] / 255, 1.0 / 2.2) * 255); } ///if (krom_metal || krom_vulkan) export_arm_bgra_swap(mesh_icon_pixels); ///end app_notify_on_next_frame(function () { image_unload(mesh_icon); }); // raw.mesh_icons = // ///if (krom_metal || krom_vulkan) // [encode(bgraSwap(mesh_icon_pixels)]; // ///else // [encode(mesh_icon_pixels)]; // ///end krom_write_png(substring(project_filepath, 0, project_filepath.length - 4) + "_icon.png", mesh_icon_pixels, 256, 256, 0); ///end ///if (is_paint || is_sculpt) let is_packed: bool = ends_with(project_filepath, "_packed_.arm"); if (is_packed) { // Pack textures export_arm_pack_assets(project_raw, project_assets); } ///end let buffer: buffer_t = armpack_encode(project_raw); krom_file_save_bytes(project_filepath, buffer, buffer_size(buffer) + 1); // Save to recent ///if krom_ios let recent_path: string = substring(project_filepath, string_last_index_of(project_filepath, "/") + 1, project_filepath.length); ///else let recent_path: string = project_filepath; ///end let recent: string[] = config_raw.recent_projects; array_remove(recent, recent_path); recent.unshift(recent_path); config_save(); console_info(tr("Project saved")); } function export_arm_texture_node_name(): string { ///if (is_paint || is_sculpt) return "TEX_IMAGE"; ///else return "ImageTextureNode"; ///end } function export_arm_export_node(n: zui_node_t, assets: asset_t[] = null) { if (n.type == export_arm_texture_node_name()) { let index: i32 = n.buttons[0].default_value[0]; n.buttons[0].data = u8_array_create_from_string(base_enum_texts(n.type)[index]); if (assets != null) { let asset: asset_t = project_assets[index]; if (array_index_of(assets, asset) == -1) { array_push(assets, asset); } } } // Pack colors if (n.color > 0) { n.color -= 4294967296; } for (let i: i32 = 0; i < n.inputs.length; ++i) { let inp: zui_node_socket_t = n.inputs[i]; if (inp.color > 0) { inp.color -= 4294967296; } } for (let i: i32 = 0; i < n.outputs.length; ++i) { let out: zui_node_socket_t = n.outputs[i]; if (out.color > 0) { out.color -= 4294967296; } } } ///if (is_paint || is_sculpt) function export_arm_run_material(path: string) { if (!ends_with(path, ".arm")) path += ".arm"; let mnodes: zui_node_canvas_t[] = []; let mgroups: zui_node_canvas_t[] = null; let m: slot_material_t = context_raw.material; let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas)); let assets: asset_t[] = []; if (ui_nodes_has_group(c)) { mgroups = []; ui_nodes_traverse_group(mgroups, c); for (let i: i32 = 0; i < mgroups.length; ++i) { let gc: zui_node_canvas_t = mgroups[i]; for (let i: i32 = 0; i < gc.nodes.length; ++i) { let n: zui_node_t = gc.nodes[i]; export_arm_export_node(n, assets); } } } for (let i: i32 = 0; i < c.nodes.length; ++i) { let n: zui_node_t = c.nodes[i]; export_arm_export_node(n, assets); } array_push(mnodes, c); let texture_files: string[] = export_arm_assets_to_files(path, assets); let is_cloud: bool = ends_with(path, "_cloud_.arm"); if (is_cloud) { path = string_replace_all(path, "_cloud_", ""); } let packed_assets: packed_asset_t[] = null; if (!context_raw.pack_assets_on_export) { packed_assets = export_arm_get_packed_assets(path, texture_files); } let micons: buffer_t[] = null; if (!is_cloud) { ///if (krom_metal || krom_vulkan) micons = [lz4_encode(export_arm_bgra_swap(image_get_pixels(m.image)))]; ///else micons = [lz4_encode(image_get_pixels(m.image))]; ///end } let raw: project_format_t = { version: manifest_version, material_nodes: mnodes, material_groups: mgroups, material_icons: micons, assets: texture_files, packed_assets: packed_assets }; if (context_raw.write_icon_on_export) { // Separate icon files krom_write_png(substring(path, 0, path.length - 4) + "_icon.png", image_get_pixels(m.image), m.image.width, m.image.height, 0); if (is_cloud) { krom_write_jpg(substring(path, 0, path.length - 4) + "_icon.jpg", image_get_pixels(m.image), m.image.width, m.image.height, 0, 50); } } if (context_raw.pack_assets_on_export) { // Pack textures export_arm_pack_assets(raw, assets); } let buffer: buffer_t = armpack_encode(raw); krom_file_save_bytes(path, buffer, buffer_size(buffer) + 1); } ///end ///if (krom_metal || krom_vulkan) function export_arm_bgra_swap(buffer: buffer_t) { let view: buffer_view_t = buffer_view_create(buffer); for (let i: i32 = 0; i < math_floor(buffer_size(buffer) / 4); ++i) { let r: i32 = buffer_view_get_u8(view, i * 4); buffer_view_set_u8(view, i * 4, buffer_view_get_u8(view, i * 4 + 2)); buffer_view_set_u8(view, i * 4 + 2, r); } return buffer; } ///end ///if (is_paint || is_sculpt) function export_arm_run_brush(path: string) { if (!ends_with(path, ".arm")) { path += ".arm"; } let bnodes: zui_node_canvas_t[] = []; let b: slot_brush_t = context_raw.brush; let c: zui_node_canvas_t = json_parse(json_stringify(b.canvas)); let assets: asset_t[] = []; for (let i: i32 = 0; i < c.nodes.length; ++i) { let n: zui_node_t = c.nodes[i]; export_arm_export_node(n, assets); } array_push(bnodes, c); let texture_files: string[] = export_arm_assets_to_files(path, assets); let is_cloud: bool = ends_with(path, "_cloud_.arm"); if (is_cloud) { path = string_replace_all(path, "_cloud_", ""); } let packed_assets: packed_asset_t[] = null; if (!context_raw.pack_assets_on_export) { packed_assets = export_arm_get_packed_assets(path, texture_files); } let bicons: buffer_t[] = null; if (!is_cloud) { ///if (krom_metal || krom_vulkan) bicons = [lz4_encode(export_arm_bgra_swap(image_get_pixels(b.image)))]; ///else bicons = [lz4_encode(image_get_pixels(b.image))]; ///end } let raw: project_format_t = { version: manifest_version, brush_nodes: bnodes, brush_icons: bicons, assets: texture_files, packed_assets: packed_assets }; if (context_raw.write_icon_on_export) { // Separate icon file krom_write_png(substring(path, 0, path.length - 4) + "_icon.png", image_get_pixels(b.image), b.image.width, b.image.height, 0); } if (context_raw.pack_assets_on_export) { // Pack textures export_arm_pack_assets(raw, assets); } let buffer: buffer_t = armpack_encode(raw); krom_file_save_bytes(path, buffer, buffer_size(buffer) + 1); } ///end function export_arm_assets_to_files(project_path: string, assets: asset_t[]): string[] { let texture_files: string[] = []; for (let i: i32 = 0; i < assets.length; ++i) { let a: asset_t = assets[i]; ///if krom_ios let same_drive: bool = false; ///else let same_drive: bool = char_at(project_path, 0) == char_at(a.file, 0); ///end // Convert image path from absolute to relative if (same_drive) { array_push(texture_files, path_to_relative(project_path, a.file)); } else { array_push(texture_files, a.file); } } return texture_files; } ///if (is_paint || is_sculpt) function export_arm_meshes_to_files(project_path: string): string[] { let mesh_files: string[] = []; for (let i: i32 = 0; i < project_mesh_assets.length; ++i) { let file: string = project_mesh_assets[i]; ///if krom_ios let same_drive: bool = false; ///else let same_drive: bool = char_at(project_path, 0) == char_at(file, 0); ///end // Convert mesh path from absolute to relative if (same_drive) { array_push(mesh_files, path_to_relative(project_path, file)); } else { array_push(mesh_files, file); } } return mesh_files; } function export_arm_fonts_to_files(project_path: string, fonts: slot_font_t[]): string[] { let font_files: string[] = []; for (let i = 1; i