UNPKG

@vrspace/babylonjs

Version:

vrspace.org babylonjs client

149 lines (146 loc) 4.97 kB
import { VRSPACEUI } from './vrspace-ui.js'; import { CameraHelper } from '../core/camera-helper.js'; /** Default progress indicator: rotating vrspace.org logo, 30 cm ahead, 5 cm below camera. Always bounds to active camera, to ensure same look and function on PC, mobile and VR devices. */ export class LoadProgressIndicator { /** Initializes VRSpaceUI, loading logo geometry so it can be reused. Installs active camera listener on the scene. @param scene @param camera current camera to bind to */ constructor(scene, camera = scene.activeCamera) { this.scene = scene; this.camera = camera; this.position = new BABYLON.Vector3(0, -0.1, 0.5); this.xrPosition = new BABYLON.Vector3(0, -0.2, 0.5); this.mesh = null; this.totalItems = 0; this.currentItem = 0; this.zeroRotation = null; this.angle = Math.PI; /** Debug log flag */ this.debug = false; /** Whether progress of individual items should be tracked. Default true rotates the logo only when an item loads. False results in continous rotation. */ this.trackItems = true; if (VRSPACEUI.initialized) { this._createIndicatorMesh() } else { VRSPACEUI.init(scene).then((ui) => this._createIndicatorMesh()); } CameraHelper.getInstance(this.scene).addCameraListener(() => { if (this.scene.activeCamera) { //console.log("Camera changed: "+this.scene.activeCamera.getClassName()); this.attachToCamera(); } }); } _createIndicatorMesh() { this.mesh = VRSPACEUI.logo.clone("LoadingProgressIndicator"); this.mesh.scaling.scaleInPlace(0.05); this.attachToCamera(); this.zeroRotation = new BABYLON.Quaternion.RotationAxis(BABYLON.Axis.X, -Math.PI / 2); this.mesh.rotationQuaternion = this.zeroRotation; this.mesh.setEnabled(this.totalItems > this.currentItem); this.log("Loaded logo, current progress " + this.currentItem + "/" + this.totalItems); } _init() { this.totalItems = 0; this.currentItem = 0; this.angle = Math.PI; } _setPosition() { if (this.scene.activeCamera.getClassName() == 'WebXRCamera') { this.mesh.position = this.xrPosition; } else { this.mesh.position = this.position; } } attachToCamera() { this.camera = this.scene.activeCamera; if (this.mesh) { this.mesh.parent = this.scene.activeCamera; this._setPosition(); } } /** Add an item to be tracked. First item added shows the indicator and starts the animation. @param item an item to track */ add(item) { if (this.mesh && !this.mesh.isEnabled()) { this.mesh.setEnabled(true); } this.totalItems++; this.log("Added " + this.currentItem + "/" + this.totalItems); this._update(); } /** Remove an item, e.g. loaded file. Last item removed stops the animation and hides the indicator. @param item to remove */ remove(item) { this.currentItem++; this._update(); this.log("Finished " + this.currentItem + "/" + this.totalItems); if (this.totalItems <= this.currentItem && this.mesh) { this.mesh.setEnabled(false); if (this.animation) { this.scene.unregisterBeforeRender(this.animation); delete this.animation; } this._init(); } } /** Stops tracking individual items and runs contionous animation */ animate() { this.trackItems = false; this.animation = () => { this._update() }; this.scene.registerBeforeRender(this.animation); } /** Call on load progress event. @param evt progress event, https://doc.babylonjs.com/typedoc/interfaces/BABYLON.ISceneLoaderProgressEvent @param item related item, not used, subclasses may use it */ progress(evt, item) { if (evt) { this.trackItems = false; if (evt.lengthComputable) { var loaded = evt.loaded / evt.total; this.log("Loaded " + (loaded * 100) + "%"); if (this.mesh && this.zeroRotation) { this.angle += 0.01; this.mesh.rotationQuaternion = this.zeroRotation.multiply(new BABYLON.Quaternion.RotationAxis(BABYLON.Axis.Y, this.angle)); } } else { var dlCount = evt.loaded / (1024 * 1024); this.log("Loaded " + dlCount + " MB"); } } } _update() { if (this.mesh && this.zeroRotation) { this._setPosition(); if (this.trackItems) { this.angle = Math.PI * (1 + this.currentItem / this.totalItems); } else { this.angle += 0.01; } this.mesh.rotationQuaternion = this.zeroRotation.multiply(new BABYLON.Quaternion.RotationAxis(BABYLON.Axis.Y, this.angle)); } } log(something) { if (this.debug) { console.log(something); } } dispose() { if (this.mesh) { this.mesh.dispose(); this.mesh = null; } } }