///
module BABYLON.GUI {
/**
* Class used to manage 3D user interface
*/
export class GUI3DManager implements BABYLON.IDisposable {
private _scene: Scene;
private _sceneDisposeObserver: Nullable>;
private _utilityLayer: Nullable;
private _rootContainer: Container3D;
private _pointerObserver: Nullable>;
/** @hidden */
public _lastPickedControl: Control3D;
/** @hidden */
public _lastControlOver: {[pointerId:number]: Control3D} = {};
/** @hidden */
public _lastControlDown: {[pointerId:number]: Control3D} = {};
/**
* Observable raised when the point picked by the pointer events changed
*/
public onPickedPointChangedObservable = new Observable>();
// Shared resources
/** @hidden */
public _sharedMaterials: {[key:string]: Material} = {};
/** Gets the hosting scene */
public get scene(): Scene {
return this._scene;
}
/** Gets associated utility layer */
public get utilityLayer(): Nullable {
return this._utilityLayer;
}
/**
* Creates a new GUI3DManager
* @param scene
*/
public constructor(scene?: Scene) {
this._scene = scene || Engine.LastCreatedScene!;
this._sceneDisposeObserver = this._scene.onDisposeObservable.add(() => {
this._sceneDisposeObserver = null;
this._utilityLayer = null;
this.dispose();
})
this._utilityLayer = new UtilityLayerRenderer(this._scene);
// Root
this._rootContainer = new Container3D("RootContainer");
this._rootContainer._host = this;
// Events
this._pointerObserver = this._scene.onPrePointerObservable.add((pi, state) => {
let pointerEvent = (pi.event);
if (this._scene.isPointerCaptured(pointerEvent.pointerId)) {
return;
}
if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
&& pi.type !== BABYLON.PointerEventTypes.POINTERUP
&& pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
return;
}
let camera = this._scene.cameraToUseForPointers || this._scene.activeCamera;
if (!camera) {
return;
}
pi.skipOnPointerObservable = this._doPicking(pi.type, pointerEvent, pi.ray)
});
// Scene
this._utilityLayer.utilityLayerScene.autoClear = false;
this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = false;
new BABYLON.HemisphericLight("hemi", Vector3.Up(), this._utilityLayer.utilityLayerScene);
}
private _doPicking(type: number, pointerEvent: PointerEvent, ray?:Nullable): boolean {
if (!this._utilityLayer || !this._utilityLayer.utilityLayerScene.activeCamera) {
return false;
}
let pointerId = pointerEvent.pointerId || 0;
let buttonIndex = pointerEvent.button;
var utilityScene = this._utilityLayer.utilityLayerScene;
let pickingInfo = ray ? utilityScene.pickWithRay(ray): utilityScene.pick(this._scene.pointerX, this._scene.pointerY);
if (!pickingInfo || !pickingInfo.hit) {
var previousControlOver = this._lastControlOver[pointerId];
if (previousControlOver) {
previousControlOver._onPointerOut(previousControlOver);
delete this._lastControlOver[pointerId];
}
if (type === BABYLON.PointerEventTypes.POINTERUP) {
if (this._lastControlDown[pointerEvent.pointerId]) {
this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
delete this._lastControlDown[pointerEvent.pointerId];
}
}
this.onPickedPointChangedObservable.notifyObservers(null);
return false;
}
let control = (pickingInfo.pickedMesh!.metadata);
if (pickingInfo.pickedPoint) {
this.onPickedPointChangedObservable.notifyObservers(pickingInfo.pickedPoint);
}
if (!control._processObservables(type, pickingInfo.pickedPoint!, pointerId, buttonIndex)) {
if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
if (this._lastControlOver[pointerId]) {
this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
}
delete this._lastControlOver[pointerId];
}
}
if (type === BABYLON.PointerEventTypes.POINTERUP) {
if (this._lastControlDown[pointerEvent.pointerId]) {
this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
delete this._lastControlDown[pointerEvent.pointerId];
}
}
return true;
}
/**
* Gets the root container
*/
public get rootContainer(): Container3D {
return this._rootContainer;
}
/**
* Gets a boolean indicating if the given control is in the root child list
* @param control defines the control to check
* @returns true if the control is in the root child list
*/
public containsControl(control: Control3D): boolean {
return this._rootContainer.containsControl(control);
}
/**
* Adds a control to the root child list
* @param control defines the control to add
* @returns the current manager
*/
public addControl(control: Control3D): GUI3DManager {
this._rootContainer.addControl(control);
return this;
}
/**
* Removes the control from the root child list
* @param control defines the control to remove
* @returns the current container
*/
public removeControl(control: Control3D): GUI3DManager {
this._rootContainer.removeControl(control);
return this;
}
/**
* Releases all associated resources
*/
public dispose() {
this._rootContainer.dispose();
for (var materialName in this._sharedMaterials) {
if (!this._sharedMaterials.hasOwnProperty(materialName)) {
continue;
}
this._sharedMaterials[materialName].dispose();
}
this._sharedMaterials = {};
this.onPickedPointChangedObservable.clear();
if (this._scene) {
if (this._pointerObserver) {
this._scene.onPrePointerObservable.remove(this._pointerObserver);
this._pointerObserver = null;
}
if (this._sceneDisposeObserver) {
this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
this._sceneDisposeObserver = null;
}
}
if (this._utilityLayer) {
this._utilityLayer.dispose();
}
}
}
}