App.hx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. package arm;
  2. import kha.graphics2.truetype.StbTruetype;
  3. import kha.Image;
  4. import kha.Font;
  5. import kha.System;
  6. import zui.Zui;
  7. import zui.Themes;
  8. import zui.Nodes;
  9. import iron.Scene;
  10. import iron.data.Data;
  11. import iron.system.Input;
  12. import arm.ui.UITrait;
  13. import arm.ui.UINodes;
  14. import arm.ui.UIView2D;
  15. import arm.ui.UIMenu;
  16. import arm.ui.UIBox;
  17. import arm.ui.UIFiles;
  18. import arm.io.ImportAsset;
  19. import arm.sys.Path;
  20. import arm.util.RenderUtil;
  21. import arm.util.ViewportUtil;
  22. import arm.data.MaterialSlot;
  23. import arm.data.LayerSlot;
  24. import arm.data.ConstData;
  25. import arm.plugin.Camera;
  26. import arm.Config;
  27. import arm.Tool;
  28. import arm.Project;
  29. using StringTools;
  30. class App {
  31. public static var version = "0.8";
  32. static var appx = 0;
  33. static var appy = 0;
  34. static var winw = 0;
  35. static var winh = 0;
  36. public static var uienabled = true;
  37. public static var isDragging = false;
  38. public static var isResizing = false;
  39. public static var dragMaterial: MaterialSlot = null;
  40. public static var dragLayer: LayerSlot = null;
  41. public static var dragAsset: TAsset = null;
  42. public static var dragOffX = 0.0;
  43. public static var dragOffY = 0.0;
  44. static var dropPaths: Array<String> = [];
  45. public static var dropX = 0.0;
  46. public static var dropY = 0.0;
  47. public static var font: Font = null;
  48. public static var theme: TTheme;
  49. public static var color_wheel: Image;
  50. public static var uibox: Zui;
  51. public static var uimenu: Zui;
  52. public static var fileArg = "";
  53. public static var ELEMENT_H = 28;
  54. public static var resHandle = new Handle({position: Res2048});
  55. public static var bitsHandle = new Handle();
  56. public function new() {
  57. Log.init();
  58. winw = System.windowWidth();
  59. winh = System.windowHeight();
  60. #if arm_resizable
  61. iron.App.onResize = onResize;
  62. #end
  63. System.notifyOnDropFiles(function(filePath: String) {
  64. #if krom_windows
  65. if (!Path.isAscii(filePath)) filePath = Path.shortPath(filePath);
  66. #end
  67. var dropPath = filePath;
  68. #if krom_linux
  69. dropPath = untyped decodeURIComponent(dropPath);
  70. dropPaths = dropPath.split("file://");
  71. for (i in 0...dropPaths.length) dropPaths[i] = dropPaths[i].rtrim();
  72. #else
  73. dropPath = dropPath.rtrim();
  74. dropPaths.push(dropPath);
  75. #end
  76. });
  77. System.notifyOnApplicationState(
  78. // Release alt after alt-tab
  79. function(){ @:privateAccess Input.getKeyboard().upListener(kha.input.KeyCode.Alt); }, // Foreground
  80. function(){}, // Resume
  81. function(){}, // Pause
  82. function(){}, // Background
  83. function(){} // Shutdown
  84. );
  85. #if krom_windows
  86. Krom.setSaveAndQuitCallback(saveAndQuitCallback);
  87. #end
  88. Data.getFont("font_default.ttf", function(f: Font) {
  89. Data.getImage("color_wheel.k", function(image: Image) {
  90. font = f;
  91. theme = zui.Themes.dark;
  92. theme.FILL_WINDOW_BG = true;
  93. var kimg: kha.Kravur.KravurImage = js.lib.Object.create(untyped kha.Kravur.KravurImage.prototype);
  94. @:privateAccess kimg.mySize = 13;
  95. @:privateAccess kimg.width = 128;
  96. @:privateAccess kimg.height = 128;
  97. @:privateAccess kimg.baseline = 10;
  98. var chars = new haxe.ds.Vector(ConstData.font_x0.length);
  99. // kha.graphics2.Graphics.fontGlyphs = [for (i in 32...127) i];
  100. kha.graphics2.Graphics.fontGlyphs = [for (i in 32...206) i]; // Fix tiny font
  101. // for (i in 0...ConstData.font_x0.length) chars[i] = new Stbtt_bakedchar();
  102. for (i in 0...174) chars[i] = new Stbtt_bakedchar();
  103. for (i in 0...ConstData.font_x0.length) chars[i].x0 = ConstData.font_x0[i];
  104. for (i in 0...ConstData.font_y0.length) chars[i].y0 = ConstData.font_y0[i];
  105. for (i in 0...ConstData.font_x1.length) chars[i].x1 = ConstData.font_x1[i];
  106. for (i in 0...ConstData.font_y1.length) chars[i].y1 = ConstData.font_y1[i];
  107. for (i in 0...ConstData.font_xoff.length) chars[i].xoff = ConstData.font_xoff[i];
  108. for (i in 0...ConstData.font_yoff.length) chars[i].yoff = ConstData.font_yoff[i];
  109. for (i in 0...ConstData.font_xadvance.length) chars[i].xadvance = ConstData.font_xadvance[i];
  110. @:privateAccess kimg.chars = chars;
  111. Data.getBlob("font13.bin", function(fontbin: kha.Blob) {
  112. @:privateAccess kimg.texture = Image.fromBytes(fontbin.toBytes(), 128, 128, kha.graphics4.TextureFormat.L8);
  113. // @:privateAccess cast(font, kha.Kravur).images.set(130095, kimg);
  114. @:privateAccess cast(font, kha.Kravur).images.set(130174, kimg);
  115. });
  116. color_wheel = image;
  117. Nodes.enumTexts = enumTexts;
  118. uibox = new Zui({ font: f, scaleFactor: Config.raw.window_scale, color_wheel: color_wheel });
  119. uimenu = new Zui({ font: f, scaleFactor: Config.raw.window_scale, color_wheel: color_wheel });
  120. ELEMENT_H = uimenu.t.ELEMENT_H;
  121. // File to open passed as argument
  122. if (Krom.getArgCount() > 1) {
  123. var path = Krom.getArg(1);
  124. if (Path.isProject(path) ||
  125. Path.isMesh(path) ||
  126. Path.isTexture(path) ||
  127. Path.isFont(path)) {
  128. fileArg = path;
  129. }
  130. }
  131. iron.App.notifyOnUpdate(update);
  132. var root = Scene.active.root;
  133. new UITrait();
  134. new UINodes();
  135. new UIView2D();
  136. new Camera();
  137. iron.App.notifyOnRender2D(UITrait.inst.renderCursor);
  138. iron.App.notifyOnUpdate(UINodes.inst.update);
  139. iron.App.notifyOnRender2D(UINodes.inst.render);
  140. iron.App.notifyOnUpdate(UITrait.inst.update);
  141. iron.App.notifyOnRender2D(UITrait.inst.render);
  142. iron.App.notifyOnRender2D(render);
  143. appx = UITrait.inst.toolbarw;
  144. appy = UITrait.inst.headerh * 2;
  145. var cam = Scene.active.camera;
  146. cam.data.raw.fov = Std.int(cam.data.raw.fov * 100) / 100;
  147. cam.buildProjection();
  148. #if arm_creator
  149. Project.projectNew(); // Spawn terrain plane
  150. #end
  151. if (fileArg != "") {
  152. iron.App.notifyOnInit(function() {
  153. #if krom_windows
  154. fileArg = fileArg.replace("/", "\\");
  155. #end
  156. ImportAsset.run(fileArg, -1, -1, false);
  157. // Parse arguments
  158. // armorpaint import_path export_path export_file_name
  159. if (Krom.getArgCount() > 2) {
  160. UITrait.inst.textureExportPath = Krom.getArg(2);
  161. if (Krom.getArgCount() > 3) {
  162. UIFiles.filename = Krom.getArg(3);
  163. // hpreset.position = presets.indexOf("unreal")
  164. }
  165. }
  166. });
  167. }
  168. });
  169. });
  170. }
  171. static function saveAndQuitCallback(save: Bool) {
  172. saveWindowRect();
  173. if (save) Project.projectSave(true);
  174. else System.stop();
  175. }
  176. public static function w(): Int {
  177. // Draw material preview
  178. if (UITrait.inst != null && UITrait.inst.materialPreview) return RenderUtil.matPreviewSize;
  179. // Drawing decal preview
  180. if (UITrait.inst != null && UITrait.inst.decalPreview) return RenderUtil.decalPreviewSize;
  181. var res = 0;
  182. if (UINodes.inst == null || UITrait.inst == null) {
  183. res = System.windowWidth() - UITrait.defaultWindowW - UITrait.defaultToolbarW;
  184. }
  185. else if (UINodes.inst.show || UIView2D.inst.show) {
  186. res = System.windowWidth() - UITrait.inst.windowW - UINodes.inst.defaultWindowW - UITrait.inst.toolbarw;
  187. }
  188. else if (UITrait.inst.show) {
  189. res = System.windowWidth() - UITrait.inst.windowW - UITrait.inst.toolbarw;
  190. }
  191. else { // Distract free
  192. res = System.windowWidth();
  193. }
  194. if (UITrait.inst != null && UITrait.inst.viewIndex > -1) res = Std.int(res / 2);
  195. return res > 0 ? res : 1; // App was minimized, force render path resize
  196. }
  197. public static function h(): Int {
  198. // Draw material preview
  199. if (UITrait.inst != null && UITrait.inst.materialPreview) return RenderUtil.matPreviewSize;
  200. // Drawing decal preview
  201. if (UITrait.inst != null && UITrait.inst.decalPreview) return RenderUtil.decalPreviewSize;
  202. var res = 0;
  203. res = System.windowHeight();
  204. if (UITrait.inst == null) res -= UITrait.defaultHeaderH * 3;
  205. if (UITrait.inst != null && UITrait.inst.show && res > 0) res -= UITrait.inst.headerh * 3;
  206. return res > 0 ? res : 1; // App was minimized, force render path resize
  207. }
  208. public static function x(): Int {
  209. if (UITrait.inst.viewIndex == 1) return appx + w();
  210. return appx;
  211. }
  212. public static function y(): Int {
  213. return appy;
  214. }
  215. #if arm_resizable
  216. static function onResize() {
  217. resize();
  218. var ratio = System.windowHeight() / winh;
  219. UITrait.inst.tabh = Std.int(UITrait.inst.tabh * ratio);
  220. UITrait.inst.tabh1 = Std.int(UITrait.inst.tabh1 * ratio);
  221. UITrait.inst.tabh2 = System.windowHeight() - UITrait.inst.tabh - UITrait.inst.tabh1;
  222. winw = System.windowWidth();
  223. winh = System.windowHeight();
  224. }
  225. #end
  226. static function saveWindowRect() {
  227. #if krom_windows
  228. Config.raw.window_w = System.windowWidth();
  229. Config.raw.window_h = System.windowHeight();
  230. Config.raw.window_x = kha.Window.get(0).x;
  231. Config.raw.window_y = kha.Window.get(0).y;
  232. Config.save();
  233. #end
  234. }
  235. public static function resize() {
  236. if (System.windowWidth() == 0 || System.windowHeight() == 0) return;
  237. var cam = Scene.active.camera;
  238. if (cam.data.raw.ortho != null) {
  239. cam.data.raw.ortho[2] = -2 * (iron.App.h() / iron.App.w());
  240. cam.data.raw.ortho[3] = 2 * (iron.App.h() / iron.App.w());
  241. }
  242. cam.buildProjection();
  243. if (UITrait.inst.cameraType == CameraOrthographic) {
  244. ViewportUtil.updateCameraType(UITrait.inst.cameraType);
  245. }
  246. Context.ddirty = 2;
  247. appx = UITrait.inst.toolbarw;
  248. appy = UITrait.inst.headerh * 2;
  249. if (!UITrait.inst.show) {
  250. appx = 0;
  251. appy = 0;
  252. }
  253. if (UINodes.inst.grid != null) {
  254. UINodes.inst.grid.unload();
  255. UINodes.inst.grid = null;
  256. }
  257. redrawUI();
  258. }
  259. public static function redrawUI() {
  260. UITrait.inst.hwnd.redraws = 2;
  261. UITrait.inst.hwnd1.redraws = 2;
  262. UITrait.inst.hwnd2.redraws = 2;
  263. UITrait.inst.headerHandle.redraws = 2;
  264. UITrait.inst.toolbarHandle.redraws = 2;
  265. UITrait.inst.statusHandle.redraws = 2;
  266. UITrait.inst.menuHandle.redraws = 2;
  267. UITrait.inst.workspaceHandle.redraws = 2;
  268. UINodes.inst.hwnd.redraws = 2;
  269. if (Context.ddirty < 0) Context.ddirty = 0; // Tag cached viewport texture redraw
  270. }
  271. static function update() {
  272. var mouse = Input.getMouse();
  273. //var kb = Input.getKeyboard();
  274. if ((dragAsset != null || dragMaterial != null || dragLayer != null) &&
  275. (mouse.movementX != 0 || mouse.movementY != 0)) {
  276. isDragging = true;
  277. }
  278. if (mouse.released() && (dragAsset != null || dragMaterial != null || dragLayer != null)) {
  279. var mx = mouse.x;
  280. var my = mouse.y;
  281. var inViewport = UITrait.inst.paintVec.x < 1 && UITrait.inst.paintVec.x > 0 &&
  282. UITrait.inst.paintVec.y < 1 && UITrait.inst.paintVec.y > 0;
  283. var inLayers = UITrait.inst.htab.position == 0 &&
  284. mx > UITrait.inst.tabx && my < UITrait.inst.tabh;
  285. var in2dView = UIView2D.inst.show && UIView2D.inst.type == View2DLayer &&
  286. mx > UIView2D.inst.wx && mx < UIView2D.inst.wx + UIView2D.inst.ww &&
  287. my > UIView2D.inst.wy && my < UIView2D.inst.wy + UIView2D.inst.wh;
  288. var inNodes = UINodes.inst.show &&
  289. mx > UINodes.inst.wx && mx < UINodes.inst.wx + UINodes.inst.ww &&
  290. my > UINodes.inst.wy && my < UINodes.inst.wy + UINodes.inst.wh;
  291. if (dragAsset != null) {
  292. if (inNodes) { // Create image texture
  293. var index = 0;
  294. for (i in 0...Project.assets.length) {
  295. if (Project.assets[i] == dragAsset) {
  296. index = i;
  297. break;
  298. }
  299. }
  300. UINodes.inst.acceptAssetDrag(index);
  301. }
  302. else if (inViewport || inLayers || in2dView) { // Create mask
  303. Layers.createImageMask(dragAsset);
  304. }
  305. dragAsset = null;
  306. }
  307. else if (dragMaterial != null) {
  308. // Material dragged onto viewport or layers tab
  309. if (inViewport || inLayers || in2dView) {
  310. Layers.createFillLayer();
  311. }
  312. else if (inNodes) {
  313. var index = 0;
  314. for (i in 0...Project.materials.length) {
  315. if (Project.materials[i] == dragMaterial) {
  316. index = i;
  317. break;
  318. }
  319. }
  320. UINodes.inst.acceptMaterialDrag(index);
  321. }
  322. dragMaterial = null;
  323. }
  324. else if (dragLayer != null) {
  325. if (inNodes) {
  326. var index = 0;
  327. for (i in 0...Project.layers.length) {
  328. if (Project.layers[i] == dragLayer) {
  329. index = i;
  330. break;
  331. }
  332. }
  333. UINodes.inst.acceptLayerDrag(index);
  334. }
  335. dragLayer = null;
  336. }
  337. isDragging = false;
  338. }
  339. if (dropPaths.length > 0) {
  340. #if krom_linux
  341. var wait = !mouse.moved; // Mouse coords not updated on Linux during drag
  342. #else
  343. var wait = false;
  344. #end
  345. if (!wait) {
  346. dropX = mouse.x;
  347. dropY = mouse.y;
  348. var dropPath = dropPaths.shift();
  349. ImportAsset.run(dropPath, dropX, dropY);
  350. }
  351. }
  352. if (UIBox.show) UIBox.update();
  353. if (UIMenu.show) UIMenu.update();
  354. var decal = Context.tool == ToolDecal || Context.tool == ToolText;
  355. var isPicker = Context.tool == ToolPicker;
  356. #if krom_windows
  357. Zui.alwaysRedrawWindow = !UITrait.inst.cacheDraws ||
  358. UIMenu.show ||
  359. UIBox.show ||
  360. isDragging ||
  361. isPicker ||
  362. decal ||
  363. UIView2D.inst.show ||
  364. !UITrait.inst.brush3d ||
  365. UITrait.inst.frame < 3;
  366. #end
  367. if (Zui.alwaysRedrawWindow && Context.ddirty < 0) Context.ddirty = 0;
  368. }
  369. static function getDragImage(): kha.Image {
  370. if (dragAsset != null) return UITrait.inst.getImage(dragAsset);
  371. if (dragMaterial != null) return dragMaterial.imageIcon;
  372. if (dragLayer != null && Context.layerIsMask) return dragLayer.texpaint_mask_preview;
  373. else return dragLayer.texpaint_preview;
  374. }
  375. static function render(g: kha.graphics2.Graphics) {
  376. if (System.windowWidth() == 0 || System.windowHeight() == 0) return;
  377. var mouse = Input.getMouse();
  378. if (isDragging) {
  379. Krom.setMouseCursor(1); // Hand
  380. var img = getDragImage();
  381. @:privateAccess var size = 50 * UITrait.inst.ui.SCALE();
  382. var ratio = size / img.width;
  383. var h = img.height * ratio;
  384. #if (kha_opengl || kha_webgl)
  385. var inv = (dragMaterial != null || dragLayer != null) ? h : 0;
  386. #else
  387. var inv = 0;
  388. #end
  389. g.drawScaledImage(img, mouse.x + dragOffX, mouse.y + dragOffY + inv, size, h - inv * 2);
  390. }
  391. var usingMenu = false;
  392. if (UIMenu.show) usingMenu = mouse.y > UITrait.inst.headerh;
  393. uienabled = !UIBox.show && !usingMenu;
  394. if (UIBox.show) UIBox.render(g);
  395. if (UIMenu.show) UIMenu.render(g);
  396. }
  397. public static function enumTexts(nodeType: String): Array<String> {
  398. if (nodeType == "TEX_IMAGE") {
  399. return Project.assetNames.length > 0 ? Project.assetNames : [""];
  400. }
  401. else if (nodeType == "LAYER" || nodeType == "LAYER_MASK") {
  402. var layerNames: Array<String> = [];
  403. for (l in Project.layers) layerNames.push(l.name);
  404. return layerNames;
  405. }
  406. else if (nodeType == "MATERIAL") {
  407. var materialNames: Array<String> = [];
  408. for (m in Project.materials) materialNames.push(m.canvas.name);
  409. return materialNames;
  410. }
  411. return null;
  412. }
  413. public static function getAssetIndex(filename: String): Int {
  414. var i = Project.assetNames.indexOf(filename);
  415. return i >= 0 ? i : 0;
  416. }
  417. }