Files
armorpaint/Sources/arm/Project.hx
T

337 lines
10 KiB
Haxe
Raw Normal View History

2019-02-02 18:49:19 +01:00
package arm;
2019-11-20 22:43:17 +01:00
import kha.System;
2019-06-20 11:23:01 +02:00
import kha.Window;
2019-10-16 23:02:57 +02:00
import zui.Zui;
import zui.Id;
2019-06-19 22:42:17 +02:00
import zui.Nodes;
2019-02-02 18:49:19 +01:00
import iron.data.SceneFormat;
import iron.data.MeshData;
2019-06-20 11:23:01 +02:00
import iron.data.Data;
2019-06-24 22:35:17 +02:00
import iron.object.MeshObject;
2019-06-20 11:23:01 +02:00
import iron.Scene;
2019-05-10 19:28:59 +02:00
import arm.util.RenderUtil;
import arm.util.ViewportUtil;
2019-11-13 13:51:17 +01:00
import arm.sys.Path;
2020-03-18 20:26:28 +01:00
import arm.ui.UISidebar;
2019-05-12 17:33:58 +02:00
import arm.ui.UIFiles;
2019-10-16 23:02:57 +02:00
import arm.ui.UIBox;
2019-06-19 22:42:17 +02:00
import arm.data.LayerSlot;
import arm.data.BrushSlot;
import arm.data.MaterialSlot;
2019-11-13 15:17:10 +01:00
import arm.node.MaterialParser;
2019-11-20 16:36:08 +01:00
import arm.io.ImportAsset;
2019-06-20 11:23:01 +02:00
import arm.io.ImportArm;
2019-11-07 19:13:34 +01:00
import arm.io.ImportBlend;
2019-11-11 22:14:32 +01:00
import arm.io.ImportMesh;
2019-11-20 22:43:17 +01:00
import arm.io.ExportArm;
2020-03-18 20:26:28 +01:00
import arm.Enums;
2019-02-02 18:49:19 +01:00
class Project {
2019-06-23 14:50:41 +02:00
2019-12-09 00:28:10 +01:00
public static var raw: TProjectFormat;
2019-06-23 14:50:41 +02:00
public static var filepath = "";
2019-12-09 00:28:10 +01:00
public static var assets: Array<TAsset> = [];
public static var assetNames: Array<String> = [];
2019-06-23 14:50:41 +02:00
public static var assetId = 0;
2019-12-09 00:28:10 +01:00
public static var meshAssets: Array<String> = [];
public static var materials: Array<MaterialSlot> = null;
public static var materialsScene: Array<MaterialSlot> = null;
public static var brushes: Array<BrushSlot> = null;
public static var layers: Array<LayerSlot> = null;
public static var paintObjects: Array<MeshObject> = null;
2019-09-13 10:14:17 +02:00
public static var assetMap = new Map<Int, Dynamic>(); // kha.Image | kha.Font
2019-08-31 20:44:37 +02:00
#if arm_world
public static var waterPass = true;
#end
2019-06-23 14:50:41 +02:00
2019-02-02 18:49:19 +01:00
public static function projectOpen() {
2019-12-09 00:28:10 +01:00
UIFiles.show("arm", false, function(path: String) {
2019-06-20 12:30:31 +02:00
if (!path.endsWith(".arm")) {
2019-11-23 22:42:09 +01:00
Log.error(Strings.error5);
2019-02-02 18:49:19 +01:00
return;
}
2019-02-27 22:34:24 +01:00
var current = @:privateAccess kha.graphics4.Graphics2.current;
if (current != null) current.end();
2019-06-20 11:23:01 +02:00
ImportArm.runProject(path);
2019-02-27 22:34:24 +01:00
if (current != null) current.begin(false);
2019-11-12 10:50:25 +01:00
});
2019-02-02 18:49:19 +01:00
}
2019-11-20 22:43:17 +01:00
public static function projectSave(saveAndQuit = false) {
2019-06-23 14:50:41 +02:00
if (filepath == "") {
2019-02-02 18:49:19 +01:00
projectSaveAs();
return;
}
2019-06-23 15:44:23 +02:00
Window.get(0).title = UIFiles.filename + " - ArmorPaint";
2019-11-20 22:43:17 +01:00
function export(_) {
ExportArm.runProject();
iron.App.removeRender(export);
if (saveAndQuit) System.stop();
}
iron.App.notifyOnRender(export);
2019-02-02 18:49:19 +01:00
}
public static function projectSaveAs() {
2019-12-09 00:28:10 +01:00
UIFiles.show("arm", true, function(path: String) {
2019-06-23 15:44:23 +02:00
var f = UIFiles.filename;
2020-03-17 19:16:19 +01:00
if (f == "") f = tr("untitled");
2020-02-16 21:50:14 +01:00
filepath = path + Path.sep + f;
2019-06-23 14:50:41 +02:00
if (!filepath.endsWith(".arm")) filepath += ".arm";
2019-02-02 18:49:19 +01:00
projectSave();
2019-11-12 10:50:25 +01:00
});
2019-02-02 18:49:19 +01:00
}
2019-10-16 23:02:57 +02:00
public static function projectNewBox() {
2019-12-09 00:28:10 +01:00
UIBox.showCustom(function(ui: Zui) {
2020-03-17 19:16:19 +01:00
if (ui.tab(Id.handle(), tr("New Project"))) {
2019-12-09 00:28:10 +01:00
ui.row([0.5, 0.5]);
2020-03-18 20:26:28 +01:00
UISidebar.inst.projectType = ui.combo(Id.handle({position: UISidebar.inst.projectType}), ["Cube", "Sphere", "Tessellated Plane"], tr("Template"));
2020-03-17 19:16:19 +01:00
if (ui.button(tr("OK")) || ui.isReturnDown) {
2019-10-16 23:02:57 +02:00
Project.projectNew();
ViewportUtil.scaleToBounds();
UIBox.show = false;
App.redrawUI();
}
}
});
}
2019-02-02 18:49:19 +01:00
public static function projectNew(resetLayers = true) {
2019-06-20 11:23:01 +02:00
Window.get(0).title = "ArmorPaint";
2019-06-23 14:50:41 +02:00
filepath = "";
if (Context.mergedObject != null) {
Context.mergedObject.remove();
Data.deleteMesh(Context.mergedObject.data.handle);
Context.mergedObject = null;
2019-02-02 18:49:19 +01:00
}
2019-02-26 13:28:53 +01:00
2019-06-13 08:29:21 +02:00
ViewportUtil.resetViewport();
2019-06-23 14:50:41 +02:00
Context.layerPreviewDirty = true;
2019-03-28 15:21:45 +01:00
2019-06-23 14:50:41 +02:00
Context.paintObject = Context.mainObject();
2019-02-26 13:28:53 +01:00
2019-06-23 14:50:41 +02:00
Context.selectPaintObject(Context.mainObject());
2019-06-24 22:35:17 +02:00
for (i in 1...paintObjects.length) {
var p = paintObjects[i];
2019-06-23 14:50:41 +02:00
if (p == Context.paintObject) continue;
2019-06-20 11:23:01 +02:00
Data.deleteMesh(p.data.handle);
2019-02-02 18:49:19 +01:00
p.remove();
}
2019-06-20 11:23:01 +02:00
var meshes = Scene.active.meshes;
2019-06-12 01:12:19 +02:00
var len = meshes.length;
for (i in 0...len) {
var m = meshes[len - i - 1];
2020-03-18 20:26:28 +01:00
if (UISidebar.inst.projectObjects.indexOf(m) == -1) {
2019-06-20 11:23:01 +02:00
Data.deleteMesh(m.data.handle);
2019-06-12 01:12:19 +02:00
m.remove();
}
}
2019-06-23 14:50:41 +02:00
var handle = Context.paintObject.data.handle;
2019-05-15 11:26:06 +02:00
if (handle != "SceneSphere" && handle != "ScenePlane") {
2019-06-20 11:23:01 +02:00
Data.deleteMesh(handle);
2019-03-24 15:44:25 +01:00
}
2019-05-21 22:28:08 +02:00
2020-03-18 20:26:28 +01:00
if (UISidebar.inst.projectType != ModelCube) {
var mesh: Dynamic = UISidebar.inst.projectType == ModelSphere ?
2019-08-31 20:44:37 +02:00
new arm.format.proc.Sphere(1, 512, 256) :
2019-07-17 12:40:24 +02:00
new arm.format.proc.Plane(1, 1, 512, 512);
2019-06-13 08:29:21 +02:00
var raw = {
2019-12-04 20:17:29 +01:00
name: "Tessellated",
2019-06-13 08:29:21 +02:00
vertex_arrays: [
2020-03-03 22:56:27 +01:00
{ values: mesh.posa, attrib: "pos", data: "short4norm" },
{ values: mesh.nora, attrib: "nor", data: "short2norm" },
{ values: mesh.texa, attrib: "tex", data: "short2norm" }
2019-06-13 08:29:21 +02:00
],
index_arrays: [
{ values: mesh.inda, material: 0 }
],
scale_pos: mesh.scalePos,
scale_tex: mesh.scaleTex
};
2019-12-09 00:28:10 +01:00
var md = new MeshData(raw, function(md: MeshData) {});
2019-12-04 20:17:29 +01:00
Data.cachedMeshes.set("SceneTessellated", md);
2019-06-13 08:29:21 +02:00
2020-03-18 20:26:28 +01:00
if (UISidebar.inst.projectType == ModelSphere) {
2019-06-19 12:03:32 +02:00
ViewportUtil.setView(0, 0, 1, 0, 0, 0); // Top
ViewportUtil.orbit(0, Math.PI / 6); // Orbit down
}
2020-03-18 20:26:28 +01:00
else if (UISidebar.inst.projectType == ModelTessellatedPlane) {
2019-08-31 20:44:37 +02:00
ViewportUtil.setView(0, 0, 5, 0, 0, 0); // Top
ViewportUtil.orbit(0, Math.PI / 6); // Orbit down
}
2019-06-13 08:29:21 +02:00
}
2020-03-18 20:26:28 +01:00
var n = UISidebar.inst.projectType == ModelCube ? "Cube" : "Tessellated";
2019-12-09 00:28:10 +01:00
Data.getMesh("Scene", n, function(md: MeshData) {
2019-10-06 19:03:59 +02:00
2019-02-27 22:34:24 +01:00
var current = @:privateAccess kha.graphics4.Graphics2.current;
if (current != null) current.end();
2019-02-12 16:34:33 +01:00
2020-03-18 20:26:28 +01:00
UISidebar.inst.pickerMaskHandle.position = MaskNone;
2019-06-23 14:50:41 +02:00
Context.paintObject.setData(md);
Context.paintObject.transform.scale.set(1, 1, 1);
2019-08-31 20:44:37 +02:00
#if arm_creator
2020-03-18 20:26:28 +01:00
if (UISidebar.inst.projectType == ModelTessellatedPlane) {
2019-08-31 20:44:37 +02:00
Context.paintObject.transform.loc.set(0, 0, -0.15);
Context.paintObject.transform.scale.set(10, 10, 1);
}
#end
2019-06-23 14:50:41 +02:00
Context.paintObject.transform.buildMatrix();
Context.paintObject.name = n;
2019-06-24 22:35:17 +02:00
paintObjects = [Context.paintObject];
2019-10-23 11:01:12 +02:00
while (materials.length > 0) materials.pop().unload();
2019-12-09 00:28:10 +01:00
Data.getMaterial("Scene", "Material", function(m: iron.data.MaterialData) {
2019-10-23 11:01:12 +02:00
materials.push(new MaterialSlot(m));
2019-03-05 13:30:11 +01:00
});
2019-06-23 14:50:41 +02:00
Context.material = materials[0];
brushes = [new BrushSlot()];
Context.brush = brushes[0];
2019-05-11 15:59:56 +02:00
History.reset();
2019-10-06 19:03:59 +02:00
2019-06-20 11:23:01 +02:00
MaterialParser.parsePaintMaterial();
2019-02-02 18:49:19 +01:00
RenderUtil.makeMaterialPreview();
2019-06-23 14:50:41 +02:00
for (a in assets) Data.deleteImage(a.file);
assets = [];
assetNames = [];
assetId = 0;
Context.ddirty = 4;
2020-03-18 20:26:28 +01:00
UISidebar.inst.hwnd.redraws = 2;
UISidebar.inst.hwnd1.redraws = 2;
UISidebar.inst.hwnd2.redraws = 2;
2019-02-12 16:34:33 +01:00
2019-06-13 08:29:21 +02:00
if (resetLayers) {
2019-10-23 11:01:12 +02:00
while (layers.length > 0) layers.pop().unload();
2019-06-13 08:29:21 +02:00
var layer = new LayerSlot();
2019-10-23 11:01:12 +02:00
layers.push(layer);
2019-06-23 14:50:41 +02:00
Context.setLayer(layer);
2019-12-04 20:17:29 +01:00
iron.App.notifyOnRender(Layers.initLayers);
2019-06-13 08:29:21 +02:00
}
2019-02-27 22:34:24 +01:00
if (current != null) current.begin(false);
2019-09-17 12:07:59 +02:00
2020-03-18 20:26:28 +01:00
UISidebar.inst.savedEnvmap = UISidebar.inst.defaultEnvmap;
Scene.active.world.envmap = UISidebar.inst.emptyEnvmap;
2019-12-12 19:18:23 +01:00
Scene.active.world.raw.envmap = "World_radiance.k";
2020-03-18 20:26:28 +01:00
UISidebar.inst.showEnvmapHandle.selected = UISidebar.inst.showEnvmap = false;
Scene.active.world.probe.radiance = UISidebar.inst.defaultRadiance;
Scene.active.world.probe.radianceMipmaps = UISidebar.inst.defaultRadianceMipmaps;
Scene.active.world.probe.irradiance = UISidebar.inst.defaultIrradiance;
2019-09-17 12:07:59 +02:00
Scene.active.world.probe.raw.strength = 4.0;
2019-02-02 18:49:19 +01:00
});
}
2019-09-17 12:38:10 +02:00
2019-11-07 19:13:34 +01:00
public static function importMaterial() {
2019-12-09 00:28:10 +01:00
UIFiles.show("arm,blend", false, function(path: String) {
2019-11-07 19:13:34 +01:00
path.endsWith(".blend") ?
ImportBlend.runMaterial(path) :
ImportArm.runMaterial(path);
2019-11-12 10:50:25 +01:00
});
2019-11-07 19:13:34 +01:00
}
2020-03-13 23:27:00 +01:00
public static function importBrush() {
UIFiles.show("arm", false, function(path: String) {
ImportArm.runBrush(path);
});
}
2019-11-07 16:54:39 +01:00
public static function importMesh() {
2019-12-09 00:28:10 +01:00
UIFiles.show(Path.meshFormats.join(","), false, function(path: String) {
2019-11-20 21:26:44 +01:00
importMeshBox(path);
});
}
2019-12-09 00:28:10 +01:00
public static function importMeshBox(path: String) {
UIBox.showCustom(function(ui: Zui) {
2020-03-17 19:16:19 +01:00
if (ui.tab(Id.handle(), tr("Import Mesh"))) {
2019-11-07 16:54:39 +01:00
2019-12-04 20:17:29 +01:00
if (path.toLowerCase().endsWith(".obj")) {
2020-03-18 20:26:28 +01:00
UISidebar.inst.splitBy = ui.combo(Id.handle(), [
2020-03-17 19:16:19 +01:00
tr("Object"),
tr("Group"),
tr("Material"),
tr("UDIM Tile"),
], tr("Split By"), true);
if (ui.isHovered) ui.tooltip(tr("Split .obj mesh into objects"));
2019-12-04 20:17:29 +01:00
}
2019-11-07 16:54:39 +01:00
2019-12-04 20:17:29 +01:00
if (path.toLowerCase().endsWith(".fbx")) {
2020-03-18 20:26:28 +01:00
UISidebar.inst.parseTransform = ui.check(Id.handle({selected: UISidebar.inst.parseTransform}), tr("Parse Transforms"));
2020-03-17 19:16:19 +01:00
if (ui.isHovered) ui.tooltip(tr("Load per-object transforms from .fbx"));
2019-12-04 20:17:29 +01:00
}
2019-11-07 16:54:39 +01:00
2020-02-28 16:14:19 +01:00
if (path.toLowerCase().endsWith(".fbx") || path.toLowerCase().endsWith(".blend")) {
2020-03-18 20:26:28 +01:00
UISidebar.inst.parseVCols = ui.check(Id.handle({selected: UISidebar.inst.parseVCols}), tr("Parse Vertex Colors"));
2020-03-17 19:16:19 +01:00
if (ui.isHovered) ui.tooltip(tr("Import vertex color data"));
2020-02-28 16:14:19 +01:00
}
2019-12-09 00:28:10 +01:00
ui.row([0.5, 0.5]);
2020-03-17 19:16:19 +01:00
if (ui.button(tr("Cancel"))) {
2019-11-07 16:54:39 +01:00
UIBox.show = false;
}
2020-03-17 19:16:19 +01:00
if (ui.button(tr("Import")) || ui.isReturnDown) {
2019-11-07 16:54:39 +01:00
UIBox.show = false;
App.redrawUI();
2019-11-20 21:26:44 +01:00
ImportMesh.run(path);
2019-11-07 16:54:39 +01:00
}
}
});
2020-02-05 18:30:24 +01:00
UIBox.clickToHide = false; // Prevent closing when going back to window from file browser
2019-11-07 16:54:39 +01:00
}
2019-10-28 21:58:04 +01:00
public static function reimportMesh() {
2019-09-17 22:28:15 +02:00
if (Project.meshAssets != null && Project.meshAssets.length > 0) {
2019-11-11 22:14:32 +01:00
ImportMesh.run(Project.meshAssets[0], false);
2019-11-23 22:42:09 +01:00
Log.info("Mesh reimported.");
2019-09-17 22:28:15 +02:00
}
2019-11-07 15:18:05 +01:00
else importAsset();
2019-09-17 12:38:10 +02:00
}
2019-10-17 22:00:59 +02:00
2019-12-09 00:28:10 +01:00
public static function importAsset(filters: String = null) {
2019-11-11 22:14:32 +01:00
if (filters == null) filters = Path.textureFormats.join(",") + "," + Path.meshFormats.join(",");
2019-12-09 00:28:10 +01:00
UIFiles.show(filters, false, function(path: String) {
2019-11-20 16:36:08 +01:00
ImportAsset.run(path);
2019-11-12 10:50:25 +01:00
});
2019-10-17 22:00:59 +02:00
}
2019-02-02 18:49:19 +01:00
}
2019-06-19 22:42:17 +02:00
typedef TProjectFormat = {
2019-12-09 00:28:10 +01:00
public var version: String;
@:optional public var brush_nodes: Array<TNodeCanvas>;
2020-03-13 23:27:00 +01:00
@:optional public var brush_icons: Array<haxe.io.Bytes>;
2019-12-09 00:28:10 +01:00
@:optional public var material_nodes: Array<TNodeCanvas>;
2020-01-28 00:02:07 +01:00
@:optional public var material_icons: Array<haxe.io.Bytes>;
2019-12-09 00:28:10 +01:00
@:optional public var assets: Array<String>; // texture_assets
@:optional public var layer_datas: Array<TLayerData>;
@:optional public var mesh_datas: Array<TMeshData>;
@:optional public var mesh_assets: Array<String>;
2019-06-19 22:42:17 +02:00
}
typedef TLayerData = {
2019-12-09 00:28:10 +01:00
public var res: Int; // Width pixels
public var bpp: Int; // Bits per pixel
public var texpaint: haxe.io.Bytes;
public var texpaint_nor: haxe.io.Bytes;
public var texpaint_pack: haxe.io.Bytes;
public var texpaint_mask: haxe.io.Bytes;
public var uv_scale: Float;
public var uv_rot: Float;
public var uv_type: Int;
public var opacity_mask: Float;
public var material_mask: Int;
public var object_mask: Int;
public var blending: Int;
2020-01-26 20:32:52 +01:00
public var parent: Int;
2019-06-19 22:42:17 +02:00
}
2019-09-13 10:14:17 +02:00
typedef TAsset = {
2019-12-09 00:28:10 +01:00
public var id: Int;
public var name: String;
public var file: String;
2019-09-13 10:14:17 +02:00
}