import {VRSPACEUI} from './vrspace-ui.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) {
this.scene = scene;
this.camera = camera;
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;
var indicator = this;
VRSPACEUI.init(scene).then( (ui) => {
indicator.mesh = ui.logo.clone("LoadingProgressIndicator");
indicator.mesh.scaling.scaleInPlace(0.05);
indicator.attachTo( indicator.camera );
indicator.zeroRotation = new BABYLON.Quaternion.RotationAxis(BABYLON.Axis.X,-Math.PI/2);
indicator.mesh.rotationQuaternion = indicator.zeroRotation;
indicator.mesh.setEnabled(indicator.totalItems > indicator.currentItem);
indicator.log("Loaded logo, current progress "+indicator.currentItem+"/"+indicator.totalItems);
});
this.scene.onActiveCameraChanged.add( () => {
if ( this.scene.activeCamera ) {
//console.log("Camera changed: "+this.scene.activeCamera.getClassName());
this.attachTo(camera); // FIXME undefined
}
});
}
_init() {
this.totalItems = 0;
this.currentItem = 0;
this.angle = Math.PI;
}
attachTo(camera) { // FIXME not used
this.camera = this.scene.activeCamera;
if ( this.mesh ) {
this.mesh.parent = this.scene.activeCamera;
// VRDeviceOrientationFreeCamera
// WebXRCamera
if ( this.scene.activeCamera.getClassName() == 'WebXRCamera' ) {
this.mesh.position = new BABYLON.Vector3(0,-0.2,0.5);
} else {
this.mesh.position = new BABYLON.Vector3(0,-0.1,0.5);
}
}
}
/** 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
@param item related item
*/
progress(evt, item) {
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 ) {
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);
}
}
}