BoxExport.hx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package arm.ui;
  2. import haxe.io.Bytes;
  3. import zui.Zui;
  4. import zui.Id;
  5. import arm.util.UVUtil;
  6. import arm.io.ExportMesh;
  7. import arm.io.ExportTexture;
  8. import arm.sys.Path;
  9. import arm.sys.File;
  10. import arm.Tool;
  11. using StringTools;
  12. class BoxExport {
  13. public static var htab = Id.handle();
  14. public static var hpreset = Id.handle();
  15. public static var files: Array<String> = null;
  16. public static var preset: TExportPreset = null;
  17. static var channels = ["base_r", "base_g", "base_b", "height", "metal", "nor_r", "nor_g", "nor_b", "occ", "opac", "rough", "smooth", "0.0", "1.0"];
  18. public static function showTextures() {
  19. UIBox.showCustom(function(ui: Zui) {
  20. if (files == null) fetchPresets();
  21. if (preset == null) {
  22. parsePreset();
  23. @:privateAccess hpreset.children = null;
  24. }
  25. if (ui.tab(htab, "Export Textures")) {
  26. ui.row([0.5, 0.5]);
  27. ui.combo(App.resHandle, ["128", "256", "512", "1K", "2K", "4K", "8K", "16K"], "Res", true);
  28. if (App.resHandle.changed) {
  29. iron.App.notifyOnRender(Layers.resizeLayers);
  30. UVUtil.uvmap = null;
  31. UVUtil.uvmapCached = false;
  32. UVUtil.trianglemap = null;
  33. UVUtil.trianglemapCached = false;
  34. #if kha_direct3d12
  35. arm.render.RenderPathRaytrace.ready = false;
  36. #end
  37. }
  38. ui.combo(App.bitsHandle, ["8bit", "16bit", "32bit"], "Color", true);
  39. if (App.bitsHandle.changed) {
  40. iron.App.notifyOnRender(Layers.setLayerBits);
  41. }
  42. ui.row([0.5, 0.5]);
  43. if (App.bitsHandle.position == Bits8) {
  44. UITrait.inst.formatType = ui.combo(Id.handle({position: UITrait.inst.formatType}), ["png", "jpg"], "Format", true);
  45. }
  46. else {
  47. UITrait.inst.formatType = ui.combo(Id.handle({position: UITrait.inst.formatType}), ["exr"], "Format", true);
  48. }
  49. ui.enabled = UITrait.inst.formatType == FormatJpg && App.bitsHandle.position == Bits8;
  50. UITrait.inst.formatQuality = ui.slider(Id.handle({value: UITrait.inst.formatQuality}), "Quality", 0.0, 100.0, true, 1);
  51. ui.enabled = true;
  52. ui.row([0.5, 0.5]);
  53. UITrait.inst.layersExport = ui.combo(Id.handle({position: UITrait.inst.layersExport}), ["Visible", "Selected"], "Layers", true);
  54. ui.combo(hpreset, files, "Preset", true);
  55. if (hpreset.changed) preset = null;
  56. @:privateAccess ui.endElement();
  57. ui.row([0.5, 0.5]);
  58. if (ui.button("Cancel")) {
  59. UIBox.show = false;
  60. }
  61. if (ui.button("Export")) {
  62. UIBox.show = false;
  63. var filters = App.bitsHandle.position != Bits8 ? "exr" : UITrait.inst.formatType == FormatPng ? "png" : "jpg";
  64. UIFiles.show(filters, true, function(path: String) {
  65. UITrait.inst.textureExportPath = path;
  66. function export(_) {
  67. ExportTexture.run(path);
  68. iron.App.removeRender(export);
  69. }
  70. iron.App.notifyOnRender(export);
  71. });
  72. }
  73. if (ui.isHovered) ui.tooltip("Export texture files (" + Config.keymap.file_export_textures + ")");
  74. }
  75. if (ui.tab(htab, "Presets")) {
  76. ui.row([3 / 5, 1 / 5, 1 / 5]);
  77. ui.combo(hpreset, files, "Preset");
  78. if (hpreset.changed) preset = null;
  79. if (ui.button("New")) {
  80. UIBox.showCustom(function(ui: Zui) {
  81. if (ui.tab(Id.handle(), "New Preset")) {
  82. ui.row([0.5, 0.5]);
  83. var presetName = ui.textInput(Id.handle({text: "new_preset"}), "Name");
  84. if (ui.button("OK") || ui.isReturnDown) {
  85. newPreset(presetName);
  86. fetchPresets();
  87. preset = null;
  88. hpreset.position = files.indexOf(presetName);
  89. UIBox.show = false;
  90. BoxExport.htab.position = 1; // Presets
  91. BoxExport.showTextures();
  92. }
  93. }
  94. });
  95. }
  96. if (ui.button("Import")) {
  97. UIFiles.show("json", false, function(path: String) {
  98. path = path.toLowerCase();
  99. if (path.endsWith(".json")) {
  100. var filename = path.substr(path.lastIndexOf(Path.sep) + 1);
  101. var dstPath = Path.data() + Path.sep + "export_presets" + Path.sep + filename;
  102. File.copy(path, dstPath); // Copy to presets folder
  103. fetchPresets();
  104. preset = null;
  105. hpreset.position = files.indexOf(filename.substr(0, filename.length - 5)); // Strip .json
  106. Log.info("Preset '" + filename + "' imported.");
  107. }
  108. else Log.error(Strings.error1);
  109. });
  110. }
  111. if (preset == null) {
  112. parsePreset();
  113. @:privateAccess hpreset.children = null;
  114. }
  115. // Texture list
  116. ui.separator(10, false);
  117. ui.row([0.2, 0.2, 0.2, 0.2, 0.2]);
  118. ui.text("Texture");
  119. ui.text("R");
  120. ui.text("G");
  121. ui.text("B");
  122. ui.text("A");
  123. ui.changed = false;
  124. for (i in 0...preset.textures.length) {
  125. var t = preset.textures[i];
  126. ui.row([0.2, 0.2, 0.2, 0.2, 0.2]);
  127. var htex = hpreset.nest(i, {text: t.name});
  128. t.name = ui.textInput(htex);
  129. if (ui.isHovered && ui.inputReleasedR) {
  130. UIMenu.draw(function(ui: Zui) {
  131. ui.fill(0, 0, @:privateAccess ui._w / ui.SCALE(), ui.t.ELEMENT_H * 2, ui.t.SEPARATOR_COL);
  132. ui.text(t.name, Right, ui.t.HIGHLIGHT_COL);
  133. if (ui.button("Delete", Left)) {
  134. preset.textures.remove(t);
  135. savePreset();
  136. }
  137. });
  138. }
  139. var hr = htex.nest(0, {position: channels.indexOf(t.channels[0])});
  140. var hg = htex.nest(1, {position: channels.indexOf(t.channels[1])});
  141. var hb = htex.nest(2, {position: channels.indexOf(t.channels[2])});
  142. var ha = htex.nest(3, {position: channels.indexOf(t.channels[3])});
  143. ui.combo(hr, channels, "R");
  144. if (hr.changed) t.channels[0] = channels[hr.position];
  145. ui.combo(hg, channels, "G");
  146. if (hg.changed) t.channels[1] = channels[hg.position];
  147. ui.combo(hb, channels, "B");
  148. if (hb.changed) t.channels[2] = channels[hb.position];
  149. ui.combo(ha, channels, "A");
  150. if (ha.changed) t.channels[3] = channels[ha.position];
  151. }
  152. if (ui.changed) {
  153. savePreset();
  154. }
  155. ui.row([1 / 8]);
  156. if (ui.button("Add")) {
  157. preset.textures.push({name: "base", channels: ["base_r", "base_g", "base_b", "1.0"]});
  158. @:privateAccess hpreset.children = null;
  159. savePreset();
  160. }
  161. }
  162. }, 500, 310);
  163. }
  164. public static function showMesh() {
  165. UIBox.showCustom(function(ui: Zui) {
  166. var htab = Id.handle();
  167. if (ui.tab(htab, "Export Mesh")) {
  168. UITrait.inst.exportMeshFormat = ui.combo(Id.handle({position: UITrait.inst.exportMeshFormat}), ["obj", "arm"], "Format", true);
  169. var mesh = Context.paintObject.data.raw;
  170. var inda = mesh.index_arrays[0].values;
  171. var tris = Std.int(inda.length / 3);
  172. ui.text(tris + " triangles");
  173. @:privateAccess ui.endElement();
  174. ui.row([0.5, 0.5]);
  175. if (ui.button("Cancel")) {
  176. UIBox.show = false;
  177. }
  178. if (ui.button("Export")) {
  179. UIBox.show = false;
  180. UIFiles.show(UITrait.inst.exportMeshFormat == FormatObj ? "obj" : "arm", true, function(path: String) {
  181. var f = UIFiles.filename;
  182. if (f == "") f = "untitled";
  183. ExportMesh.run(path + "/" + f);
  184. });
  185. }
  186. }
  187. });
  188. }
  189. static function fetchPresets() {
  190. files = File.readDirectory(Path.data() + Path.sep + "export_presets");
  191. for (i in 0...files.length) {
  192. files[i] = files[i].substr(0, files[i].length - 5); // Strip .json
  193. }
  194. }
  195. static function parsePreset() {
  196. var file = "export_presets/" + files[hpreset.position] + ".json";
  197. iron.data.Data.getBlob(file, function(blob: kha.Blob) {
  198. preset = haxe.Json.parse(blob.toString());
  199. iron.data.Data.deleteBlob("export_presets/" + file);
  200. });
  201. }
  202. static function newPreset(name: String) {
  203. var template =
  204. '{
  205. "textures": [
  206. { "name": "base", "channels": ["base_r", "base_g", "base_b", "1.0"] }
  207. ]
  208. }
  209. ';
  210. if (!name.endsWith(".json")) name += ".json";
  211. var path = Path.data() + Path.sep + "export_presets" + Path.sep + name;
  212. Krom.fileSaveBytes(path, Bytes.ofString(template).getData());
  213. }
  214. static function savePreset() {
  215. var name = files[hpreset.position];
  216. if (name == "generic") return; // generic is const
  217. var path = Path.data() + Path.sep + "export_presets" + Path.sep + name + ".json";
  218. Krom.fileSaveBytes(path, Bytes.ofString(haxe.Json.stringify(preset)).getData());
  219. }
  220. }