{"version":3,"sources":["jsdelivr-header.js","/npm/@yeti-cgi/ape@0.5.4/src/misc/Events.ts","/npm/@yeti-cgi/ape@0.5.4/src/input/Input.ts","/npm/@yeti-cgi/ape@0.5.4/src/gameobject/GameObject.ts","/npm/@yeti-cgi/ape@0.5.4/src/Time.ts","/npm/@yeti-cgi/ape@0.5.4/src/gameobject/decorators/Decorator.ts","/npm/@yeti-cgi/ape@0.5.4/src/utils/ThreeUtils.ts","/npm/@yeti-cgi/ape@0.5.4/src/input/XRInput.ts","/npm/@yeti-cgi/ape@0.5.4/src/misc/PerformanceStats.ts","/npm/@yeti-cgi/ape@0.5.4/src/utils/MiscUtils.ts","/npm/@yeti-cgi/ape@0.5.4/src/utils/MathUtils.ts","/npm/@yeti-cgi/ape@0.5.4/src/misc/PerformanceResolutionScalar.ts","/npm/@yeti-cgi/ape@0.5.4/src/utils/WaitPromises.ts","/npm/@yeti-cgi/ape@0.5.4/src/device-camera/DeviceCamera.ts","/npm/@yeti-cgi/ape@0.5.4/src/physics/Physics.ts","/npm/@yeti-cgi/ape@0.5.4/src/APEngineEvents.ts","/npm/@yeti-cgi/ape@0.5.4/src/APEngineBuildInfo.ts","/npm/@yeti-cgi/ape@0.5.4/src/APEngine.ts","/npm/@yeti-cgi/ape@0.5.4/src/dev/ThreeDevTools.ts","/npm/@yeti-cgi/ape@0.5.4/src/gameobject/decorators/CameraDecorator.ts","/npm/@yeti-cgi/ape@0.5.4/src/input/PointerEventSystem.ts","/npm/@yeti-cgi/ape@0.5.4/src/scene-management/SceneRenderOperation.ts","/npm/@yeti-cgi/ape@0.5.4/src/scene-management/SceneManager.ts","/npm/@yeti-cgi/ape@0.5.4/src/physics/XRPhysics.ts","/npm/@yeti-cgi/ape@0.5.4/src/gameobject/decorators/AnimatorDecorator.ts","/npm/@yeti-cgi/ape@0.5.4/src/gameobject/decorators/MeshDecorator.ts","/npm/@yeti-cgi/ape@0.5.4/src/misc/TransformControlsGUI.ts","/npm/@yeti-cgi/ape@0.5.4/src/misc/TransformTool.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/APEAssetTracker.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/APEResources.ts","/npm/@yeti-cgi/ape@0.5.4/src/gameobject/decorators/TransformPickerDecorator.ts","/npm/@yeti-cgi/ape@0.5.4/src/gameobject/decorators/CameraOrbitDecorator.ts","/npm/@yeti-cgi/ape@0.5.4/src/misc/Flags.ts","/npm/@yeti-cgi/ape@0.5.4/src/input/TapCode.ts","/npm/@yeti-cgi/ape@0.5.4/src/device-camera/readers/DeviceCameraReader.ts","/npm/@yeti-cgi/ape@0.5.4/src/device-camera/readers/DeviceCameraQRReader.ts","/npm/@yeti-cgi/ape@0.5.4/src/misc/StateMachine.ts","/npm/@yeti-cgi/ape@0.5.4/src/misc/PropertySpectator.ts","/npm/@yeti-cgi/ape@0.5.4/src/object-pools/ObjectPool.ts","/npm/@yeti-cgi/ape@0.5.4/src/object-pools/Object3DPool.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/ResourceManager.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/Resource.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/AudioResource.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/GLTFPrefab.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/GLTFResource.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/TextureResource.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/ImageResource.ts","/npm/@yeti-cgi/ape@0.5.4/src/resources/ResourceProgress.ts","/npm/@yeti-cgi/ape@0.5.4/src/utils/Eases.ts","/npm/@yeti-cgi/ape@0.5.4/src/utils/Stopwatch.ts"],"names":[],"mappings":"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","file":"/npm/@yeti-cgi/ape@0.5.4/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/@yeti-cgi/ape@0.5.4/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import { IDisposable } from './IDisposable';\n\n// [Ryan] I would love to have multiple versions of Event and Listener that support more than one generic parameter.\n// However, this is not supported by JavaScript. TypeScript's compiler complains about the class name already being declared even though\n// the generic parameters are different. This is because when transpiled to JavaScript,all generic types are stripped.\n// So the best way to handle this is if you need mutiple objects to store them in a custom JavaScript object / Typescript interface.\n\n/**\n * Event that has no arguments.\n */\nexport class Event implements IDisposable {\n    private _listeners: EventListener[] = [];\n\n    public addListener(listener: EventListener) {\n        this._listeners.push(listener);\n    }\n\n    public removeListener(listener: EventListener) {\n        const index = this._listeners.indexOf(listener);\n        if (index !== -1) {\n            this._listeners.splice(index, 1);\n        }\n    }\n\n    public removeAllListeners() {\n        this._listeners = [];\n    }\n\n    public invoke() {\n        const listeners = [...this._listeners];\n        listeners.forEach(l => {\n            l();\n        });\n    }\n\n    public dispose() {\n        this.removeAllListeners();\n    }\n}\n\n/**\n * Signature of event listener that has no arguments.\n */\nexport declare type EventListener = () => void;\n\n/**\n * Event that has no arguments and has listeners that return promises.\n */\nexport class PromiseEvent implements IDisposable {\n    private _listeners: PromiseEventListener[] = [];\n\n    public addListener(listener: PromiseEventListener) {\n        this._listeners.push(listener);\n    }\n\n    public removeListener(listener: PromiseEventListener) {\n        const index = this._listeners.indexOf(listener);\n        if (index !== -1) {\n            this._listeners.splice(index, 1);\n        }\n    }\n\n    public removeAllListeners() {\n        this._listeners = [];\n    }\n\n    public async invoke() {\n        const promises = [...this._listeners].map(l => l());\n        await Promise.all(promises);\n    }\n\n    public dispose() {\n        this.removeAllListeners();\n    }\n}\n\n/**\n * Signature of event listener that has no arguments.\n */\nexport declare type PromiseEventListener = () => Promise<void>;\n\n/**\n * Event that takes typed argument.\n */\nexport class ArgEvent<T> implements IDisposable {\n    private _listeners: ArgEventListener<T>[] = [];\n\n    public addListener(listener: ArgEventListener<T>) {\n        this._listeners.push(listener);\n    }\n\n    public removeListener(listener: ArgEventListener<T>) {\n        const index = this._listeners.indexOf(listener);\n        if (index !== -1) {\n            this._listeners.splice(index, 1);\n        }\n    }\n\n    public removeAllListeners() {\n        this._listeners = [];\n    }\n\n    public invoke(arg: T) {\n        const listeners = [...this._listeners];\n        listeners.forEach(l => {\n            l(arg);\n        });\n    }\n\n    public dispose() {\n        this.removeAllListeners();\n    }\n}\n\n/**\n * Signature of event listener that accepts typed argument.\n */\nexport declare type ArgEventListener<T> = (arg: T) => void;\n\n/**\n * Event that takes typed argument and has listeners that return promises.\n */\nexport class PromiseArgEvent<T> implements IDisposable {\n    private _listeners: PromiseArgEventListener<T>[] = [];\n\n    public addListener(listener: PromiseArgEventListener<T>) {\n        this._listeners.push(listener);\n    }\n\n    public removeListener(listener: PromiseArgEventListener<T>) {\n        const index = this._listeners.indexOf(listener);\n        if (index !== -1) {\n            this._listeners.splice(index, 1);\n        }\n    }\n\n    public removeAllListeners() {\n        this._listeners = [];\n    }\n\n    public async invoke(arg: T): Promise<void> {\n        const promises = [...this._listeners].map(l => l(arg));\n        await Promise.all(promises);\n    }\n\n    public dispose() {\n        this.removeAllListeners();\n    }\n}\n\n/**\n * Signature of promise arg event listener that accepts typed argument.\n */\nexport declare type PromiseArgEventListener<T> = (arg: T) => Promise<void>;\n\n/**\n * Shout is a global event dispatcher.  \n * Objects can listen for and dispatch global events (referred to as shouts).\n */\nexport namespace Shout {\n\n    let listenersMap: Map<string, ArgEventListener<unknown>[]> = new Map();\n\n    export function addEventListener(type: string, listener: ArgEventListener<unknown>): boolean {\n        let listeners: ArgEventListener<unknown>[] = listenersMap.get(type);\n\n        if (listeners) {\n            // Add listener to listeners array if it isnt already.\n            let listenerExists: boolean = listeners.some((l) => l === listener);\n            if (!listenerExists) {\n                listeners.push(listener);\n                return true;\n            } else {\n                // Listener already exists.\n                return false;\n            }\n        } else {\n            // Add listeners array for shout type to the Map with the new listener added.\n            listeners = [];\n            listeners.push(listener);\n            listenersMap.set(type, listeners);\n            return true;\n        }\n    }\n\n    export function removeEventListener(type:string, listener: ArgEventListener<unknown>): boolean {\n        let listeners: ArgEventListener<unknown>[] = listenersMap.get(type);\n\n        if (listeners) {\n            let index = listeners.findIndex((l) => l === listener);\n            if (index >= 0) {\n                listeners.splice(index, 1);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    export function dispatchEvent(type: string, arg?: unknown) {\n        let listeners: ArgEventListener<unknown>[] = listenersMap.get(type);\n\n        if (listeners) {\n            // Make a shallow copy in case dispatching alters the array.\n            let listenersCopy = listeners.slice();\n            listenersCopy.forEach((l) => l(arg));\n        }\n    }\n\n    export function removeAllEventListeners(): void {\n        listenersMap = new Map();\n    }\n}\n","import { Vector2, Vector3 } from 'three';\nimport find from 'lodash/find';\nimport some from 'lodash/some';\nimport { Time } from '../Time';\nimport { IDisposable } from '../misc/IDisposable';\n\ninterface IOptions { \n    time: Time,\n    inputElement: HTMLElement,\n    canvasElement: HTMLCanvasElement,\n    getUIHtmlElements(): HTMLElement[]\n}\n\nexport class Input implements IDisposable {\n    /**\n     * Debug level for Input class.\n     * 0: Disabled, 1: Down/Up events, 2: Move events\n     */\n    public debugLevel: number = 0;\n\n    public stopTouchPropogation = true;\n\n    // Internal pointer data.\n    private _mouseData: MouseData;\n    private _touchData: TouchData[];\n    private _keyData: Map<string, KeyData>;\n    private _touchListenerCounts: Map<EventTarget, number>;\n    private _wheelData: WheelData;\n    private _targetData: TargetData;\n\n    private _options: IOptions;\n    private _inputType: InputType = InputType.Undefined;\n\n    // Keep track of the touch data for finger index 0 at all times.\n    // This gives better support to the getMouse* functions while using touch.\n    private _lastPrimaryTouchData: TouchData;\n\n    /**\n     * @returns 'mouse' or 'touch'\n     */\n    get currentInputType(): InputType {\n        return this._inputType;\n    }\n\n    /**\n     * Sets the current input type to 'mouse' or 'touch'.\n     */\n    set currentInputType(inputType: InputType) {\n        this._inputType = inputType;\n    }\n\n    /**\n     * Calculates the Three.js screen position of the mouse from the given mouse event.\n     * Unlike viewport positions, Three.js screen positions go from -1 to +1.\n     * @param event The mouse event to get the viewport position out of.\n     * @param view The HTML element that we want the position to be relative to.\n     */\n    public static screenPosition(pagePos: Vector2, view: HTMLElement) {\n        let globalPos = new Vector2(pagePos.x, pagePos.y);\n        let viewRect = view.getBoundingClientRect();\n        let viewPos = globalPos.sub(new Vector2(viewRect.left, viewRect.top));\n        return new Vector2(\n            (viewPos.x / viewRect.width) * 2 - 1,\n            -(viewPos.y / viewRect.height) * 2 + 1\n        );\n    }\n\n    /**\n     * Measures the distance between the two mouse events in pixels.\n     * @param firstPagePos The first page position.\n     * @param secondPagePos The second page position.\n     */\n    public static mouseDistance(firstPagePos: Vector2, secondPagePos: Vector2) {\n        return firstPagePos.distanceTo(secondPagePos);\n    }\n\n    /**\n     * Determines if the mouse is directly over the given HTML element.\n     * @param clientPos The client position to test.\n     * @param element The HTML element to test against.\n     */\n    public static eventIsDirectlyOverElement(\n        clientPos: Vector2,\n        element: HTMLElement\n    ): boolean {\n        let mouseOver = document.elementFromPoint(clientPos.x, clientPos.y);\n        return mouseOver === element;\n    }\n\n    /**\n     * Determines if the mouse is over the given element.\n     * @param clientPos The client position to test.\n     * @param element The HTML element to test against.\n     */\n    public static eventIsOverElement(\n        clientPos: Vector2,\n        element: HTMLElement\n    ): boolean {\n        let elements = document.elementsFromPoint(clientPos.x, clientPos.y);\n        return some(elements, e => e === element);\n    }\n\n    constructor(options: IOptions) {\n        this._options = options;\n\n        this._mouseData = {\n            leftButtonState: new InputState(),\n            rightButtonState: new InputState(),\n            middleButtonState: new InputState(),\n            screenPos: new Vector2(0, 0),\n            pagePos: new Vector2(0, 0),\n            clientPos: new Vector2(0, 0),\n        };\n        this._targetData = {\n            inputDown: null,\n            inputUp: null,\n            inputOver: null,\n        };\n        this._touchData = [];\n        this._keyData = new Map();\n        this._touchListenerCounts = new Map();\n        this._wheelData = new WheelData();\n        this._lastPrimaryTouchData = {\n            fingerIndex: 0,\n            identifier: 0,\n            clientPos: new Vector2(0, 0),\n            pagePos: new Vector2(0, 0),\n            screenPos: new Vector2(0, 0),\n            state: new InputState(),\n        };\n\n        this._handleMouseDown = this._handleMouseDown.bind(this);\n        this._handleMouseMove = this._handleMouseMove.bind(this);\n        this._handleMouseUp = this._handleMouseUp.bind(this);\n        this._handleMouseLeave = this._handleMouseLeave.bind(this);\n        this._handleWheel = this._handleWheel.bind(this);\n        this._handleTouchStart = this._handleTouchStart.bind(this);\n        this._handleTouchMove = this._handleTouchMove.bind(this);\n        this._handleTouchEnd = this._handleTouchEnd.bind(this);\n        this._handleTouchCancel = this._handleTouchCancel.bind(this);\n        this._handleContextMenu = this._handleContextMenu.bind(this);\n        this._handleKeyDown = this._handleKeyDown.bind(this);\n        this._handleKeyUp = this._handleKeyUp.bind(this);\n\n        this.setInputElement(this._options.inputElement);\n        document.addEventListener('keydown', this._handleKeyDown);\n        document.addEventListener('keyup', this._handleKeyUp);\n\n        // Context menu is only important on the view\n        this._options.canvasElement.addEventListener(\n            'contextmenu',\n            this._handleContextMenu\n        );\n    }\n\n    /**\n     * Set the element that the input module will attach it's event listeners to.\n     * By default this is usually the three js webgl canvas but sometimes you want to attach the input event listeners\n     * on to a higher order html element and that's where this function comes in handy.\n     */\n    public setInputElement(element: HTMLElement): void {\n        if (this._options.inputElement) {\n            this._options.inputElement.removeEventListener('mousedown', this._handleMouseDown);\n            this._options.inputElement.removeEventListener('mousemove', this._handleMouseMove);\n            this._options.inputElement.removeEventListener('mouseup', this._handleMouseUp);\n            this._options.inputElement.removeEventListener('mouseleave', this._handleMouseLeave);\n            this._options.inputElement.removeEventListener('wheel', this._handleWheel);\n            this._options.inputElement.removeEventListener('touchstart', this._handleTouchStart);\n        }\n\n        this._options.inputElement = element;\n        if (this._options.inputElement) {\n            this._options.inputElement.addEventListener('mousedown', this._handleMouseDown);\n            this._options.inputElement.addEventListener('mousemove', this._handleMouseMove);\n            this._options.inputElement.addEventListener('mouseup', this._handleMouseUp);\n            this._options.inputElement.addEventListener('mouseleave', this._handleMouseLeave);\n            this._options.inputElement.addEventListener('wheel', this._handleWheel);\n            this._options.inputElement.addEventListener('touchstart', this._handleTouchStart);\n        }\n    }\n\n    public dispose() {\n        console.log('[Input] dispose');\n\n        this.setInputElement(null);\n        document.removeEventListener('keydown', this._handleKeyDown);\n        document.removeEventListener('keyup', this._handleKeyUp);\n\n        // Context menu is only important on the view\n        this._options.canvasElement.removeEventListener(\n            'contextmenu',\n            this._handleContextMenu\n        );\n\n        this._options = null;\n    }\n\n    /**\n     * Determines if the input down event happened directly over the given element.\n     * @param element The element to test.\n     */\n    public isDownOnElement(element: HTMLElement): boolean {\n        const downElement = this._targetData.inputDown;\n        return Input.isElementContainedByOrEqual(downElement, element);\n    }\n\n    /**\n     * Determines if the input down event happened directly over any of the given elements.\n     * @param elements The elements to test.\n     */\n    public isDownOnAnyElements(elements: HTMLElement[]): boolean {\n        const downElement = this._targetData.inputDown;\n        const matchingElement = elements.find(e =>\n            Input.isElementContainedByOrEqual(downElement, e)\n        );\n        return !!matchingElement;\n    }\n\n    /**\n     * Determines if the input down event happened directly over any of the input elements.\n     */\n    public isDownOnAnyInputElement(): boolean {\n        const downElement = this._targetData.inputDown;\n        const inputElements = [this._options.canvasElement, ...this._options.getUIHtmlElements()];\n        const matchingElement = inputElements.find(e => \n            Input.isElementContainedByOrEqual(downElement, e)\n        );\n        return !!matchingElement;\n    }\n\n    /**\n     * Determines if the input is currently focusing the given html element.\n     * @param element The element to test.\n     */\n    public isFocusingOnElement(element: HTMLElement): boolean {\n        const overElement = this._targetData.inputOver;\n        return Input.isElementContainedByOrEqual(overElement, element);\n    }\n\n    /**\n     * Determines if the input is currently focusing any of the given html elements.\n     * @param elements The elements to test.\n     */\n    public isFocusingOnAnyElements(elements: HTMLElement[]): boolean {\n        const overElement = this._targetData.inputOver;\n        const matchingElement = elements.find(e =>\n            Input.isElementContainedByOrEqual(overElement, e)\n        );\n        return !!matchingElement;\n    }\n\n    /**\n     * Determines if the input is currently focusing on any of the input elements.\n     */\n    public isFocusingOnAnyInputElement(): boolean {\n        const overElement = this._targetData.inputOver;\n        const inputElements = [this._options.canvasElement, ...this._options.getUIHtmlElements()];\n        const matchingElement = inputElements.find(e => \n            Input.isElementContainedByOrEqual(overElement, e)\n        );\n        return !!matchingElement;\n    }\n\n    /**\n     * Determines if the given event is for any of the the given elements and should\n     * therefore be intercepted.\n     * @param event The event.\n     * @param elements The elements.\n     */\n    public isEventForAnyElement(\n        event: MouseEvent | TouchEvent,\n        elements: HTMLElement[]\n    ): boolean {\n        let el: Element;\n        if (event instanceof MouseEvent) {\n            el = document.elementFromPoint(event.clientX, event.clientY);\n        } else {\n            el = document.elementFromPoint(\n                event.changedTouches[0].clientX,\n                event.changedTouches[0].clientY\n            );\n        }\n\n        const matchingElement = elements.find(e =>\n            Input.isElementContainedByOrEqual(el, e)\n        );\n        return !!matchingElement;\n    }\n\n    /**\n     * Determines if the given HTML element is contained by the given container element.\n     * @param element The HTML element.\n     * @param container The container.\n     */\n    public static isElementContainedByOrEqual(\n        element: Element,\n        container: HTMLElement\n    ): boolean {\n        if (element === container) {\n            return true;\n        } else {\n            if (!element) {\n                return false;\n            } else {\n                return this.isElementContainedByOrEqual(\n                    element.parentElement,\n                    container\n                );\n            }\n        }\n    }\n\n    /**\n     * Returns true the frame that the button was pressed down.\n     * If on mobile device and requresing Left Button, will return for the first finger touching the screen.\n     */\n    public getMouseButtonDown(buttonId: MouseButtonId): boolean {\n        if (this._inputType == InputType.Mouse) {\n            let buttonState = this._getMouseButtonState(buttonId);\n            if (buttonState) {\n                return buttonState.isDownOnFrame(\n                    this._options.time.frameCount\n                );\n            }\n        } else if (this._inputType == InputType.Touch) {\n            if (buttonId == MouseButtonId.Left) {\n                return this._lastPrimaryTouchData.state.isDownOnFrame(\n                    this._options.time.frameCount\n                );\n            } else {\n                // TODO: Support right button with touch?\n            }\n        }\n\n        return false;\n    }\n\n    public getTouchDown(fingerIndex: number): boolean {\n        let touchData = this.getTouchData(fingerIndex);\n        if (touchData) {\n            return touchData.state.isDownOnFrame(\n                this._options.time.frameCount\n            );\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns true on the frame that the key was pressed.\n     * @param key The key. See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n     */\n    public getKeyDown(key: string): boolean {\n        let keyData = this.getKeyData(key);\n        if (keyData) {\n            return keyData.state.isDownOnFrame(this._options.time.frameCount);\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns true the frame that the button was released.\n     * If on mobile device and requresing Left Button, will return for the first finger touching the screen.\n     */\n    public getMouseButtonUp(buttonId: MouseButtonId): boolean {\n        if (this._inputType == InputType.Mouse) {\n            let buttonState = this._getMouseButtonState(buttonId);\n            if (buttonState) {\n                return buttonState.isUpOnFrame(this._options.time.frameCount);\n            }\n        } else if (this._inputType == InputType.Touch) {\n            if (buttonId == MouseButtonId.Left) {\n                return this._lastPrimaryTouchData.state.isUpOnFrame(\n                    this._options.time.frameCount\n                );\n            } else {\n                // TODO: Support right button with touch?\n            }\n        }\n\n        return false;\n    }\n\n    public getTouchUp(fingerIndex: number): boolean {\n        let touchData = this.getTouchData(fingerIndex);\n        if (touchData) {\n            return touchData.state.isUpOnFrame(this._options.time.frameCount);\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns true on the frame that the key was released.\n     * @param key The key. See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n     */\n    public getKeyUp(key: string): boolean {\n        let keyData = this.getKeyData(key);\n        if (keyData) {\n            return keyData.state.isUpOnFrame(this._options.time.frameCount);\n        }\n\n        return false;\n    }\n\n    /**\n     * Retruns true every frame the button is held down.\n     * If on mobile device, will return the held state of the first finger touching the screen.\n     */\n    public getMouseButtonHeld(buttonId: MouseButtonId): boolean {\n        if (this._inputType == InputType.Mouse) {\n            let buttonState = this._getMouseButtonState(buttonId);\n            if (buttonState) {\n                return buttonState.isHeldOnFrame(\n                    this._options.time.frameCount\n                );\n            }\n        } else if (this._inputType == InputType.Touch) {\n            if (buttonId == MouseButtonId.Left) {\n                return this._lastPrimaryTouchData.state.isHeldOnFrame(\n                    this._options.time.frameCount\n                );\n            } else {\n                // TODO: Support right button with touch?\n            }\n        }\n\n        return false;\n    }\n\n    public getTouchHeld(fingerIndex: number): boolean {\n        let touchData = this.getTouchData(fingerIndex);\n        if (touchData) {\n            return touchData.state.isHeldOnFrame(\n                this._options.time.frameCount\n            );\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns true every frame that the given key is held down.\n     * @param key The key. See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n     */\n    public getKeyHeld(key: string): boolean {\n        let keyData = this.getKeyData(key);\n        if (keyData) {\n            return keyData.state.isHeldOnFrame(this._options.time.frameCount);\n        }\n        return false;\n    }\n\n    /**\n     * Return true the frame that wheel movement was detected.\n     */\n    public getWheelMoved(): boolean {\n        return (\n            this._wheelData.getFrame(this._options.time.frameCount) != null\n        );\n    }\n\n    /**\n     * The wheel data for the current frame.\n     */\n    public getWheelData(): WheelFrame {\n        // Deep clone the internal wheel data.\n        let wheelFrame = this._wheelData.getFrame(\n            this._options.time.frameCount\n        );\n        if (wheelFrame) return JSON.parse(JSON.stringify(wheelFrame));\n        else return null;\n    }\n\n    /**\n     * Return the last known screen position of the mouse.\n     * If on mobile device, will return the screen position of the first finger touching the screen.\n     */\n    public getMouseScreenPos(): Vector2 {\n        if (this._inputType == InputType.Mouse) {\n            return this._mouseData.screenPos;\n        } else if (this._inputType == InputType.Touch) {\n            return this._lastPrimaryTouchData.screenPos;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the last known page position of the mouse.\n     * If on mobile device, will return the page position of the first finger touching the screen.\n     */\n    public getMousePagePos(): Vector2 {\n        if (this._inputType == InputType.Mouse) {\n            return this._mouseData.pagePos;\n        } else if (this._inputType == InputType.Touch) {\n            return this._lastPrimaryTouchData.pagePos;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the last known client position of the mouse.\n     * If on mobile device, will return the client position of the first finger touching the screen.\n     */\n    public getMouseClientPos(): Vector2 {\n        if (this._inputType == InputType.Mouse) {\n            return this._mouseData.clientPos;\n        } else if (this._inputType == InputType.Touch) {\n            return this._lastPrimaryTouchData.clientPos;\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the screen position of the touch. Will return null if touch not detected.\n     * @param fingerIndex The index of the finger (first finger: 0, second finger: 1, ...)\n     */\n    public getTouchScreenPos(fingerIndex: number): Vector2 {\n        let touchData = this.getTouchData(fingerIndex);\n        if (touchData) {\n            return touchData.screenPos;\n        }\n        return null;\n    }\n\n    /**\n     * Return the page position of the touch. Will return null if touch not detected.\n     * @param fingerIndex The index of the finger (first finger: 0, second finger: 1, ...)\n     */\n    public getTouchPagePos(fingerIndex: number): Vector2 {\n        let touchData = this.getTouchData(fingerIndex);\n        if (touchData) {\n            return touchData.pagePos;\n        }\n        return null;\n    }\n\n    /**\n     * Return the client position of the touch. Will return null if touch not detected.\n     * @param fingerIndex The index of the finger (first finger: 0, second finger: 1, ...)\n     */\n    public getTouchClientPos(fingerIndex: number): Vector2 {\n        let touchData = this.getTouchData(fingerIndex);\n        if (touchData) {\n            return touchData.clientPos;\n        }\n        return null;\n    }\n\n    /**\n     * Return how many touches are currenty active.\n     */\n    public getTouchCount(): number {\n        return this._touchData.length;\n    }\n\n    public getMouseData(): MouseData {\n        return this._mouseData;\n    }\n\n    /**\n     * Returns the matching TouchData object for the provided finger index.\n     */\n    public getTouchData(finderIndex: number): TouchData {\n        if (this._touchData.length > 0) {\n            let touchData = find(this._touchData, (d: TouchData) => {\n                return d.fingerIndex === finderIndex;\n            });\n            if (touchData) {\n                return touchData;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns the matching key data for the provided key value.\n     * @param key The key that the data should be found for.\n     *            See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n     */\n    public getKeyData(key: string): KeyData {\n        return this._keyData.get(key);\n    }\n\n    /**\n     * Gets the iterable list of keys that have been used in the application.\n     * Useful to check if any keys have been pressed or released.\n     */\n    public getKeys(): Iterable<KeyData> {\n        return this._keyData.values();\n    }\n\n    /**\n     * Gets the information about what HTML elements are currently being targeted.\n     * Note that this only stores information about the last targeted elements.\n     * As such, it should only be used to tell whether touch/mouse events\n     * should be used or not.\n     */\n    public getTargetData(): TargetData {\n        return this._targetData;\n    }\n\n    /**\n     * Force all current input states to release (set the up frame to the current frame).\n     */\n    public forceReleaseInputs(): void {\n        const currentFrame = this._options.time.frameCount;\n\n        // Release currently held mouse buttons.\n        if (this._mouseData.leftButtonState.isHeldOnFrame(currentFrame)) {\n            this._mouseData.leftButtonState.setUpFrame(currentFrame);\n        }\n        if (this._mouseData.middleButtonState.isHeldOnFrame(currentFrame)) {\n            this._mouseData.middleButtonState.setUpFrame(currentFrame);\n        }\n        if (this._mouseData.rightButtonState.isHeldOnFrame(currentFrame)) {\n            this._mouseData.rightButtonState.setUpFrame(currentFrame);\n        }\n\n        // Release currenty held touches.\n        for (let i = 0; i < this._touchData.length; i++) {\n            let touchData = this._touchData[i];\n            if (touchData.state.isHeldOnFrame(currentFrame)) {\n                touchData.state.setUpFrame(currentFrame);\n            }\n        }\n    }\n\n    public update() {\n        this._cullTouchData();\n        this._wheelData.removeOldFrames(this._options.time.frameCount);\n    }\n\n    /**\n     * Loop through all current touch data and remove any that are no longer needed.\n     * Unlike the mouse, touch pointers are unique everytime they are pressed down on the screen.\n     * Remove any touch pointers that are passed their 'up' input state. No need to keep them around.\n     */\n    private _cullTouchData(): void {\n        let touchRemoved: boolean = false;\n\n        this._touchData = this._touchData.filter((t: TouchData) => {\n            let upFrame = t.state.getUpFrame();\n\n            // Up frame must have been set.\n            if (upFrame !== -1) {\n                // Current frame must be higher than the touch's up frame.\n                if (this._options.time.frameCount > upFrame) {\n                    if (this.debugLevel >= 1) {\n                        console.log(\n                            'removing touch finger: ' +\n                                t.fingerIndex +\n                                '. frame: ' +\n                                this._options.time.frameCount\n                        );\n                    }\n\n                    touchRemoved = true;\n                    return false;\n                }\n            }\n\n            return true;\n        });\n\n        if (touchRemoved && this._touchData.length > 0) {\n            // Normalize the finger index range of the remaining touch data.\n            this._touchData = this._touchData.sort(\n                (a: TouchData, b: TouchData) => {\n                    return a.fingerIndex - b.fingerIndex;\n                }\n            );\n\n            for (let i = 0; i < this._touchData.length; i++) {\n                this._touchData[i].fingerIndex = i;\n            }\n        }\n    }\n\n    private _copyToPrimaryTouchData(data: TouchData) {\n        this._lastPrimaryTouchData.fingerIndex = data.fingerIndex;\n        this._lastPrimaryTouchData.identifier = data.identifier;\n        this._lastPrimaryTouchData.clientPos = data.clientPos.clone();\n        this._lastPrimaryTouchData.pagePos = data.pagePos.clone();\n        this._lastPrimaryTouchData.screenPos = data.screenPos.clone();\n        this._lastPrimaryTouchData.state = data.state.clone();\n    }\n\n    /**\n     * Returns the matching MouseButtonData object for the provided mouse button number.\n     */\n    private _getMouseButtonState(button: MouseButtonId): InputState {\n        if (button == MouseButtonId.Left)\n            return this._mouseData.leftButtonState;\n        if (button == MouseButtonId.Right)\n            return this._mouseData.rightButtonState;\n        if (button == MouseButtonId.Middle)\n            return this._mouseData.middleButtonState;\n\n        console.warn('unsupported mouse button number: ' + button);\n        return null;\n    }\n    \n    /**\n     * Returns the matching MouseButtonData objects for the given mouse buttons number.\n     * See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons\n     * @param buttons The number that represents the buttons that are held down.\n     */\n    private _getMouseButtonStates(buttons: number): InputState[] {\n        let states = [] as InputState[];\n        if ((buttons & 1) === 1) {\n            states.push(this._getMouseButtonState(MouseButtonId.Left));\n        }\n        if ((buttons & 2) === 2) {\n            states.push(this._getMouseButtonState(MouseButtonId.Right));\n        }\n        if ((buttons & 4) === 4) {\n            states.push(this._getMouseButtonState(MouseButtonId.Middle));\n        }\n        return states;\n    }\n\n    /**\n     * Calculates the Three.js screen position of the pointer from the given pointer event.\n     * Unlike viewport positions, Three.js screen positions go from -1 to +1.\n     * @param pageX\n     * @param pageY\n     */\n    private _calculateScreenPos(pageX: number, pageY: number): Vector2 {\n        return Input.screenPosition(\n            new Vector2(pageX, pageY),\n            this._options.canvasElement\n        );\n    }\n\n    private _handleMouseDown(event: MouseEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Mouse;\n        if (this._inputType != InputType.Mouse) return;\n\n        if (\n            this.isEventForAnyElement(event, [\n                this._options.canvasElement,\n                ...this._options.getUIHtmlElements(),\n            ])\n        ) {\n            event.preventDefault();\n        }\n\n        let buttonState: InputState = this._getMouseButtonState(event.button);\n        if (buttonState) {\n            buttonState.setDownFrame(this._options.time.frameCount);\n\n            if (this.debugLevel >= 1) {\n                console.log(\n                    'mouse button ' +\n                        event.button +\n                        ' down. fireInputOnFrame: ' +\n                        this._options.time.frameCount\n                );\n            }\n\n            this._targetData.inputDown = <HTMLElement>event.target;\n            this._mouseData.clientPos = new Vector2(\n                event.clientX,\n                event.clientY\n            );\n            this._mouseData.pagePos = new Vector2(event.pageX, event.pageY);\n            this._mouseData.screenPos = this._calculateScreenPos(\n                event.pageX,\n                event.pageY\n            );\n        }\n    }\n\n    private _handleMouseUp(event: MouseEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Mouse;\n        if (this._inputType != InputType.Mouse) return;\n\n        if (\n            this.isEventForAnyElement(event, [\n                this._options.canvasElement,\n                ...this._options.getUIHtmlElements(),\n            ])\n        ) {\n            event.preventDefault();\n        }\n\n        let buttonState: InputState = this._getMouseButtonState(event.button);\n        if (buttonState) {\n            buttonState.setUpFrame(this._options.time.frameCount);\n\n            if (this.debugLevel >= 1) {\n                console.log( 'mouse button ' +\n                        event.button +\n                        ' up. fireInputOnFrame: ' +\n                        this._options.time.frameCount\n                );\n            }\n\n            this._targetData.inputUp = <HTMLElement>event.target;\n            this._mouseData.clientPos = new Vector2(event.clientX, event.pageY);\n            this._mouseData.pagePos = new Vector2(event.pageX, event.pageY);\n            this._mouseData.screenPos = this._calculateScreenPos(\n                event.pageX,\n                event.pageY\n            );\n        }\n    }\t\n    private _handleMouseLeave(event: MouseEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Mouse;\n        if (this._inputType != InputType.Mouse) return;\n\n        if (this.isEventForAnyElement(event, [\n                this._options.canvasElement,\n                ...this._options.getUIHtmlElements(),\n            ])\n        ) {\n            event.preventDefault();\n        }\n        \n        // Clear all the button states when the mouse leaves the window\n        let buttonStates: InputState[] = [\n            this._mouseData.leftButtonState,\n            this._mouseData.rightButtonState,\n            this._mouseData.middleButtonState,\n        ];\n        for (let buttonState of buttonStates) {\n            buttonState.setUpFrame(this._options.time.frameCount);\n        }\n        if (this.debugLevel >= 1) {\n            console.log('mouse button ' + event.button + ' leave. fireInputOnFrame: ' + this._options.time.frameCount);\n        }\n        this._targetData.inputUp = <HTMLElement>event.target;\n        this._mouseData.clientPos = new Vector2(event.clientX, event.pageY);\n        this._mouseData.pagePos = new Vector2(event.pageX, event.pageY);\n        this._mouseData.screenPos = this._calculateScreenPos(\n            event.pageX,\n            event.pageY\n        );\n    }\n\n    private _handleMouseMove(event: MouseEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Mouse;\n        if (this._inputType != InputType.Mouse) return;\n\n        if (\n            this.isEventForAnyElement(event, [\n                this._options.canvasElement,\n                ...this._options.getUIHtmlElements(),\n            ])\n        ) {\n            event.preventDefault();\n        }\n                \n        // Resend the mouse down events if the button is actually down\n        // but is not recorded as such.\n        const buttonStates: InputState[] = this._getMouseButtonStates(\n            event.buttons\n        );\n        let hadButtonDown = false;\n        for (let state of buttonStates) {\n            let down = state.getDownFrame();\n            let up = state.getUpFrame();\n            if (up > down || down === -1) {\n                state.setDownFrame(this._options.time.frameCount);\n                hadButtonDown = true;\n            }\n        }\n        if (hadButtonDown) {\n            if (this.debugLevel >= 1) {\n                console.log('mouse buttons ' + event.buttons + ' already down. fireInputOnFrame: ' + this._options.time.frameCount);\n            }\n        }\n\n        this._mouseData.clientPos = new Vector2(event.clientX, event.clientY);\n        this._mouseData.pagePos = new Vector2(event.pageX, event.pageY);\n        this._mouseData.screenPos = this._calculateScreenPos(\n            event.pageX,\n            event.pageY\n        );\n        this._targetData.inputOver = <HTMLElement>event.target;\n\n        if (this.debugLevel >= 2) {\n            console.log('mouse move:');\n            console.log(\n                '  screenPos: ' + JSON.stringify(this._mouseData.screenPos)\n            );\n            console.log(\n                '  pagePos: ' + JSON.stringify(this._mouseData.pagePos)\n            );\n            console.log(\n                '  clientPos: ' + JSON.stringify(this._mouseData.clientPos)\n            );\n        }\n    }\n\n    private _getKeyState(key: string) {\n        return this._keyData.get(key);\n    }\n\n    private _handleKeyUp(event: KeyboardEvent) {\n        let keyState = this._getKeyState(event.key);\n        if (keyState) {\n            keyState.state.setUpFrame(this._options.time.frameCount);\n        }\n\n        if (this.debugLevel >= 1) {\n            console.log(\n                'key ' +\n                    event.key +\n                    ' up. fireInputOnFrame: ' +\n                    this._options.time.frameCount\n            );\n        }\n    }\n\n    private _handleKeyDown(event: KeyboardEvent) {\n        let keyData = this._getKeyState(event.key);\n        if (!keyData) {\n            keyData = {\n                key: event.key,\n                state: new InputState(),\n            };\n            this._keyData.set(keyData.key, keyData);\n        }\n\n        if (!event.repeat) {\n            keyData.state.setDownFrame(this._options.time.frameCount);\n        }\n\n        if (this.debugLevel >= 1) {\n            console.log(\n                'key ' +\n                    event.key +\n                    ' down. fireInputOnFrame: ' +\n                    this._options.time.frameCount +\n                    '. repeating: ' +\n                    event.repeat\n            );\n        }\n    }\n\n    private _handleWheel(event: WheelEvent) {\n        if (this.isFocusingOnElement(this._options.canvasElement)) {\n            event.preventDefault();\n        }\n\n        let wheelFrame: WheelFrame = {\n            moveFrame: this._options.time.frameCount,\n            delta: new Vector3(event.deltaX, event.deltaY, event.deltaZ),\n            ctrl: event.ctrlKey,\n        };\n\n        this._wheelData.addFrame(wheelFrame);\n\n        if (this.debugLevel >= 2) {\n            if (wheelFrame.ctrl) {\n                console.log(\n                    `wheel w/ ctrl fireOnFrame: ${\n                        wheelFrame.moveFrame\n                    }, delta: (${wheelFrame.delta.x}, ${wheelFrame.delta.y}, ${\n                        wheelFrame.delta.z\n                    })`\n                );\n            } else {\n                console.log(\n                    `wheel fireOnFrame: ${wheelFrame.moveFrame}, delta: (${\n                        wheelFrame.delta.x\n                    }, ${wheelFrame.delta.y}, ${wheelFrame.delta.z})`\n                );\n            }\n        }\n    }\n\n    private _handleTouchStart(event: TouchEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Touch;\n        if (this._inputType != InputType.Touch) return;\n\n        const count = this._touchListenerCounts.get(event.target) || 0;\n        if (count === 0) {\n            event.target.addEventListener('touchmove', <EventListener>this._handleTouchMove);\n            event.target.addEventListener('touchend', <EventListener>this._handleTouchEnd);\n            event.target.addEventListener(\n                'touchcancel',\n                <EventListener>this._handleTouchCancel\n            );\n            this._touchListenerCounts.set(\n                event.target,\n                event.changedTouches.length\n            );\n\n            if (this.debugLevel >= 1) {\n                console.log('adding touch listeners for ', event.target);\n            }\n        } else if (count >= 0) {\n            this._touchListenerCounts.set(\n                event.target,\n                count + event.changedTouches.length\n            );\n            if (this.debugLevel >= 1) {\n                console.log(count + 1, ' touch events left for', event.target);\n            }\n        }\n\n        if (\n            this.isEventForAnyElement(event, [\n                this._options.canvasElement,\n                ...this._options.getUIHtmlElements(),\n            ])\n        ) {\n            event.preventDefault();\n        }\n\n        // For the touchstart event, it is a list of the touch points that became active with the current event.\n        let changed = event.changedTouches;\n\n        for (let i = 0; i < changed.length; i++) {\n            let touch = changed.item(i);\n\n            // Create new touch data.\n            let data: TouchData = {\n                identifier: touch.identifier,\n                fingerIndex: this.getTouchCount(),\n                state: new InputState(),\n                clientPos: new Vector2(touch.clientX, touch.clientY),\n                pagePos: new Vector2(touch.pageX, touch.pageY),\n                screenPos: this._calculateScreenPos(touch.pageX, touch.pageY),\n            };\n\n            // Set the down frame on the new touch data.\n            data.state.setDownFrame(this._options.time.frameCount);\n\n            if (data.fingerIndex === 0) {\n                this._copyToPrimaryTouchData(data);\n            }\n\n            if (this.debugLevel >= 1) {\n                console.log(\n                    'touch finger ' +\n                        data.identifier +\n                        ' ' +\n                        data.fingerIndex +\n                        ' start. fireInputOnFrame: ' +\n                        this._options.time.frameCount\n                );\n            }\n\n            this._targetData.inputDown = this._targetData.inputOver = <HTMLElement>touch.target;\n            this._touchData.push(data);\n        }\n    }\n\n    private _handleTouchMove(event: TouchEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Touch;\n        if (this._inputType != InputType.Touch) return;\n\n        if (this.stopTouchPropogation) {\n            event.stopImmediatePropagation();\n        }\n\n        if (\n            this.isEventForAnyElement(event, [\n                this._options.canvasElement,\n                ...this._options.getUIHtmlElements(),\n            ])\n        ) {\n            event.preventDefault();\n        }\n\n        // For the touchmove event, it is a list of the touch points that have changed since the last event.\n        let changed = event.changedTouches;\n\n        for (let i = 0; i < changed.length; i++) {\n            let touch = changed.item(i);\n\n            let existingTouch = find(this._touchData, d => {\n                return d.identifier === touch.identifier;\n            });\n            existingTouch.clientPos = new Vector2(touch.clientX, touch.clientY);\n            existingTouch.pagePos = new Vector2(touch.pageX, touch.pageY);\n            existingTouch.screenPos = this._calculateScreenPos(\n                touch.pageX,\n                touch.pageY\n            );\n            // Must use elementFromPoint because touch event target never changes after initial contact.\n            this._targetData.inputOver = <HTMLElement>(\n                document.elementFromPoint(touch.clientX, touch.clientY)\n            );\n\n            if (existingTouch.fingerIndex === 0) {\n                this._copyToPrimaryTouchData(existingTouch);\n            }\n\n            if (this.debugLevel >= 2) {\n                console.log('touch move:');\n                console.log('  identifier: ' + existingTouch.identifier);\n                console.log('  fingerIndex: ' + existingTouch.fingerIndex);\n                console.log(\n                    '  screenPos: ' + JSON.stringify(existingTouch.screenPos)\n                );\n                console.log(\n                    '  pagePos: ' + JSON.stringify(existingTouch.pagePos)\n                );\n                console.log(\n                    '  clientPos: ' + JSON.stringify(existingTouch.clientPos)\n                );\n            }\n        }\n    }\n\n    private _handleTouchEnd(evt: TouchEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Touch;\n        if (this._inputType != InputType.Touch) return;\n\n        if (this.stopTouchPropogation) {\n            event.stopImmediatePropagation();\n        }\n\n        const count = this._touchListenerCounts.get(evt.target) || 0;\n        if (count <= evt.changedTouches.length) {\n            evt.target.removeEventListener(\n                'touchmove',\n                <EventListener>this._handleTouchMove\n            );\n            evt.target.removeEventListener('touchend', <EventListener>this._handleTouchEnd);\n            evt.target.removeEventListener(\n                'touchcancel',\n                <EventListener>this._handleTouchCancel\n            );\n            this._touchListenerCounts.set(evt.target, 0);\n\n            if (this.debugLevel >= 1) {\n                console.log('removing touch listeners for ', evt.target);\n            }\n        } else if (count > 0) {\n            this._touchListenerCounts.set(\n                evt.target,\n                count - evt.changedTouches.length\n            );\n            if (this.debugLevel >= 1) {\n                console.log(count - 1, ' touch events left for', evt.target);\n            }\n        }\n\n        if (\n            this.isEventForAnyElement(evt, [\n                this._options.canvasElement,\n                ...this._options.getUIHtmlElements(),\n            ])\n        ) {\n            evt.preventDefault();\n        }\n\n        // For the touchend event, it is a list of the touch points that have been removed from the surface.\n        let changed = evt.changedTouches;\n\n        for (let i = 0; i < changed.length; i++) {\n            let touch = changed.item(i);\n\n            // Must use elementFromPoint because touch event target never changes after initial contact.\n            this._targetData.inputUp = this._targetData.inputOver = <HTMLElement>document.elementFromPoint(touch.clientX, touch.clientY);\n\n            let existingTouch = find(this._touchData, d => {\n                return d.identifier === touch.identifier;\n            });\n            existingTouch.state.setUpFrame(this._options.time.frameCount);\n            existingTouch.clientPos = new Vector2(touch.clientX, touch.clientY);\n            existingTouch.pagePos = new Vector2(touch.pageX, touch.pageY);\n            existingTouch.screenPos = this._calculateScreenPos(\n                touch.pageX,\n                touch.pageY\n            );\n\n            if (existingTouch.fingerIndex === 0) {\n                this._copyToPrimaryTouchData(existingTouch);\n            }\n\n            if (this.debugLevel >= 1) {\n                console.log(\n                    'touch finger ' +\n                        existingTouch.identifier +\n                        ' ' +\n                        existingTouch.fingerIndex +\n                        ' end. fireInputOnFrame: ' +\n                        this._options.time.frameCount\n                );\n            }\n        }\n    }\n\n    private _handleTouchCancel(evt: TouchEvent) {\n        if (this._inputType == InputType.Undefined)\n            this._inputType = InputType.Touch;\n        if (this._inputType != InputType.Touch) return;\n\n        if (this.stopTouchPropogation) {\n            event.stopImmediatePropagation();\n        }\n\n        const count = this._touchListenerCounts.get(evt.target) || 0;\n        if (count <= evt.changedTouches.length) {\n            evt.target.removeEventListener(\n                'touchmove',\n                <EventListener>this._handleTouchMove\n            );\n            evt.target.removeEventListener('touchend', <EventListener>this._handleTouchEnd);\n            evt.target.removeEventListener(\n                'touchcancel',\n                <EventListener>this._handleTouchCancel\n            );\n            this._touchListenerCounts.set(evt.target, 0);\n\n            if (this.debugLevel >= 1) {\n                console.log('removing touch listeners for ', evt.target);\n            }\n        } else if (count > 0) {\n            this._touchListenerCounts.set(\n                evt.target,\n                count - evt.changedTouches.length\n            );\n            if (this.debugLevel >= 1) {\n                console.log(count - 1, ' touch events left for', evt.target);\n            }\n        }\n\n        let changed = evt.changedTouches;\n\n        for (let i = 0; i < changed.length; i++) {\n            // Handle a canceled touche the same as a touch end.\n            let touch = changed.item(i);\n\n            let existingTouch = find(this._touchData, d => {\n                return d.identifier === touch.identifier;\n            });\n            existingTouch.state.setUpFrame(this._options.time.frameCount);\n            existingTouch.clientPos = new Vector2(touch.clientX, touch.clientY);\n            existingTouch.pagePos = new Vector2(touch.pageX, touch.pageY);\n            existingTouch.screenPos = this._calculateScreenPos(\n                touch.pageX,\n                touch.pageY\n            );\n\n            if (existingTouch.fingerIndex === 0) {\n                this._copyToPrimaryTouchData(existingTouch);\n            }\n\n            if (this.debugLevel >= 1) {\n                console.log(\n                    'touch finger ' +\n                        existingTouch.fingerIndex +\n                        ' canceled. fireInputOnFrame: ' +\n                        this._options.time.frameCount\n                );\n            }\n        }\n    }\n\n    private _handleContextMenu(event: MouseEvent) {\n        // Prevent context menu from triggering.\n        event.preventDefault();\n        event.stopPropagation();\n    }\n}\n\nexport enum InputType {\n    Undefined = 'undefined',\n    Mouse = 'mouse',\n    Touch = 'touch',\n}\n\nexport enum MouseButtonId {\n    Left = 0,\n    Middle = 1,\n    Right = 2,\n}\n\nexport class InputState {\n    /**\n     * The frame this input was down.\n     */\n    private _downFrame: number = -1;\n\n    /**\n     * The frame this input was up.\n     */\n    private _upFrame: number = -1;\n\n    getDownFrame(): number {\n        return this._downFrame;\n    }\n\n    setDownFrame(frame: number) {\n        this._downFrame = frame;\n    }\n\n    getUpFrame(): number {\n        return this._upFrame;\n    }\n\n    setUpFrame(frame: number) {\n        this._upFrame = frame;\n    }\n\n    /**\n     * Is the input down on the requested frame. Will only return true on the exact frame.\n     * @see isHeldOnFrame() for true result for every frame the input is down.\n     * @param frame The frame to compare against.\n     */\n    isDownOnFrame(frame: number): boolean {\n        return frame === this._downFrame;\n    }\n\n    /**\n     * Is the input held on the requested frame. Will return for every frame the input is held down.\n     * @param frame The frame to compare against.\n     */\n    isHeldOnFrame(frame: number): boolean {\n        // Down frame must have been set.\n        if (this._downFrame !== -1) {\n            // Down frame must be more recent than the up frame.\n            if (this._downFrame > this._upFrame) {\n                // Frame must be same or higher than down frame.\n                if (frame >= this._downFrame) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Is the input up on the requested frame. Will only return true on the exact frame.\n     * @param frame The frame to compare against.\n     */\n    isUpOnFrame(frame: number): boolean {\n        return frame === this._upFrame;\n    }\n\n    /**\n     * Returns a new InputState with the same values as this one.\n     */\n    clone(): InputState {\n        let clone = new InputState();\n        clone._downFrame = this._downFrame;\n        clone._upFrame = this._upFrame;\n\n        return clone;\n    }\n}\n\ninterface WheelFrame {\n    /**\n     * The frame that the wheel moved on.\n     */\n    moveFrame: number;\n\n    /**\n     * Wheel delta in a Vector3 format. (x, y, z)\n     */\n    delta: Vector3;\n\n    /**\n     * Is the wheel being invoked with ctrl?\n     * @see https://developer.mozilla.org/en-US/docs/Web/Events/wheel\n     * WheelEvent has a standardized hack that allows trackpad two finger pinching to be detected as WheelEvent + ctrl key.\n     * This boolean indicates whether the ctrl key was detected with the WheelEvent.\n     */\n    ctrl: boolean;\n}\n\n/**\n * Data about the HTML element that was targeted by a click.\n */\nexport interface TargetData {\n    inputDown: HTMLElement;\n    inputUp: HTMLElement;\n    inputOver: HTMLElement;\n}\n\ninterface TouchData {\n    /**\n     * The unique identifier for the touch.\n     */\n    identifier: number;\n\n    /**\n     * The index of the finger for the touch.\n     */\n    fingerIndex: number;\n\n    /**\n     * State of the touch input.\n     */\n    state: InputState;\n\n    /**\n     * Screen position of the touch.\n     */\n    screenPos: Vector2;\n\n    /**\n     * Page position of the touch.\n     */\n    pagePos: Vector2;\n\n    /**\n     * Client position of touch.\n     */\n    clientPos: Vector2;\n}\n\ninterface MouseData {\n    /**\n     * State of the left mouse button.\n     */\n    leftButtonState: InputState;\n\n    /**\n     * State of the right mouse button.\n     */\n    rightButtonState: InputState;\n\n    /**\n     * State of the middle mouse button.\n     */\n    middleButtonState: InputState;\n\n    /**\n     * Screen position of the mouse.\n     */\n    screenPos: Vector2;\n\n    /**\n     * Page position of the mouse.\n     */\n    pagePos: Vector2;\n\n    /**\n     * Client position of mouse.\n     */\n    clientPos: Vector2;\n}\n\n/**\n * Interface for data about a key.\n */\ninterface KeyData {\n    /**\n     * The key that the data is for.\n     */\n    key: string;\n\n    /**\n     * The state of the key.\n     */\n    state: InputState;\n}\n\nclass WheelData {\n    private _wheelFrames: WheelFrame[] = [];\n\n    /**\n     * Add the WheelFrame to the WheelData frame array.\n     * @param wheelFrame\n     */\n    addFrame(wheelFrame: WheelFrame): void {\n        this._wheelFrames.push(wheelFrame);\n    }\n\n    /**\n     * Returns the WheelFrame for the specified frame number.\n     * @param frame The frame number to retrieve.\n     */\n    getFrame(frame: number): WheelFrame {\n        let wheelFrame = find(this._wheelFrames, (f: WheelFrame) => {\n            return f.moveFrame === frame;\n        });\n        if (wheelFrame) return wheelFrame;\n        else return null;\n    }\n\n    /**\n     * Remove all WheelFrame objects that are older than the specified current frame.\n     * @param curFrame The current frame number.\n     */\n    removeOldFrames(curFrame: number): void {\n        if (this._wheelFrames.length === 0) return;\n        // console.log('removeOldFrames wheelFrameCount: ' + this._wheelFrames.length + ', curFrame: ' + curFrame);\n        this._wheelFrames = this._wheelFrames.filter((f: WheelFrame) => {\n            return f.moveFrame >= curFrame;\n        });\n        // console.log('removeOldFrames after filter wheelFrameCount: ' + this._wheelFrames.length);\n    }\n}\n","import { Object3D, Scene } from \"three\";\nimport { Decorator } from \"./decorators/Decorator\";\nimport { traverseSafe, traverseVisibleSafe } from \"../utils/ThreeUtils\";\n\n\nenum DestroyState {\n    None = -1,\n    WillDestroy = 0,\n    Destroyed = 1\n}\n\n/**\n * GameObject is an APEngine specific implemention of Three's Object3D class that supports decorators.\n */\nexport class GameObject extends Object3D {\n\n    private static __APEngine_destroyQueue: GameObject[] = [];\n\n    /**\n     * Destroy the given GameObject and all of its children.\n     */\n    static destroy(gameObject: GameObject): void {\n        // Get array of all child gameObjects in ascending order,\n        // including the given gameObject.\n        traverseSafe(gameObject, (go) => {\n            if (go instanceof GameObject) {\n                if (go._destroyState === DestroyState.None) {\n                    GameObject.__APEngine_destroyQueue.push(go);\n                    go._destroyState = DestroyState.WillDestroy;\n\n                    // Inform all gameObject decorators that it will be destroyed.\n                    go._decorators.forEach(d => d.onWillDestroy());\n                }\n            }\n        });\n    }\n\n    /**\n     * Process the GameObject destroy queue.\n     * This should ONLY be called by APEngine.\n     */\n    static __APEngine_ProcessGameObjectDestroyQueue() {\n        if (this.__APEngine_destroyQueue.length > 0) {\n            // Use a copy of the destroy queue in its current state so that \n            // any modifications to the destroy queue during processing are not affected.\n            const count = this.__APEngine_destroyQueue.length;\n\n            for (let i = 0; i < count; i++) {\n                const gameObject = this.__APEngine_destroyQueue.pop();\n                if (gameObject && gameObject._destroyState === DestroyState.WillDestroy) {\n                    // Infrom the gameobject that it is being destroyed.\n                    gameObject.onDestroy();\n\n                    gameObject._destroyState = DestroyState.Destroyed;\n                }\n            }\n        }\n    }\n\n    /**\n     * Is the given GameObject visible to rendering?\n     * This function taked into account the visibility of the gameObject's parents.\n     */\n    static isGameObjectVisible(gameObject: GameObject) {\n        let obj = gameObject as Object3D;\n\n        if (!obj) {\n            return false;\n        }\n        while (obj) {\n            if (!obj.visible) {\n                return false;\n            }\n            obj = obj.parent;\n        }\n        return true;\n    }\n\n    /**\n     * Find the GameObject that is a parent of the given object.  \n     * If the object is a GameObject, then the object itself is returned.  \n     * If the object has no GameObject parents, then null is returned.\n     */\n    static findParentGameObject(obj: Object3D): GameObject {\n        if (obj instanceof GameObject) {\n            return obj;\n        }\n        if (obj.parent) {\n            return GameObject.findParentGameObject(obj.parent);\n        }\n        return null;\n    }\n\n    /**\n     * Find a GameObject that has the given name at or underneath the given root/scene.\n     */\n    static findGameObjectByName(root: Object3D | Scene, name: string): GameObject {\n        if (root instanceof GameObject && root.name === name) {\n            return root;\n        }\n\n        for (let child of root.children) {\n            const go = GameObject.findGameObjectByName(child, name);\n            if (go) {\n                return go;\n            }\n        }\n\n        return null;\n    }\n\n    private _decorators: Decorator[] = [];\n    private _destroyState: DestroyState = DestroyState.None;\n    private _prevVisible: boolean = false;\n\n    get destroyed(): boolean {\n        return this._destroyState !== DestroyState.None;\n    }\n\n    constructor(name?: string) {\n        super();\n        \n        if (name) {\n            this.name = name;\n        }\n    }\n\n    addDecorator<T extends Decorator>(decorator: T): T {\n        if (this._decorators.some((d) => d === decorator)) {\n            // Decorator is already added.\n            return;\n        }\n\n        // Add decorator to the array.\n        this._decorators.push(decorator);\n        decorator.onAttach(this);\n\n        return decorator;\n    }\n\n    getDecorator<T extends Decorator>(type: { new(): T }): T {\n        if (!this.destroyed) {\n            for (let i = 0; i < this._decorators.length; i++) {\n                const decorator = this._decorators[i];\n                if (decorator instanceof type && !decorator.destroyed) {\n                    return decorator;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    getDecorators<T extends Decorator>(type: { new(): T }): T[] {\n        let decorators: T[] = [];\n\n        if (!this.destroyed) {\n            for (let i = 0; i < this._decorators.length; i++) {\n                const decorator = this._decorators[i];\n                if (decorator instanceof type && !decorator.destroyed) {\n                    decorators.push(decorator);\n                }\n            }\n        }\n\n        if (decorators.length > 0) {\n            return decorators;\n        } else {\n            return null;\n        }\n    }\n\n    getDecoratorInChildren<T extends Decorator>(type: { new(): T }, includeInvisible?: boolean): T {\n        // Check this gameObject for matching decorator.\n        if (includeInvisible || this.visible) {\n            const decorator = this.getDecorator(type);\n            if (decorator) {\n                return decorator;\n            }\n        }\n\n        // Recursively search through child gameObjects for matching decorator.\n        for (const child of this.children) {\n            if (child instanceof GameObject) {\n                const decorator = child.getDecoratorInChildren(type, includeInvisible);\n                if (decorator) {\n                    return decorator;\n                }\n            }\n        }\n\n        // No matching decorator found in this gameObject or its children.\n        return null;\n    }\n\n    getDecoratorsInChildren<T extends Decorator>(type: { new(): T }, includeInvisible?: boolean): T[] {\n        const decorators: T[] = [];\n\n        if (!includeInvisible) {\n            traverseVisibleSafe(this, (o) => {\n                if (o instanceof GameObject) {\n                    const decs = o.getDecorators(type);\n                    if (decs) {\n                        decorators.push(...decs);\n                    }\n                }\n            });\n        } else {\n            traverseSafe(this, (o) => {\n                if (o instanceof GameObject) {\n                    const decs = o.getDecorators(type);\n                    if (decs) {\n                        decorators.push(...decs);\n                    }\n                }\n            });\n        }\n\n        if (decorators.length > 0) {\n            return decorators;\n        } else {\n            return null;\n        }\n    }\n    \n    getDecoratorInParent<T extends Decorator>(type: { new(): T }, includeInvisible?: boolean): T {\n        // Check this gameObject for matching decorator.\n        if (includeInvisible || this.visible) {\n            const decorator = this.getDecorator(type);\n            if (decorator) {\n                return decorator;\n            }\n        }\n\n        // Recursively search through parent gameObjects for matching decorator.\n        if (this.parent && this.parent instanceof GameObject) {\n            const decorator = this.parent.getDecoratorInParent(type, includeInvisible);\n            if (decorator) {\n                return decorator;\n            }\n        }\n\n        // No matching decorator found in this gameObject or its parents.\n        return null;\n    }\n\n    /**\n     * Called for each three js frame.\n     */\n    onUpdate() {\n        if (this.destroyed) {\n            return;\n        }\n\n        let isVisible = GameObject.isGameObjectVisible(this);\n\n        this._decorators.forEach((d) => {\n            if (!d.destroyed && isVisible) {\n                if (!d.started) {\n                    this._prevVisible = true;\n                    d.onVisible();\n                    d.onStart();\n                    if (!d.started) {\n                        console.error(`Decorator ${d.constructor.name} does not have super.onStart() called.`);\n                    }\n                } else {\n                    isVisible = this.visibleChangeCheck();\n                }\n\n                if (isVisible) {\n                    d.onUpdate();\n                }\n            }\n        });\n\n        this.cleanupDestroyedDecorators();\n    }\n\n    /**\n     * Called for each three js frame but after all onUpdate calls have been made.\n     */\n    onLateUpdate() {\n        if (this.destroyed) {\n            return;\n        }\n\n        const isVisible = this.visibleChangeCheck();\n\n        this._decorators.forEach((d) => {\n            if (!d.destroyed && isVisible) {\n                d.onLateUpdate();\n            }\n        });\n\n        this.cleanupDestroyedDecorators();\n    }\n\n    /**\n     * Run a visibility change check. Returns the current state of gameobject visibility.\n     */\n    private visibleChangeCheck(): boolean {\n        const isVisible = GameObject.isGameObjectVisible(this);\n\n        if (this._prevVisible !== isVisible) {\n            this._decorators.forEach((d) => {\n                if (!d.destroyed) {\n                    if (isVisible) {\n                        d.onVisible();\n                    } else {\n                        d.onInvisible();\n                    }\n                }\n            });\n            this._prevVisible = isVisible;\n        }\n\n        return isVisible;\n    }\n\n    private onDestroy() {\n        // Destroy our decorators.\n        this._decorators.forEach((c) => {\n            Decorator.destroy(c);\n        });\n        this._decorators = [];\n\n        if (this.parent) {\n            // Remove ourself from parent object (and thus the scene).\n            this.parent.remove(this);\n        }\n    }\n\n    private cleanupDestroyedDecorators() {\n        this._decorators = this._decorators.filter((c) => {\n            return !c.destroyed;\n        });\n    }\n}","import { Clock } from 'three';\nimport { IDisposable } from './misc/IDisposable';\nimport { ArgEvent } from './misc/Events';\n\ninterface TimeWaitPromise { \n    resolveTime: number;\n    resolve: () => void;\n}\n\ninterface FrameWaitPromise {\n    frame: number;\n    resolve: () => void;\n}\n\nexport class Time implements IDisposable {\n\n    /**\n     * Scalar value for how fast time passes. 0 = paused, 0.5 = half speed, 1.0 = normal, 2.0 = 2x fast, 4.0 = 4x fast, etc.\n     */\n    timeScale: number = 1.0;\n\n    onUpdate: ArgEvent<Time> = new ArgEvent();\n    \n    private _frameCount: number = 0;\n    private _timeSinceStart: number = 0;\n    private _deltaTime: number = 0;\n    private _clock: Clock;\n    private _timeWaitPromises: TimeWaitPromise[] = [];\n    private _frameWaitPromises: FrameWaitPromise[] = [];\n    \n    constructor() {\n        this._frameCount = 0;\n        this._timeSinceStart = 0;\n        this._deltaTime = 0;\n        this._clock = new Clock(true);\n    }\n\n    /**\n     * Number of frames that have passed since this game view was created.\n     */\n    get frameCount(): number {\n        return this._frameCount;\n    }\n\n    /**\n     * Number of seconds that have passed since this game view was created. This is affected by timeScale.\n     */\n    get timeSinceStart(): number {\n        return this._timeSinceStart;\n    }\n\n    /**\n     * Time in seconds that has passed since the last frame. This is affected by timeScale.\n     */\n    get deltaTime(): number {\n        return this._deltaTime;\n    }\n\n    update() {\n        // Track time.\n        this._frameCount += 1;\n\n        const clockDelta = this._clock.getDelta();\n        this._deltaTime = clockDelta * this.timeScale;\n        \n        this._timeSinceStart += this._deltaTime;\n\n        // Check frame wait promises and resolve any that are complete.\n        if (this._frameWaitPromises.length > 0) {\n            this._frameWaitPromises = this._frameWaitPromises.filter((fw) => {\n                if (fw.frame <= this._frameCount) {\n                    fw.resolve();\n                    return false;\n                } else {\n                    return true;\n                }\n            });\n        }  \n\n        // Check time wait promises and resolve any that are complete.\n        if (this._timeWaitPromises.length > 0) {\n            this._timeWaitPromises = this._timeWaitPromises.filter((tw) => {\n                if (tw.resolveTime <= this._timeSinceStart) {\n                    tw.resolve();\n                    return false;\n                } else {\n                    return true;\n                }\n            });\n        }\n\n        this.onUpdate.invoke(this);\n    }\n\n    /**\n     * Return a promise that waits the given number of seconds before resolving.\n     * @param seconds Number of seconds to wait before resolving the promise.\n     */\n    async waitForSeconds(seconds: number): Promise<void> {\n        if (seconds <= 0) {\n            return;\n        }\n\n        return new Promise((resolve) => {\n            this._timeWaitPromises.push({\n                resolveTime: this._timeSinceStart + seconds,\n                resolve\n            });\n        });\n    }\n\n    /**\n     * Return a promise that resolves once the next frame has started.\n     */\n    async waitForNextFrame(): Promise<void> {\n        return new Promise((resolve) => {\n            this._frameWaitPromises.push({\n                frame: this._frameCount + 1,\n                resolve\n            });\n        });\n    }\n\n    /**\n     * Return a promise that resolves once the the given number of frames has passed.\n     */\n    async waitForFrames(frameCount: number): Promise<void> {\n        return new Promise((resolve) => {\n            this._frameWaitPromises.push({\n                frame: this._frameCount + frameCount,\n                resolve\n            });\n        });\n    }\n\n    dispose(): void {\n    }\n}\n","import { GameObject } from \"../GameObject\";\n\nexport interface IDecoratorOptions {\n}\n\nexport abstract class Decorator {\n\n    static destroy(decorator: Decorator) {\n        if (decorator._destroyed) {\n            return;\n        }\n\n        if (!decorator._willDestroy) {\n            decorator.onWillDestroy();\n        }\n\n        decorator.onDestroy();\n    }\n\n    private _configured: boolean = false;\n    private _willDestroy: boolean = false;\n    private _destroyed: boolean = false;\n    private _started: boolean = false;\n    private _gameObject: GameObject = null;\n\n    get destroyed() { \n        return this._destroyed;\n    }\n\n    get gameObject() { \n        return this._gameObject;\n    }\n\n    get started() {\n        return this._started;\n    }\n\n    configure(option: IDecoratorOptions) {\n        this._configured = true;\n    }\n\n    /**\n     * Called once when the Decorator is attached to a gameObject.\n     */\n    onAttach(gameObject: GameObject) {\n        if (!this._configured) {\n            throw new Error(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} did not have configure() called before being attached to gameObject.`);\n        }\n\n        this._gameObject = gameObject;\n    }\n\n    /**\n     * Called when the GameObject that this Decorator is attached to becomes visible.\n     */\n    onVisible() {\n        // console.log(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} onVisible`);\n    }\n\n    /**\n     * Called when the GameObject that this Decorator is attached to becomes invisible.\n     */\n    onInvisible() {\n        // console.log(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} onInvisible`);\n    }\n\n    /**\n     * Called once when the Decorator is first started.\n     */\n    onStart() {\n        // console.log(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} onStart`);\n        this._started = true;\n    }\n\n    /**\n     * Called for each three js frame.\n     */\n    onUpdate() {\n        // console.log(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} onUpdate`);\n    }\n\n    /**\n     * Called for each three js frame but after all onUpdate calls have been made.\n     */\n    onLateUpdate() {\n        // console.log(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} onLateUpdate`);\n    }\n\n    /**\n     * Called when the GameObject that this Decorator is attached to is marked for destruction.\n     */\n    onWillDestroy() {\n        this._willDestroy = true;\n        // console.log(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} onWillDestroy`);\n    }\n\n    /**\n     * Called once when the Decorator is being destroyed.\n     */\n    protected onDestroy() {\n        this._destroyed = true;\n        // console.log(`[Decorator] ${this.constructor.name} on ${this.gameObject.name} onDestroy`);\n    }\n}","import {\n    Object3D,\n    Scene,\n    Matrix4,\n    Box2,\n    Vector2,\n    Box3,\n    Layers,\n    Mesh,\n    SphereBufferGeometry,\n    BoxBufferGeometry,\n    MeshBasicMaterial,\n    MeshStandardMaterial,\n    Material,\n    Camera,\n    Vector3,\n    Quaternion,\n} from 'three';\n\n/**\n * Set the parent of the object3d.\n * @param object3d the object to re-parent.\n * @param parent the object to parent to.\n * @param scene the scene that these objects exist in.\n */\nexport function setParent(object3d: Object3D, parent: Object3D, scene: Scene) {\n    if (!object3d) return;\n    if (!scene)\n        throw new Error('utils.setParent needs a valid scene parameter.');\n\n    // Detach\n    if (object3d.parent && object3d.parent !== scene) {\n        object3d.applyMatrix4(object3d.parent.matrixWorld);\n        object3d.parent.remove(object3d);\n        scene.add(object3d);\n    }\n\n    // Attach\n    if (parent) {\n        object3d.applyMatrix4(parent.matrixWorld.clone().invert())\n        scene.remove(object3d);\n        parent.add(object3d);\n    }\n\n    object3d.updateMatrixWorld(true);\n}\n\n/**\n * Find the scene object that the given object is parented to.\n * Will return null if no parent scene is found.\n * @param object3d The object to find the parent scene for.\n */\nexport function findParentScene(object3d: Object3D): Scene {\n    if (!object3d) {\n        return null;\n    }\n\n    if (object3d instanceof Scene) {\n        return object3d;\n    } else {\n        return findParentScene(object3d.parent);\n    }\n}\n\n/**\n * Is the object a child of the given parent object.\n * @param parent The parent object that we want to know if the other object is a child of.\n * @param object The object that we want to know if is a child of the parent object.\n */\nexport function isObjectChildOf(object: Object3D, parent: Object3D): boolean {\n    if (!parent || !object.parent) {\n        return false;\n    }\n\n    if (object.parent === parent) {\n        return true;\n    } else {\n        return isObjectChildOf(object.parent, parent);\n    }\n}\n\n/**\n * Convert the Box3 object to a box2 object. Basically discards the z components of the Box3's min and max.\n * @param box3 The Box3 to convert to a Box2.\n */\nexport function convertToBox2(box3: Box3): Box2 {\n    return new Box2(\n        new Vector2(box3.min.x, box3.min.y),\n        new Vector2(box3.max.x, box3.max.y)\n    );\n}\n\n/**\n * Set the layer number that the given object 3d is on (and optionally all of its children too).\n * @param obj The root object 3d to change the layer.\n * @param layer The layer to set the object 3d to.\n * @param children Should change all children of given object 3d as well?\n */\nexport function setLayer(obj: Object3D, layer: number, children?: boolean) {\n    obj.layers.set(layer);\n    if (children) {\n        traverseSafe(obj, (child) => child.layers.set(layer));\n    }\n}\n\n/**\n * Set the layer mask of the given object 3d (and optionally all of its children too).\n * @param obj The root object 3d to change the layer.\n * @param layerMask The layer mask to set the object 3d to.\n * @param children Should change all children of given object 3d as well?\n */\nexport function setLayerMask(\n    obj: Object3D,\n    layerMask: number,\n    children?: boolean\n) {\n    obj.layers.mask = layerMask;\n    if (children) {\n        traverseSafe(obj, (child) => child.layers.mask = layerMask);\n    }\n}\n\n/**\n * Debug print out all 32 layers for this object and wether or not it belongs to them.\n * @param obj The object to print out layers for.\n */\nexport function debugLayersToString(obj: Object3D): string {\n    if (!obj) return;\n\n    let output: string = '\\n';\n    for (let i = 0; i < 32; i++) {\n        let l = new Layers();\n        l.set(i);\n        output += '[' + i + ']  ' + obj.layers.test(l) + '\\n';\n    }\n\n    return output;\n}\n\nexport function isObjectVisible(obj: Object3D) {\n    if (!obj) {\n        return false;\n    }\n    while (obj) {\n        if (!obj.visible) {\n            return false;\n        }\n        obj = obj.parent;\n    }\n    return true;\n}\n\nexport function disposeObject3d<T extends Object3D>(obj: T) {\n    if (obj) {\n        traverseSafe(obj, (o) => {\n            if (o instanceof Mesh) {\n                if (o.geometry) {\n                    o.geometry.dispose();\n                }\n                \n                if (Array.isArray(o.material)) {\n                    o.material.forEach((m) => m.dispose());\n                } else {\n                    o.material.dispose();\n                }\n            }\n    \n            if (o.parent) {\n                o.parent.remove(o);\n            }\n        });\n    }\n}\n\n/**\n * Dispose of each object 3d in the array and then clear the array.\n */\nexport function disposeObject3ds(objs: Object3D[]) {\n    if (objs && objs.length > 0) {\n        for (let i = 0; i < objs.length; i++) {\n            disposeObject3d(objs[i]);\n        }\n        objs = [];\n    }\n}\n\nexport function createDebugSphere(radius: number, color: string, lit?: boolean): Mesh {\n    const geometry = new SphereBufferGeometry(radius, 24, 24);\n    let material: Material;\n\n    if (lit) {\n        material = new MeshStandardMaterial({\n            color,\n        });\n    } else {\n        material = new MeshBasicMaterial({\n            color,\n        });\n    }\n\n    return new Mesh(geometry, material);\n}\n\nexport function createDebugCube(size: number, color: string, lit?: boolean): Mesh {\n    const geometry = new BoxBufferGeometry(size, size, size);\n    let material: Material;\n\n    if (lit) {\n        material = new MeshStandardMaterial({\n            color,\n        });\n    } else {\n        material = new MeshBasicMaterial({\n            color,\n        });\n    }\n\n    return new Mesh(geometry, material);\n}\n\nexport function worldToScreenPosition(target: Object3D | Vector3, camera: Camera): Vector2 {\n    const pos = new Vector3();\n    \n    if (target instanceof Object3D) {\n        pos.setFromMatrixPosition(target.matrixWorld);\n    } else {\n        pos.copy(target);\n    }\n\n    pos.project(camera);\n\n    const halfWidth = window.innerWidth * 0.5;\n    const halfHeight = window.innerHeight * 0.5;\n\n    pos.x = (pos.x * halfWidth) + halfWidth;\n    pos.y = -(pos.y * halfHeight) + halfHeight;\n    pos.z = 0;\n\n    return new Vector2(pos.x, pos.y);\n}\n\n/**\n * Return the world direction for the given local direction from the object's perspective.\n * @param localDirection The local direction.\n * @param obj The object to return the world direction for.\n */\nexport function objectWorldDirection(\n    localDirection: Vector3,\n    obj: Object3D\n): Vector3 {\n    const worldRotation = new Quaternion();\n    worldRotation.setFromRotationMatrix(obj.matrixWorld);\n    const forward = localDirection.clone().applyQuaternion(worldRotation);\n    return forward;\n}\n\nexport function getMaterials(mesh: Mesh): Material[] {\n    if (Array.isArray(mesh.material)) {\n        return mesh.material;\n    } else {\n        return [mesh.material];\n    }\n}\n\nexport function getWorldPosition(object3d: Object3D): Vector3 {\n    const worldPos = new Vector3();\n    object3d.getWorldPosition(worldPos);\n    return worldPos;\n}\n\nexport function setWorldPosition(object3d: Object3D, target: Vector3 | Object3D): void {\n    const scene = findParentScene(object3d);\n\n    if (!scene) {\n        console.error(`Cannot set world position of object3d ${object3d.name} because it is not attached to a scene.`);\n        return;\n    }\n\n    let matrixWorld: Matrix4;\n\n    if (target instanceof Vector3) {\n        matrixWorld = new Matrix4();\n        matrixWorld.setPosition(target);\n    } else {\n        matrixWorld = target.matrixWorld;\n    }\n\n    const prevParent = object3d.parent;\n    scene.attach(object3d);\n    object3d.position.setFromMatrixPosition(matrixWorld);\n    prevParent.attach(object3d);\n}\n\nexport function rotationToFace(object3d: Object3D, worldPos: Vector3): Quaternion {\n    const dummy = new Object3D();\n\n    if (object3d.parent) {\n        object3d.parent.add(dummy);\n    }\n\n    setWorldPosition(dummy, object3d);\n    dummy.rotation.copy(object3d.rotation);\n    dummy.scale.copy(object3d.scale);\n\n    dummy.lookAt(worldPos);\n\n    const faceRotation = dummy.quaternion.clone();\n\n    if (dummy.parent) {\n        dummy.parent.remove(dummy);\n    }\n\n    return faceRotation;\n}\n\n/**\n * Same function as Object3D.traverse except that it does not execute on children that have become undefined like the built-in function does.\n */\nexport function traverseSafe(object3d: Object3D, callback: (object3d: Object3D) => void) {\n    callback(object3d);\n\n    const children = object3d.children;\n    for (let i = 0, l = children.length; i < l; i++) {\n        if (children[i]) {\n            traverseSafe(children[i], callback);\n        }\n    }\n}\n\n/**\n * Same function as Object3D.traverseVisible except that it does not execute on children that have become undefined like the built-in function does.\n */\nexport function traverseVisibleSafe(object3d: Object3D, callback: (object3d: Object3D) => void) {\n\n    if (object3d.visible === false) return;\n\n    callback(object3d);\n\n    const children = object3d.children;\n    for (let i = 0, l = children.length; i < l; i++) {\n        if (children[i]) {\n            traverseVisibleSafe(children[i], callback);\n        }\n    }\n}","import { IDisposable } from \"../misc/IDisposable\";\nimport { \n    Group,\n    WebGLRenderer,\n    Vector3,\n    Quaternion\n} from \"three\";\nimport { ArgEvent } from '../misc/Events';\n\nexport interface ControllerPose {\n    position: Vector3;\n    rotation: Quaternion;\n    scale: Vector3;\n}\n\nexport class XRInput implements IDisposable {\n\n    controller: Group;\n\n    private _renderer: WebGLRenderer;\n\n    onSelectStart = new ArgEvent<ControllerPose>();\n    onSelect = new ArgEvent<ControllerPose>();\n    onSelectEnd = new ArgEvent<ControllerPose>();\n\n    constructor(renderer: WebGLRenderer) {\n        this._renderer = renderer;\n\n        this._onControllerSelectStart = this._onControllerSelectStart.bind(this);\n        this._onControllerSelect = this._onControllerSelect.bind(this);\n        this._onControllerSelectEnd = this._onControllerSelectEnd.bind(this);\n\n        // Setup AR controller.\n        this.controller = this._renderer.xr.getController(0);\n        this.controller.addEventListener('selectstart', this._onControllerSelectStart);\n        this.controller.addEventListener('select', this._onControllerSelect);\n        this.controller.addEventListener('selectend', this._onControllerSelectEnd);\n    }\n\n    /**\n     * Return the controller's pose at the current time.\n     * This is a snapshot of the controller's pose and will not change as the controller moves.\n     */\n    getCurrentControllerPose(): ControllerPose {\n        if (this.controller) {\n            const controllerPose: ControllerPose = {\n                position: new Vector3(),\n                rotation: new Quaternion(),\n                scale: new Vector3()\n            };\n\n            this.controller.matrixWorld.decompose(controllerPose.position, controllerPose.rotation, controllerPose.scale);\n            return controllerPose;\n        } else {\n            return null;\n        }\n    }\n\n    dispose(): void {\n        if (this.controller) {\n            this.controller.removeEventListener('selectstart', this._onControllerSelectStart);\n            this.controller.removeEventListener('select', this._onControllerSelect);\n            this.controller.removeEventListener('selectend', this._onControllerSelectEnd);\n        }\n    }\n\n    private _onControllerSelectStart() {\n        this.onSelectStart.invoke(this.getCurrentControllerPose());\n    }\n\n    private _onControllerSelect() {\n        this.onSelect.invoke(this.getCurrentControllerPose());\n    }\n\n\n    private _onControllerSelectEnd() {\n        this.onSelectEnd.invoke(this.getCurrentControllerPose());\n    }\n\n}","import Stats from 'stats.js';\nimport { IDisposable } from './IDisposable';\n\ndeclare type StatsPosition = 'top left' | 'top right' | 'bottom left' |'bottom right';\nexport class PerformanceStats implements IDisposable {\n\n    private _enabled: boolean = false;\n    private _position: StatsPosition = null;\n    private _stats: Stats | null = null;\n\n    get enabled() {\n        return this._enabled;\n    }\n\n    set enabled(enable: boolean) {\n        if (this._enabled !== enable) {\n            this._enabled = enable;\n\n            if (this._enabled) {\n                this._onEnable();\n            } else {\n                this._onDisable();\n            }\n        }\n    }\n\n    get position() {\n        return this._position;\n    }\n\n    set position(pos: StatsPosition) {\n        if (this._position !== pos) {\n            this._position = pos;\n            this._updatePosition();\n        }\n    }\n\n    constructor() {\n        this._onEnable = this._onEnable.bind(this);\n        this._onDisable = this._onDisable.bind(this);\n    }\n\n    update() {\n        if (this._enabled) {\n            this._stats.update();\n        }\n    }\n\n    dispose() {\n        this.enabled = false;\n    }\n\n    private _onEnable() {\n        this._stats = new Stats();\n        this._stats.showPanel(0);\n        document.body.appendChild(this._stats.dom);\n        this._updatePosition();\n    }\n\n    private _onDisable() {\n        document.body.removeChild(this._stats.dom);\n        this._stats = null;\n    }\n\n    private _updatePosition() {\n        if (!this._stats) {\n            return;\n        }\n\n        let pos = this._position;\n        if (!pos) {\n            pos = 'bottom left';\n        }\n\n        if (pos === 'top left') {\n            this._stats.dom.style.top = '0px';\n            this._stats.dom.style.left = '0px';\n            this._stats.dom.style.right = '';\n            this._stats.dom.style.bottom = '';\n        } else if (pos === 'top right') {\n            this._stats.dom.style.top = '0px';\n            this._stats.dom.style.left = '';\n            this._stats.dom.style.right = '0px';\n            this._stats.dom.style.bottom = '';\n        } else if (pos === 'bottom left') {\n            this._stats.dom.style.top = '';\n            this._stats.dom.style.left = '0px';\n            this._stats.dom.style.right = '';\n            this._stats.dom.style.bottom = '0px';\n        } else if (pos === 'bottom right') {\n            this._stats.dom.style.top = '';\n            this._stats.dom.style.left = '';\n            this._stats.dom.style.right = '0px';\n            this._stats.dom.style.bottom = '0px';\n        }\n    }\n}","\n\nexport function hasValue(obj: any): boolean {\n    return obj !== undefined && obj !== null;\n}\n\nexport function getOptionalValue<T>(obj: T, defaultValue: T): T {\n    return obj !== undefined && obj !== null ? obj : defaultValue;\n}\n\n/**\n * Post the given data object as JSON to the provided URL.\n * @returns - Promise that resolves to a Response or null if an exception occured.\n */\nexport async function postJsonData(url: string, data: any): Promise<Response> {\n    console.log(`[postJsonData] start...`);\n\n    const headers = new Headers();\n    headers.set('Content-Type', 'application/json');\n\n    const init: RequestInit = {\n        method: 'POST',\n        body: JSON.stringify(data),\n        mode: 'cors',\n        headers: headers,\n\n    }\n\n    const request = new Request(url, init);\n    console.log(request);\n\n    try {\n        // Until aux is CORS enabled, the response will always be opaque and thus checking the response for anything is pointless.\n        const response = await fetch(request);\n        console.log(`[postJsonData] response received.`);\n        return response;\n    } catch (error) {\n        console.error(`[postJsonData] Could not fetch. error: ${error}`);\n        return null;\n    }\n}\n\n/**\n * Search through element's descendents and return the first child element that contains the given class name(s). \n * An element must contain all of the given class names in order to be matched.\n * @param element The element to search the descendents of.\n * @param className The class name(s) to search for. Can be either a single class name or many.\n */\nexport function getElementByClassName(element: Element, names: string): HTMLElement {\n    if (element instanceof HTMLElement) {\n        // Check element for class names.\n        const elementClassList: DOMTokenList = element.classList;\n\n        if (elementClassList.length > 0) {\n            const classNames: string[] = names.split(' ');\n            let classFoundCount: number = 0;\n\n            for (const className of classNames) {\n                if (elementClassList.contains(className)) {\n                    classFoundCount++;\n\n                    if (classFoundCount === classNames.length) {\n                        return element;\n                    }\n                }\n            }\n        }\n    }\n\n    // Check descendents of element.\n    const children = element.children;\n    for (let i = 0; i < children.length; i++) {\n        const match = getElementByClassName(children[i], names);\n        if (match !== null) {\n            return match;\n        }\n    }\n\n    // No matching element.\n    return null;\n}\n\nexport function getFilename(path: string): string | null {\n    const lastSlashIndex = path.lastIndexOf('/');\n\n    let filename: string | null = null;\n    if (lastSlashIndex < 0) {\n        filename = path;\n    } else {\n        filename = path.substr(lastSlashIndex + 1);\n    }\n\n    // Make sure that it is a file by check for an extension.\n    const ext = getExtension(filename);\n\n    if (ext !== null) {\n        return filename;\n    } else {\n        return null;\n    }\n}\n\nexport function getExtension(path: string): string | null {\n    if (path.includes('.')) {\n        const ext = path.split('.').pop();\n\n        if (ext) {\n            if (!ext.includes('/')) {\n                return ext;\n            }\n        }\n    }\n\n    return null;\n}\n\n/**\n * Load the image from the given url (or from the cache if the browser as it stored).\n * @param url Location of the image to load.\n */\nexport async function loadImage(url: string, onProgress?: (event: ProgressEvent<EventTarget>) => void): Promise<HTMLImageElement> {\n    return new Promise<HTMLImageElement>(((resolve: (value: HTMLImageElement) => void, reject) => {\n        const img: HTMLImageElement = new Image();\n\n        img.addEventListener('load', (event) => {\n            resolve(img);\n        });\n        \n        img.addEventListener('progress', (event) => {\n            if (onProgress) {\n                onProgress(event);\n            }\n        })\n\n        img.addEventListener('error', (event) => {\n            reject(event);\n        });\n        \n        img.src = url;\n    }));\n}\n\nexport function copyToClipboard(text: string): void {\n    // Create text area element to contain text content.\n    const textArea = document.createElement('textarea');\n    textArea.style.position = 'fixed';\n    textArea.style.opacity = '0';\n    textArea.textContent = text;\n    document.body.appendChild(textArea);\n\n    // Select text area element and execute document's copy command.\n    textArea.select();\n    document.execCommand('copy');\n\n    // Remove text area element from document.\n    textArea.remove();\n}\n\nexport function appendLine(text: string, line: string): string {\n    if (!text || text.length === 0) {\n        return line;\n    } else if (text.length > 0) {\n        text += `\\n${line}`;\n    }\n\n    return text;\n}\n\nexport function sortAZ<T, K extends keyof T>(array: T[], propertyKey: K): void {\n    array.sort((a, b) => {\n        return a[propertyKey] > b[propertyKey] ? 1 : -1\n    });\n}\n\nexport function sortZA<T, K extends keyof T>(array: T[], propertyKey: K): void {\n    array.sort((a, b) => {\n        return a[propertyKey] < b[propertyKey] ? 1 : -1\n    });\n}","import { Vector3, Vector2, MathUtils } from \"three\";\nimport { hasValue } from \"./MiscUtils\";\n\nexport const Vector3_Up = new Vector3(0, 1, 0);\nexport const Vector3_Down = new Vector3(0, -1, 0);\nexport const Vector3_Forward = new Vector3(0, 0, 1);\nexport const Vector3_Back = new Vector3(0, 0, -1);\nexport const Vector3_Left = new Vector3(-1, 0, 0);\nexport const Vector3_Right = new Vector3(1, 0, 0);\nexport const Vector3_Zero = new Vector3(0, 0, 0);\nexport const Vector3_One = new Vector3(1, 1, 1);\n\nexport function interpolate(start: number, end: number, progress: number, ease?: (t: number) => number): number {\n    if (ease) {\n        progress = ease(progress);\n    }\n\n    return (1 - progress) * start + progress * end;\n}\n\nexport function interpolateClamped(start: number, end: number, progress: number, ease?: (t: number) => number): number {\n    const value = interpolate(start, end, progress, ease);\n    return clamp(value, start, end);\n}\n\nexport function clamp(value: number, min?: number, max?: number): number {\n    if (hasValue(min) && value < min) {\n        value = min;\n    }\n    if (hasValue(max) && value > max) {\n        value = max;\n    }\n\n    return value;\n}\n\nexport function inRange(value: number, min: number, max: number): boolean {\n    if (value <= max && value >= min) {\n        return true;\n    } else {\n        return false;\n    }\n}\n\nexport function isEven(value: number): boolean {\n    return value % 2 === 0;\n}\n\nexport function isOdd(value: number): boolean {\n    return !isEven(value);\n}\n\nexport function clampDegAngle(value: number, min: number, max: number): number {\n    if (value < -360)\n        value += 360;\n    if (value > 360)\n        value -= 360;\n    return clamp(value, min, max);\n}\n\nexport function pointOnSphere(center: Vector3, radius: number, rotation: Vector2): Vector3 {\n    /*\n        Reference: https://stackoverflow.com/questions/11819833/finding-3d-coordinates-from-point-with-known-xyz-angles-radius-and-origin\n        x = origin.x + radius * math.cos(math.rad(rotation.y)) * math.cos(math.rad(rotation.x))\n        y = origin.y + radius * math.sin(math.rad(rotation.x)) \n        z = origin.z + radius * math.sin(math.rad(rotation.y)) * math.cos(math.rad(rotation.x))\n     */\n\n    const pos = new Vector3();\n    pos.x = center.x + radius * Math.cos(MathUtils.DEG2RAD * rotation.y) * Math.cos(MathUtils.DEG2RAD * rotation.x);\n    pos.y = center.y + radius * Math.sin(MathUtils.DEG2RAD * rotation.x);\n    pos.z = center.z + radius * Math.sin(MathUtils.DEG2RAD * rotation.y) * Math.cos(MathUtils.DEG2RAD * rotation.x);\n\n    return pos;\n}\n\nexport function pointOnCircle(center: Vector2, radius: number, angle: number): Vector2 {\n    const angleRad: number = angle * MathUtils.DEG2RAD;\n\n    const point = new Vector2(\n        center.x + radius * Math.sin(angleRad),\n        center.y + radius * Math.cos(angleRad)\n    );\n\n    return point;\n}\n\n/**\n * Tests if point is inside the given polygon. Test is done in 2d space.\n * Reference: https://codepen.io/prisoner849/pen/ROdXzw?editors=1010\n */\nexport function pointInPolygon2D(point: Vector2, polyPoints: Vector2[]): boolean {\n\n    const x = point.x;\n    const y = point.y;\n\n    let inside = false;\n    for (let i = 0, j = polyPoints.length - 1; i < polyPoints.length; j = i++) {\n        let xi = polyPoints[i].x,\n            yi = polyPoints[i].y;\n        let xj = polyPoints[j].x,\n            yj = polyPoints[j].y;\n\n        let intersect = ((yi > y) != (yj > y)) &&\n            (x < (xj - xi) * (y - yi) / (yj - yi) + xi);\n        if (intersect) inside = !inside;\n    }\n\n    return inside;\n}\n\nexport function calculateRowOffsets(rowLength: number, cellWidth: number, alignment: 'start' | 'center' | 'end'): number[] {\n    if (rowLength <= 0) {\n        return [];\n    }\n\n    const totalWidth: number = (rowLength - 1) * cellWidth;\n\n    // Our start x and offset will be different based on which how we want to align the children.\n    let startX: number;\n    let offset: number;\n    if (alignment == 'start') {\n        startX = 0;\n        offset = -cellWidth;\n    } else if (alignment == 'center') {\n        startX = -(totalWidth * 0.5);\n        offset = cellWidth;\n    } else {\n        startX = 0;\n        offset = cellWidth;\n    }\n\n    const rowOffsets: number[] = [];\n    for (let i = 0; i < rowLength; i++) {\n        rowOffsets.push(\n            startX + (offset * i)\n        );\n    }\n\n    return rowOffsets;\n}\n\nexport function normalize(value: number, min: number, max: number): number {\n    return (value - min) / (max - min);\n}\n\nexport function normalizeClamped(value: number, min: number, max: number): number {\n    value = clamp(value, min, max);\n    return (value - min) / (max - min);\n}\n\nexport function unnormalize(normal: number, min: number, max: number): number {\n    return normal * (max - min) + min;\n}\n\nexport function unnormalizeClamped(normal: number, min: number, max: number): number {\n    normal = clamp(normal, 0.0, 1.0);\n    return normal * (max - min) + min;\n}\n\nexport function calculateFrustumPlanes(size: number, aspect: number): { left: number, right: number, top: number, bottom: number } {\n    return {\n        left: - size * aspect / 2,\n        right: size * aspect / 2,\n        top: size / 2,\n        bottom: - size / 2,\n    }\n}\n\n/**\n * Split integer number into an array of mostly equal parts.\n * @example \n * splitInteger(10, 3) // [4, 3, 3]\n * splitInteger(142, 5) // [29, 29, 28, 28, 28]\n */\nexport function splitInteger(num: number, parts: number): number[] {\n    if (!Number.isInteger(num)) {\n        return null;\n    }\n    if (num < parts) {\n        return null;\n    } \n\n    const mod = num % parts;\n    const splitArray: number[] = [];\n    \n    if (mod === 0) {\n        const value = num / parts;\n        for (let i = 0; i < parts; i++) {\n            splitArray.push(value);\n        }\n\n        return splitArray;\n    } else {\n        const value = (num - mod) / parts;\n        for (let i = 0; i < parts; i++) {\n            splitArray.push(value);\n        }\n\n        for(let i =0; i < mod; i++) {\n            splitArray[i] = splitArray[i] + 1;\n        }\n\n        return splitArray;\n    }\n}","import { WebGLRenderer } from \"three\";\nimport { clamp } from \"../utils/MathUtils\";\nimport { hasValue } from '../utils/MiscUtils';\n\nexport interface IParams {\n    startEnabled?: boolean;\n    targetFramerate?: number;\n    targetPixelRatio?: number;\n    minimumPixelRatio?: number;\n    pixelRatioAdjustRate?: number;\n}\n\nexport class PerformanceResolutionScalar {\n    enabled: boolean = true;\n    targetFramerate: number = 60;\n    targetPixelRatio: number;\n    minimumPixelRatio: number = 0.5;\n    pixelRatioAdjustRate: number = 0.01;\n    debugUI: PerformanceResolutionScalarDebugUI;\n\n    private _renderer: WebGLRenderer;\n    private _lastFrameTimestamp: number = -1;\n    private _lastFrameTime: number = -1;\n\n    constructor(renderer: WebGLRenderer, options?: IParams) {\n        this._renderer = renderer;\n\n        this.debugUI = new PerformanceResolutionScalarDebugUI();\n        this.debugUI.visible = false;\n\n        if (!options) {\n            options = {};\n        }\n\n        if (hasValue(options.startEnabled)) {\n            this.enabled = options.startEnabled;\n        }\n\n        if (hasValue(options.targetFramerate)) {\n            this.targetFramerate = options.targetFramerate;\n        }\n\n        if (hasValue(options.targetPixelRatio)) {\n            this.targetPixelRatio = options.targetPixelRatio;\n        } else {\n            this.targetPixelRatio = renderer.getPixelRatio();\n        }\n\n        if (hasValue(options.minimumPixelRatio)) {\n            this.minimumPixelRatio = options.minimumPixelRatio;\n        }\n\n        if (hasValue(options.pixelRatioAdjustRate)) {\n            this.pixelRatioAdjustRate = options.pixelRatioAdjustRate;\n        }\n    }\n\n    update(): void {\n        const frameTimestamp = performance.now();\n\n        if (this._lastFrameTimestamp > 0 && this.enabled) {\n            const currentFrameTime = frameTimestamp - this._lastFrameTimestamp;\n            const targetFrameTime = Math.ceil(1000 / this.targetFramerate);\n            this.debugUI.customText(\n                \"targetTime\",\n                `Target Frame Time: ${targetFrameTime.toFixed(2)}`\n            );\n\n            // Reference: https://software.intel.com/en-us/articles/dynamic-resolution-rendering-article/\n            const t = (targetFrameTime - currentFrameTime) / targetFrameTime;\n            this.debugUI.customText(\"t\", `T: ${t.toFixed(2)}`);\n\n            let ratioDelta = 0;\n            if (t < 0) {\n                ratioDelta = -this.pixelRatioAdjustRate;\n            } else if (t > 0) {\n                ratioDelta = this.pixelRatioAdjustRate;\n            }\n            // const ratioDelta: number =\n            // this.pixelRatioAdjustRate * this._renderer.getPixelRatio() * t;\n            this.debugUI.customText(\n                \"ratioDelta\",\n                `Ratio Delta: ${ratioDelta.toFixed(2)}`\n            );\n\n            if (ratioDelta !== 0) {\n                // Apply pixel ratio adjustment.\n                const newPixelRatio = clamp(\n                    this._renderer.getPixelRatio() + ratioDelta,\n                    this.minimumPixelRatio,\n                    this.targetPixelRatio\n                );\n\n                // console.log(`new pixel ratio: ${newPixelRatio}`);\n\n                if (this._renderer.getPixelRatio() !== newPixelRatio) {\n                    // console.log(\"new pixel ratio: \" + newPixelRatio);\n                    this._renderer.setPixelRatio(newPixelRatio);\n                }\n            }\n\n            this._lastFrameTime = currentFrameTime;\n        }\n\n        this._lastFrameTimestamp = frameTimestamp;\n        this.debugUI.update(this);\n    }\n\n    getCurrentPixelRatio(): number {\n        return this._renderer.getPixelRatio();\n    }\n\n    getLastFrameTime(): number {\n        return this._lastFrameTime;\n    }\n}\n\nclass PerformanceResolutionScalarDebugUI {\n    private _rootEl: HTMLDivElement;\n    private _pixelRatioEl: HTMLParagraphElement;\n    private _minMaxEl: HTMLParagraphElement;\n    private _frameTimeEl: HTMLParagraphElement;\n\n    private _customTextMap: Map<string, HTMLParagraphElement>;\n\n    get visible(): boolean {\n        return this._rootEl.style.display === \"block\";\n    }\n\n    set visible(visible: boolean) {\n        this._rootEl.style.display = visible ? \"block\" : \"none\";\n    }\n\n    constructor() {\n        this._rootEl = document.createElement(\"div\");\n        document.body.appendChild(this._rootEl);\n        this._rootEl.style.position = \"absolute\";\n        this._rootEl.style.left = 0 + \"px\";\n        this._rootEl.style.bottom = 0 + \"px\";\n        this._rootEl.style.minWidth = 180 + \"px\";\n        this._rootEl.style.padding = 2 + \"px\";\n        this._rootEl.style.backgroundColor = \"#000\";\n        this._rootEl.style.fontFamily = \"Courier New\";\n\n        this._pixelRatioEl = this._addTextElement(this._rootEl);\n        this._minMaxEl = this._addTextElement(this._rootEl);\n        this._frameTimeEl = this._addTextElement(this._rootEl);\n    }\n\n    private _addTextElement(parent: HTMLElement): HTMLParagraphElement {\n        const textEl = document.createElement(\"p\");\n        textEl.style.color = \"#fff\";\n        textEl.style.margin = 1 + \"px\";\n        parent.appendChild(textEl);\n        return textEl;\n    }\n\n    public customText(id: string, text: string): void {\n        if (!this.visible) {\n            return;\n        }\n\n        if (!this._customTextMap) {\n            this._customTextMap = new Map();\n        }\n\n        let textEl = this._customTextMap.get(id);\n        if (!textEl) {\n            textEl = this._addTextElement(this._rootEl);\n            this._customTextMap.set(id, textEl);\n        }\n\n        textEl.innerText = text;\n    }\n\n    update(scalar: PerformanceResolutionScalar): void {\n        if (!this.visible) {\n            return;\n        }\n        \n        this._pixelRatioEl.innerText = `Pixel Ratio: ${scalar\n            .getCurrentPixelRatio()\n            .toFixed(2)}`;\n\n        this._minMaxEl.innerText = `Min/Max: ${scalar.minimumPixelRatio} / ${\n            scalar.targetPixelRatio\n            }`;\n\n        this._frameTimeEl.innerHTML = `Frame Time: ${scalar\n            .getLastFrameTime()\n            .toFixed(2)}`;\n    }\n}\n","/**\n * Returns a promise that waits for the given condition function to return true.\n * If the condition function returns false, it will continue to be called at a regular interval until\n * the condition function returns true.\n * @param condition A function that must return true in order for the promise to resolve.\n * @param timeout An optional timeout value. Must be greater than 0 to be used. If condition is not met before timeout (ms), then the promise is rejected.\n * @param tickRate A optional tick rate value. Must be greater than 0. How frequently the condition function should be called (in ms).\n */\nexport async function waitForCondition(condition: () => boolean, timeout?: number, tickRate?: number): Promise<void> {\n    if (typeof tickRate !== 'number' || tickRate <= 0) {\n        tickRate = 30;\n    }\n\n    return new Promise<void>((resolve, reject) => {\n        let tickTimeoutId: number;\n        let timeoutId: number;\n\n        const tick = () => {\n            if (condition()) {\n                window.clearTimeout(tickTimeoutId);\n                window.clearTimeout(timeoutId);\n                return resolve();\n            } else {\n                tickTimeoutId = window.setTimeout(tick, tickRate);\n            }\n        };\n\n        tick();\n\n        if (typeof timeout === 'number' && timeout > 0) {\n            timeoutId = window.setTimeout(() => {\n                // Timeout reached before promise was able to resolve.\n                window.clearTimeout(tickTimeoutId);\n                \n                // Check for condition one last time in last ditch effort to resolve.\n                if (condition()) {\n                    return resolve();\n                } else {\n                    return reject('Timeout occured before condition could be met.');\n                }\n            }, timeout);\n        }\n    });\n}\n\n/**\n * Return a promise that waits the given number of seconds before resolving.\n * @param seconds Number of seconds to wait before resolving the promise.\n * @deprecated Use APEngine.time.waitForSeconds instead. This allows the promise to be responsive to pause/timescale.\n */\nexport async function waitForSeconds(seconds: number): Promise<void> {\n    console.warn(`DEPRECATED: Use APEngine.time.waitForSeconds instead. This allows the promise to be responsive to pause/timescale.`)\n    if (seconds > 0) {\n        return new Promise<void>((resolve, reject) => {\n            window.setTimeout(() => {\n                return resolve();\n            }, (seconds * 1000));\n        });\n    } else {\n        return Promise.resolve();\n    }\n}","\nimport { IDisposable } from '../misc/IDisposable';\nimport { waitForCondition } from '../utils/WaitPromises';\n\nexport interface IVideoStreamStartResult {\n    started: boolean;\n    error?: any;\n}\n\n/**\n * Device Camera is a class that wraps modern rowser functionality to interact with device camera hardware.\n */\nexport class DeviceCamera implements IDisposable {\n    \n    constraints: MediaStreamConstraints;\n\n    private _video: HTMLVideoElement = null;\n    private _stream: MediaStream = null;\n    private _playing: boolean = false;\n\n    constructor(constraints?: MediaStreamConstraints) {\n        this.constraints = constraints;\n    }\n\n    /**\n     * Is the device camera stream currently playing or not.\n     */\n    isPlaying(): boolean {\n        return this._playing;\n    }\n\n    /**\n     * The video element that is playing the device camera feed.\n     */\n    getVideoElement(): HTMLVideoElement {\n        return this._video;\n    }\n\n    /**\n     * Request to start device camera video stream. Promise will return true if successful, otherwise false.\n     * Uses the DeviceCamera.constraints object when requesting the camera from the browser.\n     * \n     * May provide a timeout value in milliseconds.\n     */\n    async startVideoStream(timeout?: number): Promise<IVideoStreamStartResult> {\n        if (this._video) {\n            return {\n                started: true\n            }\n        }\n\n        try {\n            this._stream = await navigator.mediaDevices.getUserMedia(this.constraints);\n        } catch (error) {\n            return {\n                started: false,\n                error: error\n            }\n        }\n\n        this._video = document.createElement('video');\n        this._video.srcObject = this._stream;\n        // this._video.setAttribute('autoplay', 'false');\n        this._video.setAttribute('playsinline', 'true');\n        this._video.play();\n\n        if (typeof timeout === 'number') {\n            if (timeout <= 0) {\n                timeout = 6000;\n            }\n        }\n\n        \n        try {\n            await waitForCondition(() => {\n                if (this._video) {\n                    return this._video.readyState === HTMLMediaElement.HAVE_ENOUGH_DATA;\n                }\n            }, timeout);\n\n            this._playing = true;\n            return {\n                started: true\n            }\n        } catch (error) {\n            this.stopVideoStream();\n            this._playing = false;\n            return {\n                started: false,\n                error: error\n            }\n        }\n    }\n\n    /**\n     * Stop running video streams and clean up related objects.\n     */\n    stopVideoStream(): void {\n        if (this._video) {\n            this._video = null;\n        }\n\n        if (this._stream) {\n            const tracks = this._stream.getTracks()\n            for (let track of tracks) {\n                track.stop();\n            }\n\n            this._stream = null;\n        }\n\n        this._playing = false;\n    }\n\n    dispose(): void {\n        this.stopVideoStream();\n    }\n}","import {\n    Vector2,\n    Camera,\n    Vector3,\n    Ray,\n    Raycaster,\n    Object3D,\n    Intersection,\n    Plane,\n} from 'three';\n\n/**\n * Container for all custom physics functions for game engine.\n */\nexport namespace Physics {\n    /**\n     * Infinite mathematical plane whos normal points up towards the sky.\n     */\n    export const GroundPlane: Plane = new Plane(new Vector3(0, 1, 0));\n\n    const _Raycaster: Raycaster = new Raycaster();\n\n    /**\n     * Defines the result of a raycast.\n     */\n    export interface RaycastResult {\n        /**\n         * The screen position used to perform this raycast.\n         */\n        pointerScreenPos: Vector2;\n\n        /**\n         * The ray used to perform this raycast.\n         */\n        ray: Ray;\n\n        /**\n         * The list of intersections from the raycast.\n         */\n        intersects: Intersection[];\n    }\n\n    /**\n     * Calculates a ray from the given screen position and camera.\n     * @pos The screen position that the ray should use for its direction vector.\n     * @camera The camera that the ray should point from.\n     */\n    export function screenPosToRay(screenPos: Vector2, camera: Camera): Ray {\n        _Raycaster.setFromCamera(screenPos, camera);\n        return _Raycaster.ray.clone();\n    }\n\n    /**\n     * Gets a point that is the given distance along the given ray.\n     * @param ray The ray.\n     * @param distance The distance along the ray from the origin.\n     */\n    export function pointOnRay(ray: Ray, distance: number): Vector3 {\n        let pos = new Vector3(\n            ray.direction.x,\n            ray.direction.y,\n            ray.direction.z\n        );\n        pos.multiplyScalar(distance);\n        pos.add(ray.origin);\n\n        return pos;\n    }\n\n    /**\n     * Calculates the point at which the given ray intersects the given plane.\n     * If the ray does not intersect the plane then null is returned.\n     * @param ray The ray.\n     * @param plane The plane that the ray should test against.\n     */\n    export function pointOnPlane(ray: Ray, plane: Plane): Vector3 | null {\n        let point = new Vector3();\n        point = ray.intersectPlane(plane, point);\n\n        return point;\n    }\n\n    /**\n     * Performs a raycast at the given screen position with the given camera against the given objects.\n     * @param screenPos The screen position to raycast from.\n     * @param objects The objects to raycast against.\n     * @param camera The camera to use.\n     * @param recursive — If true, it also checks all descendants of the objects. Otherwise it only checks intersecton with the objects. Default is false.\n     */\n    export function raycastAtScreenPos(\n        screenPos: Vector2,\n        objects: Object3D[],\n        camera: Camera,\n        recursive?: boolean\n    ): RaycastResult {\n        _Raycaster.setFromCamera(screenPos, camera);\n        const intersects = _Raycaster.intersectObjects(objects, recursive);\n\n        return {\n            pointerScreenPos: screenPos,\n            ray: _Raycaster.ray.clone(),\n            intersects,\n        };\n    }\n\n    /**\n     * Performs a raycast with the given ray against the given objects.\n     * @param ray The ray to use.\n     * @param objects The objects to raycast against.\n     * @param recursive — If true, it also checks all descendants of the objects. Otherwise it only checks intersecton with the objects. Default is false.\n     */\n    export function raycast(ray: Ray, objects: Object3D[], recursive?: boolean): RaycastResult {\n        _Raycaster.set(ray.origin, ray.direction);\n        const intersects = _Raycaster.intersectObjects(objects, recursive);\n\n        return {\n            pointerScreenPos: null,\n            ray: _Raycaster.ray.clone(),\n            intersects,\n        };\n    }\n\n    /**\n     * Returns the first intersection from the raycast test. If none exist, then null is returned.\n     */\n    export function firstRaycastHit(result: RaycastResult) {\n        return result.intersects.length > 0 ? result.intersects[0] : null;\n    }\n}\n","import { Event, ArgEvent } from './misc/Events';\n\nexport namespace APEngineEvents {\n    export const onUpdate: Event = new Event();\n    export const onLateUpdate: Event = new Event();\n    export const onResize: Event = new Event();\n    export const onXRSessionStarted: Event = new Event();\n    export const onXRSessionEnded: Event = new Event();\n    export const onVisibilityChanged: ArgEvent<boolean> = new ArgEvent();\n}","export namespace APEngineBuildInfo {\n    /**\n     * Version number of the app. \n     */\n    export const version: string = '__ape_version__';\n\n    const _time: string = '__ape-build-time__';\n\n    /**\n     * The date that this version of the app was built.\n     */\n    export function date(): Date {\n        const timeNum = parseInt(_time);\n        return new Date(timeNum);\n    }\n}\n","import {\n    WebGLRenderer,\n    WebGLRendererParameters\n} from 'three';\nimport { Time } from './Time';\nimport { Input } from './input/Input';\nimport { GameObject } from \"./gameobject/GameObject\";\nimport { XRInput } from './input/XRInput';\nimport { PerformanceStats } from './misc/PerformanceStats';\nimport { PerformanceResolutionScalar } from './misc/PerformanceResolutionScalar';\nimport { DeviceCamera } from './device-camera/DeviceCamera';\nimport { PointerEventSystem } from './input/PointerEventSystem';\nimport { APEngineBuildInfo } from './APEngineBuildInfo';\nimport { SceneManager } from './scene-management/SceneManager';\nimport { CameraDecorator } from './gameobject/decorators/CameraDecorator';\nimport { XRPhysics } from './physics/XRPhysics';\nimport { APEngineEvents } from './APEngineEvents';\nimport { Howler } from 'howler';\n\nexport namespace APEngine {\n\n    export const sceneManager = new SceneManager();\n    \n    export let webglRenderer: WebGLRenderer;\n    export let time: Time;\n    export let input: Input;\n    export let xrInput: XRInput;\n    export let xrPhysics: XRPhysics;\n    export let performanceStats: PerformanceStats;\n    export let performanceResolutionScalar: PerformanceResolutionScalar;\n    export let deviceCamera: DeviceCamera;\n    export let pointerEventSystem: PointerEventSystem;\n\n    let _initialized: boolean = false;\n    let _xrFrame: any;\n    let _xrEnabled: boolean = false;\n    let _maxPixelRatio: number = 0;\n    let _audioMutedCount: number = 0;\n\n    export function isXREnabled() {\n        return _xrEnabled;\n    }\n\n    export function getXRFrame(): any { \n        return _xrFrame;\n    }\n\n    export function init(webglParams?: WebGLRendererParameters) {\n        if (_initialized) {\n            return;\n        }\n\n        console.info(`== APEngine v${APEngineBuildInfo.version} ==\\nDate: ${APEngineBuildInfo.date().toString()}`);\n\n        _initialized = true;\n\n        // Create renderer.\n        webglRenderer = new WebGLRenderer(webglParams);\n        webglRenderer.autoClear = false;\n\n        const width = window.innerWidth;\n        const height = window.innerHeight;\n\n        webglRenderer.setSize(width, height);\n        webglRenderer.domElement.style.display = \"block\";\n        \n        // Create time module.\n        time = new Time();\n\n        // Create performance stats module.\n        performanceStats = new PerformanceStats();\n\n        // Create performance resolution scalar.\n        performanceResolutionScalar = new PerformanceResolutionScalar(webglRenderer, {\n            startEnabled: false\n        });\n        \n        // Create input module.\n        input = new Input({\n            inputElement: webglRenderer.domElement,\n            canvasElement: webglRenderer.domElement,\n            time: time,\n            getUIHtmlElements: () => []\n        });\n        \n        // Create xr input module.\n        xrInput = new XRInput(webglRenderer);\n\n        // Create xr physics module.\n        xrPhysics = new XRPhysics(webglRenderer, APEngineEvents.onXRSessionStarted, APEngineEvents.onXRSessionEnded, getXRFrame);\n\n        // Create pointer event system.\n        pointerEventSystem = new PointerEventSystem('Default', 0);\n\n        // Create device camera module.\n        deviceCamera = new DeviceCamera({\n            video: {\n                facingMode: 'environment'\n            },\n            audio: false\n        })\n\n        // Setup update loop.\n        webglRenderer.setAnimationLoop(update);\n\n        resize();\n\n        // Listen for window resize event so that we can update the webgl canvas accordingly.\n        window.addEventListener('resize', resize);\n\n        // Listen for page visibility change event so we can disable sounds, etc\n        document.addEventListener('visibilitychange', visibilityChange);\n    }\n\n    function update(timestamp: any, frame: any) {\n        performanceResolutionScalar.update();\n\n        _xrFrame = frame;\n\n        // Track state of XR presentation.\n        const xrEnabled = webglRenderer.xr.isPresenting && !!_xrFrame;\n        if (_xrEnabled !== xrEnabled) {\n            _xrEnabled = xrEnabled;\n\n            if (_xrEnabled) {\n                webglRenderer.xr.enabled = true;\n                APEngineEvents.onXRSessionStarted.invoke();\n            } else {\n                webglRenderer.xr.enabled = false;\n                APEngineEvents.onXRSessionEnded.invoke();\n            }\n        }\n\n        input.update();\n\n        // Update pointer event system.\n        PointerEventSystem.updateActiveSystems(input);\n        \n        // Update game objects in scenes.\n        sceneManager.update();\n        APEngineEvents.onUpdate.invoke();\n        sceneManager.lateUpdate();\n        APEngineEvents.onLateUpdate.invoke();\n\n        GameObject.__APEngine_ProcessGameObjectDestroyQueue();\n        \n        sceneManager.render(webglRenderer);\n\n        time.update();\n        performanceStats.update();\n    }\n\n    export function getMaxPixelRatio() {\n        return _maxPixelRatio;\n    }\n\n    export function setMaxPixelRatio(pixelRatio: number) {\n        _maxPixelRatio = pixelRatio;\n        resize();\n    }\n\n    export function dispose() {\n        window.removeEventListener('resize', resize);\n\n        sceneManager.dispose();\n\n        webglRenderer.dispose();\n        webglRenderer = null;\n\n        time.dispose();\n        time = null;\n\n        input.dispose();\n        input = null;\n\n        xrInput.dispose();\n        xrInput = null;\n\n        xrPhysics.dispose();\n        xrPhysics = null;\n\n        deviceCamera.dispose();\n        deviceCamera = null;\n\n        performanceStats.dispose();\n        performanceStats = null;\n\n        _xrEnabled = false;\n        _xrFrame = null;\n\n        APEngineEvents.onUpdate.removeAllListeners();\n        APEngineEvents.onLateUpdate.removeAllListeners();\n        APEngineEvents.onXRSessionStarted.removeAllListeners();\n        APEngineEvents.onXRSessionEnded.removeAllListeners();\n\n        _initialized = false;\n    }\n\n    function resize() {\n        const width = window.innerWidth;\n        const height = window.innerHeight;\n\n        webglRenderer.setSize(width, height);\n\n        let pixelRatio = window.devicePixelRatio;\n        if ((_maxPixelRatio > 0) && (pixelRatio > _maxPixelRatio)) {\n            pixelRatio = _maxPixelRatio;\n        }\n        \n        webglRenderer.setPixelRatio(pixelRatio);\n        CameraDecorator.Cameras.forEach(camera => camera.resize());\n\n        APEngineEvents.onResize.invoke();\n    }\n\n    function visibilityChange() {\n        setAudioMuted(document.hidden);\n\n        APEngineEvents.onVisibilityChanged.invoke(document.hidden);\n    }\n\n    export function setAudioMuted(muted:boolean) {\n        if (muted) {\n            _audioMutedCount++;\n            if (_audioMutedCount > 0) {\n                Howler.mute(true);\n            }\n        } else {\n            _audioMutedCount--;\n            if (_audioMutedCount <= 0) {\n                _audioMutedCount = 0;\n                Howler.mute(false);\n            }\n        }\n    }\n\n}","import { Scene, WebGLRenderer } from \"three\";\n \nexport namespace ThreeDevTools {\n    \n    declare var __THREE_DEVTOOLS__: any;\n    \n    /**\n     * Dispatch event to the Three JS Dev Tools (if it exists) so that it can observe the given scene and renderer.\n     */\n    export function observe(scene: Scene, renderer: WebGLRenderer) {\n        // Observe a scene or a renderer\n        if (typeof __THREE_DEVTOOLS__ !== 'undefined') {\n            console.log(`[ThreeDevTools] dispatch event to observe scene and renderer.`);\n            __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { detail: scene }));\n            __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { detail: renderer }));\n        }\n    }\n}","import { IDecoratorOptions, Decorator } from \"./Decorator\";\nimport { GameObject } from \"../GameObject\";\nimport { PerspectiveCamera, OrthographicCamera, MathUtils, Matrix4, Vector3, Euler, Frustum } from \"three\";\nimport { getOptionalValue } from \"../../utils/MiscUtils\";\nimport { calculateFrustumPlanes } from \"../../utils/MathUtils\";\nimport { APEngineEvents } from \"../../APEngineEvents\";\n\nexport declare type CameraType = 'perspective' | 'orthographic';\n\nexport declare type FieldOfViewType = 'vertical' | 'horizontal';\n\nexport interface ICameraDecoratorOptions extends IDecoratorOptions {\n    cameraType?: CameraType;\n    fovType?: FieldOfViewType;\n    vFov?: number;\n    hFov?: number;\n    zoom?: number;\n    aspect?: number;\n    near?: number;\n    far?: number;\n    size?: number;\n}\n\n/**\n * Camera decorator creates and manages ThreeJS cameras. \n * You can change the camera type on the fly by setting the cameraType property.\n */\nexport class CameraDecorator extends Decorator {\n\n    private static _PrimaryCamera: CameraDecorator = null;\n    private static _Cameras: CameraDecorator[] = [];\n\n    /**\n     * The camera that is marked as primary.\n     * If no camera is marked as primary, than the first camera is returned.\n     */\n    static get PrimaryCamera(): CameraDecorator {\n        if (this._PrimaryCamera) {\n            return this._PrimaryCamera;\n        } else if (this._Cameras.length > 0) {\n            return this._Cameras[0];\n        } else {\n            return null;\n        }\n    }\n\n    static set PrimaryCamera(cam: CameraDecorator) {\n        if (this._PrimaryCamera !== cam) {\n            this._PrimaryCamera = cam;\n        }\n    }\n\n    /**\n     * Cameras that are updated by APEngine.\n     * These camera will automatically get resized when APEngine window resize is triggered.\n     */\n    static get Cameras(): Readonly<CameraDecorator[]> {\n        return this._Cameras;\n    }\n\n    private _cameraType: CameraType;\n    private _fovType: FieldOfViewType;\n    private _vFov: number;\n    private _hFov: number;\n    private _zoom: number;\n    private _aspect: number;\n    private _near: number;\n    private _far: number;\n    private _size: number;\n    private _camera: PerspectiveCamera | OrthographicCamera;\n    private _nonXrPositon: Vector3;\n    private _nonXrRotation: Euler;\n    private _nonXrScale: Vector3;\n    private _frustum = new Frustum();\n    private _projScreenMatrix = new Matrix4();\n\n    /**\n     * Is the camera orthographic or perspective.\n     */\n    get cameraType(): CameraType { return this._cameraType }\n    set cameraType(value: CameraType) {\n        if (this._cameraType !== value) {\n            this._cameraType = value;\n            this._removeCamera();\n            this._createCamera();\n        }\n    }\n\n    /**\n     * Field of View type for perspective camera. The field of view type dictates\n     * how vertical fov is calculated based on the aspect ratio. No affect on orthographic cameras.\n     */\n    get fovType(): FieldOfViewType { return this._fovType }\n    set fovType(value: FieldOfViewType) {\n        if (this._fovType !== value) {\n            this._fovType = value;\n\n            if (this._camera && this._camera instanceof PerspectiveCamera) {\n                this.resize();\n            }\n        }\n    }\n\n    /**\n     * Vertical field of view for perspective camera. No affect on orthographic cameras.\n     * If field of view type is set to horizontal, the vertical field of view will be dynamic.\n     * This is the default FOV that Three JS cameras use.\n     */\n    get vFov(): number { return this._vFov }\n    set vFov(value: number) { \n        if (this._vFov !== value) {\n            this._vFov = value;\n\n            if (this._camera && this._camera instanceof PerspectiveCamera) {\n                this._camera.fov = this._vFov;\n                this._camera.updateProjectionMatrix();\n            }\n        }\n    }\n\n    /**\n     * Horizontal field of view for perspective camera. No affect on orthographic cameras.\n     * Only has an affect if the field of view type is set to horizontal.\n     */\n    get hFov(): number { return this._hFov }\n    set hFov(value: number) { \n        if (this._hFov !== value) {\n            this._hFov = value;\n\n            if (this._camera && this._camera instanceof PerspectiveCamera) {\n                this.resize();\n            }\n        }\n    }\n\n    /**\n     * Zoom level of the camera.\n     */\n    get zoom(): number { return this._zoom }   \n    set zoom(value: number) { \n        if (this._zoom !== value) {\n            this._zoom = value;\n\n            if (this._camera) {\n                this._camera.zoom = this._zoom;\n                this._camera.updateProjectionMatrix();\n            }\n        }\n    }\n\n    /**\n     * Aspect ratio of perspective camera. Has no effect on orthographic camera.\n     */\n    get aspect(): number { return this._aspect }\n    set aspect(value: number) {\n        if (this._aspect !== value) {\n            this._aspect = value;\n\n            if (this._camera && this._camera instanceof PerspectiveCamera) {\n                this._camera.aspect = this._aspect;\n                this._camera.updateProjectionMatrix();\n            }\n        }\n    }\n\n    /** \n     * Far clipping plane \n     */\n    get far(): number { return this._far }\n    set far(value: number) {\n        if (this._far !== value) {\n            this._far = value;\n\n            if (this._camera) {\n                this._camera.far = this._far;\n                this._camera.updateProjectionMatrix();\n            }\n        }\n    }\n\n    /**\n     * Near clipping plane\n     */\n    get near(): number { return this._near }\n    set near(value: number) { \n        if (this._near !== value) {\n            this._near = value;\n\n            if (this._camera) {\n                this._camera.near = this._near;\n                this._camera.updateProjectionMatrix();\n            }\n        }\n    }\n\n    /**\n     * The frustum size of orthographic camera. This has no affect on perspective camera.\n     */\n    get size(): number { return this._size }\n    set size(value: number) {\n        if (this._size !== value) {\n            this._size = value;\n\n            if (this._camera && this._camera instanceof OrthographicCamera) {\n                const planes = calculateFrustumPlanes(this._size, this._aspect);\n                this._camera.left = planes.left;\n                this._camera.right = planes.right;\n                this._camera.top = planes.top;\n                this._camera.bottom = planes.bottom;\n                this._camera.updateProjectionMatrix();\n            }\n        }\n    }\n\n    /**\n     * ThreeJS camera that is managed by this camera decorator.\n     */\n    get camera(): Readonly<PerspectiveCamera> | Readonly<OrthographicCamera> { return this._camera; }\n\n    /**\n     * The frustum for the camera. Useful for doing intersection tests with the area visible to the camera.\n     */\n    get frustum(): Frustum { return this._frustum }\n\n    configure(options: ICameraDecoratorOptions): void {\n        super.configure(options);\n\n        this._cameraType = getOptionalValue(options.cameraType, 'perspective');\n        this._fovType = getOptionalValue(options.fovType, 'vertical');\n        this._vFov = getOptionalValue(options.vFov, 50);\n        this._hFov = getOptionalValue(options.hFov, 50);\n        this._zoom = getOptionalValue(options.zoom, 1);\n        this._aspect = getOptionalValue(options.aspect, window.innerWidth / window.innerHeight);\n        this._far = getOptionalValue(options.far, 2000);\n        this._near = getOptionalValue(options.near, 0.1);\n        this._size = getOptionalValue(options.size, 25);\n    }\n\n    onAttach(gameObject: GameObject): void {\n        super.onAttach(gameObject);\n\n        this._createCamera();\n        this._updateFrustum();\n\n        // Add camera decorator to global list of camera decorators.\n        CameraDecorator._Cameras.push(this);\n\n        this._onXRSessionStarted = this._onXRSessionStarted.bind(this);\n        APEngineEvents.onXRSessionStarted.addListener(this._onXRSessionStarted);\n\n        this._onXRSessionEnded = this._onXRSessionEnded.bind(this);\n        APEngineEvents.onXRSessionEnded.addListener(this._onXRSessionEnded);\n\n        this.resize();\n    }\n\n    onVisible() {\n        super.onVisible();\n    }\n\n    onInvisible() {\n        super.onInvisible();\n    }\n\n    onStart(): void {\n        super.onStart();\n    }\n\n    onUpdate(): void {\n        super.onUpdate();\n\n        this._updateFrustum();\n    }\n\n    onLateUpdate(): void {\n        super.onLateUpdate();\n    }\n\n    resize(): void {\n        if (this._camera) {\n            this.aspect = window.innerWidth / window.innerHeight;\n\n            if (this._camera instanceof PerspectiveCamera) {\n                if (this._fovType === 'horizontal') {\n                    // Reference: https://github.com/mrdoob/three.js/issues/15968#issuecomment-475986352\n                    this.vFov = Math.atan( Math.tan( this._hFov * Math.PI / 360 ) / this.aspect ) * 360 / Math.PI;\n                } else {\n                    this._hFov = 2 * Math.atan( Math.tan( this.vFov * Math.PI / 180 / 2 ) * this.aspect ) * 180 / Math.PI;\n                }\n            } else {\n                // Update frustum planes for othrogtraphic camera using new aspect ratio.\n                const planes = calculateFrustumPlanes(this._size, this._aspect);\n                this._camera.left = planes.left;\n                this._camera.right = planes.right;\n                this._camera.top = planes.top;\n                this._camera.bottom = planes.bottom;\n                this._camera.updateProjectionMatrix();\n            }\n        }\n    }\n\n    private _onXRSessionStarted(): void {\n        // Store this camera decorator's game object matrix before the WebXRManager starts overtwriting camera positioning.\n        this._nonXrPositon = this.gameObject.position.clone();\n        this._nonXrRotation = this.gameObject.rotation.clone();\n        this._nonXrScale = this.gameObject.scale.clone();\n\n        // Reset the camera decorator game object to default position, rotation, and scale.\n        // WebXRManager doesnt like if the xr camera to be parented to an object with an offset.\n        this.gameObject.position.set(0, 0, 0);\n        this.gameObject.rotation.set(0, 0, 0);\n        this.gameObject.scale.set(1, 1, 1);\n    }\n\n    private _onXRSessionEnded(): void {\n        // Restore the camera decorator's game object to the position, rotation, and scale it was at before entering XR mode.\n        this.gameObject.position.copy(this._nonXrPositon);\n        this.gameObject.rotation.copy(this._nonXrRotation);\n        this.gameObject.scale.copy(this._nonXrScale);\n\n        this._nonXrPositon = null;\n        this._nonXrRotation = null;\n        this._nonXrScale = null;\n    }\n\n    private _createCamera(): void {\n        if (!this.gameObject) {\n            // Dont create camera until this decorator is attached to a GameObject.\n            return;\n        }\n\n        if (this._cameraType === 'perspective') {\n            this._camera = new PerspectiveCamera(this._vFov, this._aspect, this._near, this._far);\n        } else if (this._cameraType === 'orthographic') {\n            const planes = calculateFrustumPlanes(this._size, this._aspect);\n            this._camera = new OrthographicCamera(planes.left, planes.right, planes.top, planes.bottom, this._near, this._far);\n        } else {\n            console.error(`[CameraDecorator] Can't create camera. Unknown camera type: ${this._cameraType}`);\n        }\n\n        if (this._camera) {\n            // Rotate camera 180 degrees on the y-axis so that it faces forward.\n            this._camera.rotateY(180 * MathUtils.DEG2RAD);\n\n            // Add camera to this gameObject.\n            this.gameObject.add(this._camera);\n        }\n\n        this.resize();\n    }\n\n    private _removeCamera(): void {\n        if (!this._camera) {\n            // No camera to remove.\n            return;\n        }\n\n        if (this._camera.parent) {\n            this._camera.parent.remove(this._camera);\n        }\n        this._camera = null;\n    }\n\n    private _updateFrustum(): void {\n        if (!this._camera) {\n            // Need camera to update frustum.\n            return;\n        }\n\n        this._projScreenMatrix.multiplyMatrices(this._camera.projectionMatrix, this._camera.matrixWorldInverse);\n        this._frustum.setFromProjectionMatrix(this._projScreenMatrix);\n    }\n\n    onDestroy(): void {\n        super.onDestroy();\n\n        this._removeCamera();\n        \n        // Remove camera decorator from global list of camera decorators.\n        const index = CameraDecorator._Cameras.findIndex(cameraDecorator => cameraDecorator === this);\n        if (index >= 0) {\n            CameraDecorator._Cameras.splice(index, 1);\n        }\n\n        // If this camera is the primary camera, set primary camera back to null.\n        if (CameraDecorator._PrimaryCamera === this) {\n            CameraDecorator._PrimaryCamera = null;\n        }\n    }\n}","import { Object3D, Vector2, Intersection, Camera } from 'three';\nimport { IDisposable } from '../misc/IDisposable';\nimport { Input, InputType } from './Input';\nimport { Physics } from '../physics/Physics';\nimport { isObjectVisible } from '../utils/ThreeUtils';\nimport { CameraDecorator } from '../gameobject/decorators/CameraDecorator';\nimport { sortZA } from '../utils/MiscUtils';\n\nexport type PointerEventType = 'pointer enter' | 'pointer exit' | 'pointer down' | 'pointer up' | 'pointer click';\n\nexport interface IPointerEvent {\n    /**\n     * The string event type identifier.\n     */\n    eventType: PointerEventType;\n\n    /**\n     * The Object3D (if any) that was responsible for this event.\n     */\n    object: Object3D;\n\n    /**\n     * The object (if any) that had pointer down called on it at the time of this event.\n     */\n    pointerDown: IPointerEventListener;\n}\n\nexport interface IPointerEnterEvent extends IPointerEvent {\n}\n\nexport interface IPointerExitEvent extends IPointerEvent {\n}\n\nexport interface IPointerDownEvent extends IPointerEvent {\n}\n\nexport interface IPointerUpEvent extends IPointerEvent {\n}\n\nexport interface IPointerClickEvent extends IPointerEvent {\n}\n\nexport interface IPointerEventListener {\n    /**\n     * The objects that the pointer event system will use to detect collision for this listener.\n     */\n    pointerTargets: Object3D[];\n\n    /**\n     * Function that will be invoked when the pointer event system issues pointer enter event for this listener.\n     * If \n     */\n    onPointerEnter(event: IPointerEnterEvent): void;\n\n    /**\n     * Function that will be invoked when the pointer event system issues pointer exit event for this listener.\n     */\n    onPointerExit(event: IPointerExitEvent): void;\n\n    /**\n     * Function that will be invoked when the pointer event system issues pointer down event for this listener.\n     */\n    onPointerDown(event: IPointerDownEvent): void;\n\n    /**\n     * Function that will be invoked when the pointer event system issues pointer up event for this listener.\n     */\n    onPointerUp(event: IPointerUpEvent): void;\n\n    /**\n     * Function that will be invoked when the pointer event system issues pointer click event for this listener.\n     */\n    onPointerClick(event: IPointerClickEvent): void;\n}\n\n/**\n * A class that can be used to easily listen for some basic input events for Three JS Oojects.\n */\nexport class PointerEventSystem implements IDisposable {\n    \n    static debug: boolean = false;\n\n    private static _activeSystems: PointerEventSystem[] = [];\n    private static _focusedSystem: PointerEventSystem;\n\n    /**\n     * List of all active pointer event systems.\n     */\n    static get activeSystems(): Readonly<PointerEventSystem[]> {\n        return this._activeSystems;\n    }\n\n    /**\n     * Update all active pointer events systems.\n     * This function sorts the systems based on priority (highest to lowest priority).\n     */\n    static updateActiveSystems(input: Input): void {\n        if (!this._activeSystems || this._activeSystems.length === 0) {\n            return;\n        }\n\n        if (this._activeSystems.length === 1) {\n            // No need to sort, only one pointer event system is active.\n            this._activeSystems[0]._update(input);\n        } else {\n            // If there is a focused system, update it first.\n            // If the focuses system becomes no longer focuses then move on to updating\n            // systems until one does.\n            if (this._focusedSystem) {\n                const isFocused = this._focusedSystem._update(input);\n                if (!isFocused) {\n                    // Focused system is no longer focused.\n                    if (this.debug) {\n                        console.log(`[PointerEventSystem] ${this._focusedSystem.name} has lost focus.`);\n                    }\n\n                    this._focusedSystem = null;\n                } else {\n                    // Focused system is still focused. Dont update other pointer event systems.\n                    return; \n                }\n            }\n\n            // Sort pointer event systems in descending priority order.\n            const systems = Array.from(this._activeSystems);\n            sortZA(systems, 'priority');\n\n            // Loop through and update systems until one becomes focused.\n            // If we find a new focused system, release any active pointers for remaining systems.\n            for (const system of systems) {\n                if (!this._focusedSystem) {\n                    const isFocused = system._update(input);\n                    if (isFocused) {\n                        // Found a system that has gained focus.\n                        this._focusedSystem = system;\n\n                        if (this.debug) {\n                            console.log(`[PointerEventSystem] ${this._focusedSystem.name} has gained focus.`);\n                        }\n                    }\n                } else {\n                    // A system already gained focus, release active pointers for this system.\n                    system.releaseActivePointers();\n                }\n            }\n        }\n    }\n\n    /**\n     * The camera to use for hit testing pointer event listeners.\n     * If this is undefined, this pointer event system will use the primary camera (CameraDecorator.PrimaryCamera).\n     */\n    cameraDecorator: CameraDecorator = undefined;\n    \n    /**\n     * The priority this pointer event system has over other pointer event systems.\n     * During an update frame, pointer event systems are sorted by priority (highest to lowest) and hit testing is done\n     * in that order. If a hit is detected in a pointer system above another, all lower pointer systems have their pointers released and are then ignored.\n     * Lower priority pointer systems are only reached if the higher priority systems dont detect any hits.\n     */\n    priority: number = 0;\n\n    private _name: string;\n    private _enabled: boolean = true;\n    private _listeners: Set<IPointerEventListener> = new Set();\n    private _pointerDown: IPointerEventListener = null;\n    private _pointerEnter: IPointerEventListener = null;\n\n    get name(): string { return this._name }\n    get pointerDown(): IPointerEventListener { return this._pointerDown }\n    get pointerEnter(): IPointerEventListener { return this._pointerEnter }\n\n    get enabled(): boolean { return this._enabled }\n    set enabled(value: boolean) {\n        if (this._enabled === value) {\n            return;\n        }\n\n        this._enabled = value;\n        if (!this._enabled) {\n            this.releaseActivePointers();\n        }\n    }\n\n    constructor(name: string, priority: number, cameraDecorator?: CameraDecorator) {\n        this._name = name;\n        this.priority = priority;\n        this.cameraDecorator = cameraDecorator;\n\n        PointerEventSystem._activeSystems.push(this);\n    }\n\n    addListener(listener: IPointerEventListener): void {\n        if (!this._listeners.has(listener)) {\n            this._listeners.add(listener);\n        }\n    }\n\n    removeListener(listener: IPointerEventListener): void {\n        if (this._pointerDown === listener) { this._pointerDown = null; }\n        if (this._pointerEnter === listener) { this._pointerEnter = null; }\n        this._listeners.delete(listener);\n    }\n\n    /**\n     * Update event system. Returns true if the update causes the pointer event system to become focused.\n     */\n    private _update(input: Input): boolean {\n        if (!this._enabled) {\n            // Input must be enabled for the pointer event system.\n            return;\n        }\n\n        let cameraDecorator = this.cameraDecorator === undefined ? CameraDecorator.PrimaryCamera : this.cameraDecorator;\n\n        if (!input || !cameraDecorator || !cameraDecorator.camera) {\n            // Pointer event system needs both an input module and a camera.\n            return;\n        }\n\n        if (input.currentInputType !== InputType.Mouse &&\n            input.currentInputType !== InputType.Touch\n        ) {\n            // Pointer Event System only works with mouse and touch input types.\n            return;\n        }\n\n        // Retrieve the pointer's current screen position.\n        let pointerScreenPos: Vector2 = (input.currentInputType === InputType.Mouse) ? input.getMouseScreenPos() : input.getTouchScreenPos(0);\n\n        // Raycast against pointer event listeners using the pointer's screen position to find \n        // the event listener that is currently the closest to the camera.\n        let closestIntersection: Intersection;\n        let closestListener: IPointerEventListener;\n\n        if (pointerScreenPos) {\n            // Collect all active listener target objects.\n            const allActiveListenerTargets: Object3D[] = [];\n            this._listeners.forEach((listener) => {\n                const pointerTargets = listener.pointerTargets;\n                if (pointerTargets) {\n                    const activeTargets = pointerTargets.filter((target) => {\n                        return isObjectVisible(target);\n                    });\n    \n                    allActiveListenerTargets.push(...activeTargets);\n                }\n            });\n    \n            // Raycast againsts all pointer event listener target objects.\n            const hits = Physics.raycastAtScreenPos(pointerScreenPos, allActiveListenerTargets, cameraDecorator.camera, false);\n            closestIntersection = Physics.firstRaycastHit(hits);\n            closestListener = closestIntersection ? this._findEventListenerForObject(closestIntersection.object) : null;\n        } else {\n            // No pointer screen position currently.\n            closestIntersection = null;\n            closestListener = null;\n        }\n\n        //\n        // Pointer enter/exit events.\n        //\n        if (closestListener) {\n            if (this._pointerEnter !== null && this._pointerEnter !== closestListener) {\n                // Let the last pointer enter object know that the pointer has exited it.\n                const pointerExit = this._pointerEnter;\n                this._pointerEnter = null;\n\n                if (PointerEventSystem.debug) {\n                    console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer exit`, pointerExit);\n                }\n\n                pointerExit.onPointerExit({\n                    eventType: 'pointer exit',\n                    object: closestIntersection.object,\n                    pointerDown: this._pointerDown\n                });\n            }\n\n            if (this._pointerEnter === null) {\n                // Let the closest listener know that the pointer has entered it.\n                this._pointerEnter = closestListener;\n\n                if (PointerEventSystem.debug) {\n                    console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer enter`, this._pointerEnter);\n                }\n\n                this._pointerEnter.onPointerEnter({\n                    eventType: 'pointer enter',\n                    object: closestIntersection.object,\n                    pointerDown: this._pointerDown\n                });\n            }\n\n        } else {\n            // Pointer is not over any listeners.\n            if (this._pointerEnter !== null) {\n                // Let the last pointer enter object know that the pointer has exited it.\n                if (PointerEventSystem.debug) {\n                    console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer exit`, this._pointerEnter);\n                }\n\n                this._pointerEnter.onPointerExit({\n                    eventType: 'pointer exit',\n                    object: null,\n                    pointerDown: this._pointerDown\n                });\n                this._pointerEnter = null;\n            }\n        }\n\n        //\n        // Pointer down/up/click events.\n        //\n        const isPrimaryDown: boolean = (input.currentInputType === InputType.Mouse) ? input.getMouseButtonDown(0) : input.getTouchDown(0);\n        if (isPrimaryDown) {\n            if (this._pointerEnter !== null && this._pointerEnter === closestListener && this._pointerDown === null) {\n                // Let the closest listener know that the pointer is down on it.\n                this._pointerDown = closestListener;\n\n                if (PointerEventSystem.debug) {\n                    console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer down`, this._pointerDown);\n                }\n\n                this._pointerDown.onPointerDown({\n                    eventType: 'pointer down',\n                    object: closestIntersection.object,\n                    pointerDown: this._pointerDown\n                });\n            }\n        }\n        \n        const isPrimaryUp: boolean = (input.currentInputType === InputType.Mouse) ? input.getMouseButtonUp(0) : input.getTouchUp(0);\n        if (isPrimaryUp) {\n            if (this._pointerDown !== null) {\n                // Let the last pointer down object know that the pointer is up.\n                const pointerUp = this._pointerDown;\n                this._pointerDown = null;\n\n                if (PointerEventSystem.debug) {\n                    console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer up`, pointerUp);\n                }\n                \n                pointerUp.onPointerUp({\n                    eventType: 'pointer up',\n                    object: closestIntersection ? closestIntersection.object : null,\n                    pointerDown: this._pointerDown\n                });\n\n                // Detect if pointer click occurs. \n                // Click means that an event listener that received the down event is now receiving the up event while being hovered over.\n                const isClick: boolean = (closestListener !== null && pointerUp === closestListener);\n                if (isClick) {\n                    const pointerClick = pointerUp;\n\n                    if (PointerEventSystem.debug) {\n                        console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer click`, pointerClick);\n                    }\n\n                    pointerClick.onPointerClick({\n                        eventType: 'pointer click',\n                        object: closestIntersection.object,\n                        pointerDown: this._pointerDown\n                    });\n                }\n            }\n        }\n\n        return !!this._pointerDown;\n    }\n\n    /**\n     * Release any held pointers. If active enter/down listener, then exit/up is invoked.\n     */\n    releaseActivePointers(): void {\n        if (this._pointerDown) {\n            const pointerUp = this._pointerDown;\n            this._pointerDown = null;\n\n            if (PointerEventSystem.debug) {\n                console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer up`, pointerUp);\n            }\n            \n            pointerUp.onPointerUp({\n                eventType: 'pointer up',\n                object: null,\n                pointerDown: this._pointerDown\n            });\n        }\n\n        if (this._pointerEnter) {\n            const pointerExit = this._pointerEnter;\n            this._pointerEnter = null;\n\n            if (PointerEventSystem.debug) {\n                console.log(`[PointerEventSystem] Name: ${this.name}, Event: pointer exit`, pointerExit);\n            }\n\n            pointerExit.onPointerExit({\n                eventType: 'pointer exit',\n                object: null,\n                pointerDown: this._pointerDown\n            });\n        }\n    }\n\n    dispose(): void {\n        this.releaseActivePointers();\n\n        this._listeners = null;\n        this.cameraDecorator = null;\n\n        const index = PointerEventSystem._activeSystems.findIndex(pes => pes === this);\n        if (index >= 0) {\n            PointerEventSystem._activeSystems.splice(index, 1);\n        }\n\n        if (PointerEventSystem._focusedSystem === this) {\n            PointerEventSystem._focusedSystem = null;\n        }\n    }\n\n    private _findEventListenerForObject(obj3d: Object3D): IPointerEventListener {\n        if (obj3d) {\n            const listenerValues = Array.from(this._listeners);\n            for (const listener of listenerValues) {\n                const pointerTargets = listener.pointerTargets;\n                if (pointerTargets && pointerTargets.length > 0) {\n                    const matchFound = pointerTargets.some((target) => {\n                        return target === obj3d;\n                    });\n                    if (matchFound) {\n                        return listener;\n                    }\n                }\n            }\n        }\n\n        return null;\n    }\n}","import { Scene, Camera, WebGLRenderer } from 'three';\nimport { CameraDecorator } from '../gameobject/decorators/CameraDecorator';\n\nexport class SceneRenderOperation {\n    scene: Scene;\n    cameraDecorator: CameraDecorator;\n    enabled: boolean = true;\n\n    clearColor: boolean = false;\n    clearDepth: boolean = false;\n    clearStencil: boolean = false;\n\n    constructor(scene?: Scene, cameraDecorator?: CameraDecorator) {\n        this.scene = scene;\n        this.cameraDecorator = cameraDecorator;\n    }\n\n    render(webglRenderer: WebGLRenderer): void {\n        if (!this.scene) {\n            // No scene to render.\n            return;\n        }\n        if (!this.cameraDecorator || !this.cameraDecorator.camera) {\n            // No camera to render scene with.\n            return;\n        }\n        if (!this.enabled) {\n            // Dont render if render operatio is disabled.\n            return;\n        }\n\n        if (this.clearColor) {\n            webglRenderer.clearColor();\n        }\n\n        if (this.clearDepth) {\n            webglRenderer.clearDepth();\n        }\n\n        if (this.clearStencil) {\n            webglRenderer.clearStencil();\n        }\n\n        webglRenderer.render(this.scene, this.cameraDecorator.camera);\n    }\n}","import { IDisposable } from \"../misc/IDisposable\";\nimport { Scene, WebGLRenderer } from \"three\";\nimport { SceneRenderOperation as RenderOperation } from \"./SceneRenderOperation\";\nimport { GameObject } from \"../gameobject/GameObject\";\nimport { CameraDecorator } from \"../gameobject/decorators/CameraDecorator\";\nimport { traverseSafe } from \"../utils/ThreeUtils\";\n\nexport class SceneManager implements IDisposable {\n\n    private _scenes: Scene[] = [];\n    private _primaryScene: Scene = null;\n    private _renderList: RenderOperation[] = [];\n    private _updatedGameObjects: GameObject[];\n    \n    /**\n     * Scenes that are updated by APEngine. \n     * GameObjects that are parented to scenes in this list will get their lifecycle functions invoked.\n     */\n    get scenes(): Readonly<Scene[]> {\n        return this._scenes;\n    }\n\n    get sceneRenderList(): Readonly<RenderOperation[]> {\n        return this._renderList;\n    }\n\n    /**\n     * The scene that is marked as primary.\n     * If no scene is marked as primary, than the first scene is returned.\n     */\n    get primaryScene(): Scene {\n        if (this._primaryScene) {\n            return this._primaryScene;\n        } else if (this._scenes.length > 0) {\n            return this._scenes[0];\n        } else {\n            return null;\n        }\n    }\n\n    set primaryScene(scene: Scene) {\n        if (this._primaryScene !== scene) {\n            this._primaryScene = scene;\n        }\n    }\n    \n    constructor() {\n    }\n\n    addScene(scene: Scene): void {\n        if (!this._scenes.some(s => s === scene)) {\n            this._scenes.push(scene);\n        }\n    }\n\n    removeScene(scene: Scene): void {\n        const index = this._scenes.findIndex(s => s === scene);\n        if (index >= 0) {\n            this._scenes.splice(index, 1);\n        }\n\n        this.removeRenderOperationsUsingScene(scene);\n    }\n\n    addRenderOperation(scene: Scene, cameraDecorator: CameraDecorator): RenderOperation {\n        const renderOp = new RenderOperation(scene, cameraDecorator);\n        this._renderList.push(renderOp);\n        return renderOp;\n    }\n\n    reorderRenderOperation(renderOp: RenderOperation, renderOrder: number) {\n        const oldIndex = this._renderList.indexOf(renderOp);\n        if (oldIndex >= 0) {\n            this._renderList.splice(oldIndex, 1);\n            this._renderList.splice(renderOrder, 0, renderOp);\n        }\n    }\n\n    removeRenderOperation(scene: Scene, cameraDecorator: CameraDecorator): void {\n        const index = this._renderList.findIndex(op => op.scene === scene && op.cameraDecorator === cameraDecorator);\n        if (index >= 0) {\n            this._renderList.splice(index, 1);\n        }\n    }\n\n    removeRenderOperationsUsingScene(scene: Scene): void {\n        this._renderList = this._renderList.filter((op) => {\n            if (op.scene !== scene) {\n                return true;\n            }\n        });\n    }\n\n    removeRenderOperationsUsingCamera(cameraDecorator: CameraDecorator): void {\n        this._renderList = this._renderList.filter((op) => {\n            if (op.cameraDecorator !== cameraDecorator) {\n                return true;\n            }\n        });\n    }\n\n    removeAllRenderOperations(): void {\n        this._renderList = [];\n    }\n\n    update(): void {\n        this._updatedGameObjects = [];\n\n        for (let scene of this._scenes) {\n            if (scene) {\n                traverseSafe(scene, (go) => {\n                    if (go instanceof GameObject) {\n                        go.onUpdate();\n                        this._updatedGameObjects.push(go);\n                    }\n                });\n            }\n        }\n    }\n\n    lateUpdate(): void {\n        for (let i = 0; i < this._updatedGameObjects.length; i++) {\n            if (this._updatedGameObjects[i]) {\n                this._updatedGameObjects[i].onLateUpdate();\n            }\n        }\n    }\n\n    render(webglRenderer: WebGLRenderer): void {\n        webglRenderer.clear();\n        webglRenderer.info.autoReset = false;\n        webglRenderer.info.reset();\n        \n        for (let renderOp of this._renderList) {\n            if (renderOp) {\n                renderOp.render(webglRenderer);\n            }\n        }\n    }\n\n    dispose(): void {\n        this._scenes = [];\n        this._renderList = [];\n        this._primaryScene = null;\n        this._updatedGameObjects = [];\n    }\n}","import {\n    Vector3,\n    Matrix4,\n    Quaternion,\n    WebGLRenderer\n} from 'three';\nimport { IDisposable } from '../misc/IDisposable';\nimport { Event } from '../misc/Events';\n\nexport interface RaycastHit {\n    position: Vector3;\n    rotation: Quaternion;\n}\n\n// Reference 01: https://github.com/mrdoob/three.js/blob/dev/examples/webxr_ar_hittest.html\n// Refernece 02: https://web.dev/ar-hit-test/\nexport class XRPhysics implements IDisposable {\n\n    private _renderer: WebGLRenderer;\n    private _xrSessionStartedEvent: Event;\n    private _xrSessionEndedEvent: Event;\n    private _getFrame: () => any;\n    \n    private _viewerHitTestSource: any = null;\n\n    constructor(renderer: WebGLRenderer, onXRSessionStarted: Event, onXRSessionEnded: Event, getFrame: () => any) {\n        this._renderer = renderer;\n        this._xrSessionStartedEvent = onXRSessionStarted;\n        this._xrSessionEndedEvent = onXRSessionEnded;\n        this._getFrame = getFrame;\n\n        this._onXRSessionStarted = this._onXRSessionStarted.bind(this);\n        this._xrSessionStartedEvent.addListener(this._onXRSessionStarted);\n\n        this._onXRSessionEnded = this._onXRSessionEnded.bind(this);\n        this._xrSessionEndedEvent.addListener(this._onXRSessionEnded);\n    }\n\n    gazeRaycast(): RaycastHit | null {\n        const frame = this._getFrame();\n\n        if (frame) {\n            const referenceSpace = this._renderer.xr.getReferenceSpace();\n\n            if (this._viewerHitTestSource) {\n                const hitTestResults = frame.getHitTestResults(this._viewerHitTestSource);\n\n                if (hitTestResults.length) {\n                    const hitPose = hitTestResults[0].getPose(referenceSpace);\n                    const hitMatrix = new Matrix4();\n                    hitMatrix.fromArray(hitPose.transform.matrix);\n\n                    const position = new Vector3();\n                    const rotation = new Quaternion();\n                    const scale = new Vector3();\n\n                    hitMatrix.decompose(position, rotation, scale);\n\n                    return {\n                        position,\n                        rotation\n                    }\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private async _onXRSessionStarted() {\n        // Retrieve hit test source for viewer reference space.\n        const session = this._renderer.xr.getSession();\n        const referenceSpace = await session.requestReferenceSpace('viewer');\n        this._viewerHitTestSource = await session.requestHitTestSource({\n            space: referenceSpace\n        });\n    }\n    \n    private _onXRSessionEnded() {\n        this._viewerHitTestSource = null;\n    }\n\n    dispose() {\n        this._xrSessionStartedEvent.removeListener(this._onXRSessionStarted);\n        this._xrSessionEndedEvent.removeListener(this._onXRSessionEnded);\n    }\n}","import { \n    AnimationAction,\n    AnimationMixer,\n    AnimationClip,\n    Event as DispatcherEvent,\n    LoopOnce,\n    LoopRepeat, \n    AnimationActionLoopStyles\n} from 'three';\nimport { IDecoratorOptions, Decorator } from './Decorator';\nimport { GameObject } from '../GameObject';\nimport { APEngine } from '../../APEngine';\nimport { ArgEvent } from '../../misc/Events';\nimport { clamp, unnormalize } from '../../utils/MathUtils';\n\nexport interface IAnimatorDecoratorOptions extends IDecoratorOptions {\n    clips?: AnimationClip[];\n}\n\ndeclare type ActionEventType = 'finished' | 'loop';\n\ninterface ActionEvent extends DispatcherEvent {\n    type: ActionEventType\n    action: AnimationAction;\n}\n\ninterface ActionFinishedEvent extends ActionEvent {\n    direction: number;\n}\n\ninterface ActionLoopEvent extends ActionEvent {\n    loopDelta: number;\n}\n\nexport interface AnimatorEvent {\n    clipName: string;\n}\n\nclass ActionTracker {\n    private _actions: AnimationAction[] = [];\n    private _animator: AnimatorDecorator;\n\n    get count(): number { return this._actions.length }\n\n    constructor(animator: AnimatorDecorator) { \n        this._animator = animator;\n    }\n\n    contains(action: AnimationAction): boolean {\n        return this._actions.some(a => a === action);\n    }\n    \n    getByIndex(index: number): AnimationAction {\n        return this._actions[index];\n    }\n\n    getActionsWithWeight(): AnimationAction[] {\n        return this._actions.filter((action) => {\n            return action.getEffectiveWeight() > 0;\n        });\n    }\n\n    tryGet(index: number): AnimationAction {\n        if (index >= 0 && index < this._actions.length) {\n            return this._actions[index];\n        } else {\n            return null;\n        }\n    }\n\n    add(action: AnimationAction): boolean {\n        let added = false;\n        if (!this.contains(action)) {\n            this._actions.push(action);\n            added = true;\n\n            if (this._animator.debug) {\n                console.log(`${this._animator.gameObject.name} added action ${action.getClip().name}.`);\n            }\n\n            this.print();\n        }\n\n        return added;\n    }\n\n    remove(action: AnimationAction): boolean {\n        let removed = false;\n        const startCount = this._actions.length;\n        this._actions = this._actions.filter((a) => {\n            return a !== action;\n        });\n\n        if (startCount !== this._actions.length) {\n            removed = true;\n\n            if (this._animator.debug) {\n                console.log(`${this._animator.gameObject.name} removed action ${action.getClip().name}.`);\n            }\n\n            this.print();\n        }\n\n        return removed;\n    }\n\n    print(): void {\n        if (this._animator.debug) {\n            let message: string = `${this._animator.gameObject.name} actions: ${this._actions.length}`;\n            for (const action of this._actions) {\n                message += `\\n  ${action.getClip().name}`;\n                message += `\\n    effectiveWeight: ${action.getEffectiveWeight()}`;\n            }\n    \n            console.log(message);\n        }\n    }\n}\n\nexport interface PlayClipOptions {\n\n    /**\n     * Should the clip be set to loop.\n     */\n    loop?: boolean;\n\n    /** \n     * How quickly to transition to this animation.\n     * If this value is 0 or less, then all animations will be stopped before playing the clip.\n     */\n    transitionDuration?: number;\n\n    /**\n     * Time to start playing the clip at in normalized range (0.0 - 1.0).\n     */\n    normalizedStartTime?: number;\n\n    /**\n     * Duration of the clip in seconds.\n     */\n    durationOverride?: number;\n}\n\nexport class AnimatorDecorator extends Decorator {\n\n    debug: boolean = false;\n\n    private _mixer: AnimationMixer;\n    private _clips: Map<string, AnimationClip> = new Map();\n    private _actionTracker = new ActionTracker(this);\n    private _timeScale: number = 1.0;\n    private _visible: boolean;\n\n    onAnimationLoop: ArgEvent<AnimatorEvent> = new ArgEvent();\n    onAnimationFinished: ArgEvent<AnimatorEvent> = new ArgEvent();\n\n    get clips(): AnimationClip[] { return Array.from(this._clips.values()) }\n    \n    /**\n     * The global time scale of the animator.\n     */\n    get timeScale(): number {\n        return this._timeScale;\n    }\n    /**\n     * The global time scale of the animator.\n     */\n    set timeScale(value: number) {\n        this._timeScale = value;\n\n        if (this._mixer) {\n            this._mixer.timeScale = value;\n        }\n    }\n\n    /**\n     * The global time of the animator in seconds.\n     */\n    get time(): number {\n        return this._mixer.time;\n    }\n    /**\n     * The global time of the animator in seconds.\n     */\n    set time(value: number) {\n        this._mixer.setTime(value);\n    }\n    \n    configure(options: IAnimatorDecoratorOptions): void {\n        super.configure(options);\n        \n        if (options.clips) {\n            for(const clip of options.clips) {\n                this.addClip(clip);\n            }\n        }\n    }\n\n    addClip(clip: AnimationClip): void {\n        if (!this._clips.has(clip.name)) {\n            this._clips.set(clip.name, clip);\n        } else {\n            console.error(`Animator already has a clip named ${clip.name} on GameObject ${this.gameObject.name}. All clips on an Animator must have a unique name.`);\n        }\n    }\n\n    getClip(clipName: string): AnimationClip {\n        return this._clips.get(clipName);\n    }\n\n    onAttach(gameObject: GameObject): void {\n        super.onAttach(gameObject);\n\n        this._onActionLoop = this._onActionLoop.bind(this);\n        this._onActionFinished = this._onActionFinished.bind(this);\n\n        this._mixer = new AnimationMixer(this.gameObject);\n        this._mixer.addEventListener('loop', this._onActionLoop);\n        this._mixer.addEventListener('finished', this._onActionFinished);\n        this._mixer.timeScale = this._timeScale;\n    }\n\n    onVisible() {\n        super.onVisible();\n        this._visible = true;\n    }\n\n    onInvisible() {\n        super.onInvisible();\n        this._visible = false;\n    }\n\n    onStart(): void {\n        super.onStart();\n    }\n\n    play(clipName: string, options?: PlayClipOptions): void {\n        const clip = this._clips.get(clipName);\n        if (!clip) {\n            console.error(`There is no clip named ${clipName} in the Animator ${this.gameObject.name} for GameObject ${this.gameObject.name}`);\n            return;\n        }\n        if (this._clipAlreadyPlaying(clip, LoopOnce)) {\n            console.warn(`There is already an action that is playing the clip ${clip.name}`);\n            // There is already an action that is playing the clip.\n            return;\n        }\n\n        if (!options) {\n            options = {};\n        }\n\n        if (this.debug) {\n            console.log(`${this.gameObject.name} play ${clipName} with options: ${JSON.stringify(options)}`);\n        }\n\n        // Get action for clip.\n        const action = this._mixer.clipAction(clip).reset();\n\n        // Get list of actions that still have weight.\n        let actionsWithWeight = this._actionTracker.getActionsWithWeight();\n        if (actionsWithWeight && actionsWithWeight.length > 0) {\n            // Filter out the clip that we are about to start playing.\n            actionsWithWeight = actionsWithWeight.filter(a => a !== action);\n        }\n\n        if (this.debug) {\n            if (actionsWithWeight && actionsWithWeight.length > 0) {\n                let message = `${this.gameObject.name} other actions with weight: ${actionsWithWeight.length}`;\n                for (const action of actionsWithWeight) {\n                    message += `\\n  ${action.getClip().name}`;\n                    message += `\\n    effectiveWeight: ${action.getEffectiveWeight()}`;\n                }\n\n                console.log(message);\n            } else {\n                console.log(`${this.gameObject.name} no other actions with weight.`);\n            }\n        }\n\n        if (actionsWithWeight &&\n            actionsWithWeight.length > 0 && \n            options.transitionDuration > 0\n        ) {\n            // Fade out the action that still have weight.\n            for (let i = 0; i < actionsWithWeight.length; i++) {\n                if (this.debug) {\n                    console.log(`${this.gameObject.name} fade out action ${actionsWithWeight[i].getClip().name} over ${options.transitionDuration} seconds`);\n                }\n                actionsWithWeight[i].stopFading();\n                actionsWithWeight[i].fadeOut(options.transitionDuration);\n            }\n\n            // Fade in the new action.\n            if (this.debug) {\n                console.log(`${this.gameObject.name} fade in action ${action.getClip().name} over ${options.transitionDuration} seconds`);\n            }\n            action.stopFading();\n            action.fadeIn(options.transitionDuration);\n        } else {\n            // Stop all current actions.\n            this.stopAll();\n\n            action.setEffectiveWeight(1);\n        }\n\n        // Set the loop properties.\n        if (options.loop) {\n            action.setLoop(LoopRepeat, Infinity);\n        } else {\n            action.setLoop(LoopOnce, 0);\n        }\n\n        // Always clamp on the last frame when finished.\n        action.clampWhenFinished = true;\n\n        if (options.durationOverride >= 0) {\n            action.setDuration(options.durationOverride);\n        } else {\n            action.setEffectiveTimeScale(1);\n        }\n\n        // Change start time if one is provided.\n        if (options.normalizedStartTime >= 0) {\n            options.normalizedStartTime = clamp(options.normalizedStartTime, 0, 1);\n            action.time = unnormalize(options.normalizedStartTime, 0, action.getClip().duration);\n        }\n        \n        // Play the action.\n        action.play();\n        \n        this._actionTracker.add(action);\n    }\n\n    playAll(): void {\n        this.stopAll();\n\n        for (const [clipName, clip] of this._clips) {\n            const action = this._mixer.clipAction(clip).reset();\n            action.play();\n\n            this._actionTracker.add(action);\n        }\n    }\n\n    stopAll(): void {\n        if (this.debug) {\n            console.log(`${this.gameObject.name} stop all ${this._actionTracker.count} actions.`);\n        }\n\n        for (let i = this._actionTracker.count - 1; i >= 0; i--) {\n            const action = this._actionTracker.getByIndex(i);\n            action.stop();\n            this._actionTracker.remove(action);\n        }\n    }\n\n    onUpdate(): void {\n        super.onUpdate();\n\n        if (this._visible) {\n            this._mixer.update(APEngine.time.deltaTime);\n        }\n    }\n\n    onLateUpdate(): void {\n        super.onLateUpdate();\n    }\n\n    private _onActionLoop(e: DispatcherEvent): void {\n        const loopEvent = e as ActionLoopEvent;\n\n        if (this.debug) {\n            console.log(`${this.gameObject.name} on action ${loopEvent.action.getClip().name} loop`);\n        }\n\n        this.onAnimationLoop.invoke({\n            clipName: loopEvent.action.getClip().name\n        });\n    }\n\n    private _onActionFinished(e: DispatcherEvent): void {\n        const finishEvent = e as ActionFinishedEvent;\n\n        if (this.debug) {\n            console.log(`${this.gameObject.name} on action ${finishEvent.action.getClip().name} finished`);\n        }\n\n        this.onAnimationFinished.invoke({\n            clipName: finishEvent.action.getClip().name\n        });\n    }\n\n    private _clipAlreadyPlaying(clip: AnimationClip, loop: AnimationActionLoopStyles): boolean {\n        const action = this._mixer.clipAction(clip);\n        if (action.isRunning() && action.loop === loop) {\n            return true;\n        }\n        return false;\n    }\n\n    onDestroy(): void {\n        super.onDestroy();\n\n        this.stopAll();\n\n        this.onAnimationLoop.dispose();\n        this.onAnimationFinished.dispose();\n\n        this._mixer.removeEventListener('loop', this._onActionLoop);\n        this._mixer.removeEventListener('finished', this._onActionFinished);\n\n        this._mixer.stopAllAction();\n        this._mixer.uncacheRoot(this._mixer.getRoot());\n        this._mixer = null;\n\n        this._clips.clear();\n    }\n}","import { Decorator, IDecoratorOptions } from './Decorator';\nimport { Mesh } from 'three';\nimport { GameObject } from '../GameObject';\n\nexport interface IMeshDecoratorOptions extends IDecoratorOptions {\n    mesh: Mesh\n}\n\nexport class MeshDecorator extends Decorator {\n\n    mesh: Mesh;\n\n    configure(options: IMeshDecoratorOptions) {\n        super.configure(options);\n\n        this.mesh = options.mesh;\n    }\n\n    onAttach(gameObject: GameObject) {\n        super.onAttach(gameObject);\n\n        this.gameObject.add(this.mesh);\n    }\n\n    onStart() {\n        super.onStart();\n    }\n\n    onDestroy() {\n        super.onDestroy();\n        \n        this.gameObject.remove(this.mesh);\n    }\n}","import { TransformControls } from \"three/examples/jsm/controls/TransformControls\";\nimport { IDisposable } from \"./IDisposable\";\nimport { ArgEvent } from \"../misc/Events\";\nimport { Vector3, Euler, MathUtils } from \"three\";\n\nconst VectorFields: string[] = ['x', 'y', 'z'];\n\nexport class TransformControlsGUI implements IDisposable {\n    private _controls: TransformControls;\n    private _rootEl: HTMLDivElement;\n\n    onUnselectClick: ArgEvent<TransformControlsGUI> = new ArgEvent();\n\n    constructor(controls: TransformControls) {\n        this._controls = controls;\n\n        this._controlsChange = this._controlsChange.bind(this);\n        this._controlsObjectChange = this._controlsObjectChange.bind(this);\n\n        this._controls.addEventListener('change', this._controlsChange);\n        this._controls.addEventListener('objectChange', this._controlsObjectChange);\n\n        // Create the gui.\n        this._rootEl = document.createElement('div');\n        document.body.appendChild(this._rootEl);\n        this._rootEl.id = 'transform-controls-gui';\n\n        this._rootEl.style.position = 'fixed';\n        this._rootEl.style.right = '0';\n        this._rootEl.style.bottom = '0'\n        this._rootEl.style.minWidth = '250px';\n        this._rootEl.style.maxWidth = '50%';\n        this._rootEl.style.backgroundColor = '#333';\n        this._rootEl.style.color = '#fff';\n        this._rootEl.style.fontFamily = \"Courier New\";\n        this._rootEl.style.padding = '4px';\n        this._rootEl.style.fontSize = '14px';\n\n        this._addHeader('Object Name');\n        this._addParagraph('object-name');\n        this._addSpacer();\n        this._addHeader('Local Position');\n        this._addVector3('local-position', (vector) => {\n            this._controls.object.position.copy(vector);\n        });\n        this._addSpacer();\n        this._addHeader('Local Rotation');\n        this._addVector3('local-rotation', (vector) => {\n            const rad = vector.clone().multiplyScalar(MathUtils.DEG2RAD);\n            this._controls.object.rotation.setFromVector3(rad);\n        });\n        this._addSpacer();\n        this._addHeader('Local Scale');\n        this._addVector3('local-scale', (vector) => {\n            this._controls.object.scale.copy(vector);\n        });\n        this._addSpacer();\n        this._addHeader('Transform Mode');\n        this._addButtonRow([\n            {\n                 text: 'Translate',\n                 callback: (e) => {\n                    this._controls.setMode('translate');\n                 }\n            },\n            {\n                 text: 'Rotate',\n                 callback: (e) => {\n                    this._controls.setMode('rotate');\n                 }\n            },\n            {\n                 text: 'Scale',\n                 callback: (e) => {\n                    this._controls.setMode('scale');\n                 }\n            },\n        ]);\n        this._addSpacer();\n        this._addHeader('Transform Space');\n        this._addButtonRow([\n            {\n                 text: 'Local',\n                 callback: (e) => {\n                    this._controls.setSpace('local');\n                 }\n            },\n            {\n                 text: 'World',\n                 callback: (e) => {\n                    this._controls.setSpace('world');\n                 }\n            },\n        ]);\n        this._addSpacer('24px');\n        this._addButton('Unselect Object', (e) => {\n            this.onUnselectClick.invoke(this);\n        });\n\n        this.refresh();\n    }\n\n    private _addHeader(title: string): void {\n        const headerEl = document.createElement('div');\n        this._rootEl.appendChild(headerEl);\n\n        headerEl.style.backgroundColor = '#555';\n        headerEl.style.width = '100%';\n        headerEl.style.textAlign = 'left';\n        headerEl.style.letterSpacing = '1px';\n        headerEl.style.padding = '4px';\n        headerEl.style.boxSizing = 'border-box';\n        headerEl.textContent = title;\n    }\n\n    private _addSpacer(height?: string): void {\n        const spacerEl = document.createElement('div');\n        this._rootEl.appendChild(spacerEl);\n\n        spacerEl.style.height = height ?? '16px';\n    }\n\n    private _addParagraph(id: string): void {\n        const paragraphEl = document.createElement('p');\n        this._rootEl.appendChild(paragraphEl);\n        paragraphEl.id = id;\n\n        paragraphEl.style.boxSizing = 'border-box';\n        paragraphEl.style.margin = '4px 4px 0px 4px';\n    }\n\n    private _refreshParagraph(id: string, text: string): void {\n        const paragraphEl = document.querySelector(`#${id}`) as HTMLParamElement;\n        if (paragraphEl) {\n            paragraphEl.textContent = text;\n        }\n    }\n\n    private _addButton(text: string, callback: (e: MouseEvent) => void): void {\n        const buttonEl = document.createElement('button');\n        this._rootEl.appendChild(buttonEl);\n        \n        buttonEl.style.width = '100%';\n        buttonEl.style.fontSize = '14px';\n\n        buttonEl.textContent = text;\n        buttonEl.onclick = (e) => callback(e);\n    }\n\n    private _addButtonRow(configs: { text: string, callback: (e: MouseEvent) => void }[]): void {\n        const rowEl = document.createElement('div');\n        this._rootEl.appendChild(rowEl);\n        rowEl.style.display = 'flex';\n        rowEl.style.flexDirection = 'row';\n\n        for (let i = 0; i < configs.length; i++) {\n            const config = configs[i];\n\n            const buttonEl = document.createElement('button');\n            rowEl.appendChild(buttonEl);\n\n            buttonEl.style.width = '100%';\n            buttonEl.style.fontSize = '14px';\n\n            buttonEl.textContent = config.text;\n            buttonEl.onclick = (e) => config.callback(e);\n        }\n    }\n\n    private _addVector3(id: string, callback: (vector: Vector3) => void): void {\n        const vectorEl = document.createElement('div');\n        this._rootEl.appendChild(vectorEl);\n        vectorEl.id = id;\n\n        vectorEl.style.display = 'flex';\n        vectorEl.style.flexDirection = 'row';\n\n        for (let i = 0; i < VectorFields.length; i++) {\n            const field = VectorFields[i];\n\n            const labelEl = document.createElement('label');\n            vectorEl.appendChild(labelEl);\n            labelEl.htmlFor = field;\n            labelEl.textContent = `${field.toUpperCase()}:`;\n\n            const inputEl = document.createElement('input');\n            vectorEl.appendChild(inputEl);\n            inputEl.type = 'number';\n            inputEl.onchange = () => callback(this._getVector3(id));\n            inputEl.style.width = '75px';\n            inputEl.id = field;\n            inputEl.name = field;\n        }\n    }\n\n    private _getVector3(id: string): Vector3 {\n        const vectorEl = document.querySelector(`#${id}`);\n        if (vectorEl) {\n            const vector = new Vector3();\n            for (let i = 0; i < VectorFields.length; i++ ) {\n                const field = VectorFields[i];\n\n                const inputEl = vectorEl.querySelector(`#${field}`) as HTMLInputElement;\n                vector.setComponent(i, Number.parseFloat(inputEl.value));\n            }\n\n            return vector;\n        }\n\n        return null;\n    }\n\n    private _refreshVector3(id: string, vector: Vector3): void {\n        const vectorEl = document.querySelector(`#${id}`);\n        if (vectorEl) {\n            for (let i = 0; i < VectorFields.length; i++ ) {\n                const field = VectorFields[i];\n\n                const inputEl = vectorEl.querySelector(`#${field}`) as HTMLInputElement;\n                inputEl.value = vector.getComponent(i).toFixed(3);\n            }\n        }\n    }\n\n    refresh(): void {\n        if (!this._rootEl) {\n            return;\n        }\n\n        this._refreshParagraph('object-name', this._controls.object.name);\n        this._refreshVector3('local-position', this._controls.object.position);\n        this._refreshVector3('local-rotation', new Vector3(\n            this._controls.object.rotation.x * MathUtils.RAD2DEG,\n            this._controls.object.rotation.y * MathUtils.RAD2DEG,\n            this._controls.object.rotation.z * MathUtils.RAD2DEG\n        ));\n        this._refreshVector3('local-scale', this._controls.object.scale);\n    }\n    \n    private _controlsChange(): void {\n        this.refresh();\n    }\n\n    private _controlsObjectChange(): void {\n        this.refresh();\n    }\n\n    dispose(): void {\n        this._controls.removeEventListener('change', this._controlsChange);\n        this._controls.removeEventListener('objectChange', this._controlsObjectChange);\n        if (this._rootEl) {\n            this._rootEl.remove();\n            this._rootEl = null;\n        }\n    }\n}","import { TransformControls } from \"three/examples/jsm/controls/TransformControls\";\nimport { Object3D, Camera } from \"three\";\nimport { Event, ArgEvent } from \"../misc/Events\";\nimport { APEngine } from \"../APEngine\";\nimport { findParentScene } from \"../utils/ThreeUtils\";\nimport { TransformControlsGUI } from \"./TransformControlsGUI\";\nimport { CameraDecorator } from \"../gameobject/decorators/CameraDecorator\";\n\nexport namespace TransformTool {\n    var _controls: TransformControls;\n    var _gui: TransformControlsGUI;\n    var _mouseDown: boolean;\n\n    export const onAttach: ArgEvent<Object3D> = new ArgEvent();\n    export const onDetach: ArgEvent<Object3D> = new ArgEvent();\n    export const onMouseDown: Event = new Event();\n    export const onMouseUp: Event = new Event();\n    export const onObjectChange: ArgEvent<Object3D> = new ArgEvent();\n\n    export function attach(object3d: Object3D, cameraDecorator?: CameraDecorator): void {\n        if (_controls || _gui) {\n            detach();\n        }\n\n        const transformCamera = cameraDecorator ?? CameraDecorator.PrimaryCamera;\n        if (!transformCamera) {\n            console.error(`[TransformTool] There is no valid camera to create transfrom controls with.`);\n            return;\n        }\n        if (!APEngine.webglRenderer.domElement) {\n            console.error(`[TransformTool] There is no valid dom element to attach transfrom controls events to.`);\n            return;\n        }\n\n        _controls = new TransformControls(\n            transformCamera.camera,\n            APEngine.webglRenderer.domElement\n        );\n\n        _controls.attach(object3d);\n        _controls.setSpace('local');\n        _controls.setMode('translate');\n\n        _controls.addEventListener('change', controlsChange);\n        _controls.addEventListener('mouseDown', controlsMouseDown);\n        _controls.addEventListener('mouseUp', controlsMouseUp);\n        _controls.addEventListener('objectChange', controlsObjectChange);\n\n        // window.addEventListener('keydown', handleKeyDown);\n\n        const scene = findParentScene(object3d);\n        scene.add(_controls);\n\n        _gui = new TransformControlsGUI(_controls);\n        _gui.onUnselectClick.addListener(guiUnselectClick);\n    }\n\n    export function detach(): void {\n        if (_gui) {\n            _gui.onUnselectClick.removeListener(guiUnselectClick);\n            _gui.dispose();\n            _gui = null;\n        }\n\n        if (_controls) {\n            _controls.removeEventListener('change', controlsChange);\n            _controls.removeEventListener('mouseDown', controlsMouseDown);\n            _controls.removeEventListener('mouseUp', controlsMouseUp);\n            _controls.removeEventListener('objectChange', controlsObjectChange);\n\n            // window.removeEventListener('keydown', handleKeyDown;\n\n            _controls.parent.remove(_controls);\n            _controls.detach();\n            _controls.dispose();\n            _controls = null;\n        }\n    }\n\n    export function getAttachedObject(): Object3D {\n        if (_controls) {\n            return _controls.object;\n        } else { \n            return null;\n        }\n    }\n\n    export function isMouseDown(): boolean {\n        return _mouseDown;\n    }\n\n    function guiUnselectClick(): void {\n        detach();\n    }\n    \n    function controlsChange(): void {\n    }\n\n    function controlsObjectChange(): void {\n        onObjectChange.invoke(getAttachedObject());\n    }\n\n    function controlsMouseDown(): void {\n        _mouseDown = true;\n        onMouseDown.invoke();\n    }\n\n    function controlsMouseUp(): void {\n        _mouseDown = false;\n        onMouseUp.invoke();\n    }\n}","import { Material, Texture, Object3D, Mesh, SkinnedMesh, BufferGeometry, TextureDataType, Skeleton, MathUtils } from \"three\";\n\ndeclare type Trackable = Object3D | BufferGeometry | Material | Texture | Skeleton;\n\nexport interface IAssetCount {\n    object3d: number;\n    geometry: number;\n    material: number;\n    texture: number;\n    skeleton: number;\n    unknown: number;\n}\n\nexport interface IAssetReference { \n    asset: Trackable,\n    referenceCount: number\n}\n\nexport interface IAssetSnapshot {\n    uuid: string,\n    name: string,\n    type: string | TextureDataType,\n    referenceCount: number\n}\n\nexport interface ISnapshot {\n    assetSnapshots: IAssetSnapshot[]\n}\n\n/**\n * APE Asset Tracker is a class that tracks objects that must be manually cleaned up that are created by Three JS.\n * These include geometries, materials, and textures.\n * \n * To use this tracker, create a new instance of it and then call track() with the given asset you would like to track.\n * The tracker will then recursively search through the asset's heirarchy (if it as one) as track all geometries, materials, and textures that it finds.\n * When you are ready to dispose of the tracked assets, call the dispose() function.\n *  \n * Reference: https://threejsfundamentals.org/threejs/lessons/threejs-cleanup.html\n */\nexport namespace APEAssetTracker {\n\n    /**\n     * Map of tracked assets indexed by the trackable's uuid.\n     */\n    export let assetRefs: Map<string, IAssetReference> = new Map();\n\n    /**\n     * Debug level for asset tracker.\n     * 0: Disabled, 1: Track/Release events, 2: Total counts\n     */\n    export let debugLevel: number = 0;\n\n    export let snapshots: ISnapshot[] = [];\n\n    /**\n     * Map of uuids for objects that do not define a uuid within themselves.\n     */\n    let internalUUIDs: Map<any, string> = new Map();\n\n    function getUUID(trackable: Trackable): string {\n        if ('uuid' in trackable) {\n            return trackable.uuid;\n        } else {\n            let uuid = internalUUIDs.get(trackable);\n            if (!uuid) {\n                uuid = MathUtils.generateUUID();\n                internalUUIDs.set(trackable, uuid);\n            }\n\n            return uuid;\n        }\n    }\n\n    function getName(trackable: Trackable): string {\n        if ('name' in trackable) {\n            return trackable.name;\n        } else if (trackable instanceof Skeleton) {\n            return 'Skeleton';\n        } else {\n            return 'Unnamed';\n        }\n    }\n\n    function getType(trackable: Trackable): string | TextureDataType {\n        if ('type' in trackable) {\n            return trackable.type;\n        } else if (trackable instanceof Skeleton) {\n            return 'Skeleton';\n        } else {\n            return 'Unknown Type';\n        }\n    }\n\n    /**\n     * Recursive search function that will collect all objects underneath the given asset that can be considered a Trackable.\n     * Each item's key in the Map is the trackable's uuid.\n     */\n    function findTrackables(asset: any, trackables: Map<string, Trackable>): void {\n        if (!asset) {\n            return;\n        }\n    \n        // Handle arrays of objects, materials, and textures.\n        if (Array.isArray(asset)) {\n            asset.forEach(resource => findTrackables(resource, trackables));\n            return;\n        }\n    \n        if ('dispose' in asset || asset instanceof Object3D) {\n            trackables.set(getUUID(asset), asset);\n        }\n    \n        if (asset instanceof Object3D) {\n            if (asset instanceof Mesh) {\n                findTrackables(asset.geometry, trackables);\n                findTrackables(asset.material, trackables);\n    \n                if (asset instanceof SkinnedMesh) {\n                    findTrackables(asset.skeleton, trackables);\n                }\n            }\n    \n            findTrackables(asset.children, trackables);\n        } else if (asset instanceof Material) {\n            // We have to check if there are any textures on the material\n            for (const value of Object.values(asset)) {\n                if (value instanceof Texture) {\n                    findTrackables(value, trackables);\n                }\n            }\n            \n            // We also have to check if any uniforms reference textures or arrays of textures\n            if ('uniforms' in asset) {\n                const uniforms = (<any>asset).uniforms;\n                for (const uniform of Object.values(uniforms)) {\n                    if (uniform) {\n                        const uniformValue = (<any>uniform).value;\n                        if (uniformValue instanceof Texture || Array.isArray(uniformValue)) {\n                            findTrackables(uniformValue, trackables);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    export function getAssetCounts(): IAssetCount {\n        const assetCounts: IAssetCount = {\n            geometry: 0,\n            material: 0,\n            object3d: 0,\n            texture: 0,\n            skeleton: 0,\n            unknown: 0\n        }\n\n        assetRefs.forEach((assetRef) => {\n            const asset = assetRef.asset;\n\n            if (asset instanceof Object3D) {\n                assetCounts.object3d++;\n            } else if (asset instanceof Material) {\n                assetCounts.material++;\n            } else if (asset instanceof BufferGeometry) {\n                assetCounts.geometry++;\n            } else if (asset instanceof Texture) {\n                assetCounts.texture++;\n            } else if (asset instanceof Skeleton) {\n                assetCounts.skeleton++;\n            } else {\n                assetCounts.unknown++;\n            }\n        });\n\n        return assetCounts;\n    }\n\n    /**\n     * Take a snapshot of the current state of asset references.\n     * This is useful for comparing snapshots during debugging to figure out which assets are not \n     * being untracked and cleaned up properly.\n     */\n    export function takeSnapshot(): ISnapshot {\n        const snapshot: ISnapshot = {\n            assetSnapshots: []\n        };\n\n        assetRefs.forEach((assetRef) => {\n            snapshot.assetSnapshots.push({\n                uuid: getUUID(assetRef.asset),\n                name: getName(assetRef.asset),\n                type: getType(assetRef.asset),\n                referenceCount: assetRef.referenceCount,\n            });\n        });\n\n        snapshots.push(snapshot);\n\n        return snapshot;\n    }\n    \n    export function clearSnapshots(): void {\n        snapshots = [];\n    }\n\n    export function diffOfLastTwoSnapshots(): IAssetSnapshot[] {\n        if (snapshots.length >= 2) {\n            return diffOfSnapshots(snapshots[snapshots.length - 2], snapshots[snapshots.length - 1]);\n        } else {\n            console.warn(`Need at least two snapshots in order to diff the last two.`);\n        }\n    }\n\n    export function diffOfSnapshots(snapshotA: ISnapshot, snapshotB: ISnapshot): IAssetSnapshot[] {\n        const setA = Array.from(new Set(snapshotA.assetSnapshots));\n        const setB = Array.from(new Set(snapshotB.assetSnapshots));\n\n        // Create a diff set that has the elements from setA that are not in setB.\n        const diff = [];\n        for (const entry of setA) {\n            const inSetB = setB.some(snap => snap.uuid === entry.uuid);\n            if (!inSetB) {\n                diff.push(entry);\n            }\n        }\n        \n        return diff;\n    }\n\n    export function intersectOfLastTwoSnapshots(): IAssetSnapshot[] {\n        if (snapshots.length >= 2) {\n            return intersectOfSnapshots(snapshots[snapshots.length - 2], snapshots[snapshots.length - 1]);\n        } else {\n            console.warn(`Need at least two snapshots in order to intersect the last two.`);\n        }\n    }\n\n    export function intersectOfSnapshots(snapshotA: ISnapshot, snapshotB: ISnapshot): IAssetSnapshot[] {\n        const setA = Array.from(new Set(snapshotA.assetSnapshots));\n        const setB = Array.from(new Set(snapshotB.assetSnapshots));\n\n        // Create a intersection set that has the elements that are in both setA and setB.\n        const intersect = [];\n        for (const entry of setA) {\n            const inSetB = setB.some(snap => snap.uuid === entry.uuid);\n            if (inSetB) {\n                intersect.push(entry);\n            }\n        }\n\n        return intersect;\n    }\n\n    /**\n     * Track the given asset by incrementing the reference counter for it.\n     */\n    export function track(asset: any): void {\n        const trackables = new Map<string, Trackable>();\n        findTrackables(asset, trackables);\n\n        if (trackables && trackables.size > 0) {\n            trackables.forEach((asset, uuid) => {\n                let assetRef: IAssetReference = assetRefs.get(uuid);\n\n                if (assetRef) {\n                    assetRef.referenceCount++;\n                } else {\n                    assetRef = {\n                        asset: asset,\n                        referenceCount: 1\n                    };\n\n                    assetRefs.set(getUUID(asset), assetRef);\n                }\n\n                if (debugLevel >= 1) {\n                    console.log(`[APEAssetTracker] track asset type: ${asset.constructor.name}, uuid: ${getUUID(asset)}, refCount: ${assetRef.referenceCount}`);\n                }\n                if (debugLevel >= 2) {\n                    console.log(`[APEAssetTracker] tracked assets -> ${JSON.stringify(getAssetCounts())}`);\n                }\n            });\n        }\n    }\n\n    /**\n     * Untrack the given asset by decrementing the reference counter for it. If the reference counter reaches zero, the asset will be released.\n     */\n    export function untrack(asset: any): void {\n        const trackables = new Map<string, Trackable>();\n        findTrackables(asset, trackables);\n\n        if (trackables && trackables.size > 0) {\n            trackables.forEach((asset, uuid) => {\n                // Only release assets that are explicitly tracked by the tracker.\n                // We dont want to cause unintended behaviour by releasing an untracked trackable asset.\n                const assetRef = assetRefs.get(uuid);\n\n                if (assetRef) {\n                    if (assetRef.referenceCount > 0) {\n                        assetRef.referenceCount--;\n\n                        if (debugLevel >= 1) {\n                            console.log(`[APEAssetTracker] decrement reference count for asset type: ${asset.constructor.name}, uuid: ${getUUID(asset)}, refCount: ${assetRef.referenceCount}`);\n                        }\n                    }\n\n                    if (assetRef.referenceCount <= 0) {\n                        if (debugLevel >= 1) {\n                            console.log(`[APEAssetTracker] release asset type: ${asset.constructor.name}, uuid: ${getUUID(asset)}`);\n                        }\n                    \n                        if (asset instanceof Object3D) {\n                            if (asset.parent) {\n                                asset.parent.remove(asset);\n                            }\n                        }\n            \n                        if ('dispose' in asset) {\n                            asset.dispose();\n                        }\n                        \n                        // Remove the tracked asset from the map.\n                        assetRefs.delete(uuid);\n\n                        // Remove the asset from the internal uuid map (if it is even in it).\n                        internalUUIDs.delete(asset);\n    \n                        if (debugLevel >= 2) {\n                            console.log(`[APEAssetTracker] tracked assets -> ${JSON.stringify(getAssetCounts())}`);\n                        }\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     * Dispose of all tracked assets.\n     */\n    export function dispose(): void {\n        assetRefs.forEach((assetRef, uuid) => {\n            const asset = assetRef.asset;\n\n            untrack(asset);\n            if (asset instanceof Object3D) {\n                if (asset.parent) {\n                    asset.parent.remove(asset);\n                }\n            }\n\n            if ('dispose' in asset) {\n                asset.dispose();\n            }\n        });\n\n        assetRefs = new Map();\n        snapshots = [];\n        internalUUIDs = new Map();\n    }\n}","import { ResourceManager } from './ResourceManager';\nimport { AudioResource } from './AudioResource';\nimport { GLTFResource } from './GLTFResource';\nimport { TextureResource } from './TextureResource';\nimport { ImageResource } from './ImageResource';\nimport { ResourceProgressMap } from './ResourceProgress';\n\n/**\n * Contains all the core APEngine Resource Managers and related objects.\n */\nexport namespace APEResources {\n    \n    export const audio = new ResourceManager(AudioResource);\n    export const gltf = new ResourceManager(GLTFResource);\n    export const textures = new ResourceManager(TextureResource);\n    export const images = new ResourceManager(ImageResource);\n\n    /**\n     * Preload all resource managers.\n     */\n    export async function preloadResources(): Promise<void> {\n        await Promise.all([\n            audio.preload(),\n            gltf.preload(),\n            textures.preload(),\n            images.preload()\n        ]);\n    }\n\n    export function getProgress(): Readonly<number> {\n        const progressMap = new ResourceProgressMap();\n\n        const audioProgress = progressMap.addProgressObject({ id: 'audio', weight: audio.count() });\n        audioProgress.value = audio.getLoadProgress();\n\n        const gltfProgress = progressMap.addProgressObject({ id: 'gltf', weight: gltf.count() });\n        gltfProgress.value = gltf.getLoadProgress();\n\n        const textureProgress = progressMap.addProgressObject({ id: 'textures', weight: textures.count() });\n        textureProgress.value = textures.getLoadProgress();\n\n        const imageProgress = progressMap.addProgressObject({ id: 'images', weight: images.count() });\n        imageProgress.value = images.getLoadProgress();\n\n        return progressMap.calculateWeightedMean();\n    }\n\n    /**\n     * Dispose of all resource managers.\n     */\n    export function diposeAll(): void {\n        audio.dispose();\n        gltf.dispose();\n        textures.dispose();\n        images.dispose();\n    }\n\n    /**\n     * Print out all resource manager load states to the console.\n     */\n    export function printLoadStates(): void {\n        console.groupCollapsed(`[APEResource] Resource Manager Load States`);\n        console.log('Audio');\n        console.log(audio.loadState());\n        console.log('GLTF');\n        console.log(gltf.loadState());\n        console.log('Textures');\n        console.log(textures.loadState());\n        console.log('Images');\n        console.log(images.loadState());\n        console.groupEnd();\n    }\n}","import { IDecoratorOptions, Decorator } from \"./Decorator\";\nimport { GameObject } from \"../GameObject\";\nimport { APEngine } from \"../../APEngine\";\nimport { \n    IPointerEventListener, \n    IPointerClickEvent,\n    IPointerDownEvent,\n    IPointerEnterEvent,\n    IPointerExitEvent,\n    IPointerUpEvent\n} from \"../../input/PointerEventSystem\";\nimport { Object3D } from \"three\";\nimport { TransformTool } from \"../../misc/TransformTool\";\nimport { traverseSafe } from \"../../utils/ThreeUtils\";\n\nexport interface ITransformPickerDecoratorOptions extends IDecoratorOptions {\n}\n\nexport class TransformPickerDecorator extends Decorator implements IPointerEventListener {\n\n    get pointerTargets(): Object3D[] {\n        const children: Object3D[] = [];\n        traverseSafe(this.gameObject, (obj) => children.push(obj));\n        return children;\n    }\n\n    configure(options: ITransformPickerDecoratorOptions): void {\n        super.configure(options);\n    }\n\n    onAttach(gameObject: GameObject): void {\n        super.onAttach(gameObject);\n    }\n\n    onVisible() {\n        super.onVisible();\n\n        APEngine.pointerEventSystem.addListener(this);\n    }\n\n    onInvisible() {\n        super.onInvisible();\n\n        APEngine.pointerEventSystem.removeListener(this);\n    }\n\n    onStart(): void {\n        super.onStart();\n    }\n\n    onPointerEnter(event: IPointerEnterEvent): void {\n    }\n\n    onPointerExit(event: IPointerExitEvent): void {\n    }\n\n    onPointerDown(event: IPointerDownEvent): void {\n    }\n\n    onPointerUp(event: IPointerUpEvent): void {\n    }\n\n    onPointerClick(event: IPointerClickEvent): void {\n        TransformTool.attach(this.gameObject);\n    }\n\n    onUpdate(): void {\n        super.onUpdate();\n    }\n\n    onLateUpdate(): void {\n        super.onLateUpdate();\n    }\n\n    onDestroy(): void {\n        super.onDestroy();\n\n        if (TransformTool.getAttachedObject() === this.gameObject) {\n            TransformTool.detach();\n        }\n\n        APEngine.pointerEventSystem.removeListener(this);\n    }\n}","import { IDecoratorOptions, Decorator } from \"./Decorator\";\nimport { GameObject } from \"../GameObject\";\nimport { Vector3, Vector2 } from \"three\";\nimport { CameraDecorator } from \"./CameraDecorator\";\nimport { clamp, clampDegAngle, pointOnSphere } from \"../../utils/MathUtils\";\nimport { APEngine } from \"../../APEngine\";\nimport { InputType } from \"../../input/Input\";\nimport { getOptionalValue } from \"../../utils/MiscUtils\";\nimport { TransformTool } from \"../../misc/TransformTool\";\n\nexport interface ICameraOrbitDecoratorOptions extends IDecoratorOptions {\n    cameraDecorator?: CameraDecorator;\n}\n\n/**\n * Decorator that provided orbit controls for a camera decorator.\n */\nexport class CameraOrbitDecorator extends Decorator {\n    /**\n     * The world position that the camera is looking at.\n     */\n    target: Vector3 = new Vector3();\n\n    /**\n     * The distance in pixels that needs to be crossed in order for dragging to start.\n     */\n    dragThreshold = 10.0;\n\n    invertY: boolean = true;\n    invertX: boolean = true;\n\n    xMouseSpeed = 1.0;\n    yMouseSpeed = 1.0;\n    xTouchSpeed = 1.0;\n    yTouchSpeed = 1.0;\n\n    xMinDeg = -360.0;\n    xMaxDeg = 360.0;\n    yMinDeg = -90.0;\n    yMaxDeg = 90.0;\n\n    zoomMouseSpeed = 1.0;\n    zoomTouchSpeed = 1.0;\n\n    zoomMin = 0.0;\n    zoomMax = 40.0;\n\n    rotateWhileZooming: boolean = false;\n\n    private _camera: CameraDecorator = null;\n    private _inputEnabled: boolean = true;\n    private _zoomEnabled: boolean = true;\n    private _isDragging: boolean = false;\n    private _isZooming: boolean = false;\n    private _x: number = 0;\n    private _y: number = 0;\n    private _zoomDistance: number = 0;\n    private _inputDown: boolean = false;\n    private _inputDownStartPos: Vector2 = new Vector2();\n    private _inputDragLastPos: Vector2 = new Vector2();\n    private _inputTouchZoomDist: number = 0;\n    \n    get inputEnabled(): boolean { return this._inputEnabled; }\n    set inputEnabled(value: boolean) { \n        this._inputEnabled = value;\n\n        if (!this.inputEnabled) {\n            this._inputDown = false;\n            this._isDragging = false;\n            this._isZooming = false;\n            this._inputDownStartPos.set(0, 0);\n            this._inputDragLastPos.set(0, 0);\n            this._inputTouchZoomDist = 0;\n        }\n    }\n\n    get zoomEnabled(): boolean { return this._zoomEnabled; }\n    set zoomEnabled(value: boolean) {\n        this._zoomEnabled = value;\n\n        if (!this._zoomEnabled) {\n            this._isZooming = false;\n            this._inputTouchZoomDist = 0;\n        }\n    }\n\n    get camera(): CameraDecorator { return this._camera; } \n    get isDragging(): boolean { return this._isDragging; } \n    get isZooming(): boolean { return this._isZooming; }\n\n    configure(options: ICameraOrbitDecoratorOptions): void {\n        super.configure(options);\n\n        this._camera = getOptionalValue(options.cameraDecorator, null);\n    }\n\n    onAttach(gameObject: GameObject): void {\n        super.onAttach(gameObject);\n\n        if (!this._camera) {\n            // If no camera was provided, look for one on the gameObject we are attached to.\n            this._camera = this.gameObject.getDecorator(CameraDecorator);\n        }\n\n        if (!this._camera) {\n            console.error(`[CameraOrbitDecorator] No camera decorator to control. Need to be provided one or be attached to GameObject with CameraDecorator on it.`);\n        }\n    }\n\n    onVisible() {\n        super.onVisible();\n    }\n\n    onInvisible() {\n        super.onInvisible();\n    }\n\n    onStart(): void {\n        super.onStart();\n    }\n\n    setOrbit(x?: number, y?: number) {\n        let set = false;\n        if (typeof x === 'number') {\n            this._x = x;\n            set = true;\n        }\n        if (typeof y === 'number') {\n            this._y = y;\n            set = true;\n        }\n        if (set) {\n            this._updateCamera();\n        }\n    }\n\n    setOrbitFromGeoCoord(latitude?: number, longitude?: number): void {\n        let set = false;\n        if (typeof longitude === 'number') {\n            this._x = -90 + longitude;\n            set = true;\n        }\n        if (typeof latitude === 'number') {\n            this._y = -latitude;\n            set = true;\n        }\n        if (set) {\n            this._updateCamera();\n        }\n    }\n\n    getOrbit(): { x: number, y: number } {\n        return {\n            x: this._x,\n            y: this._y\n        }\n    }\n\n    setZoomDistance(zoom: number) {\n        zoom = clamp(zoom, this.zoomMin, this.zoomMax);\n\n        if (this._zoomDistance !== zoom) {\n            this._zoomDistance = zoom;\n            this._updateCamera();\n        }\n    }\n\n    getZoomDistance(): number {\n        return this._zoomDistance;\n    }\n\n    private _rotateControls(): void {\n        if (!this.inputEnabled) {\n            return;\n        }\n\n        const input = APEngine.input;\n\n        if (input.currentInputType === InputType.Touch && input.getTouchDown(0)) {\n            this._inputDown = true;\n            this._isDragging = false;\n            this._inputDownStartPos.copy(input.getTouchClientPos(0));\n        } else if (input.currentInputType === InputType.Mouse && input.getMouseButtonDown(0)) {\n            this._inputDown = true;\n            this._isDragging = false;\n            this._inputDownStartPos.copy(input.getMouseClientPos());\n        }\n        \n        if (this._inputDown && !this._isDragging) {\n            // Need to cross drag theshold in order to start dragging.\n            let dragDistance: number = 0.0;\n            let inputPos: Vector2;\n            if (input.currentInputType === InputType.Touch) {\n                inputPos = input.getTouchClientPos(0);\n            } else {\n                inputPos = input.getMouseClientPos();\n            }\n\n            dragDistance = this._inputDownStartPos.distanceTo(inputPos);\n\n            if (dragDistance >= this.dragThreshold) {\n                this._isDragging = true;\n                this._inputDragLastPos.copy(inputPos);\n            }\n        }\n\n        if (input.currentInputType === InputType.Touch && input.getTouchUp(0)) {\n            this._inputDown = false;\n            this._isDragging = false;\n            this._inputDownStartPos.set(0, 0);\n        } else if (input.currentInputType === InputType.Mouse && input.getMouseButtonUp(0)) {\n            this._inputDown = false;\n            this._isDragging = false;\n            this._inputDownStartPos.set(0, 0);\n        }\n\n        if (this._isDragging) {\n            const rotateAllowed = !this.isZooming || (this.isZooming && this.rotateWhileZooming);\n\n            if (input.currentInputType === InputType.Touch && input.getTouchHeld(0)) {\n                if (rotateAllowed) {\n                    const delta = this._inputDragLastPos.clone().sub(input.getTouchClientPos(0));\n                    this._x += (delta.x * this.xTouchSpeed);\n                    this._y += (delta.y * this.yTouchSpeed);\n                }\n                this._inputDragLastPos.copy(input.getTouchClientPos(0));\n            } else if (input.currentInputType === InputType.Mouse && input.getMouseButtonHeld(0)) {\n                if (rotateAllowed) {\n                    const delta = this._inputDragLastPos.clone().sub(input.getMouseClientPos());\n                    this._x += (delta.x * this.xMouseSpeed);\n                    this._y += (delta.y * this.yMouseSpeed);\n                }\n                this._inputDragLastPos.copy(input.getMouseClientPos());\n            }\n        }\n    }\n\n    private _zoomControls(): void {\n        if (!this.inputEnabled) {\n            return;\n        }\n        if (!this._zoomEnabled) {\n            return;\n        }\n\n        const input = APEngine.input;\n\n        let zoomDelta: number = 0;\n\n        if (input.currentInputType === InputType.Touch && input.getTouchCount() === 2) {\n            const posA = input.getTouchClientPos(0);\n            const posB = input.getTouchClientPos(1);\n            const distance = posA.distanceTo(posB);\n\n            if (input.getTouchDown(1)) {\n                // Pinch zoom start.\n                this._isZooming = true;\n                \n                // Calculate starting distance between the two touch points.\n                this._inputTouchZoomDist = distance;\n            } else {\n                zoomDelta = ((this._inputTouchZoomDist - distance) * this.zoomTouchSpeed);\n                this._inputTouchZoomDist = distance;\n            }\n        } else if (input.currentInputType === InputType.Mouse && input.getWheelMoved()) {\n            this._isZooming = true;\n            zoomDelta = (input.getWheelData().delta.y * this.zoomMouseSpeed);\n        } else {\n            this._isZooming = false;\n            this._inputTouchZoomDist = 0;\n        }\n\n        if (zoomDelta !== 0) {\n            this._zoomDistance = clamp(this._zoomDistance + zoomDelta, this.zoomMin, this.zoomMax);\n        }\n    }\n\n    private _updateCamera(): void {\n        this._x = clampDegAngle(this._x, this.xMinDeg, this.xMaxDeg);\n        this._y = clampDegAngle(this._y, this.yMinDeg, this.yMaxDeg);\n\n        if (this._camera) {\n            const position = pointOnSphere(\n                this.target, \n                this._zoomDistance, \n                new Vector2(\n                    this.invertY ? -this._y : this._y,\n                    this.invertX ? -this._x : this._x,\n                )\n            );\n            \n            this._camera.gameObject.position.copy(position);\n            this._camera.gameObject.lookAt(this.target);\n        }\n    }\n\n    onUpdate(): void {\n        super.onUpdate();\n        \n        if (!APEngine.isXREnabled() && !TransformTool.isMouseDown() && this.target) {\n            this._rotateControls();\n            this._zoomControls();\n            this._updateCamera();\n        }\n    }\n\n    onLateUpdate(): void {\n        super.onLateUpdate();\n    }\n\n    onDestroy(): void {\n        super.onDestroy();\n    }\n}","export interface IFlags {\n    [key: string]: boolean;\n}\n\n/**\n * An easy to use class for handling a simple collection of flags.\n * This is easier to setup than bitwise flags and uses Typescript to stay strongly typed.\n */\nexport class Flags<T extends IFlags> {\n    private _flags: T;\n\n    get flagCount(): number {\n        return Object.keys(this._flags).length;\n    }\n\n    constructor(initialFlags: T) {\n        this._flags = Object.create(initialFlags);\n        this._flags = Object.assign(this._flags, initialFlags);\n    }\n\n    /**\n     * Set wether or not the given flags are enabled.\n     * If no flags are given, all available flags are assumed.\n     */\n    set<K extends keyof T>(enabled: boolean, ...flags: K[]): void {\n        flags = this._internalGetFlags(flags);\n\n        for (const flag of flags) {\n            this._flags[flag] = enabled as T[K];\n        }\n    }\n\n    /**\n     * Return the name of the flag that sits at the given index.\n     */\n    flagFromIndex(index: number): keyof T | undefined { \n        const keys = Object.keys(this._flags);\n        if (index >= 0 && index < keys.length) {\n            return keys[index];\n        }\n        \n        console.error(`[Flags] Index ${index} is out of range (0 -> ${keys.length - 1})`);\n        return undefined;\n    }\n\n    /**\n     * Toggle the enabled state of the given flags. \n     * This will set flags that are true to false and flags that are false to true.\n     * If no flags are given, all available flags are assumed.\n     */\n    toggle<K extends keyof T>(...flags: K[]): void {\n        flags = this._internalGetFlags(flags);\n\n        for (const flag of flags) {\n            this._flags[flag] = !this._flags[flag] as T[K];\n        }\n    }\n\n    /**\n     * Will return true if one of the given flags is enabled.\n     * If no flags are given, all available flags are assumed.\n     */\n    some<K extends keyof T>(...flags: K[]): boolean {\n        flags = this._internalGetFlags(flags);\n        \n        for (const flag of flags) {\n            if (this._flags[flag]) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Will return true if all of the given flags are enabled.\n     * If no flags are given, all available flags are assumed.\n     */\n    every<K extends keyof T>(...flags: K[]): boolean {\n        flags = this._internalGetFlags(flags);\n\n        for (const flag of flags) {\n            if (!this._flags[flag]) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Will return true if none of the given flags are enabled.\n     * If no flags are given, all available flags are assumed.\n     */\n    not<K extends keyof T>(...flags: K[]): boolean {\n        flags = this._internalGetFlags(flags);\n\n        for (const flag of flags) {\n            if (this._flags[flag]) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    only<K extends keyof T>(...flags: K[]): boolean {\n        flags = this._internalGetFlags(flags);\n        const remainingFlags = new Set<keyof T>(Object.keys(this._flags));\n\n        // Check to make sure that the given flags are all enabled.\n        for (const flag of flags) {\n            if (this._flags[flag]) {\n                remainingFlags.delete(flag);\n            } else {\n                // One of the given flags is not enabled.\n                return false;\n            }\n        }\n\n        // Now make sure all of the remaining flags are set to false.\n        for (const flag of remainingFlags) {\n            if (this._flags[flag]) {\n                // One of the remaining flags is enabled.\n                return false;\n            }\n        }\n\n        // Only the given flags are enabled.\n        return true;\n    }\n\n    private _internalGetFlags<K extends keyof T>(flags: K[]): K[] {\n        if (!flags || flags.length === 0) { \n            // No flags were given, return all flags.\n            flags = Object.keys(this._flags) as K[];\n        }\n\n        return flags;\n    }\n\n    toString(): string {\n        return JSON.stringify(this._flags);\n    }\n}","import { IDisposable } from \"../misc/IDisposable\";\nimport { Flags } from \"../misc/Flags\";\n\nexport class TapCode implements IDisposable {\n\n    /**\n     * Debug flags for this tap code object.\n     */\n    debugFlags = new Flags({\n        inputEvents: false,\n        processing: false,\n    });\n\n    /**\n     * Wether or not this tap code be triggered by entering the code via the keyboard.\n     */\n    allowKeyboardEntry: boolean = false;\n    \n    private readonly _code: number[];\n    private readonly _codeStr: string;\n    private _codeEnteredCallback: (tapCode: TapCode) => void;\n    private _touchCount: number = 0;\n    private _codeQueue: number[] = [];\n\n    get code(): string { return this._codeStr; }\n\n    constructor(code: string, onCodeEntered: (tapCode: TapCode) => void) {\n        this._codeEnteredCallback = onCodeEntered;\n        this._codeStr = code;\n        this._code = [];\n\n        // Convert code string into array of numbers.\n        for (let i = 0; i < code.length; i++) {\n            const n = Number.parseInt(code[i]);\n            if (Number.isInteger(n)) {\n                if (n > 0 && n <= 5) {\n                     this._code.push(n);\n                } else {\n                    console.error(`[TapCode] ${n} must be in the range of 1 to 5.`);\n                }\n            } else {\n                console.error(`[TapCode] ${n} is not an integer. Tap code must be string of only integer numbers in the range of 1 to 5.`);\n            }\n        }\n        this._onKeyDown = this._onKeyDown.bind(this);\n        this._onTouchStart = this._onTouchStart.bind(this);\n        this._onTouchEnd = this._onTouchEnd.bind(this);\n\n        document.body.addEventListener('keydown', this._onKeyDown);\n        document.body.addEventListener('touchstart', this._onTouchStart);\n        document.body.addEventListener('touchend', this._onTouchEnd);\n    }\n\n    private _onKeyDown(event: KeyboardEvent): void {\n        if (!event.repeat && this.allowKeyboardEntry) {\n            switch (event.key) {\n                case '1': \n                    this._endTouch(1);\n                    break;\n                case '2':\n                    this._endTouch(2);\n                    break;\n                case '3':\n                    this._endTouch(3);\n                    break;\n                case '4':\n                    this._endTouch(4);\n                    break;\n                case '5':\n                    this._endTouch(5);\n                    break;\n            }\n        }\n    }\n\n    private _onTouchStart(event: TouchEvent): void {\n        this._touchCount = event.touches.length;\n\n        if (this.debugFlags.some('inputEvents')) {\n            console.log(`[TapCode] Touch began. count: ${this._touchCount}`);\n        }\n    }\n\n    private _onTouchEnd(event: TouchEvent): void {\n        if (event.touches.length < this._touchCount) {\n            if (this.debugFlags.some('inputEvents')) {\n                console.log(`[TapCode] Touch ended. count: ${this._touchCount}`);\n            }\n\n            this._endTouch(this._touchCount);\n            this._touchCount = 0;\n        }\n    }\n\n    private _endTouch(touchCount: number): void {\n        if (touchCount < 1) { \n            return;\n        }\n\n        this._codeQueue.push(touchCount);\n\n        if (this._codeQueue.length > this._code.length) {\n            this._codeQueue.splice(0, this._codeQueue.length - this._code.length);\n        }\n\n        if (this.debugFlags.some('processing')) {\n            console.log(`[TapCode] Code: ${this._codeStr} Current entry: ${JSON.stringify(this._codeQueue)}`);\n        }\n\n        if (this._codeQueue.length < this._code.length) {\n            // Not enough taps yet.\n            if (this.debugFlags.some('processing')) {\n\n            }\n            return;\n        }\n\n        for (let i = 0; i < this._codeQueue.length; i++) {\n            if (this._codeQueue[i] != this._code[i]) {\n                // Number doesn't match at this position yet.\n                return;\n            }\n        }\n\n        // Tap code success!\n        if (this.debugFlags.some('processing')) {\n            console.log(`[TapCode] ${this._codeStr} triggered!`);\n        }\n\n        this._codeQueue = [];\n        this._codeEnteredCallback(this);\n    }\n\n    dispose(): void {\n        this._codeEnteredCallback = null;\n\n        document.body.removeEventListener('keydown', this._onKeyDown);\n        document.body.removeEventListener('touchstart', this._onTouchStart);\n        document.body.removeEventListener('touchend', this._onTouchEnd);\n    }\n}","import { DeviceCamera } from '../DeviceCamera';\nimport { IDisposable } from '../../misc/IDisposable';\n\nexport interface IDeviceCameraReaderOptions {\n    deviceCamera: DeviceCamera\n}\n\nexport class DeviceCameraReader implements IDisposable {\n\n    private _deviceCamera: DeviceCamera;\n    private _canvas: HTMLCanvasElement;\n    private _running: boolean = false;\n    private _updateHandle: number;\n\n    get deviceCamera(): DeviceCamera { return this._deviceCamera };\n\n    get canvas(): HTMLCanvasElement { return this._canvas };\n\n    get running(): boolean { return this._running; };\n\n    constructor() {\n        this._canvas = document.createElement('canvas');\n\n        this._update = this._update.bind(this);\n    }\n\n    /**\n     * Start the camera reader with the given options.\n     */\n    start(options: IDeviceCameraReaderOptions): void {\n        if (this._running) {\n            throw new Error(`${this.constructor.name} is already running. Check 'running' property before calling start()`);\n        }\n        \n        this._deviceCamera = options.deviceCamera;\n        this._running = true;\n\n        this._updateHandle = requestAnimationFrame(this._update);\n    }\n\n    private _update(): void {\n        if (this._running && this._deviceCamera && this._deviceCamera.isPlaying()) {\n            const video = this._deviceCamera.getVideoElement();\n            this._canvas.width = video.videoWidth;\n            this._canvas.height = video.videoHeight;\n            const ctx = this._canvas.getContext('2d');\n            ctx.drawImage(video, 0, 0, this._canvas.width, this._canvas.height);\n\n            this.onRenderedToCanvas(this._canvas);\n        }\n\n        this._updateHandle = requestAnimationFrame(this._update);\n    }\n\n    protected onRenderedToCanvas(canvas: HTMLCanvasElement): void {\n        // Do nothing by default.\n    }\n\n    stop(): void {\n        this._deviceCamera = null;\n        this._running = false;\n\n        if (typeof this._updateHandle === 'number') {\n            cancelAnimationFrame(this._updateHandle);\n        }\n    }\n\n    dispose(): void {\n        this._deviceCamera = null;\n        this._canvas = null;\n    }\n}","import jsQR from 'jsqr';\nimport { ArgEvent } from '../../misc/Events';\nimport { IDeviceCameraReaderOptions, DeviceCameraReader } from './DeviceCameraReader';\n\nexport class DeviceCameraQRReader extends DeviceCameraReader {\n    /**\n     * Event that is invoked when a qr code is scanned.\n     */\n    onQRScanned: ArgEvent<string> = new ArgEvent();\n\n    constructor() {\n        super();\n    }\n\n    start(options: IDeviceCameraReaderOptions): void {\n        super.start(options);\n    }\n\n    protected onRenderedToCanvas(canvas: HTMLCanvasElement): void {\n        super.onRenderedToCanvas(canvas);\n\n        const ctx = canvas.getContext('2d');\n        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n        const code = jsQR(imageData.data, imageData.width, imageData.height, {\n            inversionAttempts: \"dontInvert\"\n        });\n\n        if (code) {\n            this.onQRScanned.invoke(code.data);\n        }\n    }\n    \n    stop(): void {\n        super.stop();\n    }\n\n    dispose(): void {\n        super.dispose();\n\n        this.onQRScanned.removeAllListeners();\n    }\n}","import { ArgEvent } from \"./Events\";\nimport { APEngine } from \"../APEngine\";\nimport isEqual from \"lodash/isEqual\";\nimport { IDisposable } from \"./IDisposable\";\n\nexport abstract class State<Id, Command> {\n    private _id: Id;\n    private _stateMachine: StateMachine<Id, Command>;\n\n    /**\n     * The id of the state.\n     */\n    get id(): Id { return this._id }\n\n    /**\n     * The state machine that the state belongs to.\n     */\n    get stateMachine(): StateMachine<Id, Command> { return this._stateMachine }\n\n    constructor(id: Id, stateMachine: StateMachine<Id, Command>) {\n        this._id = id;\n        this._stateMachine = stateMachine;\n    }\n\n    abstract onStateEnter(): void;\n    abstract onStateUpdate(): Command;\n    abstract onStateExit(): void;\n    abstract dispose(): void;\n}\n\ninterface ITransition<Id, Command> {\n    fromStateId: Id,\n    command: Command,\n    nextStateId: Id\n}\n\nexport class StateMachine<Id, Command> implements IDisposable {\n    /**\n     * Debug level for this state machine.  \n     * 0 = Disabled  \n     * 1 = State enter/exit  \n     * 2 = State command\n     * 3 = State update\n     */\n    debugLevel: number = 0;\n\n    private _name: string;\n    private _states: Map<Id, State<Id, Command>> = new Map();\n    private _transitions: ITransition<Id, Command>[] = [];\n    private _curState: State<Id, Command>;\n    private _changeStateId: Id;\n    private _lastStateUpdate: number;\n    private _active: boolean;\n    private _prevTransition: ITransition<Id, Command>;\n\n    /**\n     * The name of the state machine.\n     */\n    get name(): string { return this._name; } \n\n    /**\n     * The current state that the state machine is in.\n     */\n    get currentState(): State<Id, Command> { return this._curState; }\n\n    /**\n     * The previous transition used to get to the current state.\n     */\n    get previousTransition(): ITransition<Id, Command> { return this._prevTransition; }\n\n    onStateEnter: ArgEvent<Id> = new ArgEvent();\n    onStateExit: ArgEvent<Id> = new ArgEvent();\n\n    constructor(name: string) {\n        this._name = name;\n    }\n\n    /**\n     * Startup the state machine in the given state.\n     */\n    start(startingStateId: Id): void {\n        if (this._active) {\n            return;\n        }\n\n        this._active = true;\n\n        this._changeState(startingStateId);\n        this.update();\n    }\n\n    /**\n     * Pause updating the state machine.\n     */\n    pause(): void {\n        if (!this._active) {\n            return;\n        }\n\n        this._active = false;\n    }\n\n    /**\n     * Resume updating the state machine.\n     */\n    resume(): void {\n        if (this._active) {\n            return;\n        }\n\n        this._active = true;\n        this.update();\n    }\n\n    /**\n     * Add the given state to the state machine.\n     */\n    addState(state: State<Id, Command>): void {\n        if (this._active) {\n            throw new Error(`Cannot add states after the state machine has been started.`);\n        }\n\n        this._states.set(state.id, state);\n    }\n\n    /**\n     * Add the given transition to the state machine.\n     */\n    addStateTransition(fromStateId: Id, command: Command, nextStateId: Id): void {\n        if (this._active) {\n            throw new Error(`Cannot add state transitions after the state machine has been started.`);\n        }\n\n        const transition = { fromStateId, command, nextStateId };\n\n        if (!this._states.has(nextStateId)) {\n            throw new Error(`Can't add transition for State '${nextStateId}'. This state does not exist on the state machine.`);\n        }\n\n        const alreadyAdded: boolean = this._transitions.some(t => isEqual(t, transition));\n        if (!alreadyAdded) {\n            this._transitions.push(transition);\n        }\n    }\n\n    /**\n     * Return the state that is assigned the given state id.\n     */\n    getState(stateId: Id) {\n        return this._states.get(stateId);\n    }\n\n    /**\n     * Update the state machine. Should be called once per frame.\n     */\n    update(): void {\n        if (!this._active) {\n            return;\n        }\n\n        this._updateState();\n    }\n\n    /**\n     * Usually this state machine should be controlled with state transitions, but in some cases we may want to force a state change.\n     */\n    forceChangeState(stateId: Id): void {\n        this._changeState(stateId);\n    }\n\n    /**\n     * Dispose of the state machine.\n     */\n    dispose(): void {\n        for (const [id, state] of this._states) {\n            state.dispose();\n        }\n\n        this._active = false;\n        this._curState = null;\n        this._changeStateId = null;\n        this._lastStateUpdate = null;\n        this._transitions = [];\n        this._states = new Map();\n        this._prevTransition = null;\n\n        this.onStateEnter.removeAllListeners();\n        this.onStateExit.removeAllListeners();\n    }\n\n    private _changeState(stateId: Id): void {\n        this._changeStateId = stateId;\n        \n        // Set the last update frame to an invalid number so that the update state function is forced to run.\n        this._lastStateUpdate = -1;\n\n        // Run the update state function immediately to respond to change the state in the same frame.\n        this._updateState();\n    }\n\n    private _getTransition(command: Command): ITransition<Id, Command> {\n        if (!this._transitions) {\n            return null;\n        }\n\n        const transition = this._transitions.find(t => t.command === command && t.fromStateId === this._curState.id);\n\n        if (!transition) {\n            throw new Error(`[StateMachine::${this._name}] No transition found for State '${this._curState.id}' with command '${command}'`);\n        }\n\n        return transition;\n    }\n\n    private _updateState(): void {\n        if (this._lastStateUpdate === APEngine.time.frameCount) {\n            return;\n        }\n\n        this._lastStateUpdate = APEngine.time.frameCount;\n\n        if (this._changeStateId) {\n            if (this._curState) {\n                if (this.debugLevel >= 1) {\n                    console.log(`[StateMachine::${this._name}] ${this._curState.id} onStateExit. Frame: ${APEngine.time.frameCount}`);\n                }\n\n                this._curState.onStateExit();\n                this.onStateExit.invoke(this._curState.id);\n            }\n\n            this._curState = this._states.get(this._changeStateId);\n            if (this._curState) {\n                if (this.debugLevel >= 1) {\n                    console.log(`[StateMachine::${this._name}] ${this._curState.id} onStateEnter. Frame: ${APEngine.time.frameCount}`);\n                }\n\n                this._curState.onStateEnter();\n                this.onStateEnter.invoke(this._curState.id);\n            } else {\n                throw new Error(`[StateMachine::${this._name}] No State with Id ${this._changeStateId} found.`);\n            }\n\n            this._changeStateId = null;\n        }\n\n        if (this._curState) {\n            if (this.debugLevel >= 3) {\n                console.log(`[StateMachine::${this._name}] ${this._curState.id} onStateUpdate. Frame: ${APEngine.time.frameCount}`);\n            }\n\n            const command = this._curState.onStateUpdate();\n\n            if (command) {\n                const transition = this._getTransition(command);\n                this._prevTransition = transition;\n\n                if (this.debugLevel >= 2) {\n                    console.log(`[StateMachine::${this._name}] ${this._curState.id} Command: ${command}, NextStateId: ${transition.nextStateId}. Frame: ${APEngine.time.frameCount}`);\n                }\n\n                this._changeState(transition.nextStateId);\n            }\n        }\n    }\n}","import { ArgEvent } from '../misc/Events';\nimport isEqual from 'lodash/isEqual';\n\nexport interface IPropertyChangedEvent<T> {\n    newValue: T;\n    previousValue: T;\n}\n\n/**\n * Property Spectator is a simple wrapper object around any javascript value that has events for \n * when it is set/changed as well as polling function for changes.\n */\nexport class PropertySpectator<T> {\n    private _value: T = null;\n    private _prevValue: T = null;\n\n    /**\n     * Event invoked when the property value is changed.\n     */\n    onValueChanged: ArgEvent<IPropertyChangedEvent<T>> = new ArgEvent();\n    \n    constructor(value?: T) {\n        this._value = value;\n    }\n\n    /**\n     * The property's current value.\n     */\n    get value(): T {\n        return this._value;\n    }\n\n    set value(obj: T) {\n        if (!isEqual(this._value, obj)) {\n            this._prevValue = this._value;\n            this._value = obj;\n\n            this.onValueChanged.invoke({\n                newValue: this._value,\n                previousValue: this._prevValue\n            });\n        }\n    }\n\n    /**\n     * The property's previous value.\n     */\n    get previousValue(): T {\n        return this._prevValue;\n    }\n\n    /**\n     * Does the property currently have a value assigned.\n     */\n    get hasValue(): boolean {\n        return (this._value !== null && this._value !== undefined);\n    }\n}","import remove from 'lodash/remove';\nimport { MathUtils } from 'three';\nimport { getOptionalValue } from '../utils/MiscUtils';\n\n/**\n * This is a generic object pool class that can be extended from to implement a pool for\n * theoretically any type of object you would want.\n */\nexport abstract class ObjectPool<T> {\n    name: string;\n\n    /**\n     * Log a warning to the console when the pool empty, causing a new object to be generated during retrieve.\n     */\n    poolEmptyWarn: boolean;\n\n    private _pool: T[];\n\n    /**\n     * Simple map of objects that this pool is responsible for and has created.\n     * Used mostly to check that an object being placed back in the pool actually does belong here.\n     */\n    private _objectIds: Map<string, boolean>;\n\n    get poolSize(): number {\n        return this._pool.length;\n    }\n\n    constructor(name?: string, poolEmptyWarn?: boolean) {\n        this.name = getOptionalValue(name, `ObjectPool_${MathUtils.generateUUID()}`);\n        this.poolEmptyWarn = getOptionalValue(poolEmptyWarn, true);\n        this._objectIds = new Map<string, boolean>();\n    }\n\n    /**\n     * Initialize the pool of objects.\n     * @param startSize [Optional] How starting size of the object pool (Default is 5).\n     */\n    initializePool(startSize?: number): this {\n        if (this._pool) return;\n\n        startSize = startSize || 5;\n\n        this._pool = [];\n\n        for (let i = 0; i < startSize; i++) {\n            const obj = this.createPoolObject();\n            const id = this.getPoolObjectId(obj);\n            this._objectIds.set(id, true);\n\n            this._pool.push(obj);\n        }\n\n        return this;\n    }\n\n    /**\n     * Retrieve an object from the pool.\n     */\n    retrieve(): T {\n        if (!this._pool) {\n            this.initializePool();\n        }\n\n        let obj: T = null;\n\n        if (this._pool.length > 0) {\n            obj = this._pool[0];\n            remove(this._pool, o => o === obj);\n        } else {\n            if (this.poolEmptyWarn) {\n                console.warn(\n                    '[ObjectPool]',\n                    this.name,\n                    'ran out of objects in its pool, so it is generating another one.'\n                );\n            }\n            obj = this.createPoolObject();\n            const id = this.getPoolObjectId(obj);\n            this._objectIds.set(id, true);\n        }\n\n        this.onRetrieved(obj);\n\n        return obj;\n    }\n\n    /**\n     * Restore the object to the pool.\n     * @param obj\n     */\n    restore(obj: T): boolean {\n        if (!this._pool) {\n            console.warn(\n                \"[ObjectPool] Can't place object\",\n                obj,\n                'in pool',\n                this.name,\n                'because the pool was never initialized.'\n            );\n            return false;\n        }\n\n        const id = this.getPoolObjectId(obj);\n        if (!this._objectIds.has(id)) {\n            console.warn(\n                \"[ObjectPool] Can't place object\",\n                obj,\n                'in pool',\n                this.name,\n                'because it does not originate from it.'\n            );\n            return false;\n        }\n\n        this._pool.push(obj);\n        this.onRestored(obj);\n\n        return true;\n    }\n\n    /**\n     * Dispose of the pool and any objects it is holding on to.\n     */\n    dispose(): void {\n        if (this._pool) {\n            for (let i = this._pool.length - 1; i >= 0; i--) {\n                let obj = this._pool[i];\n                if (obj) {\n                    this.disposePoolObject(obj);\n                }\n\n                this._pool.splice(i, 1);\n            }\n        }\n\n        this._objectIds.clear();\n    }\n\n    /**\n     * Called when an object is retrieved from the pool.\n     * @param obj The object that was retrieved.\n     */\n    protected abstract onRetrieved(obj: T): void;\n\n    /**\n     * Called when an object is restored to the pool.\n     * @param obj The object that was restored.\n     */\n    protected abstract onRestored(obj: T): void;\n\n    /**\n     * Called to create a new object for the pool.\n     */\n    protected abstract createPoolObject(): T;\n\n    /**\n     * Called to retireve an unique id for the given object.\n     * @param obj The object to get an id for.\n     */\n    protected abstract getPoolObjectId(obj: T): string;\n\n    /**\n     * Called when the object is being disposed of.\n     * @param obj The object being disposed.\n     */\n    protected abstract disposePoolObject(obj: T): void;\n}","import { Object3D } from 'three';\nimport { APEAssetTracker } from '../resources/APEAssetTracker';\nimport { ObjectPool } from './ObjectPool';\n\nexport class Object3DPool extends ObjectPool<Object3D> {\n    private _sourceObject: Object3D;\n\n    constructor(\n        sourceObject: Object3D,\n        name?: string,\n        poolEmptyWarn?: boolean\n    ) {\n        super(name, poolEmptyWarn);\n\n        this._sourceObject = sourceObject.clone(true);\n        this._sourceObject.parent = null;\n\n        APEAssetTracker.track(this._sourceObject);\n    }\n\n    protected onRetrieved(obj: Object3D): void {\n        // Do nothing.\n    }\n\n    protected onRestored(obj: Object3D): void {\n        if (obj.parent) {\n            // Remove from its current parent.\n            obj.parent.remove(obj);\n            obj.parent = null;\n        }\n    }\n\n    protected createPoolObject(): Object3D {\n        const obj = this._sourceObject.clone(true);\n        APEAssetTracker.track(obj);\n\n        return obj;\n    }\n\n    protected getPoolObjectId(obj: Object3D): string {\n        return obj.uuid;\n    }\n\n    protected disposePoolObject(obj: Object3D): void {\n        APEAssetTracker.untrack(obj);\n    }\n}","\nimport { Resource, IResourceConfig } from './Resource';\nimport { IDisposable } from \"../misc/IDisposable\";\n\ntype ConfigType<T> = T extends Resource<any, infer P> ? P : never;\n\n/**\n * A Resource Manager is a generic class that manages any type of Resouce that it is created for.\n * Resource Managers load, track, retrieve, and dipose of any Resources assigned to it.\n */\nexport class ResourceManager<T extends Resource<any, IResourceConfig>> implements IDisposable {\n    private _resources = new Map<string, T>();\n    private _activator: { new(name: string, config: IResourceConfig): T };\n\n    constructor(resourceActivator: { new(name: string, config: any): T }) {\n        this._activator = resourceActivator;\n    }\n\n    add(name: string, config: ConfigType<T>): void {\n        if (!this._resources.has(name)) {\n            const resource = new this._activator(name, config);\n            this._resources.set(resource.name, resource);\n        }\n    }\n\n    unload(name: string) {\n        if (this._resources.has(name)) {\n            const resource = this._resources.get(name);\n            resource.unload();\n            this._resources.delete(name);\n        }\n    }\n\n    has(name: string): boolean {\n        return this._resources.has(name);\n    }\n\n    count(): number {\n        return this._resources.size;\n    }\n\n    async get(name: string): Promise<T> {\n        if (this._resources.has(name)) {\n            const resource = this._resources.get(name);\n            if (!resource.loaded) {\n                await resource.load();\n            }\n            return resource;\n        } else {\n            throw new Error(`Could not get resource: ${name}`);\n        }\n    }\n    \n    lookup(name: string): T {\n        return this._resources.get(name);\n    }\n\n    /**\n     * Returns the combined loading progress of all resources that are currently in this Resource Manager.\n     */\n    getLoadProgress(): Readonly<number> {\n        if (this._resources.size > 0) {\n            let pTotal = 0;\n\n            for (const [resourceName, resource] of this._resources) {\n                pTotal += resource.progress;\n            }\n            \n            return pTotal / this._resources.size;\n        } else {\n            return 1;\n        }\n    }\n\n    async preload(): Promise<void> {\n        if (this._resources.size > 0) {\n            const resources: Resource<any, any>[] = Array.from(this._resources.values());\n            await Promise.all(resources.map(r => r.load()));\n        }\n    }\n\n    /**\n     * Returns wether all Resources that are currently in this Resource Manager are loaded or not.\n     */\n    allLoaded(): boolean {\n        if (this._resources.size > 0) {\n            const resources: Resource<any, any>[] = Array.from(this._resources.values());\n            for (let resource of resources) {\n                if (!resource.loaded) {\n                    return false;\n                }\n            }\n            return true;\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * Returns a map of all resource names currenty in the resource manager and wether or not they are currently loaded.\n     */\n    loadState(): Map<string, boolean> {\n        const map = new Map<string, boolean>();\n\n        for (const [resourceName, resource] of this._resources) {\n            map.set(resourceName, resource.loaded);\n        }\n\n        return map;\n    }\n\n    dispose(): void {\n        this._resources.forEach((resource) => {\n            resource.dispose();\n        });\n\n        this._resources = new Map();\n    }\n}","import { IDisposable } from \"../misc/IDisposable\";\n\nexport interface IResourceConfig {\n}\n\n/**\n * Base class of all resource objects that are loaded by ResourceManagers.\n * Resource is a generic class that returns an internally loaded object/asset.\n * Classed that derive from Resource should specifify what the object being loaded is.\n */\nexport abstract class Resource<O, K extends IResourceConfig> implements IDisposable {\n    private _name: string = undefined;\n    private _loaded: boolean = false;\n    private _loadPromise: Promise<Resource<O, K>> = null;\n    private _object: O = null;\n\n    protected _progress: number = 0;\n\n    get name(): string {\n        return this._name;\n    }\n\n    get loaded(): boolean {\n        return this._loaded;\n    }\n\n    get progress(): number {\n        return this._progress;\n    }\n\n    get object(): O {\n        return this._object;\n    }\n\n    constructor(name: string, config: K) {\n        this._name = name;\n    }\n\n    async load(): Promise<Resource<O, K>> {\n        try {\n            if (!this._loaded) {\n                if (!this._loadPromise) {\n                    this._loadPromise = new Promise((resolve) => {\n                        this._loadObject().then((object) => {\n                            this._object = object;\n                            this._loaded = true;\n                            this._progress = 1;\n                            this._loadPromise = null;\n    \n                            resolve(this);\n                        });\n                    });\n                }\n\n                return this._loadPromise;\n            } else {\n                return this;\n            }\n        } catch(error) {\n            this._loaded = false;\n            this._progress = 0;\n            console.error(`Could not load resource ${this.name}.`);\n            console.error(error);\n        }\n    }\n\n    unload(): void {\n        if (this._object) {\n            this._unloadObject();\n        }\n        this._object = null;\n        this._progress = 0;\n    }\n\n    dispose(): void {\n        this.unload();\n    }\n\n    /**\n     * This function should be implemented by classed that derive from Resource\n     * to return a promise that for the Resource's given object type.\n     */\n    protected abstract _loadObject(): Promise<O>;\n\n    /**\n     * This function should be implemented by classed that derive from Resource\n     * to unload and release memory for the Resource's loaded object.\n     */\n    protected abstract _unloadObject(): void;\n}\n","import { Resource, IResourceConfig } from \"./Resource\";\nimport { getOptionalValue } from \"../utils/MiscUtils\";\nimport { Howl } from \"howler\";\n\nexport interface IAudioConfig extends IResourceConfig {\n    url: string,\n    loop?: boolean\n}\n\nexport class AudioResource extends Resource<Howl, IAudioConfig> {\n    private _url: string;\n    private _loop: boolean;\n\n    constructor(name: string, config: IAudioConfig) {\n        super(name, config);\n\n        this._url = config.url;\n        this._loop = getOptionalValue(config.loop, false);\n    }\n\n    protected _loadObject(): Promise<Howl> {\n        return new Promise<Howl>(((resolve: (value: Howl) => void, reject) => {\n            const howl = new Howl({\n                src: this._url,\n                loop: this._loop,\n                onload: () => {\n                    resolve(howl);\n                },\n                onloaderror: (soundId: number, error: any) => {\n                    reject(error);\n                }\n            });\n        }));\n    }\n\n    protected _unloadObject(): void {\n        this.object.unload();\n    }\n}","import { APEAssetTracker } from \"./APEAssetTracker\";\nimport { Object3D, AnimationClip } from \"three\";\nimport { IDisposable } from \"../misc/IDisposable\";\nimport { SkeletonUtils } from \"three/examples/jsm/utils/SkeletonUtils\";\n\nexport class GLTFPrefab implements IDisposable {\n    private _prefab: Object3D;\n    private _clips: AnimationClip[];\n\n    /**\n     * The GLTF object3d prefab object.\n     * It is NOT RECOMMENDED to use this in your scenes. \n     * If you want a clone of the prefab use the clone() function instead.\n     */\n    get prefab(): Object3D { return this._prefab; }\n\n    /**\n     * The animation clips for the GLTF model.\n     */\n    get clips(): AnimationClip[] { return this._clips; }\n\n    constructor(obj3d: Object3D, clips: AnimationClip[]) {\n        this._prefab = obj3d;\n        this._clips = clips;\n        APEAssetTracker.track(this._prefab);\n    }\n\n    /**\n     * Retrieve a clone of the Object3D.\n     * This will clone all Object3Ds and Materials on the prefab.\n     * \n     * If optional childObjectName is given then the returned clone is only of the specified child object and its children.\n     * If the given child object name is not found then an exception will be thrown.\n     * \n     * Returned object will have '(clone)' appened to its name.\n     */\n    clone(childObjectName?: string): Object3D {\n        if (childObjectName) {\n            const childObject = this.prefab.getObjectByName(childObjectName);\n            if (childObject) {\n                // const clone = childObject.clone();\n                const clone = SkeletonUtils.clone(childObject) as Object3D;\n                clone.name = `${clone.name} (clone)`;\n                return clone;\n            } else {\n                throw new Error(`Could not find child object named ${childObjectName} in the prefab ${this._prefab}`);\n            }\n        } else {\n            // const clone = this._prefab.clone();\n            const clone = SkeletonUtils.clone(this._prefab) as Object3D;\n            clone.name = `${clone.name} (clone)`;\n            return clone;\n        }\n    }\n\n    dispose(): void {\n        APEAssetTracker.untrack(this._prefab);\n    }\n}","import { Resource, IResourceConfig } from \"./Resource\";\nimport { Group, LoadingManager } from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader\";\nimport { DRACOLoader } from \"three/examples/jsm/loaders/DRACOLoader\";\nimport { getFilename, getExtension } from \"../utils/MiscUtils\";\nimport { GLTFPrefab } from \"./GLTFPrefab\";\n\nexport interface IGLTFConfig extends IResourceConfig {\n    gltfUrl: string;\n    binUrl?: string;\n    textureUrls?: GLTFTextureRedirect[] | string[];\n}\n\nexport interface GLTFTextureRedirect {\n    filename: string;\n    redirectUrl: string;\n}\n\nexport class GLTFResource extends Resource<GLTFPrefab, IGLTFConfig> {\n    private _gltfUrl: string;\n    private _binUrl?: string;\n    private _textureUrls?: GLTFTextureRedirect[] | string[];\n\n    private static _sentTextureUrlObsoleteWarning: boolean = false;\n    private static _dracoLoader: DRACOLoader = null;\n\n    constructor(name: string, config: IGLTFConfig) {\n        super(name, config);\n\n        this._gltfUrl = config.gltfUrl;\n        this._binUrl = config.binUrl;\n        this._textureUrls = config.textureUrls;\n    }\n\n    protected _loadObject(): Promise<GLTFPrefab> {\n        return new Promise<GLTFPrefab>((resolve: (value: GLTFPrefab) => void, reject) => {\n            const loadingManager = new LoadingManager();\n\n            loadingManager.setURLModifier((url): string => {\n                if (url.startsWith('data:')) {\n                    // Do not redirect data uris.\n                    return url;\n                }\n                if (url.startsWith('blob:')) {\n                    // Do not redirect blobs.\n                    return url;\n                }\n\n                // Redirect gltf relative url to CDN asset location.\n                const filename = getFilename(url);\n                const ext = getExtension(url);\n\n                if (filename === 'draco_wasm_wrapper.js' || filename === 'draco_decoder.wasm' || filename === 'draco_decoder.js') {\n                    // Do not redirect draco specific files.\n                    return url;\n                }\n\n                let redirectUrl: string = null;\n                \n                if (ext === 'gltf' || ext === 'glb') {\n                    redirectUrl = this._gltfUrl;\n                } else if (ext === 'bin') {\n                    if (this._binUrl) {\n                        redirectUrl = this._binUrl;\n                    }\n                } else {\n                    // Assume that url is for texture image.\n                    if (this._textureUrls) {\n                        if (isStringArray(this._textureUrls)) {\n                            if (!GLTFResource._sentTextureUrlObsoleteWarning) {\n                                console.warn(`[GLTFResource] WARNING! OBSOLETE! It is highly recommended that GLTFResource textureUrls be in GLTFTextureRedirect format and not a plain string array.\n                                The string array implementation was designed for a specific CDN use case and requires that filesnames match. This filename matching does \n                                not work if using local assets that are hashed at build time.\n                                `);\n\n                                GLTFResource._sentTextureUrlObsoleteWarning = true;\n                            }\n\n                            redirectUrl = this._textureUrls.find((textureUrl) => filename === getFilename(textureUrl));\n                        } else {\n                            const textureRedirect = this._textureUrls.find((tr) => filename === tr.filename);\n                            if (textureRedirect) {\n                                redirectUrl = textureRedirect.redirectUrl;\n                            }\n                        }\n                    }\n                }\n\n                if (!redirectUrl) {\n                    console.error(`[GLTFResource] ${this.name} could not find a redirect url for ${url}`);\n                }\n                \n                return redirectUrl;\n            });\n\n            const gltfLoader = new GLTFLoader(loadingManager);\n\n            if (!GLTFResource._dracoLoader) {\n                GLTFResource._dracoLoader = new DRACOLoader(loadingManager);\n                GLTFResource._dracoLoader.setDecoderPath('public/draco/');\n                GLTFResource._dracoLoader.setDecoderConfig({ type: 'js' });\n            }\n            gltfLoader.setDRACOLoader(GLTFResource._dracoLoader);\n\n            gltfLoader.load(\n                this._gltfUrl,\n                (gltf) => {\n                    const prefab = new GLTFPrefab(gltf.scene, gltf.animations);\n                    resolve(prefab);\n                },\n                (progressEvent) => {\n                    this._progress = progressEvent.loaded / progressEvent.total;\n                },\n                (errorEvent) => {\n                    console.error(`[GLTFResource] ${this.name} Error: ${errorEvent}`);\n                    reject(errorEvent);\n                }\n            );\n        });\n    }\n\n    protected _unloadObject(): void {\n        this.object.dispose();\n    }\n}\n\nfunction isStringArray(value: any): value is string[] {\n    if (value && Array.isArray(value) && value.length > 0) {\n        if (typeof value[0] === 'string') {\n            return true;\n        }\n    }\n\n    return false;\n}","import { Resource } from \"./Resource\";\nimport { Texture, TextureLoader, sRGBEncoding, TextureEncoding } from \"three\";\nimport { getOptionalValue } from \"../utils/MiscUtils\";\n\nexport interface ITextureConfig {\n    url: string;\n    encoding?: TextureEncoding;\n    flipY?: boolean;\n}\n\nexport class TextureResource extends Resource<Texture, ITextureConfig> {\n    private _url: string;\n    private _encoding: TextureEncoding;\n    private _flipY: boolean;\n\n    constructor(name: string, config: ITextureConfig) {\n        super(name, config);\n\n        this._url = config.url;\n        this._encoding = config.encoding;\n        this._flipY = getOptionalValue(this._flipY, true); // This is the defualt value as of ThreeJS r113\n    }\n\n    protected _loadObject(): Promise<Texture> {\n        return new Promise<Texture>(((resolve: (value: Texture) => void, reject) => {\n            const loader = new TextureLoader();\n            loader.load(\n                this._url, \n                (texture) => {\n                    if (this._encoding) {\n                        texture.encoding = this._encoding;\n                        texture.needsUpdate = true;\n                    }\n\n                    texture.flipY = this._flipY ? true : false;\n                    texture.needsUpdate = true;\n\n                    resolve(texture);\n                },\n                (progressEvent) => {\n                    this._progress = progressEvent.loaded / progressEvent.total;\n                },\n                (errorEvent) => {\n                    reject(errorEvent);\n                }\n            );\n        }));\n    }\n\n    protected _unloadObject(): void {\n        this.object.dispose();\n    }\n}","import { Resource } from \"./Resource\";\nimport { loadImage } from \"../utils/MiscUtils\";\n\nexport interface IImageConfig {\n    url: string\n}\n\nexport class ImageResource extends Resource<HTMLImageElement, IImageConfig> {\n    private _url: string;\n\n    constructor(name: string, config: IImageConfig) {\n        super(name, config);\n\n        this._url = config.url;\n    }\n\n    protected _loadObject(): Promise<HTMLImageElement> {\n        const onProgress = (event: ProgressEvent<EventTarget>) => {\n            this._progress = event.loaded / event.total;\n        } \n        return loadImage(this._url, onProgress);\n    }\n\n    protected _unloadObject(): void {\n    }\n}","export class ResourceProgress {\n    private _id: string;\n    private _weight: number;\n\n    get id(): string { return this._id; }\n    get weight(): number { return this._weight; }\n    \n    value: number = 0;\n\n    constructor(id: string, weight: number) {\n        this._id = id;\n        this._weight = weight;\n    }\n}\n\ninterface ResourceProgressConfig {\n    id: string;\n    weight: number;\n}\n\nexport class ResourceProgressMap {\n\n    private _progressMap = new Map<string, ResourceProgress>();\n\n    addProgressObject(config: ResourceProgressConfig): ResourceProgress {\n        let p = this._progressMap.get(config.id);\n        if (!p) {\n            p = new ResourceProgress(config.id, config.weight);\n            this._progressMap.set(config.id, p);\n        }\n\n        return p;\n    }\n\n    removeProgressObject(id: string): void {\n        this._progressMap.delete(id);\n    }\n\n    clearProgressObjects(): void {\n        this._progressMap = new Map();\n    }\n\n    calculateWeightedMean(): number {\n        if (this._progressMap.size === 0) {\n            return 0;\n        }\n\n        let pSum = 0;\n        let wSum = 0;\n\n        for (const [id, p] of this._progressMap) {\n            pSum += p.value * p.weight;\n            wSum += p.weight;\n        }\n\n        const mean = pSum / wSum;\n        return mean;\n    }\n\n}","/**\n * Easing functions from https://easings.net/\n */\n\nexport function easeInSine(x: number): number {\n    return 1 - Math.cos((x * Math.PI) / 2);\n}\n\nexport function easeOutSine(x: number): number {\n    return Math.sin((x * Math.PI) / 2);\n}\n\nexport function easeInOutSine(x: number): number {\n    return -(Math.cos(Math.PI * x) - 1) / 2;\n}\n\nexport function easeInCubic(x: number): number {\n    return x * x * x;\n}\n\nexport function easeOutCubic(x: number): number {\n    return 1 - Math.pow(1 - x, 3);\n}\n\nexport function easeInOutCubic(x: number): number {\n    return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;\n}\n\nexport function easeInQuint(x: number): number {\n    return x * x * x * x * x;\n}\n\nexport function easeOutQuint(x: number): number {\n    return 1 - Math.pow(1 - x, 5);\n}\n\nexport function easeInOutQuint(x: number): number {\n    return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;\n}\n\nexport function easeInCirc(x: number): number {\n    return 1 - Math.sqrt(1 - Math.pow(x, 2));\n}\n\nexport function easeOutCirc(x: number): number {\n    return Math.sqrt(1 - Math.pow(x - 1, 2));\n}\n\nexport function easeInOutCirc(x: number): number {\n    return x < 0.5\n        ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2\n        : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2;\n}\n\nexport function easeInElastic(x: number): number {\n    const c4 = (2 * Math.PI) / 3;\n\n    return x === 0\n        ? 0\n        : x === 1\n            ? 1\n            : -Math.pow(2, 10 * x - 10) * Math.sin((x * 10 - 10.75) * c4);\n}\n\nexport function easeOutElastic(x: number): number {\n    const c4 = (2 * Math.PI) / 3;\n\n    return x === 0\n        ? 0\n        : x === 1\n            ? 1\n            : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;\n}\n\nexport function easeInOutElastic(x: number): number {\n    const c5 = (2 * Math.PI) / 4.5;\n\n    return x === 0\n        ? 0\n        : x === 1\n            ? 1\n            : x < 0.5\n                ? -(Math.pow(2, 20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2\n                : (Math.pow(2, -20 * x + 10) * Math.sin((20 * x - 11.125) * c5)) / 2 + 1;\n}\n\nexport function easeInQuad(x: number): number {\n    return x * x;\n}\n\nexport function easeOutQuad(x: number): number {\n    return 1 - (1 - x) * (1 - x);\n}\n\nexport function easeInOutQuad(x: number): number {\n    return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;\n}\n\nexport function easeInQuart(x: number): number {\n    return x * x * x * x;\n}\n\nexport function easeOutQuart(x: number): number {\n    return 1 - Math.pow(1 - x, 4);\n}\n\nexport function easeInOutQuart(x: number): number {\n    return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;\n}\n\nexport function easeInExpo(x: number): number {\n    return x === 0 ? 0 : Math.pow(2, 10 * x - 10);\n}\n\nexport function easeOutExpo(x: number): number {\n    return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);\n}\n\nexport function easeInOutExpo(x: number): number {\n    return x === 0\n        ? 0\n        : x === 1\n            ? 1\n            : x < 0.5\n                ? Math.pow(2, 20 * x - 10) / 2\n                : (2 - Math.pow(2, -20 * x + 10)) / 2;\n}\n\nexport function easeInBack(x: number): number {\n    const c1 = 1.70158;\n    const c3 = c1 + 1;\n\n    return c3 * x * x * x - c1 * x * x;\n}\n\nexport function easeOutBack(x: number): number {\n    const c1 = 1.70158;\n    const c3 = c1 + 1;\n\n    return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);\n}\n\nexport function easeInOutBack(x: number): number {\n    const c1 = 1.70158;\n    const c2 = c1 * 1.525;\n\n    return x < 0.5\n        ? (Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2\n        : (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;\n}\n\nexport function easeInBounce(x: number): number {\n    return 1 - easeOutBounce(1 - x);\n}\n\nexport function easeOutBounce(x: number): number {\n    const n1 = 7.5625;\n    const d1 = 2.75;\n\n    if (x < 1 / d1) {\n        return n1 * x * x;\n    } else if (x < 2 / d1) {\n        return n1 * (x -= 1.5 / d1) * x + 0.75;\n    } else if (x < 2.5 / d1) {\n        return n1 * (x -= 2.25 / d1) * x + 0.9375;\n    } else {\n        return n1 * (x -= 2.625 / d1) * x + 0.984375;\n    }\n}\n\nexport function easeInOutBounce(x: number): number {\n    return x < 0.5\n        ? (1 - easeOutBounce(1 - 2 * x)) / 2\n        : (1 + easeOutBounce(2 * x - 1)) / 2;\n}","\n/**\n * Simple object that can mesaure the passage of time. \n * Useful for debugging code performance or simply getting elapsed time values.\n */\nexport class Stopwatch {\n\n    private _startTime: number = null;\n    private _stopTime: number = null;\n\n    /**\n     * Create a new Stopwatch with the start time set to time of creation.\n     */\n    constructor() {\n        this.start();\n    }\n\n    /**\n     * STart the stopwatch. Set's the start time to now.\n     */\n    start(): void {\n        this._startTime = Date.now();\n        this._stopTime = null;\n    }\n\n    /**\n     * Stop the stopwatch. Set's the stop time to now.\n     */\n    stop(): void {\n        this._stopTime = Date.now();\n    }\n\n    /**\n     * Reset the stopwatch. Clears both the start and stop time.\n     */\n    reset(): void {\n        this._startTime = null;\n        this._stopTime = null;\n    }\n\n    /**\n     * Return number of milliseconds that have elapsed.\n     */\n    elapsed(): number {\n        if (this._startTime) {\n            const endTime = this._stopTime ?? Date.now();\n            return endTime - this._startTime;\n        } else {\n            return 0;\n        }\n    }\n}"]}