diff --git a/js/main.js b/js/main.js index 999d478..f889089 100644 --- a/js/main.js +++ b/js/main.js @@ -29,7 +29,6 @@ APP.UI.pauseAudio = function(triggerSelector) { // You can place here UI setup (HTML), events handling, etc. APP.setup = ()=>{ Map.init('map'); - Scene.toggleScene('back'); APP.UI.pauseAudio('[data-bs-dismiss="modal"'); //APP.UI.showClipper('#clipper'); }; diff --git a/js/map.js b/js/map.js index 78bde3b..05db3cc 100644 --- a/js/map.js +++ b/js/map.js @@ -2,7 +2,7 @@ import {config} from '../config.js'; import Scene from './scene.js'; -import { AppState } from './state.js'; +import AppState from './state.js'; const Map = {}; diff --git a/js/scene.js b/js/scene.js index 94c1379..5789467 100644 --- a/js/scene.js +++ b/js/scene.js @@ -1,6 +1,6 @@ // Global ATON -import { AppState, getSceneStatus, setSceneStatus, getCurrentScene, setCurrentScene } from "./state.js"; +import AppState from "./state.js"; import { config } from "../config.js"; const Scene = {}; @@ -81,16 +81,7 @@ Scene.UI.toggleClipper = function(triggerSelector, targetSelector) { }); } else { AppState.clipping.enabled = false; - ATON.disableClipPlanes(); - // Disable DragControls to avoid invoking events... - if (AppState.clipping.controls) { - AppState.clipping.controls.deactivate(); - AppState.clipping.controls.dispose(); - AppState.clipping.controls = null; - } - AppState.root.remove(AppState.clipping.helper); - AppState.clipping.helper = null; - AppState.clipping.plane = null; + Scene.resetClipping(); let noBorder = trigger.className.replace(/ border.*$/g, ''); trigger.className = noBorder; Scene.toggleAmbientOcclusion(aoCurrentState); @@ -422,91 +413,96 @@ Scene.init = function() { AppState.camera = ATON.Nav._camera; AppState.renderer = ATON._renderer; + + ATON.Nav.setUserControl(true); } /** * @param {String} btnId - The back-to-map button id */ -Scene.toggleScene = function(btnId) { - const btn = document.querySelector(`#${btnId}`); +Scene.closeScene = function() { const scene = document.querySelector('#scene'); + scene.classList.toggle('d-none'); - btn.addEventListener('click', () => { - const currentScene = getCurrentScene(); - // Deactivate the current scene before toggling - setSceneStatus(currentScene.id, false); - scene.classList.toggle('d-none'); - // Pause rendering the 3D scene to free resources (hopefully) - // when browsing the map - ATON.renderPause(); - if (AppState.clipping.enabled) { - ATON.disableClipPlanes(); - AppState.clipping.enabled = false; - Scene.UI.reset(); - AppState.root.remove(AppState.clipping.helper); - AppState.clipping.helper = null; - } - AppState.root.setRotation(AppState.initialRotation ?? new THREE.Vector3(0, 1.5, 0)); + const canvas = ATON._renderer?.domElement; + Scene.resetClipping(); + AppState.root.clear(); + // Ensure GPU resources are freed... + ATON.renderPause(); + AppState.renderer.dispose(); + ATON._renderer.dispose(); + ATON.Nav._camera = undefined; - document.querySelector('#map').classList.toggle('d-none'); - AppState.map.invalidateSize(); - }); + Scene.UI.reset(); + document.querySelector('#map').classList.toggle('d-none'); + AppState.map.invalidateSize(); + AppState.resetSceneState(AppState.map); + // Remove ATON's canvas from the DOM + if (canvas && canvas.parentElement) { + canvas.parentElement.removeChild(canvas); + } +} + +Scene.resetClipping = function () { + AppState.clipping.controls?.dispose(); + AppState.clipping.controls = null; + ATON.disableClipPlanes(); + AppState.clipping.enabled = false; + AppState.root.remove(AppState.clipping.helper); + AppState.clipping.helper = null; + AppState.clipping.plane = null; + AppState.clipping.vector = null; + // Ensure nav controls are reactivated! + ATON.Nav.setUserControl(true); } /** * @param {Object} marker - The marker object from config */ Scene.openScene = function(marker) { - let canvas = document.querySelector('canvas'); + //let canvas = document.querySelector('canvas'); let scene = document.querySelector('#scene'); - if (canvas === null) { - Scene.init(); - } + Scene.init(); + + // Button to go back to the map... + const btn = document.querySelector('#back'); + btn.addEventListener('click', () => { + Scene.closeScene('back'); + }); Scene.UI.toggleClipper('#clipper', '#clipper-bar'); scene.classList.toggle('d-none'); ATON.renderResume(); - // TODO: reset scene only if changing to a different model from the map - // set scene status to inactive, first get current scene id... - let currentScene = getCurrentScene(); - if (currentScene && currentScene.id !== marker.id) { - AppState.root.removeChildren(); - currentScene.current = false; - } if (!AppState.scenes.find(s => s.id === marker.id)) { const newScene = {id: marker.id, active: false, current: true}; AppState.scenes.push(newScene); } - if (!getSceneStatus(marker.id)) { - // Set scene as active - setSceneStatus(marker.id, true); - // Load 3D model - let mainNode = ATON.createSceneNode(marker.label).load(marker.model); - // TODO: only for the main ('larger') node in the scene - AppState.mainNodeId = marker.label; - ATON.setMainPanorama(marker.pano); - //mainNode.setMaterial(new THREE.MeshPhongMaterial(material)); - // TODO: hardcoded... - mainNode.setRotation(0, 1.5, 0) - AppState.initialRotation = new THREE.Vector3(0, 1.5, 0); - Scene.showEdges(mainNode); + // Load 3D model then + let mainNode = ATON.createSceneNode(marker.label); + mainNode.load(marker.model); + // TODO: only for the main ('larger') node in the scene + AppState.mainNodeId = marker.label; + ATON.setMainPanorama(marker.pano); + //mainNode.setMaterial(new THREE.MeshPhongMaterial(material)); + // TODO: hardcoded... + mainNode.setRotation(0, 1.5, 0) + AppState.initialRotation = new THREE.Vector3(0, 1.5, 0); + Scene.showEdges(mainNode); - mainNode.attachToRoot(); + mainNode.attachToRoot(); - ATON.setAutoLP(config.scene.autoLP); - AppState.lightProbe = config.scene.autoLP; - Scene.toggleAmbientOcclusion(true); - AppState.ambientOcclusion = true; + ATON.setAutoLP(config.scene.autoLP); + AppState.lightProbe = config.scene.autoLP; + Scene.toggleAmbientOcclusion(true); + AppState.ambientOcclusion = true; - AppState.root = ATON.getRootScene(); - // ATON.Node.getBound() returns a THREE.Sphere object - AppState.clipping.boundingSphere = mainNode.getBound(); + AppState.root = ATON.getRootScene(); + // ATON.Node.getBound() returns a THREE.Sphere object + AppState.clipping.boundingSphere = mainNode.getBound(); - // TODO: set the scene as current!! - setCurrentScene(marker.id); - } + console.log(ATON.Nav._camera); } export default Scene; \ No newline at end of file diff --git a/js/state.js b/js/state.js index 6f681d7..1c4e00d 100644 --- a/js/state.js +++ b/js/state.js @@ -1,10 +1,13 @@ -export const AppState = { +/** + * @namespace AppState + */ +let AppState = { // The root scene object root: null, mainNodeId: null, initialRotation: null, - camera: ATON.Nav._camera, - renderer: ATON._renderer, + camera: null, + renderer: null, scenes : [], ambientOcclusion : true, shadows : true, @@ -16,48 +19,46 @@ export const AppState = { controls: null, onDrag: null, helper : null, - // Change to boundingSphere boundingSphere: null, listeners: { button: false, plane: false, }, vector: null, + }, + /** + * Reset the overall app state + * to default values but keep map + * + * @param {L.Map} map - The Leaflet map object + */ + resetSceneState(map) { + AppState = { + root: null, + mainNodeId: null, + initialRotation: null, + camera: null, + renderer: null, + scenes : [], + ambientOcclusion : true, + shadows : true, + lightProbe : false, + map, + clipping : { + enabled: false, + plane : null, + controls: null, + onDrag: null, + helper : null, + boundingSphere: null, + listeners: { + button: false, + plane: false, + }, + vector: null, + } + } } } -/** - * @todo Buggyyyyy!!!! - * @param {String} id - * @returns {Boolean} - */ -export function getSceneStatus(id) { - return AppState.scenes.find(s => s.id === id).active; -} - -/** - * @todo Buggyyyyy!!!! - * @param {String} id - * @param {Boolean} status - * @returns {Boolean} - */ -export function setSceneStatus(id, status) { - AppState.scenes.find(s => s.id === id).active = status; -} - -export function getCurrentScene() { - return AppState.scenes.find(s => s.current); -} - -/** - * - * @param {String} id The scene's id - * @returns - */ -export function setCurrentScene(id) { - // First set the correct status for the other scenes - let otherScenes = AppState.scenes.filter(s => s.id !== id); - otherScenes.forEach(scene => scene.current = false) - - AppState.scenes.find(s => s.id === id).current = true; -} \ No newline at end of file +export default AppState; \ No newline at end of file