411 lines
13 KiB
Haxe
411 lines
13 KiB
Haxe
package arm;
|
|
|
|
import kha.graphics2.truetype.StbTruetype;
|
|
import kha.Image;
|
|
import kha.Font;
|
|
import kha.System;
|
|
import zui.Zui;
|
|
import zui.Zui.Handle;
|
|
import zui.Themes;
|
|
import zui.Nodes;
|
|
import iron.Scene;
|
|
import iron.data.Data;
|
|
import iron.system.Input;
|
|
import arm.ui.UITrait;
|
|
import arm.ui.UINodes;
|
|
import arm.ui.UIView2D;
|
|
import arm.ui.UIMenu;
|
|
import arm.ui.UIBox;
|
|
import arm.ui.UIFiles;
|
|
import arm.io.Importer;
|
|
import arm.util.Path;
|
|
import arm.util.RenderUtil;
|
|
import arm.util.ViewportUtil;
|
|
import arm.data.MaterialSlot;
|
|
import arm.data.ConstData;
|
|
import arm.plugin.Camera;
|
|
import arm.Config;
|
|
import arm.Tool;
|
|
using StringTools;
|
|
|
|
class App {
|
|
|
|
public static var version = "0.6";
|
|
public static function x():Int { return appx; }
|
|
public static function y():Int { return appy; }
|
|
static var appx = 0;
|
|
static var appy = 0;
|
|
public static var uienabled = true;
|
|
public static var isDragging = false;
|
|
public static var dragMaterial:MaterialSlot = null;
|
|
public static var dragAsset:zui.Canvas.TAsset = null;
|
|
public static var dragOffX = 0.0;
|
|
public static var dragOffY = 0.0;
|
|
public static var dropPath = "";
|
|
public static var dropX = 0.0;
|
|
public static var dropY = 0.0;
|
|
public static var font:Font = null;
|
|
public static var theme:TTheme;
|
|
public static var color_wheel:Image;
|
|
public static var uibox:Zui;
|
|
public static var fileArg = "";
|
|
public static var saveAndQuit = false;
|
|
|
|
public function new() {
|
|
Config.init();
|
|
|
|
#if arm_resizable
|
|
iron.App.onResize = onResize;
|
|
#end
|
|
|
|
System.notifyOnDropFiles(function(filePath:String) {
|
|
if (!checkAscii(filePath)) return;
|
|
dropPath = filePath;
|
|
dropPath = dropPath.replace("%20", " "); // Linux can pass %20 on drop
|
|
dropPath = dropPath.split("file://")[0]; // Multiple files dropped on Linux, take first
|
|
dropPath = dropPath.rtrim();
|
|
});
|
|
|
|
System.notifyOnApplicationState(
|
|
// Release alt after alt-tab
|
|
function(){ @:privateAccess Input.getKeyboard().upListener(kha.input.KeyCode.Alt); }, // Foreground
|
|
function(){}, // Resume
|
|
function(){}, // Pause
|
|
function(){}, // Background
|
|
function(){} // Shutdown
|
|
);
|
|
|
|
#if krom_windows
|
|
if (untyped Krom.setSaveAndQuitCallback != null) {
|
|
untyped Krom.setSaveAndQuitCallback(saveAndQuitCallback);
|
|
}
|
|
#end
|
|
|
|
Data.getFont("font_default.ttf", function(f:Font) {
|
|
Data.getImage('color_wheel.png', function(image:Image) {
|
|
font = f;
|
|
theme = zui.Themes.dark;
|
|
theme.FILL_WINDOW_BG = true;
|
|
|
|
#if kha_krom // Pre-baked font texture
|
|
var kimg:kha.Kravur.KravurImage = js.Object.create(untyped kha.Kravur.KravurImage.prototype);
|
|
@:privateAccess kimg.mySize = 13;
|
|
@:privateAccess kimg.width = 128;
|
|
@:privateAccess kimg.height = 128;
|
|
@:privateAccess kimg.baseline = 10;
|
|
var chars = new haxe.ds.Vector(ConstData.font_x0.length);
|
|
// kha.graphics2.Graphics.fontGlyphs = [for (i in 32...127) i];
|
|
kha.graphics2.Graphics.fontGlyphs = [for (i in 32...206) i]; // Fix tiny font
|
|
// for (i in 0...ConstData.font_x0.length) chars[i] = new Stbtt_bakedchar();
|
|
for (i in 0...174) chars[i] = new Stbtt_bakedchar();
|
|
for (i in 0...ConstData.font_x0.length) chars[i].x0 = ConstData.font_x0[i];
|
|
for (i in 0...ConstData.font_y0.length) chars[i].y0 = ConstData.font_y0[i];
|
|
for (i in 0...ConstData.font_x1.length) chars[i].x1 = ConstData.font_x1[i];
|
|
for (i in 0...ConstData.font_y1.length) chars[i].y1 = ConstData.font_y1[i];
|
|
for (i in 0...ConstData.font_xoff.length) chars[i].xoff = ConstData.font_xoff[i];
|
|
for (i in 0...ConstData.font_yoff.length) chars[i].yoff = ConstData.font_yoff[i];
|
|
for (i in 0...ConstData.font_xadvance.length) chars[i].xadvance = ConstData.font_xadvance[i];
|
|
@:privateAccess kimg.chars = chars;
|
|
Data.getBlob("font13.bin", function(fontbin:kha.Blob) {
|
|
@:privateAccess kimg.texture = Image.fromBytes(fontbin.toBytes(), 128, 128, kha.graphics4.TextureFormat.L8);
|
|
// @:privateAccess cast(font, kha.Kravur).images.set(130095, kimg);
|
|
@:privateAccess cast(font, kha.Kravur).images.set(130174, kimg);
|
|
});
|
|
#end
|
|
|
|
color_wheel = image;
|
|
Nodes.getEnumTexts = getEnumTexts;
|
|
Nodes.mapEnum = mapEnum;
|
|
uibox = new Zui({ font: f, scaleFactor: Config.raw.window_scale });
|
|
|
|
// File to open passed as argument
|
|
#if kha_krom
|
|
if (Krom.getArgCount() > 1) {
|
|
var path = Krom.getArg(1);
|
|
if (Path.checkProjectFormat(path) ||
|
|
Path.checkMeshFormat(path) ||
|
|
Path.checkTextureFormat(path) ||
|
|
Path.checkFontFormat(path)) {
|
|
fileArg = path;
|
|
}
|
|
}
|
|
#end
|
|
iron.App.notifyOnUpdate(update);
|
|
var root = Scene.active.root;
|
|
new UITrait();
|
|
new UINodes();
|
|
new UIView2D();
|
|
new Camera();
|
|
iron.App.notifyOnRender2D(@:privateAccess UITrait.inst.renderCursor);
|
|
iron.App.notifyOnUpdate(@:privateAccess UINodes.inst.update);
|
|
iron.App.notifyOnRender2D(@:privateAccess UINodes.inst.render);
|
|
iron.App.notifyOnUpdate(@:privateAccess UITrait.inst.update);
|
|
iron.App.notifyOnRender2D(@:privateAccess UITrait.inst.render);
|
|
iron.App.notifyOnRender2D(render);
|
|
appx = Config.raw.ui_layout == 0 ? UITrait.inst.toolbarw : UITrait.inst.windowW + UITrait.inst.toolbarw;
|
|
appy = UITrait.inst.headerh * 2;
|
|
var cam = Scene.active.camera;
|
|
cam.data.raw.fov = Std.int(cam.data.raw.fov * 100) / 100;
|
|
cam.buildProjection();
|
|
if (fileArg != "") {
|
|
Importer.importFile(fileArg);
|
|
if (Path.checkMeshFormat(fileArg)) {
|
|
UITrait.inst.toggleDistractFree();
|
|
}
|
|
else if (Path.checkTextureFormat(fileArg)) {
|
|
UITrait.inst.show2DView(1);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
static function saveAndQuitCallback() {
|
|
saveAndQuit = true;
|
|
Project.projectSave();
|
|
}
|
|
|
|
public static function w():Int {
|
|
// Draw material preview
|
|
if (UITrait.inst != null && UITrait.inst.materialPreview) return RenderUtil.matPreviewSize;
|
|
|
|
// Drawing decal preview
|
|
if (UITrait.inst != null && UITrait.inst.decalPreview) return RenderUtil.decalPreviewSize;
|
|
|
|
var res = 0;
|
|
if (UINodes.inst == null || UITrait.inst == null) {
|
|
res = System.windowWidth() - UITrait.defaultWindowW;
|
|
res -= UITrait.defaultToolbarW;
|
|
}
|
|
else if (UINodes.inst.show || UIView2D.inst.show) {
|
|
res = Std.int((System.windowWidth() - UITrait.inst.windowW) / 2);
|
|
res -= UITrait.inst.toolbarw;
|
|
}
|
|
else if (UITrait.inst.show) {
|
|
res = System.windowWidth() - UITrait.inst.windowW;
|
|
res -= UITrait.inst.toolbarw;
|
|
}
|
|
else {
|
|
res = System.windowWidth();
|
|
}
|
|
|
|
return res > 0 ? res : 1; // App was minimized, force render path resize
|
|
}
|
|
|
|
public static function h():Int {
|
|
// Draw material preview
|
|
if (UITrait.inst != null && UITrait.inst.materialPreview) return RenderUtil.matPreviewSize;
|
|
|
|
// Drawing decal preview
|
|
if (UITrait.inst != null && UITrait.inst.decalPreview) return RenderUtil.decalPreviewSize;
|
|
|
|
var res = 0;
|
|
res = System.windowHeight();
|
|
if (UITrait.inst == null) res -= UITrait.defaultHeaderH * 3;
|
|
if (UITrait.inst != null && UITrait.inst.show && res > 0) res -= UITrait.inst.headerh * 3;
|
|
|
|
return res > 0 ? res : 1; // App was minimized, force render path resize
|
|
}
|
|
|
|
#if arm_resizable
|
|
static function onResize() {
|
|
resize();
|
|
|
|
// Save window size
|
|
// Config.raw.window_w = System.windowWidth();
|
|
// Config.raw.window_h = System.windowHeight();
|
|
// Cap height, window is not centered properly
|
|
// var disp = kha.Display.primary;
|
|
// if (disp.height > 0 && Config.raw.window_h > disp.height - 140) {
|
|
// Config.raw.window_h = disp.height - 140;
|
|
// }
|
|
// Config.save();
|
|
}
|
|
#end
|
|
|
|
public static function resize() {
|
|
if (System.windowWidth() == 0 || System.windowHeight() == 0) return;
|
|
|
|
var cam = Scene.active.camera;
|
|
if (cam.data.raw.ortho != null) {
|
|
cam.data.raw.ortho[2] = -2 * (iron.App.h() / iron.App.w());
|
|
cam.data.raw.ortho[3] = 2 * (iron.App.h() / iron.App.w());
|
|
}
|
|
cam.buildProjection();
|
|
|
|
if (UITrait.inst.cameraType == 1) {
|
|
ViewportUtil.updateCameraType(UITrait.inst.cameraType);
|
|
}
|
|
|
|
Context.ddirty = 2;
|
|
|
|
var lay = Config.raw.ui_layout;
|
|
appx = lay == 0 ? UITrait.inst.toolbarw : UITrait.inst.windowW + UITrait.inst.toolbarw;
|
|
if (lay == 1 && (UINodes.inst.show || UIView2D.inst.show)) {
|
|
appx += iron.App.w() + UITrait.inst.toolbarw;
|
|
}
|
|
appy = UITrait.inst.headerh * 2;
|
|
|
|
if (!UITrait.inst.show) {
|
|
appx = 0;
|
|
appy = 0;
|
|
}
|
|
|
|
if (UINodes.inst.grid != null) {
|
|
UINodes.inst.grid.unload();
|
|
UINodes.inst.grid = null;
|
|
}
|
|
|
|
redrawUI();
|
|
}
|
|
|
|
public static function redrawUI() {
|
|
UITrait.inst.hwnd.redraws = 2;
|
|
UITrait.inst.hwnd1.redraws = 2;
|
|
UITrait.inst.hwnd2.redraws = 2;
|
|
UITrait.inst.headerHandle.redraws = 2;
|
|
UITrait.inst.toolbarHandle.redraws = 2;
|
|
UITrait.inst.statusHandle.redraws = 2;
|
|
UITrait.inst.menuHandle.redraws = 2;
|
|
UITrait.inst.workspaceHandle.redraws = 2;
|
|
UINodes.inst.hwnd.redraws = 2;
|
|
if (Context.ddirty < 0) Context.ddirty = 0; // Tag cached viewport texture redraw
|
|
}
|
|
|
|
static function update() {
|
|
var mouse = Input.getMouse();
|
|
var kb = Input.getKeyboard();
|
|
|
|
if ((dragAsset != null || dragMaterial != null) &&
|
|
(mouse.movementX != 0 || mouse.movementY != 0)) {
|
|
isDragging = true;
|
|
}
|
|
if (mouse.released() && (dragAsset != null || dragMaterial != null)) {
|
|
var mx = mouse.x + iron.App.x();
|
|
var my = mouse.y + iron.App.y();
|
|
var inViewport = UITrait.inst.paintVec.x < 1 && UITrait.inst.paintVec.x > 0 &&
|
|
UITrait.inst.paintVec.y < 1 && UITrait.inst.paintVec.y > 0;
|
|
var inLayers = UITrait.inst.htab.position == 0 &&
|
|
mx > UITrait.inst.tabx && my < UITrait.inst.tabh;
|
|
var in2dView = UIView2D.inst.show && UIView2D.inst.type == 0 &&
|
|
mx > UIView2D.inst.wx && mx < UIView2D.inst.wx + UIView2D.inst.ww &&
|
|
my > UIView2D.inst.wy && my < UIView2D.inst.wy + UIView2D.inst.wh;
|
|
var inNodes = UINodes.inst.show &&
|
|
mx > UINodes.inst.wx && mx < UINodes.inst.wx + UINodes.inst.ww &&
|
|
my > UINodes.inst.wy && my < UINodes.inst.wy + UINodes.inst.wh;
|
|
if (dragAsset != null) {
|
|
// Create image texture
|
|
if (inNodes) {
|
|
var index = 0;
|
|
for (i in 0...Project.assets.length) {
|
|
if (Project.assets[i] == dragAsset) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
UINodes.inst.acceptDrag(index);
|
|
}
|
|
// Create mask
|
|
else if (inViewport || inLayers || in2dView) {
|
|
Layers.createImageMask(dragAsset);
|
|
}
|
|
dragAsset = null;
|
|
}
|
|
if (dragMaterial != null) {
|
|
// Material dragged onto viewport or layers tab
|
|
if (inViewport || inLayers || in2dView) {
|
|
Layers.createFillLayer();
|
|
}
|
|
dragMaterial = null;
|
|
}
|
|
isDragging = false;
|
|
}
|
|
|
|
if (dropPath != "") {
|
|
#if krom_linux
|
|
var wait = !mouse.moved; // Mouse coords not updated on Linux during drag
|
|
#else
|
|
var wait = false;
|
|
#end
|
|
if (!wait) {
|
|
dropX = mouse.x + App.x();
|
|
dropY = mouse.y + App.y();
|
|
Importer.importFile(dropPath, dropX, dropY);
|
|
dropPath = "";
|
|
}
|
|
}
|
|
|
|
if (UIFiles.show || UIBox.show) UIBox.update();
|
|
|
|
var decal = Context.tool == ToolDecal || Context.tool == ToolText;
|
|
var isPicker = Context.tool == ToolPicker;
|
|
#if krom_windows
|
|
Zui.alwaysRedrawWindow =
|
|
UIMenu.show ||
|
|
UIBox.show ||
|
|
isDragging ||
|
|
isPicker ||
|
|
decal ||
|
|
UIView2D.inst.show ||
|
|
!UITrait.inst.brush3d ||
|
|
UITrait.inst.frame < 3;
|
|
#end
|
|
if (Zui.alwaysRedrawWindow && Context.ddirty < 0) Context.ddirty = 0;
|
|
}
|
|
|
|
static function render(g:kha.graphics2.Graphics) {
|
|
if (System.windowWidth() == 0 || System.windowHeight() == 0) return;
|
|
|
|
var mouse = Input.getMouse();
|
|
if (isDragging) {
|
|
var img = dragAsset != null ? UITrait.inst.getImage(dragAsset) : dragMaterial.imageIcon;
|
|
@:privateAccess var size = 50 * UITrait.inst.ui.SCALE;
|
|
var ratio = size / img.width;
|
|
var h = img.height * ratio;
|
|
#if (kha_opengl || kha_webgl)
|
|
var inv = dragMaterial != null ? h : 0;
|
|
#else
|
|
var inv = 0;
|
|
#end
|
|
g.drawScaledImage(img, mouse.x + iron.App.x() + dragOffX, mouse.y + iron.App.y() + dragOffY + inv, size, h - inv * 2);
|
|
}
|
|
|
|
var usingMenu = false;
|
|
if (UIMenu.show) usingMenu = mouse.y + App.y() > UITrait.inst.headerh;
|
|
|
|
uienabled = !UIFiles.show && !UIBox.show && !usingMenu;
|
|
if (UIFiles.show) UIFiles.render(g);
|
|
else if (UIBox.show) UIBox.render(g);
|
|
else if (UIMenu.show) UIMenu.render(g);
|
|
}
|
|
|
|
public static function getEnumTexts():Array<String> {
|
|
return Project.assetNames.length > 0 ? Project.assetNames : [""];
|
|
}
|
|
|
|
public static function mapEnum(s:String):String {
|
|
for (a in Project.assets) if (a.name == s) return a.file;
|
|
return "";
|
|
}
|
|
|
|
public static function getAssetIndex(f:String):Int {
|
|
for (i in 0...Project.assets.length) {
|
|
if (Project.assets[i].file == f) {
|
|
return i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public static function checkAscii(s:String):Bool {
|
|
for (i in 0...s.length) {
|
|
if (s.charCodeAt(i) > 127) {
|
|
// Bail out for now :(
|
|
UITrait.inst.showError(Strings.error0);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|