376 lines
11 KiB
Haxe
376 lines
11 KiB
Haxe
package arm.ui;
|
|
|
|
import haxe.io.Bytes;
|
|
import zui.Zui;
|
|
import zui.Id;
|
|
import arm.util.UVUtil;
|
|
import arm.io.ExportMesh;
|
|
import arm.io.ExportTexture;
|
|
import arm.io.ExportArm;
|
|
import arm.sys.Path;
|
|
import arm.sys.File;
|
|
import arm.Enums;
|
|
|
|
class BoxExport {
|
|
|
|
public static var htab = Id.handle();
|
|
public static var hpreset = Id.handle();
|
|
public static var files: Array<String> = null;
|
|
public static var preset: TExportPreset = null;
|
|
static var channels = ["base_r", "base_g", "base_b", "height", "metal", "nor_r", "nor_g", "nor_b", "occ", "opac", "rough", "smooth", "emis", "subs", "0.0", "1.0"];
|
|
static var colorSpaces = ["linear", "srgb"];
|
|
|
|
public static function showTextures() {
|
|
UIBox.showCustom(function(ui: Zui) {
|
|
|
|
if (files == null) fetchPresets();
|
|
if (preset == null) {
|
|
parsePreset();
|
|
@:privateAccess hpreset.children = null;
|
|
}
|
|
|
|
tabExportTextures(ui, tr("Export Textures"));
|
|
tabPresets(ui);
|
|
tabAtlases(ui);
|
|
|
|
}, 540, 310);
|
|
}
|
|
|
|
public static function showBakeMaterial() {
|
|
UIBox.showCustom(function(ui: Zui) {
|
|
|
|
if (files == null) fetchPresets();
|
|
if (preset == null) {
|
|
parsePreset();
|
|
@:privateAccess hpreset.children = null;
|
|
}
|
|
|
|
tabExportTextures(ui, tr("Bake to Textures"), true);
|
|
tabPresets(ui);
|
|
|
|
}, 540, 310);
|
|
}
|
|
|
|
static function tabExportTextures(ui: Zui, title: String, bakeMaterial = false) {
|
|
if (ui.tab(htab, title)) {
|
|
ui.row([0.5, 0.5]);
|
|
ui.combo(App.resHandle, ["128", "256", "512", "1K", "2K", "4K", "8K", "16K"], tr("Resolution"), true);
|
|
if (App.resHandle.changed) {
|
|
iron.App.notifyOnInit(Layers.resizeLayers);
|
|
UVUtil.uvmap = null;
|
|
UVUtil.uvmapCached = false;
|
|
UVUtil.trianglemap = null;
|
|
UVUtil.trianglemapCached = false;
|
|
UVUtil.dilatemapCached = false;
|
|
#if (kha_direct3d12 || kha_vulkan)
|
|
arm.render.RenderPathRaytrace.ready = false;
|
|
#end
|
|
}
|
|
ui.combo(App.bitsHandle, ["8bit", "16bit", "32bit"], tr("Color"), true);
|
|
if (App.bitsHandle.changed) {
|
|
iron.App.notifyOnInit(Layers.setLayerBits);
|
|
}
|
|
|
|
ui.row([0.5, 0.5]);
|
|
if (App.bitsHandle.position == Bits8) {
|
|
Context.formatType = ui.combo(Id.handle({position: Context.formatType}), ["png", "jpg"], tr("Format"), true);
|
|
}
|
|
else {
|
|
Context.formatType = ui.combo(Id.handle({position: Context.formatType}), ["exr"], tr("Format"), true);
|
|
}
|
|
ui.enabled = Context.formatType == FormatJpg && App.bitsHandle.position == Bits8;
|
|
Context.formatQuality = ui.slider(Id.handle({value: Context.formatQuality}), tr("Quality"), 0.0, 100.0, true, 1);
|
|
ui.enabled = true;
|
|
ui.row([0.5, 0.5]);
|
|
ui.enabled = !bakeMaterial;
|
|
var layersExportHandle = Id.handle();
|
|
layersExportHandle.position = Context.layersExport;
|
|
Context.layersExport = ui.combo(layersExportHandle, [tr("Visible"), tr("Selected"), tr("Per Object"), tr("Per Udim Tile")], tr("Layers"), true);
|
|
ui.enabled = true;
|
|
ui.combo(hpreset, files, tr("Preset"), true);
|
|
if (hpreset.changed) preset = null;
|
|
|
|
@:privateAccess ui.endElement();
|
|
|
|
ui.row([0.5, 0.5]);
|
|
if (ui.button(tr("Cancel"))) {
|
|
UIBox.show = false;
|
|
}
|
|
if (ui.button(tr("Export"))) {
|
|
UIBox.show = false;
|
|
var filters = App.bitsHandle.position != Bits8 ? "exr" : Context.formatType == FormatPng ? "png" : "jpg";
|
|
UIFiles.show(filters, true, function(path: String) {
|
|
Context.textureExportPath = path;
|
|
function _init() {
|
|
ExportTexture.run(path, bakeMaterial);
|
|
}
|
|
iron.App.notifyOnInit(_init);
|
|
});
|
|
}
|
|
if (ui.isHovered) ui.tooltip(tr("Export texture files") + ' (${Config.keymap.file_export_textures})');
|
|
}
|
|
}
|
|
|
|
static function tabPresets(ui: Zui) {
|
|
if (ui.tab(htab, tr("Presets"))) {
|
|
ui.row([3 / 5, 1 / 5, 1 / 5]);
|
|
|
|
ui.combo(hpreset, files, tr("Preset"));
|
|
if (hpreset.changed) preset = null;
|
|
|
|
if (ui.button(tr("New"))) {
|
|
UIBox.showCustom(function(ui: Zui) {
|
|
if (ui.tab(Id.handle(), tr("New Preset"))) {
|
|
ui.row([0.5, 0.5]);
|
|
var presetName = ui.textInput(Id.handle({text: "new_preset"}), tr("Name"));
|
|
if (ui.button(tr("OK")) || ui.isReturnDown) {
|
|
newPreset(presetName);
|
|
fetchPresets();
|
|
preset = null;
|
|
hpreset.position = files.indexOf(presetName);
|
|
UIBox.show = false;
|
|
BoxExport.htab.position = 1; // Presets
|
|
BoxExport.showTextures();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
if (ui.button(tr("Import"))) {
|
|
UIFiles.show("json", false, function(path: String) {
|
|
path = path.toLowerCase();
|
|
if (path.endsWith(".json")) {
|
|
var filename = path.substr(path.lastIndexOf(Path.sep) + 1);
|
|
var dstPath = Path.data() + Path.sep + "export_presets" + Path.sep + filename;
|
|
File.copy(path, dstPath); // Copy to presets folder
|
|
fetchPresets();
|
|
preset = null;
|
|
hpreset.position = files.indexOf(filename.substr(0, filename.length - 5)); // Strip .json
|
|
Log.info("Preset '" + filename + "' imported.");
|
|
}
|
|
else Log.error(Strings.error1());
|
|
});
|
|
}
|
|
|
|
if (preset == null) {
|
|
parsePreset();
|
|
@:privateAccess hpreset.children = null;
|
|
}
|
|
|
|
// Texture list
|
|
ui.separator(10, false);
|
|
ui.row([1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6]);
|
|
ui.text(tr("Texture"));
|
|
ui.text(tr("R"));
|
|
ui.text(tr("G"));
|
|
ui.text(tr("B"));
|
|
ui.text(tr("A"));
|
|
ui.text(tr("Color Space"));
|
|
ui.changed = false;
|
|
for (i in 0...preset.textures.length) {
|
|
var t = preset.textures[i];
|
|
ui.row([1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6]);
|
|
var htex = hpreset.nest(i);
|
|
htex.text = t.name;
|
|
t.name = ui.textInput(htex);
|
|
|
|
if (ui.isHovered && ui.inputReleasedR) {
|
|
UIMenu.draw(function(ui: Zui) {
|
|
ui.text(t.name, Right, ui.t.HIGHLIGHT_COL);
|
|
if (ui.button(tr("Delete"), Left)) {
|
|
preset.textures.remove(t);
|
|
savePreset();
|
|
}
|
|
}, 2);
|
|
}
|
|
|
|
var hr = htex.nest(0);
|
|
hr.position = channels.indexOf(t.channels[0]);
|
|
var hg = htex.nest(1);
|
|
hg.position = channels.indexOf(t.channels[1]);
|
|
var hb = htex.nest(2);
|
|
hb.position = channels.indexOf(t.channels[2]);
|
|
var ha = htex.nest(3);
|
|
ha.position = channels.indexOf(t.channels[3]);
|
|
|
|
ui.combo(hr, channels, tr("R"));
|
|
if (hr.changed) t.channels[0] = channels[hr.position];
|
|
ui.combo(hg, channels, tr("G"));
|
|
if (hg.changed) t.channels[1] = channels[hg.position];
|
|
ui.combo(hb, channels, tr("B"));
|
|
if (hb.changed) t.channels[2] = channels[hb.position];
|
|
ui.combo(ha, channels, tr("A"));
|
|
if (ha.changed) t.channels[3] = channels[ha.position];
|
|
|
|
var hspace = htex.nest(4);
|
|
hspace.position = colorSpaces.indexOf(t.color_space);
|
|
ui.combo(hspace, colorSpaces, tr("Color Space"));
|
|
if (hspace.changed) t.color_space = colorSpaces[hspace.position];
|
|
}
|
|
|
|
if (ui.changed) {
|
|
savePreset();
|
|
}
|
|
|
|
ui.row([1 / 8]);
|
|
if (ui.button(tr("Add"))) {
|
|
preset.textures.push({name: "base", channels: ["base_r", "base_g", "base_b", "1.0"], color_space: "linear"});
|
|
@:privateAccess hpreset.children = null;
|
|
savePreset();
|
|
}
|
|
}
|
|
}
|
|
|
|
static function tabAtlases(ui: Zui) {
|
|
if (ui.tab(htab, tr("Atlases"))) {
|
|
if (Project.atlasObjects == null || Project.atlasObjects.length != Project.paintObjects.length) {
|
|
Project.atlasObjects = [];
|
|
Project.atlasNames = [];
|
|
for (i in 0...Project.paintObjects.length) {
|
|
Project.atlasObjects.push(0);
|
|
Project.atlasNames.push(tr("Atlas") + " " + (i + 1));
|
|
}
|
|
}
|
|
for (i in 0...Project.paintObjects.length) {
|
|
ui.row([1 / 2, 1 / 2]);
|
|
ui.text(Project.paintObjects[i].name);
|
|
var hatlas = Id.handle().nest(i);
|
|
hatlas.position = Project.atlasObjects[i];
|
|
Project.atlasObjects[i] = ui.combo(hatlas, Project.atlasNames, tr("Atlas"));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static function showMesh() {
|
|
UIBox.showCustom(function(ui: Zui) {
|
|
var htab = Id.handle();
|
|
if (ui.tab(htab, tr("Export Mesh"))) {
|
|
|
|
Context.exportMeshFormat = ui.combo(Id.handle({position: Context.exportMeshFormat}), ["obj", "arm"], tr("Format"), true);
|
|
|
|
var applyDisplacement = ui.check(Id.handle(), tr("Apply Displacement"));
|
|
|
|
var tris = 0;
|
|
for (po in Project.paintObjects) {
|
|
for (inda in po.data.raw.index_arrays) {
|
|
tris += Std.int(inda.values.length / 3);
|
|
}
|
|
}
|
|
ui.text(tris + " triangles");
|
|
|
|
ui.row([0.5, 0.5]);
|
|
if (ui.button(tr("Cancel"))) {
|
|
UIBox.show = false;
|
|
}
|
|
if (ui.button(tr("Export"))) {
|
|
UIBox.show = false;
|
|
UIFiles.show(Context.exportMeshFormat == FormatObj ? "obj" : "arm", true, function(path: String) {
|
|
var f = UIFiles.filename;
|
|
if (f == "") f = tr("untitled");
|
|
ExportMesh.run(path + Path.sep + f, applyDisplacement);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static function showMaterial() {
|
|
UIBox.showCustom(function(ui: Zui) {
|
|
var htab = Id.handle();
|
|
if (ui.tab(htab, tr("Export Material"))) {
|
|
var h1 = Id.handle();
|
|
var h2 = Id.handle();
|
|
h1.selected = Context.packAssetsOnExport;
|
|
h2.selected = Context.writeIconOnExport;
|
|
Context.packAssetsOnExport = ui.check(h1, tr("Pack Assets"));
|
|
Context.writeIconOnExport = ui.check(h2, tr("Export Icon"));
|
|
ui.row([0.5, 0.5]);
|
|
if (ui.button(tr("Cancel"))) {
|
|
UIBox.show = false;
|
|
}
|
|
if (ui.button(tr("Export"))) {
|
|
UIBox.show = false;
|
|
UIFiles.show("arm", true, function(path: String) {
|
|
var f = UIFiles.filename;
|
|
if (f == "") f = tr("untitled");
|
|
iron.App.notifyOnInit(function() {
|
|
ExportArm.runMaterial(path + Path.sep + f);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static function showBrush() {
|
|
UIBox.showCustom(function(ui: Zui) {
|
|
var htab = Id.handle();
|
|
if (ui.tab(htab, tr("Export Brush"))) {
|
|
var h1 = Id.handle();
|
|
var h2 = Id.handle();
|
|
h1.selected = Context.packAssetsOnExport;
|
|
h2.selected = Context.writeIconOnExport;
|
|
Context.packAssetsOnExport = ui.check(h1, tr("Pack Assets"));
|
|
Context.writeIconOnExport = ui.check(h2, tr("Export Icon"));
|
|
ui.row([0.5, 0.5]);
|
|
if (ui.button(tr("Cancel"))) {
|
|
UIBox.show = false;
|
|
}
|
|
if (ui.button(tr("Export"))) {
|
|
UIBox.show = false;
|
|
UIFiles.show("arm", true, function(path: String) {
|
|
var f = UIFiles.filename;
|
|
if (f == "") f = tr("untitled");
|
|
iron.App.notifyOnInit(function() {
|
|
ExportArm.runBrush(path + Path.sep + f);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
static function fetchPresets() {
|
|
#if (krom_android || krom_ios)
|
|
|
|
files = ["generic"];
|
|
|
|
#else
|
|
|
|
files = File.readDirectory(Path.data() + Path.sep + "export_presets");
|
|
for (i in 0...files.length) {
|
|
files[i] = files[i].substr(0, files[i].length - 5); // Strip .json
|
|
}
|
|
|
|
#end
|
|
}
|
|
|
|
static function parsePreset() {
|
|
var file = "export_presets/" + files[hpreset.position] + ".json";
|
|
iron.data.Data.getBlob(file, function(blob: kha.Blob) {
|
|
preset = haxe.Json.parse(blob.toString());
|
|
iron.data.Data.deleteBlob("export_presets/" + file);
|
|
});
|
|
}
|
|
|
|
static function newPreset(name: String) {
|
|
var template =
|
|
'{
|
|
"textures": [
|
|
{ "name": "base", "channels": ["base_r", "base_g", "base_b", "1.0"] }
|
|
]
|
|
}
|
|
';
|
|
if (!name.endsWith(".json")) name += ".json";
|
|
var path = Path.data() + Path.sep + "export_presets" + Path.sep + name;
|
|
Krom.fileSaveBytes(path, Bytes.ofString(template).getData());
|
|
}
|
|
|
|
static function savePreset() {
|
|
var name = files[hpreset.position];
|
|
if (name == "generic") return; // generic is const
|
|
var path = Path.data() + Path.sep + "export_presets" + Path.sep + name + ".json";
|
|
Krom.fileSaveBytes(path, Bytes.ofString(haxe.Json.stringify(preset)).getData());
|
|
}
|
|
}
|