2
0

Project.hx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. package arm;
  2. import kha.System;
  3. import kha.Window;
  4. import kha.Image;
  5. import zui.Zui;
  6. import zui.Id;
  7. import zui.Nodes;
  8. import iron.data.SceneFormat;
  9. import iron.data.MeshData;
  10. import iron.data.Data;
  11. import iron.object.MeshObject;
  12. import iron.Scene;
  13. import arm.Viewport;
  14. import arm.sys.File;
  15. import arm.sys.Path;
  16. import arm.ui.UIFiles;
  17. import arm.ui.UIBox;
  18. import arm.ui.UINodes;
  19. import arm.ui.BoxPreferences;
  20. import arm.util.MeshUtil;
  21. import arm.shader.MakeMaterial;
  22. import arm.io.ImportAsset;
  23. import arm.io.ImportArm;
  24. import arm.io.ImportGpl;
  25. import arm.io.ImportMesh;
  26. import arm.io.ImportTexture;
  27. import arm.io.ExportArm;
  28. import arm.io.ExportGpl;
  29. import arm.ProjectFormat;
  30. #if (is_paint || is_sculpt)
  31. import arm.util.RenderUtil;
  32. import arm.ui.UIBase;
  33. import arm.data.LayerSlot;
  34. import arm.data.BrushSlot;
  35. import arm.data.FontSlot;
  36. import arm.data.MaterialSlot;
  37. import arm.io.ImportBlendMaterial;
  38. import arm.logic.NodesBrush;
  39. #end
  40. #if is_lab
  41. import kha.Blob;
  42. #end
  43. class Project {
  44. public static var raw: TProjectFormat = {};
  45. public static var filepath = "";
  46. public static var assets: Array<TAsset> = [];
  47. public static var assetNames: Array<String> = [];
  48. public static var assetId = 0;
  49. public static var meshAssets: Array<String> = [];
  50. public static var materialGroups: Array<TNodeGroup> = [];
  51. public static var paintObjects: Array<MeshObject> = null;
  52. public static var assetMap = new Map<Int, Dynamic>(); // kha.Image | kha.Font
  53. static var meshList: Array<String> = null;
  54. #if (is_paint || is_sculpt)
  55. public static var materials: Array<MaterialSlot> = null;
  56. public static var brushes: Array<BrushSlot> = null;
  57. public static var layers: Array<LayerSlot> = null;
  58. public static var fonts: Array<FontSlot> = null;
  59. public static var atlasObjects: Array<Int> = null;
  60. public static var atlasNames: Array<String> = null;
  61. #end
  62. #if is_lab
  63. public static var materialData: iron.data.MaterialData = null; ////
  64. public static var materials: Array<Dynamic> = null; ////
  65. public static var nodes = new Nodes();
  66. public static var canvas: TNodeCanvas;
  67. public static var defaultCanvas: Blob = null;
  68. #end
  69. public static function projectOpen() {
  70. UIFiles.show("arm", false, false, function(path: String) {
  71. if (!path.endsWith(".arm")) {
  72. Console.error(Strings.error0());
  73. return;
  74. }
  75. var current = @:privateAccess kha.graphics2.Graphics.current;
  76. if (current != null) current.end();
  77. ImportArm.runProject(path);
  78. if (current != null) current.begin(false);
  79. });
  80. }
  81. public static function projectSave(saveAndQuit = false) {
  82. if (filepath == "") {
  83. #if krom_ios
  84. var documentDirectory = Krom.saveDialog("", "");
  85. documentDirectory = documentDirectory.substr(0, documentDirectory.length - 8); // Strip /'untitled'
  86. filepath = documentDirectory + "/" + kha.Window.get(0).title + ".arm";
  87. #elseif krom_android
  88. filepath = Krom.savePath() + "/" + kha.Window.get(0).title + ".arm";
  89. #else
  90. projectSaveAs(saveAndQuit);
  91. return;
  92. #end
  93. }
  94. #if (krom_windows || krom_linux || krom_darwin)
  95. var filename = Project.filepath.substring(Project.filepath.lastIndexOf(Path.sep) + 1, Project.filepath.length - 4);
  96. Window.get(0).title = filename + " - " + Manifest.title;
  97. #end
  98. function _init() {
  99. ExportArm.runProject();
  100. if (saveAndQuit) System.stop();
  101. }
  102. iron.App.notifyOnInit(_init);
  103. }
  104. public static function projectSaveAs(saveAndQuit = false) {
  105. UIFiles.show("arm", true, false, function(path: String) {
  106. var f = UIFiles.filename;
  107. if (f == "") f = tr("untitled");
  108. filepath = path + Path.sep + f;
  109. if (!filepath.endsWith(".arm")) filepath += ".arm";
  110. projectSave(saveAndQuit);
  111. });
  112. }
  113. public static function projectNewBox() {
  114. #if (is_paint || is_sculpt)
  115. UIBox.showCustom(function(ui: Zui) {
  116. if (ui.tab(Id.handle(), tr("New Project"))) {
  117. if (meshList == null) {
  118. meshList = File.readDirectory(Path.data() + Path.sep + "meshes");
  119. for (i in 0...meshList.length) meshList[i] = meshList[i].substr(0, meshList[i].length - 4); // Trim .arm
  120. meshList.unshift("plane");
  121. meshList.unshift("sphere");
  122. meshList.unshift("rounded_cube");
  123. }
  124. ui.row([0.5, 0.5]);
  125. Context.raw.projectType = ui.combo(Id.handle({ position: Context.raw.projectType }), meshList, tr("Template"), true);
  126. Context.raw.projectAspectRatio = ui.combo(Id.handle({ position: Context.raw.projectAspectRatio }), ["1:1", "2:1", "1:2"], tr("Aspect Ratio"), true);
  127. @:privateAccess ui.endElement();
  128. ui.row([0.5, 0.5]);
  129. if (ui.button(tr("Cancel"))) {
  130. UIBox.hide();
  131. }
  132. if (ui.button(tr("OK")) || ui.isReturnDown) {
  133. Project.projectNew();
  134. Viewport.scaleToBounds();
  135. UIBox.hide();
  136. }
  137. }
  138. });
  139. #end
  140. #if is_lab
  141. Project.projectNew();
  142. Viewport.scaleToBounds();
  143. #end
  144. }
  145. public static function projectNew(resetLayers = true) {
  146. #if (krom_windows || krom_linux || krom_darwin)
  147. Window.get(0).title = Manifest.title;
  148. #end
  149. filepath = "";
  150. #if (is_paint || is_sculpt)
  151. if (Context.raw.mergedObject != null) {
  152. Context.raw.mergedObject.remove();
  153. Data.deleteMesh(Context.raw.mergedObject.data.handle);
  154. Context.raw.mergedObject = null;
  155. }
  156. Context.raw.layerPreviewDirty = true;
  157. Context.raw.layerFilter = 0;
  158. Project.meshAssets = [];
  159. #end
  160. Viewport.reset();
  161. Context.raw.paintObject = Context.mainObject();
  162. Context.selectPaintObject(Context.mainObject());
  163. for (i in 1...paintObjects.length) {
  164. var p = paintObjects[i];
  165. if (p == Context.raw.paintObject) continue;
  166. Data.deleteMesh(p.data.handle);
  167. p.remove();
  168. }
  169. var meshes = Scene.active.meshes;
  170. var len = meshes.length;
  171. for (i in 0...len) {
  172. var m = meshes[len - i - 1];
  173. if (Context.raw.projectObjects.indexOf(m) == -1 &&
  174. m.name != ".ParticleEmitter" &&
  175. m.name != ".Particle") {
  176. Data.deleteMesh(m.data.handle);
  177. m.remove();
  178. }
  179. }
  180. var handle = Context.raw.paintObject.data.handle;
  181. if (handle != "SceneSphere" && handle != "ScenePlane") {
  182. Data.deleteMesh(handle);
  183. }
  184. if (Context.raw.projectType != ModelRoundedCube) {
  185. var raw: TMeshData = null;
  186. if (Context.raw.projectType == ModelSphere || Context.raw.projectType == ModelTessellatedPlane) {
  187. var mesh: Dynamic = Context.raw.projectType == ModelSphere ?
  188. new arm.geom.Sphere(1, 512, 256) :
  189. new arm.geom.Plane(1, 1, 512, 512);
  190. raw = {
  191. name: "Tessellated",
  192. vertex_arrays: [
  193. { values: mesh.posa, attrib: "pos", data: "short4norm" },
  194. { values: mesh.nora, attrib: "nor", data: "short2norm" },
  195. { values: mesh.texa, attrib: "tex", data: "short2norm" }
  196. ],
  197. index_arrays: [
  198. { values: mesh.inda, material: 0 }
  199. ],
  200. scale_pos: mesh.scalePos,
  201. scale_tex: mesh.scaleTex
  202. };
  203. }
  204. else {
  205. Data.getBlob("meshes/" + meshList[Context.raw.projectType] + ".arm", function(b: kha.Blob) {
  206. raw = iron.system.ArmPack.decode(b.toBytes()).mesh_datas[0];
  207. });
  208. }
  209. var md = new MeshData(raw, function(md: MeshData) {});
  210. Data.cachedMeshes.set("SceneTessellated", md);
  211. if (Context.raw.projectType == ModelTessellatedPlane) {
  212. Viewport.setView(0, 0, 0.75, 0, 0, 0); // Top
  213. }
  214. }
  215. var n = Context.raw.projectType == ModelRoundedCube ? ".Cube" : "Tessellated";
  216. Data.getMesh("Scene", n, function(md: MeshData) {
  217. var current = @:privateAccess kha.graphics2.Graphics.current;
  218. if (current != null) current.end();
  219. #if is_paint
  220. Context.raw.pickerMaskHandle.position = MaskNone;
  221. #end
  222. Context.raw.paintObject.setData(md);
  223. Context.raw.paintObject.transform.scale.set(1, 1, 1);
  224. Context.raw.paintObject.transform.buildMatrix();
  225. Context.raw.paintObject.name = n;
  226. paintObjects = [Context.raw.paintObject];
  227. while (materials.length > 0) materials.pop().unload();
  228. Data.getMaterial("Scene", "Material", function(m: iron.data.MaterialData) {
  229. #if (is_paint || is_sculpt)
  230. materials.push(new MaterialSlot(m));
  231. #end
  232. #if is_lab
  233. materialData = m;
  234. #end
  235. });
  236. #if (is_paint || is_sculpt)
  237. Context.raw.material = materials[0];
  238. #end
  239. arm.ui.UINodes.inst.hwnd.redraws = 2;
  240. arm.ui.UINodes.inst.groupStack = [];
  241. materialGroups = [];
  242. #if (is_paint || is_sculpt)
  243. brushes = [new BrushSlot()];
  244. Context.raw.brush = brushes[0];
  245. fonts = [new FontSlot("default.ttf", App.font)];
  246. Context.raw.font = fonts[0];
  247. #end
  248. Project.setDefaultSwatches();
  249. Context.raw.swatch = Project.raw.swatches[0];
  250. Context.raw.pickedColor = Project.makeSwatch();
  251. Context.raw.colorPickerCallback = null;
  252. History.reset();
  253. MakeMaterial.parsePaintMaterial();
  254. #if (is_paint || is_sculpt)
  255. RenderUtil.makeMaterialPreview();
  256. #end
  257. for (a in assets) Data.deleteImage(a.file);
  258. assets = [];
  259. assetNames = [];
  260. assetMap = [];
  261. assetId = 0;
  262. Project.raw.packed_assets = [];
  263. Context.raw.ddirty = 4;
  264. #if (is_paint || is_sculpt)
  265. UIBase.inst.hwnds[TabSidebar0].redraws = 2;
  266. UIBase.inst.hwnds[TabSidebar1].redraws = 2;
  267. #end
  268. if (resetLayers) {
  269. #if (is_paint || is_sculpt)
  270. var aspectRatioChanged = layers[0].texpaint.width != Config.getTextureResX() || layers[0].texpaint.height != Config.getTextureResY();
  271. while (layers.length > 0) layers.pop().unload();
  272. var layer = new LayerSlot();
  273. layers.push(layer);
  274. Context.setLayer(layer);
  275. if (aspectRatioChanged) {
  276. iron.App.notifyOnInit(App.resizeLayers);
  277. }
  278. #end
  279. iron.App.notifyOnInit(App.initLayers);
  280. }
  281. if (current != null) current.begin(false);
  282. Context.raw.savedEnvmap = null;
  283. Context.raw.envmapLoaded = false;
  284. Scene.active.world.envmap = Context.raw.emptyEnvmap;
  285. Scene.active.world.raw.envmap = "World_radiance.k";
  286. Context.raw.showEnvmapHandle.selected = Context.raw.showEnvmap = false;
  287. Scene.active.world.probe.radiance = Context.raw.defaultRadiance;
  288. Scene.active.world.probe.radianceMipmaps = Context.raw.defaultRadianceMipmaps;
  289. Scene.active.world.probe.irradiance = Context.raw.defaultIrradiance;
  290. Scene.active.world.probe.raw.strength = 4.0;
  291. #if (is_paint || is_sculpt)
  292. Context.initTool();
  293. #end
  294. });
  295. #if (kha_direct3d12 || kha_vulkan || kha_metal)
  296. arm.render.RenderPathRaytrace.ready = false;
  297. #end
  298. }
  299. #if (is_paint || is_sculpt)
  300. public static function importMaterial() {
  301. UIFiles.show("arm,blend", false, true, function(path: String) {
  302. path.endsWith(".blend") ?
  303. ImportBlendMaterial.run(path) :
  304. ImportArm.runMaterial(path);
  305. });
  306. }
  307. public static function importBrush() {
  308. UIFiles.show("arm," + Path.textureFormats.join(","), false, true, function(path: String) {
  309. // Create brush from texture
  310. if (Path.isTexture(path)) {
  311. // Import texture
  312. ImportAsset.run(path);
  313. var assetIndex = 0;
  314. for (i in 0...Project.assets.length) {
  315. if (Project.assets[i].file == path) {
  316. assetIndex = i;
  317. break;
  318. }
  319. }
  320. // Create a new brush
  321. Context.raw.brush = new BrushSlot();
  322. Project.brushes.push(Context.raw.brush);
  323. // Create and link image node
  324. var n = NodesBrush.createNode("TEX_IMAGE");
  325. n.x = 83;
  326. n.y = 340;
  327. n.buttons[0].default_value = assetIndex;
  328. var links = Context.raw.brush.canvas.links;
  329. links.push({
  330. id: Context.raw.brush.nodes.getLinkId(links),
  331. from_id: n.id,
  332. from_socket: 0,
  333. to_id: 0,
  334. to_socket: 4
  335. });
  336. // Parse brush
  337. MakeMaterial.parseBrush();
  338. UINodes.inst.hwnd.redraws = 2;
  339. function _init() {
  340. RenderUtil.makeBrushPreview();
  341. }
  342. iron.App.notifyOnInit(_init);
  343. }
  344. // Import from project file
  345. else {
  346. ImportArm.runBrush(path);
  347. }
  348. });
  349. }
  350. #end
  351. public static function importMesh(replaceExisting = true, done: Void->Void = null) {
  352. UIFiles.show(Path.meshFormats.join(","), false, false, function(path: String) {
  353. importMeshBox(path, replaceExisting, true, done);
  354. });
  355. }
  356. public static function importMeshBox(path: String, replaceExisting = true, clearLayers = true, done: Void->Void = null) {
  357. #if krom_ios
  358. // Import immediately while access to resource is unlocked
  359. // Data.getBlob(path, function(b: kha.Blob) {});
  360. #end
  361. UIBox.showCustom(function(ui: Zui) {
  362. var tabVertical = Config.raw.touch_ui;
  363. if (ui.tab(Id.handle(), tr("Import Mesh"), tabVertical)) {
  364. if (path.toLowerCase().endsWith(".obj")) {
  365. Context.raw.splitBy = ui.combo(Id.handle(), [
  366. tr("Object"),
  367. tr("Group"),
  368. tr("Material"),
  369. tr("UDIM Tile"),
  370. ], tr("Split By"), true);
  371. if (ui.isHovered) ui.tooltip(tr("Split .obj mesh into objects"));
  372. }
  373. if (path.toLowerCase().endsWith(".fbx")) {
  374. Context.raw.parseTransform = ui.check(Id.handle({ selected: Context.raw.parseTransform }), tr("Parse Transforms"));
  375. if (ui.isHovered) ui.tooltip(tr("Load per-object transforms from .fbx"));
  376. }
  377. #if (is_paint || is_sculpt)
  378. if (path.toLowerCase().endsWith(".fbx") || path.toLowerCase().endsWith(".blend")) {
  379. Context.raw.parseVCols = ui.check(Id.handle({ selected: Context.raw.parseVCols }), tr("Parse Vertex Colors"));
  380. if (ui.isHovered) ui.tooltip(tr("Import vertex color data"));
  381. }
  382. #end
  383. ui.row([0.45, 0.45, 0.1]);
  384. if (ui.button(tr("Cancel"))) {
  385. UIBox.hide();
  386. }
  387. if (ui.button(tr("Import")) || ui.isReturnDown) {
  388. UIBox.hide();
  389. function doImport() {
  390. #if (is_paint || is_sculpt)
  391. ImportMesh.run(path, clearLayers, replaceExisting);
  392. #end
  393. #if is_lab
  394. ImportMesh.run(path, replaceExisting);
  395. #end
  396. if (done != null) done();
  397. }
  398. #if (krom_android || krom_ios)
  399. arm.App.notifyOnNextFrame(function() {
  400. Console.toast(tr("Importing mesh"));
  401. arm.App.notifyOnNextFrame(doImport);
  402. });
  403. #else
  404. doImport();
  405. #end
  406. }
  407. if (ui.button(tr("?"))) {
  408. File.loadUrl("https://github.com/armory3d/armorpaint_docs/blob/master/faq.md");
  409. }
  410. }
  411. });
  412. UIBox.clickToHide = false; // Prevent closing when going back to window from file browser
  413. }
  414. public static function reimportMesh() {
  415. if (Project.meshAssets != null && Project.meshAssets.length > 0 && File.exists(Project.meshAssets[0])) {
  416. importMeshBox(Project.meshAssets[0], true, false);
  417. }
  418. else importAsset();
  419. }
  420. public static function unwrapMeshBox(mesh: Dynamic, done: Void->Void) {
  421. UIBox.showCustom(function(ui: Zui) {
  422. var tabVertical = Config.raw.touch_ui;
  423. if (ui.tab(Id.handle(), tr("Unwrap Mesh"), tabVertical)) {
  424. var unwrapPlugins = [];
  425. if (BoxPreferences.filesPlugin == null) {
  426. BoxPreferences.fetchPlugins();
  427. }
  428. for (f in BoxPreferences.filesPlugin) {
  429. if (f.indexOf("uv_unwrap") >= 0 && f.endsWith(".js")) {
  430. unwrapPlugins.push(f);
  431. }
  432. }
  433. unwrapPlugins.push("equirect");
  434. var unwrapBy = ui.combo(Id.handle(), unwrapPlugins, tr("Plugin"), true);
  435. ui.row([0.5, 0.5]);
  436. if (ui.button(tr("Cancel"))) {
  437. UIBox.hide();
  438. }
  439. if (ui.button(tr("Unwrap")) || ui.isReturnDown) {
  440. UIBox.hide();
  441. function doImport() {
  442. if (unwrapBy == unwrapPlugins.length - 1) {
  443. MeshUtil.equirectUnwrap(mesh);
  444. }
  445. else {
  446. var f = unwrapPlugins[unwrapBy];
  447. if (Config.raw.plugins.indexOf(f) == -1) {
  448. Config.enablePlugin(f);
  449. Console.info(f + " " + tr("plugin enabled"));
  450. }
  451. MeshUtil.unwrappers.get(f)(mesh);
  452. }
  453. done();
  454. }
  455. #if (krom_android || krom_ios)
  456. arm.App.notifyOnNextFrame(function() {
  457. Console.toast(tr("Unwrapping mesh"));
  458. arm.App.notifyOnNextFrame(doImport);
  459. });
  460. #else
  461. doImport();
  462. #end
  463. }
  464. }
  465. });
  466. }
  467. public static function importAsset(filters: String = null, hdrAsEnvmap = true) {
  468. if (filters == null) filters = Path.textureFormats.join(",") + "," + Path.meshFormats.join(",");
  469. UIFiles.show(filters, false, true, function(path: String) {
  470. ImportAsset.run(path, -1.0, -1.0, true, hdrAsEnvmap);
  471. });
  472. }
  473. public static function importSwatches(replaceExisting = false) {
  474. UIFiles.show("arm,gpl", false, false, function(path: String) {
  475. if (Path.isGimpColorPalette(path)) ImportGpl.run(path, replaceExisting);
  476. else ImportArm.runSwatches(path, replaceExisting);
  477. });
  478. }
  479. public static function reimportTextures() {
  480. for (asset in Project.assets) {
  481. reimportTexture(asset);
  482. }
  483. }
  484. public static function reimportTexture(asset: TAsset) {
  485. function load(path: String) {
  486. asset.file = path;
  487. var i = Project.assets.indexOf(asset);
  488. Data.deleteImage(asset.file);
  489. Project.assetMap.remove(asset.id);
  490. var oldAsset = Project.assets[i];
  491. Project.assets.splice(i, 1);
  492. Project.assetNames.splice(i, 1);
  493. ImportTexture.run(asset.file);
  494. Project.assets.insert(i, Project.assets.pop());
  495. Project.assetNames.insert(i, Project.assetNames.pop());
  496. #if (is_paint || is_sculpt)
  497. if (Context.raw.texture == oldAsset) Context.raw.texture = Project.assets[i];
  498. #end
  499. function _next() {
  500. MakeMaterial.parsePaintMaterial();
  501. #if (is_paint || is_sculpt)
  502. RenderUtil.makeMaterialPreview();
  503. UIBase.inst.hwnds[TabSidebar1].redraws = 2;
  504. #end
  505. }
  506. App.notifyOnNextFrame(_next);
  507. }
  508. if (!File.exists(asset.file)) {
  509. var filters = Path.textureFormats.join(",");
  510. UIFiles.show(filters, false, false, function(path: String) {
  511. load(path);
  512. });
  513. }
  514. else load(asset.file);
  515. }
  516. public static function getImage(asset: TAsset): Image {
  517. return asset != null ? Project.assetMap.get(asset.id) : null;
  518. }
  519. #if (is_paint || is_sculpt)
  520. public static function getUsedAtlases(): Array<String> {
  521. if (Project.atlasObjects == null) return null;
  522. var used: Array<Int> = [];
  523. for (i in Project.atlasObjects) if (used.indexOf(i) == -1) used.push(i);
  524. if (used.length > 1) {
  525. var res: Array<String> = [];
  526. for (i in used) res.push(Project.atlasNames[i]);
  527. return res;
  528. }
  529. else return null;
  530. }
  531. public static function isAtlasObject(p: MeshObject): Bool {
  532. if (Context.raw.layerFilter <= Project.paintObjects.length) return false;
  533. var atlasName = getUsedAtlases()[Context.raw.layerFilter - Project.paintObjects.length - 1];
  534. var atlasI = Project.atlasNames.indexOf(atlasName);
  535. return atlasI == Project.atlasObjects[Project.paintObjects.indexOf(p)];
  536. }
  537. public static function getAtlasObjects(objectMask: Int): Array<MeshObject> {
  538. var atlasName = Project.getUsedAtlases()[objectMask - Project.paintObjects.length - 1];
  539. var atlasI = Project.atlasNames.indexOf(atlasName);
  540. var visibles: Array<MeshObject> = [];
  541. for (i in 0...Project.paintObjects.length) if (Project.atlasObjects[i] == atlasI) visibles.push(Project.paintObjects[i]);
  542. return visibles;
  543. }
  544. #end
  545. public static function packedAssetExists(packed_assets: Array<TPackedAsset>, name: String): Bool {
  546. for (pa in packed_assets) if (pa.name == name) return true;
  547. return false;
  548. }
  549. public static function exportSwatches() {
  550. UIFiles.show("arm,gpl", true, false, function(path: String) {
  551. var f = UIFiles.filename;
  552. if (f == "") f = tr("untitled");
  553. if (Path.isGimpColorPalette(f)) ExportGpl.run(path + Path.sep + f, f.substring(0, f.lastIndexOf(".")), Project.raw.swatches);
  554. else ExportArm.runSwatches(path + Path.sep + f);
  555. });
  556. }
  557. public static function makeSwatch(base = 0xffffffff): TSwatchColor {
  558. return { base: base, opacity: 1.0, occlusion: 1.0, roughness: 0.0, metallic: 0.0, normal: 0xff8080ff, emission: 0.0, height: 0.0, subsurface: 0.0 };
  559. }
  560. public static function cloneSwatch(swatch: TSwatchColor): TSwatchColor {
  561. return { base: swatch.base, opacity: swatch.opacity, occlusion: swatch.occlusion, roughness: swatch.roughness, metallic: swatch.metallic, normal: swatch.normal, emission: swatch.emission, height: swatch.height, subsurface: swatch.subsurface };
  562. }
  563. public static function setDefaultSwatches() {
  564. // 32-Color Palette by Andrew Kensler
  565. // http://eastfarthing.com/blog/2016-05-06-palette/
  566. Project.raw.swatches = [];
  567. var colors = [0xffffffff, 0xff000000, 0xffd6a090, 0xffa12c32, 0xfffa2f7a, 0xfffb9fda, 0xffe61cf7, 0xff992f7c, 0xff47011f, 0xff051155, 0xff4f02ec, 0xff2d69cb, 0xff00a6ee, 0xff6febff, 0xff08a29a, 0xff2a666a, 0xff063619, 0xff4a4957, 0xff8e7ba4, 0xffb7c0ff, 0xffacbe9c, 0xff827c70, 0xff5a3b1c, 0xffae6507, 0xfff7aa30, 0xfff4ea5c, 0xff9b9500, 0xff566204, 0xff11963b, 0xff51e113, 0xff08fdcc];
  568. for (c in colors) Project.raw.swatches.push(Project.makeSwatch(c));
  569. }
  570. public static function getMaterialGroupByName(groupName: String): TNodeGroup {
  571. for (g in materialGroups) if (g.canvas.name == groupName) return g;
  572. return null;
  573. }
  574. #if (is_paint || is_sculpt)
  575. public static function isMaterialGroupInUse(group: TNodeGroup): Bool {
  576. var canvases: Array<TNodeCanvas> = [];
  577. for (m in materials) canvases.push(m.canvas);
  578. for (m in materialGroups) canvases.push(m.canvas);
  579. for (canvas in canvases) {
  580. for (n in canvas.nodes) {
  581. if (n.type == "GROUP" && n.name == group.canvas.name) {
  582. return true;
  583. }
  584. }
  585. }
  586. return false;
  587. }
  588. #end
  589. }
  590. typedef TNodeGroup = {
  591. public var nodes: Nodes;
  592. public var canvas: TNodeCanvas;
  593. }