Files
armorpaint/Sources/arm/Project.hx
T

389 lines
13 KiB
Haxe
Raw Normal View History

2019-02-02 18:49:19 +01:00
package arm;
import iron.data.SceneFormat;
import iron.data.MeshData;
import arm.ProjectFormat;
2019-05-10 19:28:59 +02:00
import arm.util.MeshUtil;
import arm.util.RenderUtil;
import arm.util.ViewportUtil;
import arm.util.Path;
import arm.util.Lz4;
import arm.ui.UITrait;
import arm.ui.UINodes;
2019-02-02 18:49:19 +01:00
class Project {
public static function projectOpen() {
arm.App.showFiles = true;
@:privateAccess zui.Ext.lastPath = ""; // Refresh
arm.App.whandle.redraws = 2;
arm.App.foldersOnly = false;
arm.App.showFilename = false;
arm.App.filesDone = function(path:String) {
if (!StringTools.endsWith(path, ".arm")) {
2019-03-02 23:05:33 +01:00
UITrait.inst.showError("Error: .arm file expected");
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-02-02 18:49:19 +01:00
importProject(path);
2019-02-27 22:34:24 +01:00
if (current != null) current.begin(false);
2019-02-02 18:49:19 +01:00
};
}
public static function exportProject() {
var mnodes:Array<zui.Nodes.TNodeCanvas> = [];
var bnodes:Array<zui.Nodes.TNodeCanvas> = [];
2019-03-18 23:50:20 +01:00
for (m in UITrait.inst.materials) {
2019-05-11 13:09:10 +02:00
var c:zui.Nodes.TNodeCanvas = haxe.Json.parse(haxe.Json.stringify(UINodes.inst.canvasMap.get(m)));
2019-03-18 23:50:20 +01:00
for (n in c.nodes) {
2019-03-23 12:59:39 +01:00
if (n.type == "TEX_IMAGE") { // Convert image path from absolute to relative
2019-05-07 14:21:26 +02:00
var sameDrive = UITrait.inst.projectPath.charAt(0) == n.buttons[0].data.charAt(0);
if (sameDrive) {
2019-05-09 22:38:50 +02:00
n.buttons[0].data = Path.toRelative(UITrait.inst.projectPath, n.buttons[0].data);
2019-05-07 14:21:26 +02:00
}
2019-03-18 23:50:20 +01:00
}
}
mnodes.push(c);
}
2019-02-02 18:49:19 +01:00
for (b in UITrait.inst.brushes) bnodes.push(UINodes.inst.canvasBrushMap.get(b));
var md:Array<TMeshData> = [];
for (p in UITrait.inst.paintObjects) md.push(p.data.raw);
var asset_files:Array<String> = [];
2019-03-18 23:50:20 +01:00
for (a in UITrait.inst.assets) {
2019-05-07 14:21:26 +02:00
// Convert image path from absolute to relative
var sameDrive = UITrait.inst.projectPath.charAt(0) == a.file.charAt(0);
if (sameDrive) {
2019-05-09 22:38:50 +02:00
asset_files.push(Path.toRelative(UITrait.inst.projectPath, a.file));
2019-05-07 14:21:26 +02:00
}
else {
asset_files.push(a.file);
}
2019-03-18 23:50:20 +01:00
}
2019-02-02 18:49:19 +01:00
var ld:Array<TLayerData> = [];
for (l in UITrait.inst.layers) {
ld.push({
res: l.texpaint.width,
2019-05-06 16:16:38 +02:00
texpaint: Lz4.encode(l.texpaint.getPixels()),
texpaint_nor: Lz4.encode(l.texpaint_nor.getPixels()),
texpaint_pack: Lz4.encode(l.texpaint_pack.getPixels()),
texpaint_mask: l.texpaint_mask != null ? Lz4.encode(l.texpaint_mask.getPixels()) : null,
2019-04-17 10:13:29 +02:00
opacity_mask: l.maskOpacity,
2019-05-09 22:38:50 +02:00
material_mask: l.material_mask != null ? UITrait.inst.materials.indexOf(l.material_mask) : -1,
2019-04-17 10:13:29 +02:00
object_mask: l.objectMask
2019-02-02 18:49:19 +01:00
});
}
UITrait.inst.project = {
2019-03-07 12:44:43 +01:00
version: arm.App.version,
2019-02-02 18:49:19 +01:00
material_nodes: mnodes,
brush_nodes: bnodes,
mesh_datas: md,
layer_datas: ld,
assets: asset_files
};
var bytes = iron.system.ArmPack.encode(UITrait.inst.project);
#if kha_krom
Krom.fileSaveBytes(UITrait.inst.projectPath, bytes.getData());
#elseif kha_kore
sys.io.File.saveBytes(UITrait.inst.projectPath, bytes);
#end
}
public static function projectSave() {
if (UITrait.inst.projectPath == "") {
projectSaveAs();
return;
}
kha.Window.get(0).title = arm.App.filenameHandle.text + " - ArmorPaint";
UITrait.inst.projectExport = true;
}
public static function projectSaveAs() {
arm.App.showFiles = true;
@:privateAccess zui.Ext.lastPath = ""; // Refresh
arm.App.whandle.redraws = 2;
arm.App.foldersOnly = true;
arm.App.showFilename = true;
arm.App.filesDone = function(path:String) {
var f = arm.App.filenameHandle.text;
if (f == "") f = "untitled";
UITrait.inst.projectPath = path + "/" + f;
if (!StringTools.endsWith(UITrait.inst.projectPath, ".arm")) UITrait.inst.projectPath += ".arm";
projectSave();
};
}
public static function projectNew(resetLayers = true) {
kha.Window.get(0).title = "ArmorPaint";
UITrait.inst.projectPath = "";
if (UITrait.inst.mergedObject != null) {
UITrait.inst.mergedObject.remove();
iron.data.Data.deleteMesh(UITrait.inst.mergedObject.data.handle);
UITrait.inst.mergedObject = null;
}
2019-02-26 13:28:53 +01:00
2019-03-28 15:21:45 +01:00
UITrait.inst.layerPreviewDirty = true;
LayerSlot.counter = 0;
2019-02-26 13:28:53 +01:00
UITrait.inst.paintObject = UITrait.inst.mainObject();
2019-02-02 18:49:19 +01:00
UITrait.inst.selectPaintObject(UITrait.inst.mainObject());
for (i in 1...UITrait.inst.paintObjects.length) {
var p = UITrait.inst.paintObjects[i];
2019-02-26 13:28:53 +01:00
if (p == UITrait.inst.paintObject) continue;
2019-02-02 18:49:19 +01:00
iron.data.Data.deleteMesh(p.data.handle);
p.remove();
}
var n = UITrait.inst.newObjectNames[UITrait.inst.newObject];
2019-03-24 15:44:25 +01:00
var handle = UITrait.inst.paintObject.data.handle;
if (handle != "mesh_SphereSphere" && handle != "mesh_PlanePlane") {
iron.data.Data.deleteMesh(handle);
}
2019-02-02 18:49:19 +01:00
iron.data.Data.getMesh("mesh_" + n, n, function(md:MeshData) {
2019-02-12 16:34:33 +01: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
2019-03-21 11:15:43 +01:00
UITrait.inst.pickerMaskHandle.position = 0;
2019-02-02 18:49:19 +01:00
UITrait.inst.paintObject.setData(md);
UITrait.inst.paintObject.transform.scale.set(1, 1, 1);
UITrait.inst.paintObject.transform.buildMatrix();
UITrait.inst.paintObject.name = n;
UITrait.inst.paintObjects = [UITrait.inst.paintObject];
2019-03-25 21:56:39 +01:00
// UITrait.inst.maskHandle.position = 0;
2019-03-05 13:30:11 +01:00
// UITrait.inst.materials = [new MaterialSlot()];
iron.data.Data.getMaterial("Scene", "Material", function(m:iron.data.MaterialData) {
UITrait.inst.materials = [new MaterialSlot(m)];
});
2019-02-02 18:49:19 +01:00
UITrait.inst.selectedMaterial = UITrait.inst.materials[0];
UINodes.inst.canvasMap = new Map();
UINodes.inst.canvasBrushMap = new Map();
UITrait.inst.brushes = [new BrushSlot()];
UITrait.inst.selectedBrush = UITrait.inst.brushes[0];
if (resetLayers) {
// for (l in layers) l.unload();
UITrait.inst.layers = [new LayerSlot()];
2019-03-28 15:21:45 +01:00
UITrait.inst.setLayer(UITrait.inst.layers[0]);
2019-02-02 18:49:19 +01:00
iron.App.notifyOnRender(Layers.initLayers);
}
UINodes.inst.updateCanvasMap();
2019-05-09 22:38:50 +02:00
arm.MaterialParser.parsePaintMaterial();
2019-02-02 18:49:19 +01:00
RenderUtil.makeMaterialPreview();
UITrait.inst.assets = [];
UITrait.inst.assetNames = [];
UITrait.inst.assetId = 0;
ViewportUtil.resetViewport();
2019-03-21 11:15:43 +01:00
UITrait.inst.ddirty = 4;
UITrait.inst.hwnd.redraws = 2;
2019-03-27 14:26:51 +01:00
UITrait.inst.hwnd1.redraws = 2;
UITrait.inst.hwnd2.redraws = 2;
2019-02-12 16:34:33 +01:00
2019-02-27 22:34:24 +01:00
if (current != null) current.begin(false);
2019-02-02 18:49:19 +01:00
});
}
public static function importProject(path:String) {
iron.data.Data.getBlob(path, function(b:kha.Blob) {
2019-03-27 18:26:37 +01:00
2019-05-07 12:59:31 +02:00
UITrait.inst.layersPreviewDirty = true;
2019-03-27 18:26:37 +01:00
LayerSlot.counter = 0;
2019-02-02 18:49:19 +01:00
var resetLayers = false;
projectNew(resetLayers);
UITrait.inst.projectPath = path;
arm.App.filenameHandle.text = new haxe.io.Path(UITrait.inst.projectPath).file;
kha.Window.get(0).title = arm.App.filenameHandle.text + " - ArmorPaint";
2019-05-04 00:02:41 +02:00
var project:TProjectFormat = iron.system.ArmPack.decode(b.toBytes());
// Read as .arm mesh instead
if (project.version == null) {
new MeshData(project.mesh_datas[0], function(md:MeshData) {
UITrait.inst.paintObject.setData(md);
UITrait.inst.paintObject.transform.scale.set(1, 1, 1);
UITrait.inst.paintObject.transform.buildMatrix();
UITrait.inst.paintObject.name = md.name;
UITrait.inst.paintObjects = [UITrait.inst.paintObject];
});
return;
}
UITrait.inst.project = project;
2019-02-02 18:49:19 +01:00
2019-05-09 22:38:50 +02:00
var base = Path.baseDir(path);
2019-03-18 23:50:20 +01:00
for (file in project.assets) {
2019-05-07 14:21:26 +02:00
// Convert image path from relative to absolute
var isAbsolute = file.charAt(0) == "/" || file.charAt(1) == ":";
var abs = isAbsolute ? file : base + file;
2019-03-18 23:50:20 +01:00
var exists = 1;
if (kha.System.systemId == "Windows") {
2019-05-06 11:32:40 +02:00
#if kha_krom
2019-03-18 23:50:20 +01:00
exists = Krom.sysCommand('IF EXIST "' + abs + '" EXIT /b 1');
2019-05-06 11:32:40 +02:00
#end
2019-03-18 23:50:20 +01:00
}
//else { test -e file && echo 1 || echo 0 }
if (exists == 0) {
trace("Could not locate texture " + abs);
var b = haxe.io.Bytes.alloc(4);
b.set(0, 255);
b.set(1, 0);
b.set(2, 255);
b.set(3, 255);
var pink = kha.Image.fromBytes(b, 1, 1);
iron.data.Data.cachedImages.set(abs, pink);
}
Importer.importTexture(abs);
}
2019-02-02 18:49:19 +01:00
2019-03-05 13:30:11 +01:00
var m0:iron.data.MaterialData = null;
iron.data.Data.getMaterial("Scene", "Material", function(m:iron.data.MaterialData) {
m0 = m;
});
2019-02-02 18:49:19 +01:00
UITrait.inst.materials = [];
for (n in project.material_nodes) {
2019-03-18 23:50:20 +01:00
for (node in n.nodes) {
2019-03-23 12:59:39 +01:00
if (node.type == "TEX_IMAGE") { // Convert image path from relative to absolute
2019-05-07 14:21:26 +02:00
var filepath = node.buttons[0].data;
var isAbsolute = filepath.charAt(0) == "/" || filepath.charAt(1) == ":";
if (!isAbsolute) {
var abs = base + filepath;
node.buttons[0].data = abs;
}
2019-03-18 23:50:20 +01:00
}
2019-03-23 12:59:39 +01:00
for (inp in node.inputs) { // Round input socket values
if (inp.type == "VALUE") inp.default_value = Math.round(inp.default_value * 100) / 100;
}
2019-03-18 23:50:20 +01:00
}
2019-03-05 13:30:11 +01:00
var mat = new MaterialSlot(m0);
2019-02-02 18:49:19 +01:00
UINodes.inst.canvasMap.set(mat, n);
UITrait.inst.materials.push(mat);
UITrait.inst.selectedMaterial = mat;
UINodes.inst.updateCanvasMap();
2019-05-09 22:38:50 +02:00
arm.MaterialParser.parsePaintMaterial();
2019-02-02 18:49:19 +01:00
RenderUtil.makeMaterialPreview();
}
UITrait.inst.brushes = [];
for (n in project.brush_nodes) {
var brush = new BrushSlot();
UINodes.inst.canvasBrushMap.set(brush, n);
UITrait.inst.brushes.push(brush);
}
// Synchronous for now
new MeshData(project.mesh_datas[0], function(md:MeshData) {
UITrait.inst.paintObject.setData(md);
UITrait.inst.paintObject.transform.scale.set(1, 1, 1);
UITrait.inst.paintObject.transform.buildMatrix();
UITrait.inst.paintObject.name = md.name;
UITrait.inst.paintObjects = [UITrait.inst.paintObject];
});
for (i in 1...project.mesh_datas.length) {
var raw = project.mesh_datas[i];
new MeshData(raw, function(md:MeshData) {
var object = iron.Scene.active.addMeshObject(md, UITrait.inst.paintObject.materials, UITrait.inst.paintObject);
object.name = md.name;
object.skip_context = "paint";
UITrait.inst.paintObjects.push(object);
});
}
// No mask by default
if (UITrait.inst.mergedObject == null) MeshUtil.mergeMesh();
UITrait.inst.selectPaintObject(UITrait.inst.mainObject());
ViewportUtil.scaleToBounds();
UITrait.inst.paintObject.skip_context = "paint";
UITrait.inst.mergedObject.visible = true;
UITrait.inst.resHandle.position = Config.getTextureResPos(project.layer_datas[0].res);
2019-03-13 16:03:40 +01:00
if (UITrait.inst.layers[0].texpaint.width != Config.getTextureRes()) {
var i = 0;
for (l in UITrait.inst.layers) {
2019-05-09 22:38:50 +02:00
l.resize(i == 0);
2019-03-13 16:03:40 +01:00
if (i > 0) l.texpaint.setDepthStencilFrom(UITrait.inst.layers[0].texpaint);
i++;
}
for (l in UITrait.inst.undoLayers) {
2019-05-09 22:38:50 +02:00
l.resize(false);
2019-03-13 16:03:40 +01:00
l.texpaint.setDepthStencilFrom(UITrait.inst.layers[0].texpaint);
}
var rts = iron.RenderPath.active.renderTargets;
2019-03-27 18:26:37 +01:00
rts.get("texpaint_blend0").image.unload();
rts.get("texpaint_blend0").raw.width = Config.getTextureRes();
rts.get("texpaint_blend0").raw.height = Config.getTextureRes();
rts.get("texpaint_blend0").image = kha.Image.createRenderTarget(Config.getTextureRes(), Config.getTextureRes(), kha.graphics4.TextureFormat.L8, kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
rts.get("texpaint_blend1").image.unload();
rts.get("texpaint_blend1").raw.width = Config.getTextureRes();
rts.get("texpaint_blend1").raw.height = Config.getTextureRes();
rts.get("texpaint_blend1").image = kha.Image.createRenderTarget(Config.getTextureRes(), Config.getTextureRes(), kha.graphics4.TextureFormat.L8, kha.graphics4.DepthStencilFormat.NoDepthAndStencil);
UITrait.inst.brushBlendDirty = true;
2019-02-02 18:49:19 +01:00
}
// for (l in UITrait.inst.layers) l.unload();
UITrait.inst.layers = [];
for (i in 0...project.layer_datas.length) {
var ld = project.layer_datas[i];
var l = new LayerSlot();
UITrait.inst.layers.push(l);
// TODO: create render target from bytes
2019-05-06 16:16:38 +02:00
var texpaint = kha.Image.fromBytes(Lz4.decode(ld.texpaint, ld.res * ld.res * 4), ld.res, ld.res);
2019-02-02 18:49:19 +01:00
l.texpaint.g2.begin(false);
l.texpaint.g2.drawImage(texpaint, 0, 0);
l.texpaint.g2.end();
// texpaint.unload();
2019-05-06 16:16:38 +02:00
var texpaint_nor = kha.Image.fromBytes(Lz4.decode(ld.texpaint_nor, ld.res * ld.res * 4), ld.res, ld.res);
2019-02-02 18:49:19 +01:00
l.texpaint_nor.g2.begin(false);
l.texpaint_nor.g2.drawImage(texpaint_nor, 0, 0);
l.texpaint_nor.g2.end();
// texpaint_nor.unload();
2019-05-06 16:16:38 +02:00
var texpaint_pack = kha.Image.fromBytes(Lz4.decode(ld.texpaint_pack, ld.res * ld.res * 4), ld.res, ld.res);
2019-02-02 18:49:19 +01:00
l.texpaint_pack.g2.begin(false);
l.texpaint_pack.g2.drawImage(texpaint_pack, 0, 0);
l.texpaint_pack.g2.end();
// texpaint_pack.unload();
2019-04-17 10:13:29 +02:00
if (ld.texpaint_mask != null) {
l.createMask(0, false);
2019-05-06 16:16:38 +02:00
var texpaint_mask = kha.Image.fromBytes(Lz4.decode(ld.texpaint_mask, ld.res * ld.res), ld.res, ld.res, kha.graphics4.TextureFormat.L8);
2019-04-17 10:13:29 +02:00
l.texpaint_mask.g2.begin(false);
l.texpaint_mask.g2.drawImage(texpaint_mask, 0, 0);
l.texpaint_mask.g2.end();
// texpaint_mask.unload();
}
l.maskOpacity = ld.opacity_mask;
2019-05-09 22:38:50 +02:00
l.material_mask = ld.material_mask > -1 ? UITrait.inst.materials[ld.material_mask] : null;
2019-04-17 10:13:29 +02:00
l.objectMask = ld.object_mask;
2019-02-02 18:49:19 +01:00
}
2019-03-28 15:21:45 +01:00
UITrait.inst.setLayer(UITrait.inst.layers[0]);
2019-02-02 18:49:19 +01:00
UITrait.inst.ddirty = 4;
UITrait.inst.hwnd.redraws = 2;
2019-03-27 14:26:51 +01:00
UITrait.inst.hwnd1.redraws = 2;
UITrait.inst.hwnd2.redraws = 2;
2019-03-04 13:21:14 +01:00
iron.data.Data.deleteBlob(path);
2019-02-02 18:49:19 +01:00
});
}
}