Prefab.hx 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
  1. package hide.view;
  2. import hrt.prefab.l3d.Instance;
  3. import hide.view.CameraController.CamController;
  4. using Lambda;
  5. import hxd.Math;
  6. import hxd.Key as K;
  7. import hrt.prefab.Prefab as PrefabElement;
  8. import hrt.prefab.Object3D;
  9. import hide.comp.cdb.DataFiles;
  10. class FiltersPopup extends hide.comp.Popup {
  11. var editor:Prefab;
  12. public function new(?parent:Element, editor:Prefab, filters:Map<String, Bool>, type:String) {
  13. super(parent);
  14. this.editor = editor;
  15. element.addClass("settings-popup");
  16. element.css("max-width", "300px");
  17. var form_div = new Element("<div>").addClass("form-grid").appendTo(element);
  18. {
  19. for (typeid in filters.keys()) {
  20. var on = filters[typeid];
  21. var input = new Element('<input type="checkbox" id="$typeid" value="$typeid"/>');
  22. if (on)
  23. input.get(0).toggleAttribute("checked", true);
  24. input.change((e) -> {
  25. @:privateAccess editor.sceneFiltersChanged();
  26. var on = !filters[typeid];
  27. filters.set(typeid, on);
  28. switch (type) {
  29. case "Graphics":
  30. @:privateAccess editor.applyGraphicsFilter(typeid, on);
  31. case "Scene":
  32. @:privateAccess editor.applySceneFilter(typeid, on);
  33. }
  34. });
  35. form_div.append(input);
  36. var nameCap = typeid.substr(0, 1).toUpperCase() + typeid.substr(1);
  37. form_div.append(new Element('<label for="$typeid" class="left">$nameCap</label>'));
  38. }
  39. }
  40. }
  41. }
  42. @:access(hide.view.Prefab)
  43. class PrefabSceneEditor extends hide.comp.SceneEditor {
  44. var parent : Prefab;
  45. public function new(view) {
  46. super(view);
  47. parent = cast view;
  48. this.localTransform = false; // TODO: Expose option
  49. }
  50. override function update(dt) {
  51. super.update(dt);
  52. parent.onUpdate(dt);
  53. }
  54. override function applySceneStyle(p:PrefabElement) {
  55. parent.applySceneStyle(p);
  56. }
  57. override function onPrefabChange(p: PrefabElement, ?pname: String) {
  58. super.onPrefabChange(p, pname);
  59. parent.onPrefabChange(p, pname);
  60. }
  61. override function getNewContextMenu(current: PrefabElement, ?onMake: PrefabElement->Void=null, ?groupByType = true ) {
  62. var newItems = super.getNewContextMenu(current, onMake, groupByType);
  63. var recents = getNewRecentContextMenu(current, onMake);
  64. function setup(p : PrefabElement) {
  65. autoName(p);
  66. haxe.Timer.delay(() -> addElements([p]), 0);
  67. }
  68. function addNewInstances() {
  69. var items = new Array<hide.comp.ContextMenu.MenuItem>();
  70. for(type in DataFiles.getAvailableTypes() ) {
  71. var typeId = DataFiles.getTypeName(type);
  72. var label = typeId.charAt(0).toUpperCase() + typeId.substr(1);
  73. var refCols = Instance.findRefColumns(type);
  74. var refSheet = refCols == null ? null : type.base.getSheet(refCols.sheet);
  75. var idCol = refCols == null ? null : Instance.findIDColumn(refSheet);
  76. function make(name) {
  77. var p = new Instance(current == null ? sceneData : current, null);
  78. p.name = name;
  79. p.props = makeCdbProps(p, type);
  80. setup(p);
  81. if(onMake != null)
  82. onMake(p);
  83. return p;
  84. }
  85. if(idCol != null && refSheet.props.dataFiles == null ) {
  86. var kindItems = new Array<hide.comp.ContextMenu.MenuItem>();
  87. for(line in refSheet.lines) {
  88. var kind : String = Reflect.getProperty(line, idCol.name);
  89. kindItems.push({
  90. label : kind,
  91. click : function() {
  92. var p = make(kind.charAt(0).toLowerCase() + kind.substr(1));
  93. var obj : Dynamic = p.props;
  94. for( c in refCols.cols ) {
  95. if( c == refCols.cols[refCols.cols.length-1] )
  96. Reflect.setField(obj, c.name, kind);
  97. else {
  98. var s = Reflect.field(obj,c.name);
  99. if( s == null ) {
  100. s = {};
  101. Reflect.setField(obj, c.name, s);
  102. }
  103. obj = s;
  104. }
  105. }
  106. }
  107. });
  108. }
  109. items.unshift({
  110. label : label,
  111. menu: kindItems
  112. });
  113. }
  114. else {
  115. items.push({
  116. label : label,
  117. click : make.bind(typeId)
  118. });
  119. }
  120. }
  121. newItems.unshift({
  122. label : "Instance",
  123. menu: items
  124. });
  125. };
  126. addNewInstances();
  127. newItems.unshift({
  128. label : "Recents",
  129. menu : recents,
  130. });
  131. var shaders = newItems.find(i -> i.label == "Shader");
  132. if (shaders != null) {
  133. //newItems.push({label: null, isSeparator: true});
  134. //newItems.remove(shaders);
  135. //splitMenu(newItems, "Shader", shaders.menu);
  136. }
  137. return newItems;
  138. }
  139. override function getAvailableTags() {
  140. return cast ide.currentConfig.get("sceneeditor.tags");
  141. }
  142. }
  143. @:keep
  144. class Prefab extends hide.view.FileView {
  145. public var sceneEditor : PrefabSceneEditor;
  146. var data : hrt.prefab.Prefab;
  147. var tools : hide.comp.Toolbar;
  148. var layerToolbar : hide.comp.Toolbar;
  149. var layerButtons : Map<PrefabElement, hide.comp.Toolbar.ToolToggle>;
  150. var resizablePanel : hide.comp.ResizablePanel;
  151. // autoSync
  152. var autoSync : Bool;
  153. var currentVersion : Int = 0;
  154. var lastSyncChange : Float = 0.;
  155. var sceneFilters : Map<String, Bool>;
  156. var graphicsFilters : Map<String, Bool>;
  157. var viewModes : Map<String, Bool>;
  158. var posToolTip : h2d.Text;
  159. var matLibPath : String;
  160. var renameMatsHistory : Array<Dynamic>;
  161. var scene(get, null): hide.comp.Scene;
  162. function get_scene() return sceneEditor.scene;
  163. public var properties(get, null): hide.comp.PropsEditor;
  164. function get_properties() return sceneEditor.properties;
  165. override function new(state) {
  166. super(state);
  167. var config = hide.Config.loadForFile(ide, ide.getPath(state.path));
  168. var matLibs : Array<Dynamic> = config.get("materialLibraries");
  169. if (matLibs != null) {
  170. for (lib in matLibs) {
  171. if (state.path == lib.path) {
  172. matLibPath = lib.path;
  173. renameMatsHistory = [];
  174. break;
  175. }
  176. }
  177. }
  178. }
  179. function createData() {
  180. data = new hrt.prefab.Prefab(null, null);
  181. }
  182. var sceneReadyDelayed : Array<() -> Void> = [];
  183. /**
  184. Call a function when the sceneEditor is properly initialized
  185. **/
  186. public function delaySceneEditor(callback : () -> Void) {
  187. if (sceneEditor != null) {
  188. sceneEditor.delayReady(callback);
  189. }
  190. else {
  191. sceneReadyDelayed.push(callback);
  192. }
  193. }
  194. function createEditor() {
  195. sceneEditor = new PrefabSceneEditor(this);
  196. sceneEditor.onSceneReady = onSceneReady;
  197. for (callback in sceneReadyDelayed) {
  198. sceneEditor.delayReady(callback);
  199. }
  200. sceneReadyDelayed.empty();
  201. }
  202. override function onHide() {
  203. super.onHide();
  204. //ide.closeInspector();
  205. }
  206. override function onDisplay() {
  207. if( sceneEditor != null ) sceneEditor.dispose();
  208. createData();
  209. var content = sys.io.File.getContent(getPath());
  210. currentSign = ide.makeSignature(content);
  211. element.html('
  212. <div class="flex vertical">
  213. <div id="prefab-toolbar"></div>
  214. <div class="scene-partition" style="display: flex; flex-direction: row; flex: 1; overflow: hidden;">
  215. <div class="heaps-scene"></div>
  216. <div class="tree-column">
  217. <div class="flex vertical">
  218. <div class="hide-toolbar">
  219. <div class="toolbar-label">
  220. <div class="icon ico ico-sitemap"></div>
  221. Scene
  222. </div>
  223. <div class="button collapse-btn" title="Collapse all">
  224. <div class="icon ico ico-reply-all"></div>
  225. </div>
  226. <div class="button combine-btn layout-btn" title="Toggle columns layout">
  227. <div class="icon ico ico-compress"></div>
  228. </div>
  229. <div class="button separate-btn layout-btn" title="Toggle columns layout">
  230. <div class="icon ico ico-expand"></div>
  231. </div>
  232. <div
  233. class="button hide-cols-btn close-btn"
  234. title="Hide Tree & Props (${config.get("key.sceneeditor.toggleLayout")})"
  235. >
  236. <div class="icon ico ico-chevron-right"></div>
  237. </div>
  238. </div>
  239. <div class="hide-scenetree"></div>
  240. <div class="render-props-edition">
  241. <div class="hide-toolbar">
  242. <div class="toolbar-label">
  243. <div class="icon ico ico-sun-o"></div>
  244. Render props
  245. </div>
  246. </div>
  247. <div class="hide-scenetree"></div>
  248. </div>
  249. </div>
  250. </div>
  251. <div class="props-column">
  252. <div class="hide-toolbar">
  253. <div class="toolbar-label">
  254. <div class="icon ico ico-sitemap"></div>
  255. Properties
  256. </div>
  257. </div>
  258. <div class="hide-scroll"></div>
  259. </div>
  260. <div
  261. class="button show-cols-btn close-btn"
  262. title="Show Tree & Props (${config.get("key.sceneeditor.toggleLayout")})"
  263. >
  264. <div class="icon ico ico-chevron-left"></div>
  265. </div>
  266. </div>
  267. </div>
  268. ');
  269. tools = new hide.comp.Toolbar(null,element.find("#prefab-toolbar"));
  270. layerToolbar = new hide.comp.Toolbar(null,element.find(".layer-buttons"));
  271. currentVersion = undo.currentID;
  272. createEditor();
  273. element.find(".hide-scenetree").first().append(sceneEditor.sceneTree.element);
  274. element.find(".render-props-edition").find('.hide-scenetree').append(sceneEditor.renderPropsTree.element);
  275. element.find(".hide-scroll").first().append(properties.element);
  276. element.find(".heaps-scene").first().append(scene.element);
  277. var treeColumn = element.find(".tree-column").first();
  278. resizablePanel = new hide.comp.ResizablePanel(Horizontal, treeColumn);
  279. resizablePanel.saveDisplayKey = "treeColumn";
  280. resizablePanel.onResize = () -> @:privateAccess if( scene.window != null) scene.window.checkResize();
  281. sceneEditor.sceneTree.element.addClass("small");
  282. sceneEditor.renderPropsTree.element.addClass("small");
  283. refreshColLayout();
  284. element.find(".combine-btn").first().click((_) -> setCombine(true));
  285. element.find(".separate-btn").first().click((_) -> setCombine(false));
  286. element.find(".show-cols-btn").first().click(showColumns);
  287. element.find(".hide-cols-btn").first().click(hideColumns);
  288. element.find(".collapse-btn").click(function(e) {
  289. sceneEditor.collapseTree();
  290. });
  291. var rpEditionvisible = Ide.inst.currentConfig.get("sceneeditor.renderprops.edit", false);
  292. setRenderPropsEditionVisibility(rpEditionvisible);
  293. keys.register("sceneeditor.toggleLayout", () -> {
  294. if( element.find(".tree-column").first().css('display') == 'none' )
  295. showColumns();
  296. else
  297. hideColumns();
  298. });
  299. refreshSceneFilters();
  300. refreshGraphicsFilters();
  301. refreshViewModes();
  302. }
  303. override function onBeforeClose() {
  304. if(Ide.inst.ideConfig.autoSavePrefab)
  305. this.save();
  306. return super.onBeforeClose();
  307. }
  308. function refreshColLayout() {
  309. var config = ide.ideConfig;
  310. if( config.sceneEditorLayout == null ) {
  311. config.sceneEditorLayout = {
  312. colsVisible: true,
  313. colsCombined: false,
  314. };
  315. }
  316. setCombine(config.sceneEditorLayout.colsCombined);
  317. if( config.sceneEditorLayout.colsVisible )
  318. showColumns();
  319. else
  320. hideColumns();
  321. if (resizablePanel != null) resizablePanel.setSize();
  322. }
  323. override function onActivate() {
  324. if( element == null )
  325. return;
  326. if( sceneEditor != null )
  327. refreshColLayout();
  328. if (tools != null)
  329. tools.refreshToggles();
  330. setRenderPropsEditionVisibility(Ide.inst.currentConfig.get("sceneeditor.renderprops.edit", false));
  331. }
  332. public function hideColumns(?_) {
  333. element.find(".tree-column").first().hide();
  334. element.find(".props-column").first().hide();
  335. element.find(".splitter").first().hide();
  336. element.find(".show-cols-btn").first().show();
  337. ide.ideConfig.sceneEditorLayout.colsVisible = false;
  338. @:privateAccess ide.config.global.save();
  339. @:privateAccess if( scene.window != null) scene.window.checkResize();
  340. }
  341. public function showColumns(?_) {
  342. element.find(".tree-column").first().show();
  343. element.find(".props-column").first().show();
  344. element.find(".splitter").first().show();
  345. element.find(".show-cols-btn").first().hide();
  346. ide.ideConfig.sceneEditorLayout.colsVisible = true;
  347. @:privateAccess ide.config.global.save();
  348. @:privateAccess if( scene.window != null) scene.window.checkResize();
  349. }
  350. function setCombine(val) {
  351. var fullscene = element.find(".scene-partition").first();
  352. var props = element.find(".props-column").first();
  353. fullscene.toggleClass("reduced-columns", val);
  354. if( val ) {
  355. element.find(".hide-scenetree").first().parent().append(props);
  356. element.find(".combine-btn").first().hide();
  357. element.find(".separate-btn").first().show();
  358. resizablePanel.setSize();
  359. } else {
  360. fullscene.append(props);
  361. element.find(".combine-btn").first().show();
  362. element.find(".separate-btn").first().hide();
  363. }
  364. ide.ideConfig.sceneEditorLayout.colsCombined = val;
  365. @:privateAccess ide.config.global.save();
  366. @:privateAccess if( scene.window != null) scene.window.checkResize();
  367. }
  368. public function onSceneReady() {
  369. data = hxd.res.Loader.currentInstance.load(state.path).toPrefab().loadBypassCache();
  370. sceneEditor.setPrefab(cast data);
  371. refreshSceneFilters();
  372. refreshGraphicsFilters();
  373. refreshViewModes();
  374. tools.saveDisplayKey = "Prefab/toolbar";
  375. /*gridStep = @:privateAccess sceneEditor.gizmo.moveStep;*/
  376. var toolsDefs = new Array<hide.comp.Toolbar.ToolDef>();
  377. toolsDefs.push({id: "perspectiveCamera", title : "Perspective camera", icon : "video-camera", type : Button(() -> resetCamera(false)) });
  378. toolsDefs.push({id: "camSettings", title : "Camera Settings", icon : "camera", type : Popup((e : hide.Element) -> new hide.comp.CameraControllerEditor(sceneEditor, e)) });
  379. toolsDefs.push({id: "topCamera", title : "Top camera", icon : "video-camera", iconStyle: { transform: "rotateZ(90deg)" }, type : Button(() -> resetCamera(true))});
  380. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  381. toolsDefs.push({id: "snapToGroundToggle", title : "Snap to ground", icon : "anchor", type : Toggle((v) -> sceneEditor.snapToGround = v)});
  382. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  383. toolsDefs.push({id: "translationMode", title : "Gizmo translation Mode", icon : "arrows", type : Button(@:privateAccess sceneEditor.gizmo.translationMode)});
  384. toolsDefs.push({id: "rotationMode", title : "Gizmo rotation Mode", icon : "refresh", type : Button(@:privateAccess sceneEditor.gizmo.rotationMode)});
  385. toolsDefs.push({id: "scalingMode", title : "Gizmo scaling Mode", icon : "expand", type : Button(@:privateAccess sceneEditor.gizmo.scalingMode)});
  386. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  387. toolsDefs.push({id: "toggleSnap", title : "Snap Toggle", icon: "magnet", type : Toggle((v) -> {sceneEditor.snapToggle = v; sceneEditor.updateGrid();})});
  388. toolsDefs.push({id: "snap-menu", title : "", icon: "", type : Popup((e) -> new hide.comp.SceneEditor.SnapSettingsPopup(e, sceneEditor))});
  389. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  390. toolsDefs.push({id: "localTransformsToggle", title : "Local transforms", icon : "compass", type : Toggle((v) -> sceneEditor.localTransform = v)});
  391. toolsDefs.push({id: "selfOnlyTransformsToggle", title : "Self only transforms", icon : "map-pin", type : Toggle((v) -> sceneEditor.selfOnlyTransform = v)});
  392. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  393. toolsDefs.push({id: "ruler", title : "Ruler mode", icon : "arrows-h", type : Toggle((v) -> sceneEditor.toggleRuler(v)), defaultValue: false, saveToggleState: false});
  394. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  395. toolsDefs.push({id: "showViewportOverlays", title : "Viewport Overlays", icon : "eye", type : Toggle((v) -> { sceneEditor.updateViewportOverlays(); }) });
  396. toolsDefs.push({id: "viewportoverlays-menu", title : "", icon: "", type : Popup((e) -> new hide.comp.SceneEditor.ViewportOverlaysPopup(e, sceneEditor))});
  397. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  398. toolsDefs.push({id: "autoSyncToggle", title : "Auto synchronize", icon : "refresh", type : Toggle((b) -> autoSync = b)});
  399. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  400. toolsDefs.push({id: "help", title : "help", icon: "question", type : Popup((e) -> new hide.comp.SceneEditor.HelpPopup(e, sceneEditor))});
  401. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  402. toolsDefs.push({id: "viewModes", title: "View Modes", type: Popup((e) -> new hide.comp.SceneEditor.ViewModePopup(e, Std.downcast(@:privateAccess scene.s3d.renderer, h3d.scene.pbr.Renderer), sceneEditor))});
  403. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  404. toolsDefs.push({id: "graphicsFilters", title : "Graphics filters", type : Popup((e) -> new FiltersPopup(e, this, graphicsFilters, "Graphics"))});
  405. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  406. toolsDefs.push({id: "sceneFilters", title : "Scene filters", type : Popup((e) -> new FiltersPopup(e, this, sceneFilters, "Scene"))});
  407. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  408. toolsDefs.push({
  409. id: "renderProps",
  410. title: "Render props",
  411. type: Popup((e) -> new hide.comp.SceneEditor.RenderPropsPopup(e, this, sceneEditor, true))
  412. });
  413. toolsDefs.push({
  414. id: "",
  415. title: "",
  416. icon: "",
  417. type: Separator
  418. });
  419. toolsDefs.push({id: "sceneSpeed", title : "Speed", type : Range((v) -> scene.speed = v)});
  420. toolsDefs.push({id: "", title : "", icon : "", type : Separator});
  421. tools.makeToolbar(toolsDefs, config, keys);
  422. posToolTip = new h2d.Text(hxd.res.DefaultFont.get(), scene.s2d);
  423. posToolTip.dropShadow = { dx : 1, dy : 1, color : 0, alpha : 0.5 };
  424. var gizmo = @:privateAccess sceneEditor.gizmo;
  425. var onSetGizmoMode = function(mode: hrt.tools.Gizmo.EditMode) {
  426. tools.element.find("#translationMode").get(0).toggleAttribute("checked", mode == Translation);
  427. tools.element.find("#rotationMode").get(0).toggleAttribute("checked", mode == Rotation);
  428. tools.element.find("#scalingMode").get(0).toggleAttribute("checked", mode == Scaling);
  429. };
  430. gizmo.onChangeMode = onSetGizmoMode;
  431. onSetGizmoMode(gizmo.editMode);
  432. initGraphicsFilters();
  433. initSceneFilters();
  434. sceneEditor.onRefresh = () -> {
  435. initGraphicsFilters();
  436. initSceneFilters();
  437. }
  438. }
  439. function resetCamera( top : Bool ) {
  440. var targetPt = new h3d.col.Point(0, 0, 0);
  441. if(sceneEditor.selectedPrefabs.length > 0) {
  442. targetPt = sceneEditor.selectedPrefabs[0].findFirstLocal3d().getAbsPos().getPosition().toPoint();
  443. }
  444. if(top)
  445. sceneEditor.cameraController.set(200, Math.PI/2, 0.001, targetPt);
  446. else
  447. sceneEditor.cameraController.set(200, -4.7, 0.8, targetPt);
  448. sceneEditor.cameraController.toTarget();
  449. }
  450. override function getDefaultContent() {
  451. @:privateAccess return haxe.io.Bytes.ofString(ide.toJSON(new hrt.prefab.Prefab(null, null).serialize()));
  452. }
  453. override function canSave() {
  454. return data != null;
  455. }
  456. public static function cleanupPrefabCdb(prefab: hrt.prefab.Prefab, optionalBackup: hide.comp.cdb.Editor.OptionalBackup) {
  457. var cdbType = prefab.getCdbType();
  458. if (cdbType != null) {
  459. var db = hide.Ide.inst.database;
  460. var sheet = db.getSheet(cdbType);
  461. hide.comp.cdb.Editor.cleanupOptionalLines([prefab.props], sheet, optionalBackup);
  462. }
  463. for (child in prefab.children) {
  464. cleanupPrefabCdb(child, optionalBackup);
  465. }
  466. }
  467. override function save() {
  468. if( !canSave() )
  469. return;
  470. // Save render props
  471. if (Ide.inst.currentConfig.get("sceneeditor.renderprops.edit", false) && sceneEditor.renderPropsRoot != null)
  472. sceneEditor.renderPropsRoot.save();
  473. var backup = [];
  474. cleanupPrefabCdb(data, backup);
  475. @:privateAccess var content = ide.toJSON(data.serialize());
  476. hide.comp.cdb.Editor.restoreOptionals(backup);
  477. var newSign = ide.makeSignature(content);
  478. if(newSign != currentSign)
  479. haxe.Timer.delay(saveBackup.bind(content), 0);
  480. currentSign = newSign;
  481. sys.io.File.saveContent(getPath(), content);
  482. super.save();
  483. // if (renameMatsHistory != null) {
  484. // for (entry in renameMatsHistory)
  485. // saveMatLibsRenames(entry.previousName, entry.newName, entry.prefab);
  486. // renameMatsHistory = [];
  487. // }
  488. }
  489. function saveMatLibsRenames(oldName : String, newName : String, prefab : hrt.prefab.Prefab) {
  490. function renameContent(content:Dynamic) {
  491. var visited = new Array<Dynamic>();
  492. function renamePath(p: String) {
  493. if( p == null )
  494. return null;
  495. var pos = p.indexOf(oldName);
  496. if (pos < 0)
  497. return p;
  498. if( p == newName )
  499. return p;
  500. if ((pos == 0 || p.charAt(pos -1) == '/') && (pos + oldName.length >= p.length || p.charAt(pos + oldName.length) == '/'))
  501. p = StringTools.replace(p, oldName, newName);
  502. return p;
  503. }
  504. function renameObj(obj:Dynamic) : Dynamic {
  505. switch( Type.typeof(obj) ) {
  506. case TObject:
  507. if( visited.indexOf(obj) >= 0 ) return null;
  508. visited.push(obj);
  509. if (Reflect.hasField(obj, "__ref") && Reflect.getProperty(obj, "__ref") != matLibPath)
  510. return null;
  511. for( f in Reflect.fields(obj) ) {
  512. var v : Dynamic = Reflect.field(obj, f);
  513. v = renameObj(v);
  514. if( v != null ) Reflect.setField(obj, f, v);
  515. }
  516. case TClass(Array):
  517. if( visited.indexOf(obj) >= 0 ) return null;
  518. visited.push(obj);
  519. var arr : Array<Dynamic> = obj;
  520. for( i in 0...arr.length ) {
  521. var v : Dynamic = arr[i];
  522. v = renameObj(v);
  523. if( v != null ) arr[i] = v;
  524. }
  525. case TClass(String):
  526. return renamePath(obj);
  527. default:
  528. }
  529. return null;
  530. }
  531. for( f in Reflect.fields(content) ) {
  532. var v = renameObj(Reflect.field(content,f));
  533. if( v != null ) Reflect.setField(content,f,v);
  534. }
  535. }
  536. ide.filterProps(function(content:Dynamic, path: String) {
  537. renameContent(content);
  538. return true;
  539. });
  540. }
  541. function onUpdate(dt:Float) {
  542. if(K.isDown(K.ALT)) {
  543. posToolTip.visible = true;
  544. var proj = sceneEditor.screenToGround(scene.s2d.mouseX, scene.s2d.mouseY);
  545. posToolTip.text = proj != null ? '${Math.fmt(proj.x)}, ${Math.fmt(proj.y)}, ${Math.fmt(proj.z)}' : '???';
  546. posToolTip.setPosition(scene.s2d.mouseX, scene.s2d.mouseY - 12);
  547. }
  548. else {
  549. posToolTip.visible = false;
  550. }
  551. if( autoSync && (currentVersion != undo.currentID || lastSyncChange != properties.lastChange) ) {
  552. save();
  553. lastSyncChange = properties.lastChange;
  554. currentVersion = undo.currentID;
  555. }
  556. }
  557. function onRefresh() {
  558. }
  559. override function onDragDrop(items : Array<String>, isDrop : Bool, event: js.html.DragEvent) {
  560. return sceneEditor.onDragDrop(items, isDrop, event);
  561. }
  562. function applyGraphicsFilter(typeid: String, enable: Bool) {
  563. saveDisplayState("graphicsFilters/" + typeid, enable);
  564. var r : h3d.scene.Renderer = scene.s3d.renderer;
  565. var all = data.findAll(hrt.prefab.Object3D, true);
  566. for (obj in all) {
  567. if (obj.getDisplayFilters().contains(typeid)) {
  568. obj.updateInstance();
  569. }
  570. }
  571. switch (typeid)
  572. {
  573. case "shadows":
  574. r.shadows = enable;
  575. default:
  576. }
  577. }
  578. function applySceneFilter(typeid: String, visible: Bool) {
  579. saveDisplayState("sceneFilters/" + typeid, visible);
  580. if (data == null)
  581. return;
  582. var all = [];
  583. if (typeid != 'light')
  584. all = data.findAll(hrt.prefab.Prefab, true);
  585. else
  586. all = data.flatten(hrt.prefab.Prefab);
  587. var tag = StringTools.replace(typeid, "tag:", "");
  588. tag = tag != typeid ? tag : null;
  589. for(p in all) {
  590. if(p.type == typeid || p.getCdbType() == typeid || (tag != null && (p.props:Dynamic)?.tag == tag)) {
  591. sceneEditor.applySceneStyle(p);
  592. }
  593. }
  594. }
  595. function refreshSceneFilters() {
  596. var filters : Array<String> = ide.currentConfig.get("sceneeditor.filterTypes");
  597. filters = filters.copy();
  598. for(sheet in DataFiles.getAvailableTypes()) {
  599. filters.push(DataFiles.getTypeName(sheet));
  600. }
  601. sceneFilters = new Map();
  602. for(f in filters) {
  603. sceneFilters.set(f, getDisplayState("sceneFilters/" + f) != false);
  604. }
  605. }
  606. function initGraphicsFilters() {
  607. for (typeid in graphicsFilters.keys())
  608. {
  609. applyGraphicsFilter(typeid, graphicsFilters.get(typeid));
  610. }
  611. }
  612. function initSceneFilters() {
  613. for (typeid in sceneFilters.keys())
  614. {
  615. applySceneFilter(typeid, sceneFilters.get(typeid));
  616. }
  617. }
  618. function refreshGraphicsFilters() {
  619. var filters : Array<String> = ["shadows"];
  620. var all = data.findAll(hrt.prefab.Object3D, true);
  621. for (obj in all) {
  622. var objFilters = obj.getDisplayFilters();
  623. for (f in filters) {
  624. objFilters.remove(f);
  625. }
  626. filters = filters.concat(objFilters);
  627. }
  628. filters = filters.copy();
  629. graphicsFilters = new Map();
  630. for(f in filters) {
  631. graphicsFilters.set(f, getDisplayState("graphicsFilters/" + f) != false);
  632. }
  633. }
  634. function refreshViewModes() {
  635. var filters : Array<String> = ["LIT", "Full", "Albedo", "Normal", "Roughness", "Metalness", "Emissive", "AO", "Shadows", "Performance", "Velocity"];
  636. viewModes = new Map();
  637. for(f in filters) {
  638. viewModes.set(f, false);
  639. }
  640. }
  641. function filtersToMenuItem(filters : Map<String, Bool>, type : String) : Array<hide.comp.ContextMenu.MenuItem> {
  642. var content : Array<hide.comp.ContextMenu.MenuItem> = [];
  643. var initDone = false;
  644. for(typeid in filters.keys()) {
  645. if ( type == "View" ) {
  646. content.push({label : typeid, click : function() {
  647. var r = Std.downcast(scene.s3d.renderer, h3d.scene.pbr.Renderer);
  648. if ( r == null )
  649. return;
  650. var slides = @:privateAccess r.slides;
  651. if ( slides == null )
  652. return;
  653. switch(typeid) {
  654. case "LIT":
  655. r.displayMode = Pbr;
  656. case "Full":
  657. r.displayMode = Debug;
  658. slides.shader.mode = Full;
  659. case "Albedo":
  660. r.displayMode = Debug;
  661. slides.shader.mode = Albedo;
  662. case "Normal":
  663. r.displayMode = Debug;
  664. slides.shader.mode = Normal;
  665. case "Roughness":
  666. r.displayMode = Debug;
  667. slides.shader.mode = Roughness;
  668. case "Metalness":
  669. r.displayMode = Debug;
  670. slides.shader.mode = Metalness;
  671. case "Emissive":
  672. r.displayMode = Debug;
  673. slides.shader.mode = Emissive;
  674. case "AO":
  675. r.displayMode = Debug;
  676. slides.shader.mode = AO;
  677. case "Shadows":
  678. r.displayMode = Debug;
  679. slides.shader.mode = Shadow;
  680. case "Performance":
  681. r.displayMode = Performance;
  682. case "Velocity":
  683. r.displayMode = Performance;
  684. default:
  685. }
  686. }
  687. });
  688. } else {
  689. content.push({label : typeid, checked : filters[typeid], click : function() {
  690. var on = !filters[typeid];
  691. filters.set(typeid, on);
  692. if(initDone)
  693. switch (type){
  694. case "Graphics":
  695. applyGraphicsFilter(typeid, on);
  696. case "Scene":
  697. applySceneFilter(typeid, on);
  698. }
  699. content.find(function(item) return item.label == typeid).checked = on;
  700. }});
  701. }
  702. }
  703. initDone = true;
  704. return content;
  705. }
  706. function onPrefabChange(p: PrefabElement, ?pname: String) {
  707. }
  708. function applySceneStyle(p: PrefabElement) {
  709. if( p != null && p.parent == null && p.shared.parentPrefab == null) {
  710. sceneEditor.updateGrid();
  711. return;
  712. }
  713. var color = getDisplayColor(p);
  714. if(color != null){
  715. color = (color & 0xffffff) | 0xa0000000;
  716. var box = p.to(hrt.prefab.l3d.Box);
  717. if(box != null) {
  718. box.setColor(color);
  719. }
  720. var poly = p.to(hrt.prefab.l3d.Polygon);
  721. if(poly != null) {
  722. poly.setColor(color);
  723. }
  724. }
  725. var obj3d = p.to(Object3D);
  726. if(obj3d != null && obj3d.local3d != null) {
  727. // Apply scene filters visibility first
  728. var ref = Std.downcast(p, hrt.prefab.Reference);
  729. if (!obj3d.visible || (sceneFilters.get(p.type) == false || (ref?.refInstance != null && sceneFilters.get(ref.refInstance.type) == false))) {
  730. obj3d.local3d.visible = false;
  731. return;
  732. }
  733. // Apply
  734. if (sceneEditor.isHidden(obj3d)) {
  735. obj3d.local3d.visible = false;
  736. return;
  737. }
  738. var cdbType = p.getCdbType();
  739. if(cdbType != null && sceneFilters.get(cdbType) == false) {
  740. obj3d.local3d.visible = false;
  741. return;
  742. }
  743. if ((p.props:Dynamic)?.tag != null) {
  744. obj3d.local3d.visible = sceneFilters.get('tag:${(p.props:Dynamic).tag}') != false;
  745. return;
  746. }
  747. obj3d.local3d.visible = true;
  748. }
  749. }
  750. public function setRenderPropsEditionVisibility(visible : Bool) {
  751. var renderPropsEditionEl = this.element.find('.render-props-edition');
  752. if (!visible) {
  753. renderPropsEditionEl.css({ display : 'none' });
  754. return;
  755. }
  756. renderPropsEditionEl.css({ display : 'block' });
  757. }
  758. function getDisplayColor(p: PrefabElement) : Null<Int> {
  759. var typeId = p.getCdbType();
  760. if(typeId != null) {
  761. var colors = ide.currentConfig.get("sceneeditor.colors");
  762. var color = Reflect.field(colors, typeId);
  763. if(color != null) {
  764. return Std.parseInt("0x"+color.substr(1)) | 0xff000000;
  765. }
  766. }
  767. return null;
  768. }
  769. function sceneFiltersChanged() {}
  770. static var _ = Extension.registerExtension(Prefab, ["prefab"], { icon : "sitemap", createNew : "Prefab", name: "Prefab" });
  771. static var _1 = Extension.registerExtension(Prefab, ["l3d"], { icon : "sitemap", name: "Prefab" });
  772. }