UNPKG

@babylonjs/gui

Version:

Babylon.js GUI module =====================

233 lines 9.7 kB
import { Observable } from "@babylonjs/core/Misc/observable.js"; import { Vector3 } from "@babylonjs/core/Maths/math.vector.js"; import { PointerEventTypes } from "@babylonjs/core/Events/pointerEvents.js"; import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight.js"; import { UtilityLayerRenderer } from "@babylonjs/core/Rendering/utilityLayerRenderer.js"; import { EngineStore } from "@babylonjs/core/Engines/engineStore.js"; import { Container3D } from "./controls/container3D.js"; /** * Class used to manage 3D user interface * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui3D */ export class GUI3DManager { /** Gets the hosting scene */ get scene() { return this._scene; } /** Gets associated utility layer */ get utilityLayer() { return this._utilityLayer; } /** Gets the scaling for all UI elements owned by this manager */ get controlScaling() { return this._customControlScaling; } /** Sets the scaling adjustment for all UI elements owned by this manager */ set controlScaling(newScale) { if (this._customControlScaling !== newScale && newScale > 0) { const scaleRatio = newScale / this._customControlScaling; this._customControlScaling = newScale; for (const control of this._rootContainer.children) { control.scaling.scaleInPlace(scaleRatio); if (newScale !== 1) { control._isScaledByManager = true; } } } } /** Gets if controls attached to this manager are realistically sized, based on the fact that 1 unit length is 1 meter */ get useRealisticScaling() { return this.controlScaling === GUI3DManager.MRTK_REALISTIC_SCALING; } /** Sets if controls attached to this manager are realistically sized, based on the fact that 1 unit length is 1 meter */ set useRealisticScaling(newValue) { this.controlScaling = newValue ? GUI3DManager.MRTK_REALISTIC_SCALING : 1; } /** * Creates a new GUI3DManager * @param scene */ constructor(scene) { this._customControlScaling = 1.0; /** @internal */ this._lastControlOver = {}; /** @internal */ this._lastControlDown = {}; /** * Observable raised when the point picked by the pointer events changed */ this.onPickedPointChangedObservable = new Observable(); /** * Observable raised when a picking happens */ this.onPickingObservable = new Observable(); // Shared resources /** @internal */ this._sharedMaterials = {}; /** @internal */ this._touchSharedMaterials = {}; this._scene = scene || EngineStore.LastCreatedScene; this._sceneDisposeObserver = this._scene.onDisposeObservable.add(() => { this._sceneDisposeObserver = null; this._utilityLayer = null; this.dispose(); }); this._utilityLayer = UtilityLayerRenderer._CreateDefaultUtilityLayerFromScene(this._scene); this._utilityLayer.onlyCheckPointerDownEvents = false; this._utilityLayer.pickUtilitySceneFirst = false; this._utilityLayer.mainSceneTrackerPredicate = (mesh) => { return mesh && mesh.reservedDataStore?.GUI3D?.control?._node; }; // Root this._rootContainer = new Container3D("RootContainer"); this._rootContainer._host = this; const utilityLayerScene = this._utilityLayer.utilityLayerScene; // Events this._pointerOutObserver = this._utilityLayer.onPointerOutObservable.add((pointerId) => { this._handlePointerOut(pointerId, true); }); this._pointerObserver = utilityLayerScene.onPointerObservable.add((pi) => { this._doPicking(pi); }); // Scene this._utilityLayer.utilityLayerScene.autoClear = false; this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = false; new HemisphericLight("hemi", Vector3.Up(), this._utilityLayer.utilityLayerScene); } _handlePointerOut(pointerId, isPointerUp) { const previousControlOver = this._lastControlOver[pointerId]; if (previousControlOver) { previousControlOver._onPointerOut(previousControlOver); delete this._lastControlOver[pointerId]; } if (isPointerUp) { if (this._lastControlDown[pointerId]) { this._lastControlDown[pointerId].forcePointerUp(); delete this._lastControlDown[pointerId]; } } this.onPickedPointChangedObservable.notifyObservers(null); } _doPicking(pi) { if (!this._utilityLayer || !this._utilityLayer.shouldRender || !this._utilityLayer.utilityLayerScene.activeCamera) { return false; } const pointerEvent = pi.event; const pointerId = pointerEvent.pointerId || 0; const buttonIndex = pointerEvent.button; const pickingInfo = pi.pickInfo; if (pickingInfo) { this.onPickingObservable.notifyObservers(pickingInfo.pickedMesh); } if (!pickingInfo || !pickingInfo.hit) { this._handlePointerOut(pointerId, pi.type === PointerEventTypes.POINTERUP); return false; } if (pickingInfo.pickedPoint) { this.onPickedPointChangedObservable.notifyObservers(pickingInfo.pickedPoint); } const control = pickingInfo.pickedMesh.reservedDataStore?.GUI3D?.control; if (!!control && !control._processObservables(pi.type, pickingInfo.pickedPoint, pickingInfo.originMesh?.position || null, pointerId, buttonIndex)) { if (pi.type === PointerEventTypes.POINTERMOVE) { if (this._lastControlOver[pointerId]) { this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]); } delete this._lastControlOver[pointerId]; } } if (pi.type === PointerEventTypes.POINTERUP) { if (this._lastControlDown[pointerEvent.pointerId]) { this._lastControlDown[pointerEvent.pointerId].forcePointerUp(); delete this._lastControlDown[pointerEvent.pointerId]; } if (pointerEvent.pointerType === "touch" || (pointerEvent.pointerType === "xr" && this._scene.getEngine().hostInformation.isMobile)) { this._handlePointerOut(pointerId, false); } } return true; } /** * Gets the root container */ get rootContainer() { 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 */ containsControl(control) { return this._rootContainer.containsControl(control); } /** * Adds a control to the root child list * @param control defines the control to add * @returns the current manager */ addControl(control) { this._rootContainer.addControl(control); if (this._customControlScaling !== 1) { control.scaling.scaleInPlace(this._customControlScaling); control._isScaledByManager = true; } return this; } /** * Removes a control from the root child list * @param control defines the control to remove * @returns the current container */ removeControl(control) { this._rootContainer.removeControl(control); if (control._isScaledByManager) { control.scaling.scaleInPlace(1 / this._customControlScaling); control._isScaledByManager = false; } return this; } /** * Releases all associated resources */ dispose() { this._rootContainer.dispose(); for (const materialName in this._sharedMaterials) { if (!Object.prototype.hasOwnProperty.call(this._sharedMaterials, materialName)) { continue; } this._sharedMaterials[materialName].dispose(); } this._sharedMaterials = {}; for (const materialName in this._touchSharedMaterials) { if (!Object.prototype.hasOwnProperty.call(this._touchSharedMaterials, materialName)) { continue; } this._touchSharedMaterials[materialName].dispose(); } this._touchSharedMaterials = {}; if (this._pointerOutObserver && this._utilityLayer) { this._utilityLayer.onPointerOutObservable.remove(this._pointerOutObserver); this._pointerOutObserver = null; } this.onPickedPointChangedObservable.clear(); this.onPickingObservable.clear(); const utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null; if (utilityLayerScene) { if (this._pointerObserver) { utilityLayerScene.onPointerObservable.remove(this._pointerObserver); this._pointerObserver = null; } } if (this._scene) { if (this._sceneDisposeObserver) { this._scene.onDisposeObservable.remove(this._sceneDisposeObserver); this._sceneDisposeObserver = null; } } if (this._utilityLayer) { this._utilityLayer.dispose(); } } } GUI3DManager.MRTK_REALISTIC_SCALING = 0.032; //# sourceMappingURL=gui3DManager.js.map