UNPKG

363 kBSource Map (JSON)View Raw
1{"version":3,"file":"view3d.pkgd.min.js","sources":["../src/core/EventEmitter.ts","../src/core/Renderer.ts","../src/consts/internal.ts","../src/View3DError.ts","../src/consts/error.ts","../src/utils.ts","../src/consts/easing.ts","../src/core/Scene.ts","../src/consts/event.ts","../src/core/camera/Controller.ts","../src/core/camera/Pose.ts","../src/consts/default.ts","../src/controls/Motion.ts","../src/controls/AnimationControl.ts","../src/core/camera/Camera.ts","../src/core/ModelAnimator.ts","../src/core/XRManager.ts","../src/View3D.ts","../src/core/Model.ts","../src/controls/AutoControl.ts","../src/consts/css.ts","../src/controls/RotateControl.ts","../src/controls/TranslateControl.ts","../src/controls/DistanceControl.ts","../src/controls/OrbitControl.ts","../src/loaders/DracoLoader.ts","../src/environments/AutoDirectionalLight.ts","../src/environments/ShadowPlane.ts","../src/loaders/GLTFLoader.ts","../src/loaders/TextureLoader.ts","../src/consts/xr.ts","../src/controls/ar/floor/ARFloorTranslateControl.ts","../src/xr/features/DOMOverlay.ts","../src/xr/WebARSession.ts","../src/xr/features/HitTest.ts","../src/core/Animation.ts","../src/controls/ar/ui/RotationIndicator.ts","../src/controls/ar/common/ARSwirlControl.ts","../src/consts/touch.ts","../src/controls/ar/common/DeadzoneChecker.ts","../src/controls/ar/ui/ScaleUI.ts","../src/controls/ar/common/ARScaleControl.ts","../src/controls/ar/ui/FloorIndicator.ts","../src/controls/ar/common/ARSwipeControl.ts","../src/controls/ar/floor/ARFloorControl.ts","../src/xr/FloorARSession.ts","../src/controls/ar/ui/ArrowIndicator.ts","../src/controls/ar/wall/ARWallTranslateControl.ts","../src/controls/ar/wall/ARWallControl.ts","../src/xr/WallARSession.ts","../src/controls/ar/hover/ARHoverRotateControl.ts","../src/controls/ar/hover/ARHoverTranslateControl.ts","../src/controls/ar/hover/ARHoverControl.ts","../src/xr/HoverARSession.ts","../src/consts/browser.ts","../src/xr/SceneViewerSession.ts","../src/xr/QuickLookSession.ts","../src/extra/TextureModel.ts","../src/index.umd.ts"],"sourcesContent":["/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport { AnyFunction } from \"~/types/external\";\n\ntype NoArguments = undefined | null | void | never;\ntype EventMap = Record<string, any>;\ntype EventKey<T extends EventMap> = string & keyof T;\ntype EventCallback<T extends EventMap, K extends EventKey<T>>\n = T[K] extends NoArguments\n ? () => any\n : T[K] extends AnyFunction\n ? T[K]\n : (event: T[K]) => any;\n\nclass EventEmitter<T extends EventMap> {\n private _listenerMap: {\n [keys: string]: EventCallback<T, EventKey<T>>[],\n };\n\n constructor() {\n this._listenerMap = {};\n }\n\n public on<K extends EventKey<T>>(eventName: K, callback: EventCallback<T, K>): this {\n const listenerMap = this._listenerMap;\n const listeners = listenerMap[eventName];\n\n if (listeners && listeners.indexOf(callback) < 0) {\n listeners.push(callback);\n } else {\n listenerMap[eventName] = [callback];\n }\n return this;\n }\n\n public once<K extends EventKey<T>>(eventName: K, callback: EventCallback<T, K>): this {\n const listenerMap = this._listenerMap;\n const listeners = listenerMap[eventName];\n\n const onceCallback = (...params: any[]) => {\n callback(params);\n this.off(eventName, onceCallback as any);\n };\n\n if (listeners && listeners.indexOf(callback) < 0) {\n listeners.push(callback);\n } else {\n listenerMap[eventName] = [callback];\n }\n return this;\n }\n\n public off<K extends EventKey<T>>(eventName?: K, callback?: EventCallback<T, K>): this {\n const listenerMap = this._listenerMap;\n\n if (!eventName) {\n this._listenerMap = {};\n return this;\n }\n\n if (!callback) {\n delete listenerMap[eventName];\n return this;\n }\n\n const listeners = listenerMap[eventName];\n\n if (listeners) {\n const callbackIdx = listeners.indexOf(callback);\n if (callbackIdx >= 0) {\n listeners.splice(callbackIdx, 1);\n }\n }\n\n return this;\n }\n\n public emit<K extends EventKey<T>>(\n eventName: K,\n ...event: T[K] extends NoArguments ? void[] : T[K] extends AnyFunction ? Parameters<T[K]> : [T[K]]\n ): this {\n const listeners = this._listenerMap[eventName];\n\n if (listeners) {\n listeners.forEach(callback => {\n callback(...event);\n });\n }\n\n return this;\n }\n}\n\nexport default EventEmitter;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Scene from \"./Scene\";\nimport Camera from \"./camera/Camera\";\n\n/**\n * Renderer that renders View3D's Scene\n * @category Core\n */\nclass Renderer {\n private _renderer: THREE.WebGLRenderer;\n private _canvas: HTMLCanvasElement;\n private _clock: THREE.Clock;\n\n /**\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement HTMLCanvasElement} given when creating View3D instance\n * @type HTMLCanvasElement\n * @readonly\n */\n public get canvas() { return this._canvas; }\n /**\n * Current {@link https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext WebGLRenderingContext}\n * @type WebGLRenderingContext\n * @readonly\n */\n public get context() { return this._renderer.context; }\n /**\n * The width and height of the renderer's output canvas\n * @see https://threejs.org/docs/#api/en/math/Vector2\n * @type THREE.Vector2\n */\n public get size() { return this._renderer.getSize(new THREE.Vector2()); }\n /**\n * Three.js {@link https://threejs.org/docs/#api/en/renderers/WebGLRenderer WebGLRenderer} instance\n * @type THREE.WebGLRenderer\n * @readonly\n */\n public get threeRenderer() { return this._renderer; }\n\n public set size(val: THREE.Vector2) {\n this._renderer.setSize(val.x, val.y, false);\n }\n\n /**\n * Create new Renderer instance\n * @param canvas \\<canvas\\> element to render 3d model\n */\n constructor(canvas: HTMLCanvasElement) {\n this._canvas = canvas;\n\n this._renderer = new THREE.WebGLRenderer({\n canvas: this._canvas,\n alpha: true,\n antialias: true,\n preserveDrawingBuffer: true,\n });\n\n this._renderer.xr.enabled = true;\n\n this._renderer.outputEncoding = THREE.sRGBEncoding;\n\n this._clock = new THREE.Clock(false);\n this.enableShadow();\n }\n\n /**\n * Resize the renderer based on current canvas width / height\n * @returns {void} Nothing\n */\n public resize(): void {\n const renderer = this._renderer;\n const canvas = this._canvas;\n\n if (renderer.xr.isPresenting) return;\n\n renderer.setPixelRatio(window.devicePixelRatio);\n renderer.setSize(canvas.offsetWidth, canvas.offsetHeight, false);\n }\n\n /**\n * Render a scene using a camera.\n * @see https://threejs.org/docs/#api/en/renderers/WebGLRenderer.render\n * @param scene {@link Scene} to render\n * @param camera {@link Camera} to render\n */\n public render(scene: Scene, camera: Camera): void {\n this._renderer.render(scene.root, camera.threeCamera);\n }\n\n public setAnimationLoop(callback: (delta: number, frame?: any) => void): void {\n this._clock.start();\n this._renderer.setAnimationLoop((timestamp: number, frame: any) => {\n const delta = this._clock.getDelta();\n callback(delta, frame);\n });\n }\n\n public stopAnimationLoop(): void {\n this._clock.stop();\n // See https://threejs.org/docs/#api/en/renderers/WebGLRenderer.setAnimationLoop\n this._renderer.setAnimationLoop(null);\n }\n\n /**\n * Enable shadow map\n */\n public enableShadow() {\n const threeRenderer = this._renderer;\n\n threeRenderer.shadowMap.enabled = true;\n threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;\n }\n\n /**\n * Disable shadow map\n */\n public disableShadow() {\n const threeRenderer = this._renderer;\n\n threeRenderer.shadowMap.enabled = false;\n }\n}\n\nexport default Renderer;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\n// Constants that used internally\n\n// Texture map names that used in THREE#MeshStandardMaterial\nexport const STANDARD_MAPS = [\n \"alphaMap\",\n \"aoMap\",\n \"bumpMap\",\n \"displacementMap\",\n \"emissiveMap\",\n \"envMap\",\n \"lightMap\",\n \"map\",\n \"metalnessMap\",\n \"normalMap\",\n \"roughnessMap\",\n];\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nclass View3DError extends Error {\n constructor(\n public message: string,\n public code: number) {\n super(message);\n Object.setPrototypeOf(this, View3DError.prototype);\n this.name = \"View3DError\";\n }\n}\n\nexport default View3DError;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\n/**\n * Error codes of {@link View3DError}\n * @name ERROR_CODES\n * @memberof Constants\n * @type object\n * @property {number} WRONG_TYPE 0\n * @property {number} ELEMENT_NOT_FOUND 1\n * @property {number} CANVAS_NOT_FOUND 2\n * @property {number} WEBGL_NOT_SUPPORTED 3\n * @property {number} ADD_CONTROL_FIRST 4\n * @property {number} PROVIDE_WIDTH_OR_HEIGHT 5\n */\nexport const CODES: {\n [key in keyof typeof MESSAGES]: number;\n} = {\n WRONG_TYPE: 0,\n ELEMENT_NOT_FOUND: 1,\n ELEMENT_NOT_CANVAS: 2,\n WEBGL_NOT_SUPPORTED: 3,\n ADD_CONTROL_FIRST: 4,\n PROVIDE_WIDTH_OR_HEIGHT: 5,\n};\n\nexport const MESSAGES = {\n WRONG_TYPE: (val: any, types: string[]) => `${typeof val} is not a ${types.map(type => `\"${type}\"`).join(\" or \")}.`,\n ELEMENT_NOT_FOUND: (query: string) => `Element with selector \"${query}\" not found.`,\n ELEMENT_NOT_CANVAS: (el: HTMLElement) => `Given element <${el.tagName}> is not a canvas.`,\n WEBGL_NOT_SUPPORTED: \"WebGL is not supported on this browser.\",\n ADD_CONTROL_FIRST: \"Control is enabled before setting a target element.\",\n PROVIDE_WIDTH_OR_HEIGHT: \"Either width or height should be given.\",\n};\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport View3DError from \"./View3DError\";\nimport * as ERROR from \"~/consts/error\";\n\nexport function getElement(el: HTMLElement | string | null, parent?: HTMLElement): HTMLElement | null {\n let targetEl: HTMLElement | null = null;\n\n if (typeof el === \"string\") {\n const parentEl = parent ? parent : document;\n const queryResult = parentEl.querySelector(el);\n if (!queryResult) {\n throw new View3DError(ERROR.MESSAGES.ELEMENT_NOT_FOUND(el), ERROR.CODES.ELEMENT_NOT_FOUND);\n }\n targetEl = queryResult as HTMLElement;\n } else if (el && el.nodeType === Node.ELEMENT_NODE) {\n targetEl = el;\n }\n\n return targetEl;\n}\n\nexport function getCanvas(el: HTMLElement | string): HTMLCanvasElement {\n const targetEl = getElement(el);\n\n if (!targetEl) {\n throw new View3DError(ERROR.MESSAGES.WRONG_TYPE(el, [\"HTMLElement\", \"string\"]), ERROR.CODES.WRONG_TYPE);\n }\n\n if (!/^canvas$/i.test(targetEl.tagName)) {\n throw new View3DError(ERROR.MESSAGES.ELEMENT_NOT_CANVAS(targetEl), ERROR.CODES.ELEMENT_NOT_CANVAS);\n }\n\n return targetEl as HTMLCanvasElement;\n}\n\nexport function range(end: number): number[] {\n if (!end || end <= 0) {\n return [];\n }\n\n return Array.apply(0, Array(end)).map((undef, idx) => idx);\n}\n\nexport function toRadian(x: number) {\n return x * Math.PI / 180;\n}\n\nexport function clamp(x: number, min: number, max: number) {\n return Math.max(Math.min(x, max), min);\n}\n\nexport function findIndex<T>(target: T, list: T[]) {\n let index = -1;\n for (const itemIndex of range(list.length)) {\n if (list[itemIndex] === target) {\n index = itemIndex;\n break;\n }\n }\n return index;\n}\n\n// Linear interpolation between a and b\nexport function mix(a: number, b: number, t: number) {\n return a * (1 - t) + b * t;\n}\n\nexport function circulate(val: number, min: number, max: number) {\n const size = Math.abs(max - min);\n\n if (val < min) {\n const offset = (min - val) % size;\n val = max - offset;\n } else if (val > max) {\n const offset = (val - max) % size;\n val = min + offset;\n }\n\n return val;\n}\n\nexport function merge(target: object, ...srcs: object[]): object {\n srcs.forEach(source => {\n Object.keys(source).forEach(key => {\n const value = source[key];\n if (Array.isArray(target[key]) && Array.isArray(value)) {\n target[key] = [...target[key], ...value];\n } else {\n target[key] = value;\n }\n });\n });\n\n return target;\n}\n\nexport function getBoxPoints(box: THREE.Box3) {\n return [\n box.min.clone(),\n new THREE.Vector3(box.min.x, box.min.y, box.max.z),\n new THREE.Vector3(box.min.x, box.max.y, box.min.z),\n new THREE.Vector3(box.min.x, box.max.y, box.max.z),\n new THREE.Vector3(box.max.x, box.min.y, box.min.z),\n new THREE.Vector3(box.max.x, box.min.y, box.max.z),\n new THREE.Vector3(box.max.x, box.max.y, box.min.z),\n box.max.clone(),\n ];\n}\n\nexport function toPowerOfTwo(val: number) {\n let result = 1;\n\n while (result < val) {\n result *= 2;\n }\n\n return result;\n}\n\nexport function getPrimaryAxisIndex(basis: THREE.Vector3[], viewDir: THREE.Vector3) {\n let primaryIdx = 0;\n let maxDot = 0;\n\n basis.forEach((axes, axesIdx) => {\n const dotProduct = Math.abs(viewDir.dot(axes));\n\n if (dotProduct > maxDot) {\n primaryIdx = axesIdx;\n maxDot = dotProduct;\n }\n });\n\n return primaryIdx;\n}\n\n// In radian\nexport function getRotationAngle(center: THREE.Vector2, v1: THREE.Vector2, v2: THREE.Vector2) {\n const centerToV1 = new THREE.Vector2().subVectors(v1, center).normalize();\n const centerToV2 = new THREE.Vector2().subVectors(v2, center).normalize();\n\n // Get the rotation angle with the model's NDC coordinates as the center.\n const deg = centerToV2.angle() - centerToV1.angle();\n const compDeg = -Math.sign(deg) * (2 * Math.PI - Math.abs(deg));\n // Take the smaller deg\n const rotationAngle = Math.abs(deg) < Math.abs(compDeg) ? deg : compDeg;\n\n return rotationAngle;\n}\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\n/**\n * Collection of easing functions\n * @namespace EASING\n * @example\n * import View3D, { RotateControl, EASING } from \"@egjs/view3d\";\n *\n * new RotateControl({\n * easing: EASING.EASE_OUT_CUBIC,\n * });\n */\n\n/**\n * @memberof EASING\n * @name SINE_WAVE\n */\nexport const SINE_WAVE = (x: number) => Math.sin(x * Math.PI * 2);\n/**\n * @memberof EASING\n * @name EASE_OUT_CUBIC\n */\nexport const EASE_OUT_CUBIC = (x: number) => 1 - Math.pow(1 - x, 3);\n/**\n * @memberof EASING\n * @name EASE_OUT_BOUNCE\n */\nexport const EASE_OUT_BOUNCE = (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","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Model from \"./Model\";\nimport Environment from \"~/environments/Environment\";\nimport { STANDARD_MAPS } from \"~/consts/internal\";\nimport { findIndex } from \"~/utils\";\n\n/**\n * Scene that View3D will render.\n * All model datas including Mesh, Lights, etc. will be included on this\n * @category Core\n */\nclass Scene {\n private _root: THREE.Scene;\n private _userObjects: THREE.Group;\n private _envObjects: THREE.Group;\n private _envs: Environment[];\n\n /**\n * Root {@link https://threejs.org/docs/#api/en/scenes/Scene THREE.Scene} object\n */\n public get root() { return this._root; }\n\n /**\n * {@link Environment}s inside scene\n */\n public get environments() { return this._envs; }\n\n /**\n * Return the visibility of the root scene\n */\n public get visible() { return this._root.visible; }\n\n /**\n * Create new Scene instance\n */\n constructor() {\n this._root = new THREE.Scene();\n this._userObjects = new THREE.Group();\n this._envObjects = new THREE.Group();\n this._envs = [];\n\n const root = this._root;\n const userObjects = this._userObjects;\n const envObjects = this._envObjects;\n\n userObjects.name = \"userObjects\";\n envObjects.name = \"envObjects\";\n\n root.add(userObjects);\n root.add(envObjects);\n }\n\n /**\n * Update scene to fit the given model\n * @param model model to fit\n * @param override options for specific environments\n */\n public update(model: Model, override?: any): void {\n this._envs.forEach(env => env.fit(model, override));\n }\n\n /**\n * Reset scene to initial state\n * @returns {void} Nothing\n */\n public reset(): void {\n this.resetModel();\n this.resetEnv();\n }\n\n /**\n * Fully remove all objects that added by calling {@link Scene#add add()}\n * @returns {void} Nothing\n */\n public resetModel(): void {\n this._removeChildsOf(this._userObjects);\n }\n\n /**\n * Remove all objects that added by calling {@link Scene#addEnv addEnv()}\n * This will also reset scene background & envmap\n * @returns {void} Nothing\n */\n public resetEnv(): void {\n this._removeChildsOf(this._envObjects);\n this._envs = [];\n\n this._root.background = null;\n this._root.environment = null;\n }\n\n /**\n * Add new Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D} into the scene\n * @param object {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add\n * @returns {void} Nothing\n */\n public add(...object: THREE.Object3D[]): void {\n this._userObjects.add(...object);\n }\n\n /**\n * Add new {@link Environment} or Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D}s to the scene, which won't be removed after displaying another 3D model\n * @param envs {@link Environment} | {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add\n * @returns {void} Nothing\n */\n public addEnv(...envs: (Environment | THREE.Object3D)[]): void {\n envs.forEach(env => {\n if ((env as THREE.Object3D).isObject3D) {\n this._envObjects.add(env as THREE.Object3D);\n } else {\n this._envs.push(env as Environment);\n this._envObjects.add(...(env as Environment).objects);\n }\n });\n }\n\n /**\n * Remove Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D} into the scene\n * @param object {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add\n * @returns {void} Nothing\n */\n public remove(...object: THREE.Object3D[]): void {\n this._userObjects.remove(...object);\n }\n\n /**\n * Remove {@link Environment} or Three.js {@link https://threejs.org/docs/#api/en/core/Object3D Object3D}s to the scene, which won't be removed after displaying another 3D model\n * @param envs {@link Environment} | {@link https://threejs.org/docs/#api/en/core/Object3D THREE.Object3D}s to add\n * @returns {void} Nothing\n */\n public removeEnv(...envs: (Environment | THREE.Object3D)[]): void {\n envs.forEach(env => {\n if ((env as THREE.Object3D).isObject3D) {\n this._envObjects.remove(env as THREE.Object3D);\n } else {\n const envIndex = findIndex(env as Environment, this._envs);\n if (envIndex > -1) {\n this._envs.splice(envIndex, 1);\n }\n this._envObjects.remove(...(env as Environment).objects);\n }\n });\n }\n\n /**\n * Set background of the scene.\n * @see {@link https://threejs.org/docs/#api/en/scenes/Scene.background THREE.Scene.background}\n * @param background A texture to set as background\n * @returns {void} Nothing\n */\n public setBackground(background: THREE.Color | THREE.Texture | THREE.CubeTexture | THREE.WebGLCubeRenderTarget | null): void {\n // Three.js's type definition does not include WebGLCubeRenderTarget, but it works and defined on their document\n // See https://threejs.org/docs/#api/en/scenes/Scene.background\n this._root.background = background as THREE.Texture | null;\n }\n\n /**\n * Set scene's environment map that affects all physical materials in the scene\n * @see {@link https://threejs.org/docs/#api/en/scenes/Scene.environment THREE.Scene.environment}\n * @param envmap A texture to set as environment map\n * @returns {void} Nothing\n */\n public setEnvMap(envmap: THREE.Texture | THREE.CubeTexture | THREE.WebGLCubeRenderTarget | null): void {\n // Next line written to silence Three.js's warning\n const environment = (envmap as THREE.WebGLCubeRenderTarget).texture ? (envmap as THREE.WebGLCubeRenderTarget).texture : envmap;\n this._root.environment = environment as THREE.Texture | null;\n }\n\n /**\n * Make this scene visible\n * @returns {void} Nothing\n */\n public show(): void {\n this._root.visible = true;\n }\n\n /**\n * Make this scene invisible\n * @returns {void} Nothing\n */\n public hide(): void {\n this._root.visible = false;\n }\n\n private _removeChildsOf(obj: THREE.Object3D) {\n obj.traverse(child => {\n if ((child as any).isMesh) {\n const mesh = child as THREE.Mesh;\n\n // Release geometry & material memory\n mesh.geometry.dispose();\n const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];\n\n materials.forEach(mat => {\n STANDARD_MAPS.forEach(map => {\n if (mat[map]) {\n mat[map].dispose();\n }\n });\n });\n }\n });\n\n while (obj.children.length > 0) {\n obj.remove(obj.children[0]);\n }\n }\n}\n\nexport default Scene;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nexport const EVENTS = {\n MOUSE_DOWN: \"mousedown\",\n MOUSE_MOVE: \"mousemove\",\n MOUSE_UP: \"mouseup\",\n TOUCH_START: \"touchstart\",\n TOUCH_MOVE: \"touchmove\",\n TOUCH_END: \"touchend\",\n WHEEL: \"wheel\",\n RESIZE: \"resize\",\n CONTEXT_MENU: \"contextmenu\",\n MOUSE_ENTER: \"mouseenter\",\n MOUSE_LEAVE: \"mouseleave\",\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button\nexport enum MOUSE_BUTTON {\n LEFT,\n MIDDLE,\n RIGHT,\n}\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Camera from \"./Camera\";\nimport CameraControl from \"~/controls/CameraControl\";\nimport { findIndex } from \"~/utils\";\n\n/**\n * Controller that controls camera of the View3D\n * @category Core\n */\nclass Controller {\n private _canvas: HTMLCanvasElement;\n private _camera: Camera;\n private _controls: CameraControl[] = [];\n\n /**\n * {@link CameraControl CameraControl} instances that is added on this controller.\n */\n public get controls() { return this._controls; }\n\n /**\n * Create new Controller instance\n */\n constructor(canvas: HTMLCanvasElement, camera: Camera) {\n this._canvas = canvas;\n this._camera = camera;\n }\n\n /**\n * Remove all attached controls, and removes all event listeners attached by that controls.\n * @returns {void} Nothing\n */\n public clear(): void {\n this._controls.forEach(control => control.destroy());\n this._controls = [];\n }\n\n /**\n * Add a new control\n * @param control {@link CameraControl CameraControl} instance to add\n * @see Adding Controls\n * @returns {void} Nothing\n */\n public add(control: CameraControl): void {\n const canvas = this._canvas;\n if (!control.element) {\n // Set canvas as default element\n control.setElement(canvas);\n }\n control.sync(this._camera);\n control.enable();\n this._controls.push(control);\n }\n\n /**\n * Remove control and disable it\n * @param control {@link CameraControl CameraControl} instance to remove\n * @returns removed control or null if it doesn't exists\n */\n public remove(control: CameraControl): CameraControl | null {\n const controls = this._controls;\n const controlIndex = findIndex(control, controls);\n if (controlIndex < 0) return null;\n\n const removedControl = controls.splice(controlIndex, 1)[0];\n removedControl.disable();\n\n return removedControl;\n }\n\n /**\n * Enable all controls attached\n * @returns {void} Nothing\n */\n public enableAll(): void {\n this._controls.forEach(control => control.enable());\n this.syncToCamera();\n }\n\n /**\n * Disable all controls attached\n * @returns {void} Nothing\n */\n public disableAll(): void {\n this._controls.forEach(control => control.disable());\n }\n\n /**\n * Update all controls attached to given screen size.\n * @param size Size of the screen. Noramlly size of the canvas is used.\n * @returns {void} Nothing\n */\n public resize(size: THREE.Vector2): void {\n this._controls.forEach(control => control.resize(size));\n }\n\n /**\n * Synchronize all controls attached to current camera position.\n * @returns {void} Nothing\n */\n public syncToCamera(): void {\n this._controls.forEach(control => control.sync(this._camera));\n }\n\n /**\n * Update all controls attached to this controller & update camera position based on it.\n * @param delta number of seconds to update controls\n * @returns {void} Nothing\n */\n public update(delta: number): void {\n const deltaMiliSec = delta * 1000;\n const camera = this._camera;\n\n this._controls.forEach(control => {\n control.update(camera, deltaMiliSec);\n });\n\n camera.updatePosition();\n }\n}\n\nexport default Controller;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Data class of camera's pose\n */\nclass Pose {\n /**\n * Create new instance of pose\n * @param yaw yaw\n * @param pitch pitch\n * @param distance distance\n * @param pivot pivot\n * @see https://threejs.org/docs/#api/en/math/Vector3\n * @example\n * import { THREE, Pose } from \"@egjs/view3d\";\n *\n * const pose = new Pose(180, 45, 150, new THREE.Vector3(5, -1, 3));\n */\n constructor(\n public yaw: number,\n public pitch: number,\n public distance: number,\n public pivot: THREE.Vector3 = new THREE.Vector3(0, 0, 0),\n ) {}\n\n /**\n * Clone this pose\n * @returns Cloned pose\n */\n public clone(): Pose {\n return new Pose(\n this.yaw, this.pitch, this.distance,\n this.pivot.clone(),\n );\n }\n}\n\nexport default Pose;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Pose from \"~/core/camera/Pose\";\nimport { EASE_OUT_CUBIC } from \"./easing\";\nimport { Range } from \"~/types/internal\";\n\nexport const MODEL_SIZE = 80;\n\n// Animation related\nexport const EASING = EASE_OUT_CUBIC;\nexport const ANIMATION_DURATION = 500;\nexport const ANIMATION_LOOP = false;\nexport const ANIMATION_RANGE: Readonly<Range> = {\n min: 0, max: 1,\n};\n\n// Camera related\nexport const CAMERA_POSE: Readonly<Pose> = new Pose(0, 0, 100, new THREE.Vector3(0, 0, 0));\nexport const INFINITE_RANGE: Readonly<Range> = {\n min: -Infinity, max: Infinity,\n};\nexport const PITCH_RANGE: Readonly<Range> = {\n min: -89.9, max: 89.9,\n};\nexport const DISTANCE_RANGE: Readonly<Range> = {\n min: 0, max: 500,\n};\nexport const MINIMUM_DISTANCE = 1;\nexport const MAXIMUM_DISTANCE = 500;\nexport const NULL_ELEMENT: HTMLElement | string | null = null;\nexport const DRACO_DECODER_URL = \"https://www.gstatic.com/draco/v1/decoders/\";\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport { clamp, mix, circulate } from \"~/utils\";\nimport { Range } from \"~/types/internal\";\nimport * as DEFAULT from \"~/consts/default\";\n\nclass Motion {\n // Options\n private _duration: number;\n private _loop: boolean;\n private _range: Range;\n private _easing: (x: number) => number;\n\n // Internal states\n private _progress: number;\n private _val: number;\n private _start: number;\n private _end: number;\n private _activated: boolean;\n\n public get val() { return this._val; }\n public get start() { return this._start; }\n public get end() { return this._end; }\n public get progress() { return this._progress; }\n public get duration() { return this._duration; }\n public get loop() { return this._loop; }\n public get range() { return this._range; }\n public get easing() { return this._easing; }\n\n public set duration(val: number) { this._duration = val; }\n public set loop(val: boolean) { this._loop = val; }\n public set range(val: Range) { this._range = val; }\n public set easing(val: (x: number) => number) { this._easing = val; }\n\n constructor({\n duration = DEFAULT.ANIMATION_DURATION,\n loop = DEFAULT.ANIMATION_LOOP,\n range = DEFAULT.ANIMATION_RANGE,\n easing = DEFAULT.EASING,\n } = {}) {\n this._duration = duration;\n this._loop = loop;\n this._range = range;\n this._easing = easing;\n this._activated = false;\n this.reset(0);\n }\n\n /**\n * Update motion and progress it by given deltaTime\n * @param deltaTime number of milisec to update motion\n * @returns Difference(delta) of the value from the last update.\n */\n public update(deltaTime: number): number {\n if (!this._activated) return 0;\n\n const start = this._start;\n const end = this._end;\n const duration = this._duration;\n const prev = this._val;\n const loop = this._loop;\n\n const nextProgress = this._progress + deltaTime / duration;\n\n this._progress = loop\n ? circulate(nextProgress, 0, 1)\n : clamp(nextProgress, 0, 1);\n\n const easedProgress = this._easing(this._progress);\n this._val = mix(start, end, easedProgress);\n\n if (!loop && this._progress >= 1) {\n this._activated = false;\n }\n\n return this._val - prev;\n }\n\n public reset(defaultVal: number): void {\n const range = this._range;\n const val = clamp(defaultVal, range.min, range.max);\n this._start = val;\n this._end = val;\n this._val = val;\n this._progress = 0;\n this._activated = false;\n }\n\n public setEndDelta(delta: number): void {\n const range = this._range;\n\n this._start = this._val;\n this._end = clamp(this._end + delta, range.min, range.max);\n this._progress = 0;\n this._activated = true;\n }\n}\n\nexport default Motion;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport CameraControl from \"./CameraControl\";\nimport Motion from \"./Motion\";\nimport Camera from \"~/core/camera/Camera\";\nimport Pose from \"~/core/camera/Pose\";\nimport * as DEFAULT from \"~/consts/default\";\nimport { AnyFunction } from \"~/types/external\";\nimport { mix, circulate } from \"~/utils\";\n\n/**\n * Control that animates model without user input\n * @category Controls\n */\nclass AnimationControl implements CameraControl {\n // Options\n private _from: Pose;\n private _to: Pose;\n\n // Internal values\n private _motion: Motion;\n private _enabled: boolean = false;\n private _finishCallbacks: AnyFunction[] = [];\n\n public get element() { return null; }\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n /**\n * Duration of the animation\n */\n public get duration() { return this._motion.duration; }\n /**\n * Easing function of the animation\n */\n public get easing() { return this._motion.easing; }\n\n public set duration(val: number) { this._motion.duration = val; }\n public set easing(val: (x: number) => number) { this._motion.easing = val; }\n\n /**\n * Create new instance of AnimationControl\n * @param from Start pose\n * @param to End pose\n * @param {object} options Options\n * @param {number} [options.duration=500] Animation duration\n * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Animation easing function\n */\n constructor(from: Pose, to: Pose, {\n duration = DEFAULT.ANIMATION_DURATION,\n easing = DEFAULT.EASING,\n } = {}) {\n from = from.clone();\n to = to.clone();\n\n from.yaw = circulate(from.yaw, 0, 360);\n to.yaw = circulate(to.yaw, 0, 360);\n\n // Take the smaller degree\n if (Math.abs(to.yaw - from.yaw) > 180) {\n to.yaw = to.yaw < from.yaw\n ? to.yaw + 360\n : to.yaw - 360;\n }\n\n this._motion = new Motion({ duration, range: DEFAULT.ANIMATION_RANGE, easing });\n this._from = from;\n this._to = to;\n }\n\n /**\n * Destroy the instance and remove all event listeners attached\n * This also will reset CSS cursor to intial\n * @returns {void} Nothing\n */\n public destroy(): void {\n this.disable();\n }\n\n /**\n * Update control by given deltaTime\n * @param camera Camera to update position\n * @param deltaTime Number of milisec to update\n * @returns {void} Nothing\n */\n public update(camera: Camera, deltaTime: number): void {\n if (!this._enabled) return;\n\n const from = this._from;\n const to = this._to;\n const motion = this._motion;\n motion.update(deltaTime);\n\n // Progress that easing is applied\n const progress = motion.val;\n\n camera.yaw = mix(from.yaw, to.yaw, progress);\n camera.pitch = mix(from.pitch, to.pitch, progress);\n camera.distance = mix(from.distance, to.distance, progress);\n camera.pivot = from.pivot.clone().lerp(to.pivot, progress);\n\n if (motion.progress >= 1) {\n this.disable();\n this._finishCallbacks.forEach(callback => callback());\n }\n }\n\n /**\n * Enable this input and add event listeners\n * @returns {void} Nothing\n */\n public enable(): void {\n if (this._enabled) return;\n\n this._enabled = true;\n this._motion.reset(0);\n this._motion.setEndDelta(1);\n }\n\n /**\n * Disable this input and remove all event handlers\n * @returns {void} Nothing\n */\n public disable(): void {\n if (!this._enabled) return;\n\n this._enabled = false;\n }\n\n /**\n * Add callback which is called when animation is finished\n * @param callback Callback that will be called when animation finishes\n * @returns {void} Nothing\n */\n public onFinished(callback: AnyFunction): void {\n this._finishCallbacks.push(callback);\n }\n\n /**\n * Remove all onFinished callbacks\n * @returns {void} Nothing\n */\n public clearFinished(): void {\n this._finishCallbacks = [];\n }\n\n public resize(size: THREE.Vector2) {\n // DO NOTHING\n }\n\n public setElement(element: HTMLElement) {\n // DO NOTHING\n }\n\n public sync(camera: Camera): void {\n // Do nothing\n }\n}\n\nexport default AnimationControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Pose from \"./Pose\";\nimport Controller from \"./Controller\";\nimport AnimationControl from \"~/controls/AnimationControl\";\nimport { toRadian, clamp, circulate } from \"~/utils\";\nimport * as DEFAULT from \"~/consts/default\";\n\n/**\n * Camera that renders the scene of View3D\n * @category Core\n */\nclass Camera {\n private _threeCamera: THREE.PerspectiveCamera;\n private _controller: Controller;\n private _minDistance: number = DEFAULT.MINIMUM_DISTANCE;\n private _maxDistance: number = DEFAULT.MAXIMUM_DISTANCE;\n private _defaultPose: Pose = DEFAULT.CAMERA_POSE;\n private _currentPose: Pose = this._defaultPose.clone();\n\n /**\n * Three.js {@link https://threejs.org/docs/#api/en/cameras/PerspectiveCamera PerspectiveCamera} instance\n * @readonly\n * @type THREE.PerspectiveCamera\n */\n public get threeCamera() { return this._threeCamera; }\n\n /**\n * Controller of the camera\n * @readonly\n * @type Controller\n */\n public get controller() { return this._controller; }\n\n /**\n * Camera's default pose(yaw, pitch, distance, pivot)\n * This will be new currentPose when {@link Camera#reset reset()} is called\n * @readonly\n * @type Pose\n */\n public get defaultPose(): Readonly<Pose> { return this._defaultPose; }\n\n /**\n * Camera's current pose value\n * @readonly\n * @type Pose\n */\n public get currentPose(): Pose { return this._currentPose.clone(); }\n\n /**\n * Camera's current yaw\n * {@link Camera#updatePosition} should be called after changing this value, and normally it is called every frame.\n * @type number\n */\n public get yaw() { return this._currentPose.yaw; }\n\n /**\n * Camera's current pitch\n * {@link Camera#updatePosition} should be called after changing this value, and normally it is called every frame.\n * @type number\n */\n public get pitch() { return this._currentPose.pitch; }\n\n /**\n * Camera's current distance\n * {@link Camera#updatePosition} should be called after changing this value, and normally it is called every frame.\n * @type number\n */\n public get distance() { return this._currentPose.distance; }\n\n /**\n * Current pivot point of camera rotation\n * @readonly\n * @type THREE.Vector3\n * @see {@link https://threejs.org/docs/#api/en/math/Vector3 THREE#Vector3}\n */\n public get pivot() { return this._currentPose.pivot; }\n\n /**\n * Minimum distance from lookAtPosition\n * @type number\n * @example\n * import View3D from \"@egjs/view3d\";\n *\n * const view3d = new View3D(\"#view3d-canvas\");\n * view3d.camera.minDistance = 100;\n */\n public get minDistance() { return this._minDistance; }\n\n /**\n * Maximum distance from lookAtPosition\n * @type number\n * @example\n * import View3D from \"@egjs/view3d\";\n *\n * const view3d = new View3D(\"#view3d-canvas\");\n * view3d.camera.maxDistance = 400;\n */\n public get maxDistance() { return this._maxDistance; }\n\n /**\n * Camera's focus of view value\n * @type number\n * @see {@link https://threejs.org/docs/#api/en/cameras/PerspectiveCamera.fov THREE#PerspectiveCamera}\n */\n public get fov() { return this._threeCamera.fov; }\n\n /**\n * Camera's frustum width on current distance value\n * @type number\n */\n public get renderWidth() { return this.renderHeight * this._threeCamera.aspect; }\n\n /**\n * Camera's frustum height on current distance value\n * @type number\n */\n public get renderHeight() { return 2 * this.distance * Math.tan(toRadian(this.fov / 2)); }\n\n public set minDistance(val: number) { this._minDistance = val; }\n public set maxDistance(val: number) { this._maxDistance = val; }\n public set pose(val: Pose) {\n this._currentPose = val;\n this._controller.syncToCamera();\n }\n public set yaw(val: number) { this._currentPose.yaw = val; }\n public set pitch(val: number) { this._currentPose.pitch = val; }\n public set distance(val: number) { this._currentPose.distance = val; }\n public set pivot(val: THREE.Vector3) { this._currentPose.pivot = val; }\n\n public set fov(val: number) {\n this._threeCamera.fov = val;\n this._threeCamera.updateProjectionMatrix();\n }\n\n /**\n * Create new Camera instance\n * @param canvas \\<canvas\\> element to render 3d model\n */\n constructor(canvas: HTMLCanvasElement) {\n this._threeCamera = new THREE.PerspectiveCamera();\n this._controller = new Controller(canvas, this);\n }\n\n /**\n * Reset camera to default pose\n * @param duration Duration of the reset animation\n * @param easing Easing function for the reset animation\n * @returns Promise that resolves when the animation finishes\n */\n public reset(duration: number = 0, easing: (x: number) => number = DEFAULT.EASING): Promise<void> {\n const controller = this._controller;\n const currentPose = this._currentPose;\n const defaultPose = this._defaultPose;\n\n if (duration <= 0) {\n // Reset camera immediately\n this._currentPose = defaultPose.clone();\n\n controller.syncToCamera();\n\n return Promise.resolve();\n } else {\n // Add reset animation control to controller\n const resetControl = new AnimationControl(currentPose, defaultPose);\n resetControl.duration = duration;\n resetControl.easing = easing;\n\n return new Promise(resolve => {\n resetControl.onFinished(() => {\n controller.remove(resetControl);\n controller.syncToCamera();\n resolve();\n });\n\n controller.add(resetControl);\n });\n }\n }\n\n /**\n * Update camera's aspect to given size\n * @param size {@link THREE.Vector2} instance that has width(x), height(y)\n * @returns {void} Nothing\n */\n public resize(size: THREE.Vector2): void {\n const cam = this._threeCamera;\n const aspect = size.x / size.y;\n\n cam.aspect = aspect;\n cam.updateProjectionMatrix();\n\n this._controller.resize(size);\n }\n\n /**\n * Set default position of camera relative to the 3d model\n * New default pose will be used when {@link Camera#reset reset()} is called\n * @param newDefaultPose new default pose to apply\n * @returns {void} Nothing\n */\n public setDefaultPose(newDefaultPose: Partial<{\n yaw: number,\n pitch: number,\n distance: number,\n pivot: THREE.Vector3,\n }>): void {\n const defaultPose = this._defaultPose;\n const { yaw, pitch, distance, pivot } = newDefaultPose;\n\n if (yaw != null) {\n defaultPose.yaw = yaw;\n }\n if (pitch != null) {\n defaultPose.pitch = pitch;\n }\n if (distance != null) {\n defaultPose.distance = distance;\n }\n if (pivot != null) {\n defaultPose.pivot = pivot;\n }\n }\n\n /**\n * Update camera position base on the {@link Camera#currentPose currentPose} value\n * @returns {void} Nothing\n */\n public updatePosition(): void {\n this._clampCurrentPose();\n\n const threeCamera = this._threeCamera;\n const pose = this._currentPose;\n\n const yaw = toRadian(pose.yaw);\n const pitch = toRadian(pose.pitch);\n // Should use minimum distance to prevent distance becomes 0, which makes whole x,y,z to 0 regardless of pose\n const distance = Math.max(pose.distance + this._minDistance, DEFAULT.MINIMUM_DISTANCE);\n\n const newCamPos = new THREE.Vector3(0, 0, 0);\n newCamPos.y = distance * Math.sin(pitch);\n newCamPos.z = distance * Math.cos(pitch);\n\n newCamPos.x = newCamPos.z * Math.sin(-yaw);\n newCamPos.z = newCamPos.z * Math.cos(-yaw);\n\n newCamPos.add(pose.pivot);\n\n threeCamera.position.copy(newCamPos);\n threeCamera.lookAt(pose.pivot);\n threeCamera.updateProjectionMatrix();\n }\n\n private _clampCurrentPose() {\n const currentPose = this._currentPose;\n\n currentPose.yaw = circulate(currentPose.yaw, 0, 360);\n currentPose.pitch = clamp(currentPose.pitch, DEFAULT.PITCH_RANGE.min, DEFAULT.PITCH_RANGE.max);\n currentPose.distance = clamp(currentPose.distance, this._minDistance, this._maxDistance);\n }\n}\n\nexport default Camera;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Component that manages animations of the 3D Model\n * @category Core\n */\nclass ModelAnimator {\n private _mixer: THREE.AnimationMixer;\n private _clips: THREE.AnimationClip[];\n private _actions: THREE.AnimationAction[];\n\n /**\n * Three.js {@link https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip}s that stored\n * @type THREE.AnimationClip\n * @readonly\n */\n public get clips() { return this._clips; }\n\n /**\n * {@link https://threejs.org/docs/index.html#api/en/animation/AnimationMixer THREE.AnimationMixer} instance\n * @type THREE.AnimationMixer\n * @readonly\n */\n public get mixer() { return this._mixer; }\n\n /**\n * Create new ModelAnimator instance\n * @param scene {@link https://threejs.org/docs/index.html#api/en/scenes/Scene THREE.Scene} instance that is root of all 3d objects\n */\n constructor(scene: THREE.Scene) {\n this._mixer = new THREE.AnimationMixer(scene);\n this._clips = [];\n this._actions = [];\n }\n\n /**\n * Store the given clips\n * @param clips Three.js {@link https://threejs.org/docs/#api/en/animation/AnimationClip AnimationClip}s of the model\n * @returns {void} Nothing\n * @example\n * // After loading model\n * view3d.animator.setClips(model.animations);\n */\n public setClips(clips: THREE.AnimationClip[]): void {\n const mixer = this._mixer;\n this._clips = clips;\n this._actions = clips.map(clip => mixer.clipAction(clip));\n }\n\n /**\n * Play one of the model's animation\n * @param index Index of the animation to play\n * @returns {void} Nothing\n */\n public play(index: number): void {\n const action = this._actions[index];\n\n if (action) {\n action.play();\n }\n }\n\n /**\n * Pause one of the model's animation\n * If you want to stop animation completely, you should call {@link ModelAnimator#stop stop} instead\n * You should call {@link ModelAnimator#resume resume} to resume animation\n * @param index Index of the animation to pause\n * @returns {void} Nothing\n */\n public pause(index: number): void {\n const action = this._actions[index];\n\n if (action) {\n action.timeScale = 0;\n }\n }\n\n /**\n * Resume one of the model's animation\n * This will play animation from the point when the animation is paused\n * @param index Index of the animation to resume\n * @returns {void} Nothing\n */\n public resume(index: number): void {\n const action = this._actions[index];\n\n if (action) {\n action.timeScale = 1;\n }\n }\n\n /**\n * Fully stops one of the model's animation\n * @param index Index of the animation to stop\n * @returns {void} Nothing\n */\n public stop(index: number): void {\n const action = this._actions[index];\n\n if (action) {\n action.stop();\n }\n }\n\n /**\n * Update animations\n * @param delta number of seconds to play animations attached\n * @returns {void} Nothing\n */\n public update(delta: number): void {\n this._mixer.update(delta);\n }\n\n /**\n * Reset the instance and remove all cached animation clips attached to it\n * @returns {void} Nothing\n */\n public reset(): void {\n const mixer = this._mixer;\n\n mixer.uncacheRoot(mixer.getRoot());\n\n this._clips = [];\n this._actions = [];\n }\n}\n\nexport default ModelAnimator;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport View3D from \"~/View3D\";\nimport XRSession from \"../xr/XRSession\";\nimport WebARSession from \"../xr/WebARSession\";\n\n/**\n * XRManager that manages XRSessions\n * @category Core\n */\nclass XRManager {\n private _view3d: View3D;\n private _sessions: XRSession[];\n private _currentSession: XRSession | null;\n\n /**\n * Array of {@link XRSession}s added\n */\n public get sessions() { return this._sessions; }\n /**\n * Current entry session. Note that only WebXR type session can be returned.\n */\n public get currentSession() { return this._currentSession; }\n\n /**\n * Create a new instance of the XRManager\n * @param view3d Instance of the View3D\n */\n constructor(view3d: View3D) {\n this._view3d = view3d;\n this._sessions = [];\n this._currentSession = null;\n }\n\n /**\n * Return a Promise containing whether any of the added session is available\n */\n public async isAvailable(): Promise<boolean> {\n const results = await Promise.all(this._sessions.map(session => session.isAvailable()));\n\n return results.some(result => result === true);\n }\n\n /**\n * Add new {@link XRSession}.\n * The XRSession's order added is the same as the order of entry.\n * @param xrSession XRSession to add\n */\n public addSession(...xrSession: XRSession[]) {\n this._sessions.push(...xrSession);\n }\n\n /**\n * Enter XR Session.\n */\n public async enter(): Promise<void> {\n return this._enterSession(0, []);\n }\n\n /**\n * Exit current XR Session.\n */\n public exit() {\n if (this._currentSession) {\n this._currentSession.exit(this._view3d);\n this._currentSession = null;\n }\n }\n\n private async _enterSession(sessionIdx: number, errors: any[]) {\n const view3d = this._view3d;\n const sessions = this._sessions;\n\n if (sessionIdx >= sessions.length) {\n if (errors.length < 1) {\n errors.push(new Error(\"No sessions available\"));\n }\n return Promise.reject(errors);\n }\n\n const xrSession = sessions[sessionIdx];\n const isSessionAvailable = await xrSession.isAvailable();\n if (!isSessionAvailable) {\n return this._enterSession(sessionIdx + 1, errors);\n }\n\n return await xrSession.enter(view3d).then(() => {\n if (xrSession.isWebXRSession) {\n // Non-webxr sessions are ignored\n this._currentSession = xrSession;\n (xrSession as WebARSession).session.addEventListener(\"end\", () => {\n this._currentSession = null;\n });\n }\n return errors;\n }).catch(e => {\n errors.push(e);\n return this._enterSession(sessionIdx + 1, errors);\n });\n }\n}\n\nexport default XRManager;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport EventEmitter from \"./core/EventEmitter\";\nimport Renderer from \"./core/Renderer\";\nimport Scene from \"./core/Scene\";\nimport Camera from \"./core/camera/Camera\";\nimport Model from \"./core/Model\";\nimport ModelAnimator from \"./core/ModelAnimator\";\nimport XRManager from \"./core/XRManager\";\nimport { EVENTS } from \"./consts/event\";\nimport * as DEFAULT from \"./consts/default\";\nimport { getCanvas } from \"./utils\";\n\n/**\n * Yet another 3d model viewer\n * @category Core\n * @mermaid\n * classDiagram\n * class View3D\n * View3D *-- Camera\n * View3D *-- Renderer\n * View3D *-- Scene\n * View3D *-- ModelAnimator\n * Camera *-- Controller\n * @event resize\n * @event beforeRender\n * @event afterRender\n */\nclass View3D extends EventEmitter<{\n resize: {\n width: number;\n height: number;\n target: View3D;\n };\n beforeRender: View3D;\n afterRender: View3D;\n}> {\n /**\n * Current version of the View3D\n */\n public static VERSION: string = \"#__VERSION__#\";\n\n private _model: Model | null;\n private _renderer: Renderer;\n private _scene: Scene;\n private _camera: Camera;\n private _animator: ModelAnimator;\n private _xr: XRManager;\n\n /**\n * {@link Renderer} instance of the View3D\n * @type {Renderer}\n */\n public get renderer() { return this._renderer; }\n /**\n * {@link Scene} instance of the View3D\n * @type {Scene}\n */\n public get scene() { return this._scene; }\n /**\n * {@link Camera} instance of the View3D\n * @type {Camera}\n */\n public get camera() { return this._camera; }\n /**\n * {@link Controller} instance of the Camera\n * @type {Controller}\n */\n public get controller() { return this._camera.controller; }\n /**\n * {@link ModelAnimator} instance of the View3D\n * @type {ModelAnimator}\n */\n public get animator() { return this._animator; }\n /**\n * {@link XRManager} instance of the View3D\n * @type {XRManager}\n */\n public get xr() { return this._xr; }\n /**\n * {@link Model} that View3D is currently showing\n * @type {Model|null}\n */\n public get model() { return this._model; }\n\n /**\n * Creates new View3D instance\n * @example\n * import View3D, { ERROR_CODES } from \"@egjs/view3d\";\n *\n * try {\n * const view3d = new View3D(\"#wrapper\")\n * } catch (e) {\n * if (e.code === ERROR_CODES.ELEMENT_NOT_FOUND) {\n * console.error(\"Element not found\")\n * }\n * }\n * @throws {View3DError} `CODES.WRONG_TYPE`<br/>When the parameter is not either string or the canvas element.\n * @throws {View3DError} `CODES.ELEMENT_NOT_FOUND`<br/>When the element with given query does not exist.\n * @throws {View3DError} `CODES.ELEMENT_NOT_CANVAS`<br/>When the element given is not a \\<canvas\\> element.\n * @throws {View3DError} `CODES.WEBGL_NOT_SUPPORTED`<br/>When browser does not support WebGL.\n * @see Model\n * @see Camera\n * @see Renderer\n * @see Scene\n * @see Controller\n * @see XRManager\n */\n constructor(el: string | HTMLCanvasElement) {\n super();\n const canvas = getCanvas(el);\n\n this._renderer = new Renderer(canvas);\n this._camera = new Camera(canvas);\n this._scene = new Scene();\n this._animator = new ModelAnimator(this._scene.root);\n this._xr = new XRManager(this);\n this._model = null;\n\n this.resize();\n\n window.addEventListener(EVENTS.RESIZE, this.resize);\n }\n\n /**\n * Destroy View3D instance and remove all events attached to it\n * @returns {void} Nothing\n */\n public destroy(): void {\n this._scene.reset();\n this.controller.clear();\n this._model = null;\n\n window.removeEventListener(EVENTS.RESIZE, this.resize);\n }\n\n /**\n * Resize View3D instance to fit current canvas size\n * @method\n * @returns {void} Nothing\n */\n public resize = (): void => {\n this._renderer.resize();\n\n const newSize = this._renderer.size;\n this._camera.resize(newSize);\n\n this.emit(\"resize\", { ...newSize, target: this });\n }\n\n /**\n * Display the given model.\n * This method will remove the current displaying model, and reset the camera & control to default position.\n * View3D can only show one model at a time\n * @param model {@link Model} instance to show\n * @param {object} [options={}] Display options\n * @param {number} [options.applySize=true] Whether to change model size to given \"size\" option.\n * @param {number} [options.size=80] Size of the model to show as.\n * @param {boolean} [options.resetView=true] Whether to reset the view to the camera's default pose.\n * @returns {void} Nothing\n */\n public display(model: Model, {\n applySize = true,\n size = DEFAULT.MODEL_SIZE,\n resetView = true,\n } = {}): void {\n const renderer = this._renderer;\n const scene = this._scene;\n const camera = this._camera;\n const animator = this._animator;\n\n if (applySize) {\n model.size = size;\n }\n // model.moveToOrigin();\n\n scene.resetModel();\n\n if (resetView) {\n camera.reset();\n }\n\n animator.reset();\n\n this._model = model;\n\n scene.add(model.scene);\n animator.setClips(model.animations);\n\n scene.update(model);\n\n renderer.stopAnimationLoop();\n renderer.setAnimationLoop(this.renderLoop);\n }\n\n /**\n * View3D's basic render loop function\n * @param delta Number of seconds passed since last frame\n */\n public renderLoop = (delta: number) => {\n const renderer = this._renderer;\n const scene = this._scene;\n const camera = this._camera;\n const controller = this.controller;\n const animator = this._animator;\n\n animator.update(delta);\n controller.update(delta);\n\n this.emit(\"beforeRender\", this);\n renderer.render(scene, camera);\n this.emit(\"afterRender\", this);\n }\n}\n\nexport default View3D;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Data class for loaded 3d model\n * @category Core\n */\nclass Model {\n private _scene: THREE.Group;\n private _animations: THREE.AnimationClip[];\n private _initialBbox: THREE.Box3;\n private _originalSize: number;\n private _cachedLights: THREE.Light[] | null;\n private _cachedMeshes: THREE.Mesh[] | null;\n private _fixSkinnedBbox: boolean;\n\n /**\n * Scene of the model, see {@link https://threejs.org/docs/#api/en/objects/Group THREE.Group}\n * @readonly\n */\n public get scene() { return this._scene; }\n /**\n * {@link https://threejs.org/docs/#api/en/animation/AnimationClip THREE.AnimationClip}s inside model\n */\n public get animations() { return this._animations; }\n /***\n * {@link https://threejs.org/docs/#api/en/lights/Light THREE.Light}s inside model if there's any.\n * @readonly\n */\n public get lights() {\n return this._cachedLights ? this._cachedLights : this._getAllLights();\n }\n /**\n * {@link https://threejs.org/docs/#api/en/objects/Mesh THREE.Mesh}es inside model if there's any.\n * @readonly\n */\n public get meshes() {\n return this._cachedMeshes ? this._cachedMeshes : this._getAllMeshes();\n }\n /**\n * Get a copy of model's current bounding box\n * @type THREE#Box3\n * @see https://threejs.org/docs/#api/en/math/Box3\n */\n public get bbox() {\n return this._getTransformedBbox();\n }\n /**\n * Get a copy of model's initial bounding box without transform\n */\n public get initialBbox() {\n return this._initialBbox.clone();\n }\n /**\n * Model's bounding box size\n * Changing this will scale the model.\n * @type number\n * @example\n * import { GLTFLoader } from \"@egjs/view3d\";\n * new GLTFLoader().load(URL_TO_GLTF)\n * .then(model => {\n * model.size = 100;\n * })\n */\n public get size() {\n return this._getTransformedBbox().getSize(new THREE.Vector3()).length();\n }\n\n /**\n * Whether to apply inference from skeleton when calculating bounding box\n * This can fix some models with skinned mesh when it has wrong bounding box\n * @type boolean\n */\n public get fixSkinnedBbox() { return this._fixSkinnedBbox; }\n\n /**\n * Return the model's original bbox size before applying any transform\n * @type number\n */\n public get originalSize() { return this._originalSize; }\n\n /**\n * Whether the model's meshes gets rendered into shadow map\n * @type boolean\n * @example\n * model.castShadow = true;\n */\n public set castShadow(val: boolean) {\n const meshes = this.meshes;\n meshes.forEach(mesh => mesh.castShadow = val);\n }\n\n /**\n * Whether the model's mesh materials receive shadows\n * @type boolean\n * @example\n * model.receiveShadow = true;\n */\n public set receiveShadow(val: boolean) {\n const meshes = this.meshes;\n meshes.forEach(mesh => mesh.receiveShadow = val);\n }\n\n public set size(val: number) {\n const scene = this._scene;\n const initialBbox = this._initialBbox;\n\n // Modify scale\n const bboxSize = initialBbox.getSize(new THREE.Vector3());\n const scale = val / bboxSize.length();\n scene.scale.setScalar(scale);\n scene.updateMatrix();\n }\n\n public set fixSkinnedBbox(val: boolean) { this._fixSkinnedBbox = val; }\n\n /**\n * Create new Model instance\n */\n constructor({\n scenes,\n animations = [],\n fixSkinnedBbox = false,\n castShadow = true,\n receiveShadow = false,\n }: {\n scenes: THREE.Object3D[],\n animations?: THREE.AnimationClip[],\n fixSkinnedBbox?: boolean,\n castShadow?: boolean,\n receiveShadow?: boolean,\n }) {\n // This guarantees model's root has identity matrix at creation\n this._scene = new THREE.Group();\n const pivot = new THREE.Object3D();\n pivot.name = \"Pivot\";\n pivot.add(...scenes);\n this._scene.add(pivot);\n\n this._animations = animations;\n this._fixSkinnedBbox = fixSkinnedBbox;\n this._cachedLights = null;\n this._cachedMeshes = null;\n\n this._setInitialBbox();\n\n const bboxCenter = this._initialBbox.getCenter(new THREE.Vector3());\n pivot.position.copy(bboxCenter.negate());\n\n this._moveInitialBboxToCenter();\n\n this._originalSize = this.size;\n\n this.castShadow = castShadow;\n this.receiveShadow = receiveShadow;\n }\n\n /**\n * Translate the model to center the model's bounding box to world origin (0, 0, 0).\n */\n public moveToOrigin() {\n // Translate scene position to origin\n const scene = this._scene;\n const initialBbox = this._initialBbox.clone();\n\n initialBbox.min.multiply(scene.scale);\n initialBbox.max.multiply(scene.scale);\n\n const bboxCenter = initialBbox.getCenter(new THREE.Vector3());\n scene.position.copy(bboxCenter.negate());\n scene.updateMatrix();\n }\n\n private _setInitialBbox() {\n this._scene.updateMatrixWorld();\n if (this._fixSkinnedBbox && this._hasSkinnedMesh()) {\n this._initialBbox = this._getSkeletonBbox();\n } else {\n this._initialBbox = new THREE.Box3().setFromObject(this._scene);\n }\n }\n\n private _getSkeletonBbox() {\n const bbox = new THREE.Box3();\n\n this.meshes.forEach((mesh: THREE.SkinnedMesh) => {\n if (!mesh.isSkinnedMesh) {\n bbox.expandByObject(mesh);\n return;\n }\n\n const geometry = mesh.geometry as THREE.BufferGeometry;\n const positions = geometry.attributes.position;\n const skinIndicies = geometry.attributes.skinIndex;\n const skinWeights = geometry.attributes.skinWeight;\n const skeleton = mesh.skeleton;\n\n skeleton.update();\n const boneMatricies = skeleton.boneMatrices;\n\n const finalMatrix = new THREE.Matrix4();\n for (let posIdx = 0; posIdx < positions.count; posIdx++) {\n finalMatrix.identity();\n\n const skinned = new THREE.Vector4();\n skinned.set(0, 0, 0, 0);\n const skinVertex = new THREE.Vector4();\n skinVertex.set(\n positions.getX(posIdx),\n positions.getY(posIdx),\n positions.getZ(posIdx),\n 1,\n ).applyMatrix4(mesh.bindMatrix);\n\n const weights = [\n skinWeights.getX(posIdx),\n skinWeights.getY(posIdx),\n skinWeights.getZ(posIdx),\n skinWeights.getW(posIdx),\n ];\n\n const indicies = [\n skinIndicies.getX(posIdx),\n skinIndicies.getY(posIdx),\n skinIndicies.getZ(posIdx),\n skinIndicies.getW(posIdx),\n ];\n\n weights.forEach((weight, index) => {\n const boneMatrix = new THREE.Matrix4().fromArray(boneMatricies, indicies[index] * 16);\n skinned.add(skinVertex.clone().applyMatrix4(boneMatrix).multiplyScalar(weight));\n });\n\n const transformed = new THREE.Vector3().fromArray(skinned.applyMatrix4(mesh.bindMatrixInverse).toArray());\n transformed.applyMatrix4(mesh.matrixWorld);\n\n bbox.expandByPoint(transformed);\n }\n });\n\n return bbox;\n }\n\n private _moveInitialBboxToCenter() {\n const bboxCenter = this._initialBbox.getCenter(new THREE.Vector3());\n this._initialBbox.translate(bboxCenter.negate());\n }\n\n private _getAllLights(): THREE.Light[] {\n const lights: THREE.Light[] = [];\n\n this._scene.traverse(obj => {\n if ((obj as any).isLight) {\n lights.push(obj as THREE.Light);\n }\n });\n\n this._cachedLights = lights;\n\n return lights;\n }\n\n /**\n * Get all {@link https://threejs.org/docs/#api/en/objects/Mesh THREE.Mesh}es inside model if there's any.\n * @private\n * @returns Meshes found at model's scene\n */\n private _getAllMeshes(): THREE.Mesh[] {\n const meshes: THREE.Mesh[] = [];\n\n this._scene.traverse(obj => {\n if ((obj as any).isMesh) {\n meshes.push(obj as THREE.Mesh);\n }\n });\n\n this._cachedMeshes = meshes;\n\n return meshes;\n }\n\n private _hasSkinnedMesh(): boolean {\n return this.meshes.some(mesh => (mesh as THREE.SkinnedMesh).isSkinnedMesh);\n }\n\n private _getTransformedBbox(): THREE.Box3 {\n return this._initialBbox.clone().applyMatrix4(this._scene.matrix);\n }\n}\n\nexport default Model;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport CameraControl from \"./CameraControl\";\nimport View3DError from \"~/View3DError\";\nimport Camera from \"~/core/camera/Camera\";\nimport { getElement } from \"~/utils\";\nimport { EVENTS, MOUSE_BUTTON } from \"~/consts/event\";\nimport * as ERROR from \"~/consts/error\";\nimport * as DEFAULT from \"~/consts/default\";\n\n/**\n * Control that animates model without user input\n * @category Controls\n */\nclass AutoControl implements CameraControl {\n // Options\n private _delay: number;\n private _delayOnMouseLeave: number;\n private _speed: number;\n private _pauseOnHover: boolean;\n private _canInterrupt: boolean;\n private _disableOnInterrupt: boolean;\n\n // Internal values\n private _targetEl: HTMLElement | null = null;\n private _enabled: boolean = false;\n private _interrupted: boolean = false;\n private _interruptionTimer: number = -1;\n private _hovering: boolean = false;\n\n /**\n * Control's current target element to attach event listeners\n * @readonly\n */\n public get element() { return this._targetEl; }\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n /**\n * Reactivation delay after mouse input in milisecond\n */\n public get delay() { return this._delay; }\n /**\n * Reactivation delay after mouse leave\n * This option only works when {@link AutoControl#pauseOnHover pauseOnHover} is activated\n */\n public get delayOnMouseLeave() { return this._delayOnMouseLeave; }\n /**\n * Y-axis(yaw) rotation speed\n * @default 1\n */\n public get speed() { return this._speed; }\n /**\n * Whether to pause rotation on mouse hover\n * @default false\n */\n public get pauseOnHover() { return this._pauseOnHover; }\n /**\n * Whether user can interrupt the rotation with click/wheel input\n * @default true\n */\n public get canInterrupt() { return this._canInterrupt; }\n /**\n * Whether to disable control on user interrupt\n * @default false\n */\n public get disableOnInterrupt() { return this._disableOnInterrupt; }\n\n public set delay(val: number) { this._delay = val; }\n public set delayOnMouseLeave(val: number) { this._delayOnMouseLeave = val; }\n public set speed(val: number) { this._speed = val; }\n public set pauseOnHover(val: boolean) { this._pauseOnHover = val; }\n public set canInterrupt(val: boolean) { this._canInterrupt = val; }\n public set disableOnInterrupt(val: boolean) { this._disableOnInterrupt = val; }\n\n /**\n * Create new RotateControl instance\n * @param {object} options Options\n * @param {HTMLElement | string | null} [options.element=null] Attaching element / selector of the element\n * @param {number} [options.delay=2000] Reactivation delay after mouse input in milisecond\n * @param {number} [options.delayOnMouseLeave=0] Reactivation delay after mouse leave\n * @param {number} [options.speed=1] Y-axis(yaw) rotation speed\n * @param {boolean} [options.pauseOnHover=false] Whether to pause rotation on mouse hover\n * @param {boolean} [options.canInterrupt=true] Whether user can interrupt the rotation with click/wheel input\n * @param {boolean} [options.disableOnInterrupt=false] Whether to disable control on user interrupt\n * @tutorial Adding Controls\n */\n constructor({\n element = DEFAULT.NULL_ELEMENT,\n delay = 2000,\n delayOnMouseLeave = 0,\n speed = 1,\n pauseOnHover = false,\n canInterrupt = true,\n disableOnInterrupt = false,\n } = {}) {\n const targetEl = getElement(element);\n if (targetEl) {\n this.setElement(targetEl);\n }\n this._delay = delay;\n this._delayOnMouseLeave = delayOnMouseLeave;\n this._speed = speed;\n this._pauseOnHover = pauseOnHover;\n this._canInterrupt = canInterrupt;\n this._disableOnInterrupt = disableOnInterrupt;\n }\n\n /**\n * Destroy the instance and remove all event listeners attached\n * This also will reset CSS cursor to intial\n * @returns {void} Nothing\n */\n public destroy(): void {\n this.disable();\n }\n\n /**\n * Update control by given deltaTime\n * @param camera Camera to update position\n * @param deltaTime Number of milisec to update\n * @returns {void} Nothing\n */\n public update(camera: Camera, deltaTime: number): void {\n if (!this._enabled) return;\n if (this._interrupted) {\n if (this._disableOnInterrupt) {\n this.disable();\n }\n\n return;\n }\n\n camera.yaw += this._speed * deltaTime / 100;\n }\n\n // This is not documetned on purpose as it doesn't do nothing\n public resize(size: THREE.Vector2) {\n // DO NOTHING\n }\n\n /**\n * Enable this input and add event listeners\n * @returns {void} Nothing\n */\n public enable(): void {\n if (this._enabled) return;\n if (!this._targetEl) {\n throw new View3DError(ERROR.MESSAGES.ADD_CONTROL_FIRST, ERROR.CODES.ADD_CONTROL_FIRST);\n }\n\n const targetEl = this._targetEl;\n\n targetEl.addEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);\n\n targetEl.addEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);\n targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n targetEl.addEventListener(EVENTS.MOUSE_ENTER, this._onMouseEnter, false);\n targetEl.addEventListener(EVENTS.MOUSE_LEAVE, this._onMouseLeave, false);\n\n targetEl.addEventListener(EVENTS.WHEEL, this._onWheel, false);\n\n this._enabled = true;\n }\n\n /**\n * Disable this input and remove all event handlers\n * @returns {void} Nothing\n */\n public disable(): void {\n if (!this._enabled || !this._targetEl) return;\n\n const targetEl = this._targetEl;\n\n targetEl.removeEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);\n window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n\n targetEl.removeEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);\n targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n targetEl.removeEventListener(EVENTS.MOUSE_ENTER, this._onMouseEnter, false);\n targetEl.removeEventListener(EVENTS.MOUSE_LEAVE, this._onMouseLeave, false);\n\n targetEl.removeEventListener(EVENTS.WHEEL, this._onWheel, false);\n\n this._enabled = false;\n this._interrupted = false;\n this._hovering = false;\n\n this._clearTimeout();\n }\n\n // This does nothing\n public sync(camera: Camera): void {\n // Do nothing\n }\n\n /**\n * Set target element to attach event listener\n * @param element target element\n * @returns {void} Nothing\n */\n public setElement(element: HTMLElement): void {\n this._targetEl = element;\n }\n\n private _onMouseDown = (evt: MouseEvent) => {\n if (!this._canInterrupt) return;\n if (evt.button !== MOUSE_BUTTON.LEFT && evt.button !== MOUSE_BUTTON.RIGHT) return;\n\n this._interrupted = true;\n this._clearTimeout();\n window.addEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n }\n\n private _onMouseUp = () => {\n window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n this._setUninterruptedAfterDelay(this._delay);\n }\n\n private _onTouchStart = () => {\n if (!this._canInterrupt) return;\n this._interrupted = true;\n this._clearTimeout();\n }\n\n private _onTouchEnd = () => {\n this._setUninterruptedAfterDelay(this._delay);\n }\n\n private _onMouseEnter = () => {\n if (!this._pauseOnHover) return;\n this._interrupted = true;\n this._hovering = true;\n }\n\n private _onMouseLeave = () => {\n if (!this._pauseOnHover) return;\n this._hovering = false;\n this._setUninterruptedAfterDelay(this._delayOnMouseLeave);\n }\n\n private _onWheel = () => {\n if (!this._canInterrupt) return;\n this._interrupted = true;\n this._setUninterruptedAfterDelay(this._delay);\n }\n\n private _setUninterruptedAfterDelay(delay: number): void {\n if (this._hovering) return;\n\n this._clearTimeout();\n\n if (delay > 0) {\n this._interruptionTimer = window.setTimeout(() => {\n this._interrupted = false;\n this._interruptionTimer = -1;\n }, delay);\n } else {\n this._interrupted = false;\n this._interruptionTimer = -1;\n }\n }\n\n private _clearTimeout(): void {\n if (this._interruptionTimer >= 0) {\n window.clearTimeout(this._interruptionTimer);\n this._interruptionTimer = -1;\n }\n }\n}\n\nexport default AutoControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nexport const CURSOR: {\n GRAB: \"grab\",\n GRABBING: \"grabbing\",\n} = {\n GRAB: \"grab\",\n GRABBING: \"grabbing\",\n};\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport CameraControl from \"./CameraControl\";\nimport Motion from \"./Motion\";\nimport View3DError from \"~/View3DError\";\nimport Camera from \"~/core/camera/Camera\";\nimport { getElement } from \"~/utils\";\nimport { EVENTS, MOUSE_BUTTON } from \"~/consts/event\";\nimport { CURSOR } from \"~/consts/css\";\nimport * as DEFAULT from \"~/consts/default\";\nimport * as ERROR from \"~/consts/error\";\nimport { ValueOf } from \"~/types/internal\";\n\n/**\n * Model's rotation control that supports both mouse & touch\n * @category Controls\n */\nclass RotateControl implements CameraControl {\n // Options\n private _useGrabCursor: boolean;\n private _scaleToElement: boolean;\n private _userScale: THREE.Vector2;\n\n // Internal values\n private _targetEl: HTMLElement | null = null;\n private _xMotion: Motion;\n private _yMotion: Motion;\n private _screenScale: THREE.Vector2 = new THREE.Vector2(0, 0);\n private _prevPos: THREE.Vector2 = new THREE.Vector2(0, 0);\n private _enabled: boolean = false;\n\n /**\n * Control's current target element to attach event listeners\n * @readonly\n */\n public get element() { return this._targetEl; }\n /**\n * Scale factor for panning, x is for horizontal and y is for vertical panning.\n * @type THREE.Vector2\n * @see https://threejs.org/docs/#api/en/math/Vector2\n * @example\n * const rotateControl = new View3D.RotateControl();\n * rotateControl.scale.setX(2);\n */\n public get scale() { return this._userScale; }\n /**\n * Whether to apply CSS style `cursor: grab` on the target element or not\n * @default true\n * @example\n * const rotateControl = new View3D.RotateControl();\n * rotateControl.useGrabCursor = true;\n */\n public get useGrabCursor() { return this._useGrabCursor; }\n /**\n * Whether to scale control to fit element size.\n * When this is true and {@link RotateControl#scale scale.x} is 1, panning through element's width will make 3d model's yaw rotate 360°.\n * When this is true and {@link RotateControl#scale scale.y} is 1, panning through element's height will make 3d model's pitch rotate 180°.\n * @default true\n * @example\n * import View3D, { RotateControl } from \"@egjs/view3d\";\n * const view3d = new View3D(\"#view3d-canvas\");\n * const rotateControl = new RotateControl();\n * rotateControl.scaleToElement = true;\n * view3d.controller.add(rotateControl);\n * view3d.resize();\n */\n public get scaleToElement() { return this._scaleToElement; }\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n\n public set scale(val: THREE.Vector2) {\n this._userScale.copy(val);\n }\n public set useGrabCursor(val: boolean) {\n if (!val) {\n this._setCursor(\"\");\n this._useGrabCursor = false;\n } else {\n this._useGrabCursor = true;\n this._setCursor(CURSOR.GRAB);\n }\n }\n public set scaleToElement(val: boolean) {\n this._scaleToElement = val;\n }\n\n /**\n * Create new RotateControl instance\n * @param {object} options Options\n * @param {HTMLElement | null} [options.element] Target element.\n * @param {number} [options.duration=500] Motion's duration.\n * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Motion's easing function.\n * @param {THREE.Vector2} [options.scale=new THREE.Vector2(1, 1)] Scale factor for panning, x is for horizontal and y is for vertical panning.\n * @param {boolean} [options.useGrabCursor=true] Whether to apply CSS style `cursor: grab` on the target element or not.\n * @param {boolean} [options.scaleToElement=true] Whether to scale control to fit element size.\n * @tutorial Adding Controls\n */\n constructor({\n element = DEFAULT.NULL_ELEMENT,\n duration = DEFAULT.ANIMATION_DURATION,\n easing = DEFAULT.EASING,\n scale = new THREE.Vector2(1, 1),\n useGrabCursor = true,\n scaleToElement = true,\n } = {}) {\n const targetEl = getElement(element);\n if (targetEl) {\n this.setElement(targetEl);\n }\n this._userScale = scale;\n this._useGrabCursor = useGrabCursor;\n this._scaleToElement = scaleToElement;\n this._xMotion = new Motion({ duration, range: DEFAULT.INFINITE_RANGE, easing });\n this._yMotion = new Motion({ duration, range: DEFAULT.PITCH_RANGE, easing });\n }\n\n /**\n * Destroy the instance and remove all event listeners attached\n * This also will reset CSS cursor to intial\n * @returns {void} Nothing\n */\n public destroy(): void {\n this.disable();\n }\n\n /**\n * Update control by given deltaTime\n * @param camera Camera to update position\n * @param deltaTime Number of milisec to update\n * @returns {void} Nothing\n */\n public update(camera: Camera, deltaTime: number): void {\n const xMotion = this._xMotion;\n const yMotion = this._yMotion;\n\n const delta = new THREE.Vector2(\n xMotion.update(deltaTime),\n yMotion.update(deltaTime),\n );\n\n camera.yaw += delta.x;\n camera.pitch += delta.y;\n }\n\n /**\n * Resize control to match target size\n * This method is only meaningful when {@link RotateControl#scaleToElement scaleToElement} is enabled\n * @param size {@link https://threejs.org/docs/#api/en/math/Vector2 THREE.Vector2} instance of width(x), height(y)\n */\n public resize(size: THREE.Vector2) {\n this._screenScale.set(360 / size.x, 180 / size.y);\n }\n\n /**\n * Enable this input and add event listeners\n * @returns {void} Nothing\n */\n public enable(): void {\n if (this._enabled) return;\n if (!this._targetEl) {\n throw new View3DError(ERROR.MESSAGES.ADD_CONTROL_FIRST, ERROR.CODES.ADD_CONTROL_FIRST);\n }\n\n const targetEl = this._targetEl;\n\n targetEl.addEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);\n\n targetEl.addEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);\n targetEl.addEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);\n targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n this._enabled = true;\n this._setCursor(CURSOR.GRAB);\n }\n\n /**\n * Disable this input and remove all event handlers\n * @returns {void} Nothing\n */\n public disable(): void {\n if (!this._enabled || !this._targetEl) return;\n\n const targetEl = this._targetEl;\n\n targetEl.removeEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);\n window.removeEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);\n window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n\n targetEl.removeEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);\n targetEl.removeEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);\n targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n this._setCursor(\"\");\n this._enabled = false;\n }\n\n /**\n * Synchronize this control's state to given camera position\n * @param camera Camera to match state\n * @returns {void} Nothing\n */\n public sync(camera: Camera): void {\n this._xMotion.reset(camera.yaw);\n this._yMotion.reset(camera.pitch);\n }\n\n /**\n * Set target element to attach event listener\n * @param element target element\n * @returns {void} Nothing\n */\n public setElement(element: HTMLElement): void {\n this._targetEl = element;\n this.resize(new THREE.Vector2(element.offsetWidth, element.offsetHeight));\n }\n\n private _setCursor(val: ValueOf<typeof CURSOR> | \"\") {\n const targetEl = this._targetEl;\n if (!this._useGrabCursor || !targetEl || !this._enabled) return;\n\n targetEl.style.cursor = val;\n }\n\n private _onMouseDown = (evt: MouseEvent) => {\n if (evt.button !== MOUSE_BUTTON.LEFT) return;\n\n const targetEl = this._targetEl!;\n evt.preventDefault();\n\n targetEl.focus ? targetEl.focus() : window.focus();\n\n this._prevPos.set(evt.clientX, evt.clientY);\n window.addEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);\n window.addEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n\n this._setCursor(CURSOR.GRABBING);\n }\n\n private _onMouseMove = (evt: MouseEvent) => {\n evt.preventDefault();\n\n const prevPos = this._prevPos;\n const rotateDelta = new THREE.Vector2(evt.clientX, evt.clientY)\n .sub(prevPos)\n .multiply(this._userScale);\n\n if (this._scaleToElement) {\n rotateDelta.multiply(this._screenScale);\n }\n\n this._xMotion.setEndDelta(rotateDelta.x);\n this._yMotion.setEndDelta(rotateDelta.y);\n\n prevPos.set(evt.clientX, evt.clientY);\n }\n\n private _onMouseUp = () => {\n this._prevPos.set(0, 0);\n window.removeEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);\n window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n\n this._setCursor(CURSOR.GRAB);\n }\n\n private _onTouchStart = (evt: TouchEvent) => {\n evt.preventDefault();\n\n const touch = evt.touches[0];\n this._prevPos.set(touch.clientX, touch.clientY);\n }\n\n private _onTouchMove = (evt: TouchEvent) => {\n // Only the one finger motion should be considered\n if (evt.touches.length > 1) return;\n\n if (evt.cancelable !== false) {\n evt.preventDefault();\n }\n evt.stopPropagation();\n\n const touch = evt.touches[0];\n\n const prevPos = this._prevPos;\n const rotateDelta = new THREE.Vector2(touch.clientX, touch.clientY)\n .sub(prevPos)\n .multiply(this._userScale);\n\n if (this._scaleToElement) {\n rotateDelta.multiply(this._screenScale);\n }\n\n this._xMotion.setEndDelta(rotateDelta.x);\n this._yMotion.setEndDelta(rotateDelta.y);\n\n prevPos.set(touch.clientX, touch.clientY);\n }\n\n private _onTouchEnd = (evt: TouchEvent) => {\n const touch = evt.touches[0];\n if (touch) {\n this._prevPos.set(touch.clientX, touch.clientY);\n } else {\n this._prevPos.set(0, 0);\n }\n }\n}\n\nexport default RotateControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport CameraControl from \"./CameraControl\";\nimport Motion from \"./Motion\";\nimport View3DError from \"~/View3DError\";\nimport Camera from \"~/core/camera/Camera\";\nimport { getElement } from \"~/utils\";\nimport { EVENTS, MOUSE_BUTTON } from \"~/consts/event\";\nimport { CURSOR } from \"~/consts/css\";\nimport * as DEFAULT from \"~/consts/default\";\nimport * as ERROR from \"~/consts/error\";\nimport { ValueOf } from \"~/types/internal\";\n\n/**\n * Model's translation control that supports both mouse & touch\n * @category Controls\n */\nclass TranslateControl implements CameraControl {\n // Options\n private _useGrabCursor: boolean;\n private _scaleToElement: boolean;\n private _userScale: THREE.Vector2;\n\n // Internal values\n private _targetEl: HTMLElement | null = null;\n private _enabled: boolean = false;\n // Sometimes, touchstart for second finger doesn't triggered.\n // This flag checks whether that happened\n private _touchInitialized: boolean = false;\n private _xMotion: Motion;\n private _yMotion: Motion;\n private _prevPos: THREE.Vector2 = new THREE.Vector2(0, 0);\n private _screenSize: THREE.Vector2 = new THREE.Vector2(0, 0);\n\n /**\n * Control's current target element to attach event listeners\n * @readonly\n */\n public get element() { return this._targetEl; }\n /**\n * Scale factor for translation\n * @type THREE.Vector2\n * @see https://threejs.org/docs/#api/en/math/Vector2\n * @example\n * import { TranslateControl } from \"@egjs/view3d\";\n * const translateControl = new TranslateControl();\n * translateControl.scale.set(2, 2);\n */\n public get scale() { return this._userScale; }\n /**\n * Whether to apply CSS style `cursor: grab` on the target element or not\n * @default true\n * @example\n * import { TranslateControl } from \"@egjs/view3d\";\n * const translateControl = new TranslateControl();\n * translateControl.useGrabCursor = true;\n */\n public get useGrabCursor() { return this._useGrabCursor; }\n /**\n * Scale control to fit element size.\n * When this is true, camera's pivot change will correspond same amount you've dragged.\n * @default true\n * @example\n * import View3D, { TranslateControl } from \"@egjs/view3d\";\n * const view3d = new View3D(\"#view3d-canvas\");\n * const translateControl = new TranslateControl();\n * translateControl.scaleToElement = true;\n * view3d.controller.add(translateControl);\n * view3d.resize();\n */\n public get scaleToElement() { return this._scaleToElement; }\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n\n public set scale(val: THREE.Vector2) {\n this._userScale.copy(val);\n }\n public set useGrabCursor(val: boolean) {\n if (!val) {\n this._setCursor(\"\");\n this._useGrabCursor = false;\n } else {\n this._useGrabCursor = true;\n this._setCursor(CURSOR.GRAB);\n }\n }\n public set scaleToElement(val: boolean) {\n this._scaleToElement = val;\n }\n\n /**\n * Create new TranslateControl instance\n * @param {object} options Options\n * @param {HTMLElement | null} [options.element] Target element.\n * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Motion's easing function.\n * @param {THREE.Vector2} [options.scale=new THREE.Vector2(1, 1)] Scale factor for translation.\n * @param {boolean} [options.useGrabCursor=true] Whether to apply CSS style `cursor: grab` on the target element or not.\n * @param {boolean} [options.scaleToElement=true] Whether to scale control to fit element size.\n * @tutorial Adding Controls\n */\n constructor({\n element = DEFAULT.NULL_ELEMENT,\n easing = DEFAULT.EASING,\n scale = new THREE.Vector2(1, 1),\n useGrabCursor = true,\n scaleToElement = true,\n } = {}) {\n const targetEl = getElement(element);\n if (targetEl) {\n this.setElement(targetEl);\n }\n this._xMotion = new Motion({ duration: 0, range: DEFAULT.INFINITE_RANGE, easing });\n this._yMotion = new Motion({ duration: 0, range: DEFAULT.INFINITE_RANGE, easing });\n this._userScale = scale;\n this._useGrabCursor = useGrabCursor;\n this._scaleToElement = scaleToElement;\n }\n\n /**\n * Destroy the instance and remove all event listeners attached\n * This also will reset CSS cursor to intial\n * @returns {void} Nothing\n */\n public destroy(): void {\n this.disable();\n }\n\n /**\n * Update control by given deltaTime\n * @param deltaTime Number of milisec to update\n * @returns {void} Nothing\n */\n public update(camera: Camera, deltaTime: number): void {\n const screenSize = this._screenSize;\n\n const delta = new THREE.Vector2(\n this._xMotion.update(deltaTime),\n this._yMotion.update(deltaTime),\n );\n\n const viewXDir = new THREE.Vector3(1, 0, 0).applyQuaternion(camera.threeCamera.quaternion);\n const viewYDir = new THREE.Vector3(0, 1, 0).applyQuaternion(camera.threeCamera.quaternion);\n\n if (this._scaleToElement) {\n const screenScale = new THREE.Vector2(camera.renderWidth, camera.renderHeight).divide(screenSize);\n delta.multiply(screenScale);\n }\n\n camera.pivot.add(viewXDir.multiplyScalar(delta.x));\n camera.pivot.add(viewYDir.multiplyScalar(delta.y));\n }\n\n /**\n * Resize control to match target size\n * This method is only meaningful when {@link RotateControl#scaleToElementSize scaleToElementSize} is enabled\n * @param size {@link https://threejs.org/docs/#api/en/math/Vector2 THREE.Vector2} instance of width(x), height(y)\n */\n public resize(size: THREE.Vector2) {\n const screenSize = this._screenSize;\n\n screenSize.copy(size);\n }\n\n /**\n * Enable this input and add event listeners\n * @returns {void} Nothing\n */\n public enable(): void {\n if (this._enabled) return;\n if (!this._targetEl) {\n throw new View3DError(ERROR.MESSAGES.ADD_CONTROL_FIRST, ERROR.CODES.ADD_CONTROL_FIRST);\n }\n\n const targetEl = this._targetEl;\n\n targetEl.addEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);\n\n targetEl.addEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);\n targetEl.addEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);\n targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n targetEl.addEventListener(EVENTS.CONTEXT_MENU, this._onContextMenu, false);\n\n this._enabled = true;\n this._setCursor(CURSOR.GRAB);\n }\n\n /**\n * Disable this input and remove all event handlers\n * @returns {void} Nothing\n */\n public disable(): void {\n if (!this._enabled || !this._targetEl) return;\n\n const targetEl = this._targetEl;\n\n targetEl.removeEventListener(EVENTS.MOUSE_DOWN, this._onMouseDown, false);\n window.removeEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);\n window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n\n targetEl.removeEventListener(EVENTS.TOUCH_START, this._onTouchStart, false);\n targetEl.removeEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);\n targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n targetEl.removeEventListener(EVENTS.CONTEXT_MENU, this._onContextMenu, false);\n\n this._setCursor(\"\");\n this._enabled = false;\n }\n\n /**\n * Synchronize this control's state to given camera position\n * @param camera Camera to match state\n * @returns {void} Nothing\n */\n public sync(camera: Camera): void {\n this._xMotion.reset(0);\n this._yMotion.reset(0);\n }\n\n /**\n * Set target element to attach event listener\n * @param element target element\n * @returns {void} Nothing\n */\n public setElement(element: HTMLElement): void {\n this._targetEl = element;\n this.resize(new THREE.Vector2(element.offsetWidth, element.offsetHeight));\n }\n\n private _setCursor(val: ValueOf<typeof CURSOR> | \"\") {\n const targetEl = this._targetEl;\n if (!this._useGrabCursor || !targetEl || !this._enabled) return;\n\n targetEl.style.cursor = val;\n }\n\n private _onMouseDown = (evt: MouseEvent) => {\n if (evt.button !== MOUSE_BUTTON.RIGHT) return;\n\n const targetEl = this._targetEl!;\n evt.preventDefault();\n\n targetEl.focus ? targetEl.focus() : window.focus();\n\n this._prevPos.set(evt.clientX, evt.clientY);\n window.addEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);\n window.addEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n\n this._setCursor(CURSOR.GRABBING);\n }\n\n private _onMouseMove = (evt: MouseEvent) => {\n evt.preventDefault();\n\n const prevPos = this._prevPos;\n const delta = new THREE.Vector2(evt.clientX, evt.clientY)\n .sub(prevPos)\n .multiply(this._userScale);\n\n // X value is negated to match cursor direction\n this._xMotion.setEndDelta(-delta.x);\n this._yMotion.setEndDelta(delta.y);\n\n prevPos.set(evt.clientX, evt.clientY);\n }\n\n private _onMouseUp = () => {\n this._prevPos.set(0, 0);\n window.removeEventListener(EVENTS.MOUSE_MOVE, this._onMouseMove, false);\n window.removeEventListener(EVENTS.MOUSE_UP, this._onMouseUp, false);\n\n this._setCursor(CURSOR.GRAB);\n }\n\n private _onTouchStart = (evt: TouchEvent) => {\n // Only the two finger motion should be considered\n if (evt.touches.length !== 2) return;\n evt.preventDefault();\n\n this._prevPos.copy(this._getTouchesMiddle(evt.touches));\n this._touchInitialized = true;\n }\n\n private _onTouchMove = (evt: TouchEvent) => {\n // Only the two finger motion should be considered\n if (evt.touches.length !== 2) return;\n\n if (evt.cancelable !== false) {\n evt.preventDefault();\n }\n evt.stopPropagation();\n\n const prevPos = this._prevPos;\n const middlePoint = this._getTouchesMiddle(evt.touches);\n\n if (!this._touchInitialized) {\n prevPos.copy(middlePoint);\n this._touchInitialized = true;\n return;\n }\n\n const delta = new THREE.Vector2()\n .subVectors(middlePoint, prevPos)\n .multiply(this._userScale);\n\n // X value is negated to match cursor direction\n this._xMotion.setEndDelta(-delta.x);\n this._yMotion.setEndDelta(delta.y);\n\n prevPos.copy(middlePoint);\n }\n\n private _onTouchEnd = (evt: TouchEvent) => {\n // Only the two finger motion should be considered\n if (evt.touches.length !== 2) {\n this._touchInitialized = false;\n return;\n }\n\n // Three fingers to two fingers\n this._prevPos.copy(this._getTouchesMiddle(evt.touches));\n this._touchInitialized = true;\n }\n\n private _getTouchesMiddle(touches: TouchEvent[\"touches\"]): THREE.Vector2 {\n return new THREE.Vector2(\n touches[0].clientX + touches[1].clientX,\n touches[0].clientY + touches[1].clientY,\n ).multiplyScalar(0.5);\n }\n\n private _onContextMenu = (evt: MouseEvent) => {\n evt.preventDefault();\n }\n}\n\nexport default TranslateControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport CameraControl from \"./CameraControl\";\nimport Motion from \"./Motion\";\nimport View3DError from \"~/View3DError\";\nimport Camera from \"~/core/camera/Camera\";\nimport { getElement } from \"~/utils\";\nimport { EVENTS } from \"~/consts/event\";\nimport * as DEFAULT from \"~/consts/default\";\nimport * as ERROR from \"~/consts/error\";\n\n/**\n * Distance controller handling both mouse wheel and pinch zoom\n * @category Controls\n */\nclass DistanceControl implements CameraControl {\n // Options\n private _scale: number = 1;\n\n // Internal values\n private _targetEl: HTMLElement | null = null;\n private _scaleModifier: number = 0.25;\n private _motion: Motion;\n private _prevTouchDistance: number = -1;\n private _enabled: boolean = false;\n\n /**\n * Control's current target element to attach event listeners\n * @readonly\n */\n public get element() { return this._targetEl; }\n /**\n * Scale factor of the distance\n * @type number\n * @example\n * import { DistanceControl } from \"@egjs/view3d\";\n * const distanceControl = new DistanceControl();\n * distanceControl.scale = 2;\n */\n public get scale() { return this._scale; }\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n\n public set scale(val: number) { this._scale = val; }\n\n /**\n * Create new DistanceControl instance\n * @tutorial Adding Controls\n * @param {object} options Options\n * @param {HTMLElement | string | null} [options.element=null] Attaching element / selector of the element.\n * @param {number} [options.duration=500] Motion's duration.\n * @param {object} [options.range={min: 0, max: 500}] Motion's range.\n * @param {function} [options.easing=(x: number) => 1 - Math.pow(1 - x, 3)] Motion's easing function.\n */\n constructor({\n element = DEFAULT.NULL_ELEMENT,\n duration = DEFAULT.ANIMATION_DURATION,\n range = DEFAULT.DISTANCE_RANGE,\n easing = DEFAULT.EASING,\n } = {}) {\n const targetEl = getElement(element);\n if (targetEl) {\n this.setElement(targetEl);\n }\n this._motion = new Motion({ duration, range, easing });\n }\n\n /**\n * Destroy the instance and remove all event listeners attached\n * @returns {void} Nothing\n */\n public destroy(): void {\n this.disable();\n }\n\n /**\n * Update control by given deltaTime\n * @param camera Camera to update position\n * @param deltaTime Number of milisec to update\n * @returns {void} Nothing\n */\n public update(camera: Camera, deltaTime: number): void {\n const motion = this._motion;\n\n camera.distance += motion.update(deltaTime);\n }\n\n // This is not documetned on purpose as it doesn't do nothing\n public resize(size: THREE.Vector2) {\n // DO NOTHING\n }\n\n /**\n * Enable this input and add event listeners\n * @returns {void} Nothing\n */\n public enable(): void {\n if (this._enabled) return;\n if (!this._targetEl) {\n throw new View3DError(ERROR.MESSAGES.ADD_CONTROL_FIRST, ERROR.CODES.ADD_CONTROL_FIRST);\n }\n\n const targetEl = this._targetEl;\n\n targetEl.addEventListener(EVENTS.WHEEL, this._onWheel, false);\n targetEl.addEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);\n targetEl.addEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n this._enabled = true;\n }\n\n /**\n * Disable this input and remove all event handlers\n * @returns {void} Nothing\n */\n public disable(): void {\n if (!this._enabled || !this._targetEl) return;\n\n const targetEl = this._targetEl;\n\n targetEl.removeEventListener(EVENTS.WHEEL, this._onWheel, false);\n targetEl.removeEventListener(EVENTS.TOUCH_MOVE, this._onTouchMove, false);\n targetEl.removeEventListener(EVENTS.TOUCH_END, this._onTouchEnd, false);\n\n this._enabled = false;\n }\n\n /**\n * Synchronize this control's state to given camera position\n * @param camera Camera to match state\n * @returns {void} Nothing\n */\n public sync(camera: Camera): void {\n this._motion.range.min = camera.minDistance;\n this._motion.range.max = camera.maxDistance;\n this._motion.reset(camera.distance);\n }\n\n /**\n * Set target element to attach event listener\n * @param element target element\n * @returns {void} Nothing\n */\n public setElement(element: HTMLElement): void {\n this._targetEl = element;\n }\n\n private _onWheel = (evt: MouseWheelEvent) => {\n if (evt.deltaY === 0) return;\n\n evt.preventDefault();\n evt.stopPropagation();\n\n const animation = this._motion;\n const delta = this._scale * this._scaleModifier * evt.deltaY;\n\n animation.setEndDelta(delta);\n }\n\n private _onTouchMove = (evt: TouchEvent) => {\n const touches = evt.touches;\n if (touches.length !== 2) return;\n\n if (evt.cancelable !== false) {\n evt.preventDefault();\n }\n evt.stopPropagation();\n\n const animation = this._motion;\n const prevTouchDistance = this._prevTouchDistance;\n\n const touchPoint1 = new THREE.Vector2(touches[0].pageX, touches[0].pageY);\n const touchPoint2 = new THREE.Vector2(touches[1].pageX, touches[1].pageY);\n const touchDiff = touchPoint1.sub(touchPoint2);\n const touchDistance = touchDiff.length() * this._scale * this._scaleModifier;\n const delta = -(touchDistance - prevTouchDistance);\n\n this._prevTouchDistance = touchDistance;\n\n if (prevTouchDistance < 0) return;\n\n animation.setEndDelta(delta);\n }\n\n private _onTouchEnd = () => {\n this._prevTouchDistance = -1;\n }\n}\n\nexport default DistanceControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport CameraControl from \"./CameraControl\";\nimport RotateControl from \"./RotateControl\";\nimport TranslateControl from \"./TranslateControl\";\nimport DistanceControl from \"./DistanceControl\";\nimport Camera from \"~/core/camera/Camera\";\nimport View3DError from \"~/View3DError\";\nimport { getElement } from \"~/utils\";\nimport * as ERROR from \"~/consts/error\";\nimport * as DEFAULT from \"~/consts/default\";\n\n/**\n * Aggregation of {@link RotateControl}, {@link TranslateControl}, and {@link DistanceControl}.\n * @category Controls\n */\nclass OrbitControl implements CameraControl {\n private _targetEl: HTMLElement | null;\n private _rotateControl: RotateControl;\n private _translateControl: TranslateControl;\n private _distanceControl: DistanceControl;\n private _enabled: boolean = false;\n\n /**\n * Control's current target element to attach event listeners\n * @readonly\n */\n public get element() { return this._targetEl; }\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n /**\n * {@link RotateControl} of this control\n */\n public get rotate() { return this._rotateControl; }\n /**\n * {@link TranslateControl} of this control\n */\n public get translate() { return this._translateControl; }\n /**\n * {@link DistanceControl} of this control\n */\n public get distance() { return this._distanceControl; }\n\n /**\n * Create new OrbitControl instance\n * @param {object} options Options\n * @param {HTMLElement | string | null} [options.element=null] Attaching element / selector of the element\n * @param {object} [options.rotate={}] Constructor options of {@link RotateControl}\n * @param {object} [options.translate={}] Constructor options of {@link TranslateControl}\n * @param {object} [options.distance={}] Constructor options of {@link DistanceControl}\n * @tutorial Adding Controls\n */\n constructor({\n element = DEFAULT.NULL_ELEMENT,\n rotate = {},\n translate = {},\n distance = {},\n }: Partial<{\n rotate: ConstructorParameters<typeof RotateControl>[0],\n translate: ConstructorParameters<typeof TranslateControl>[0],\n distance: ConstructorParameters<typeof DistanceControl>[0],\n element: HTMLElement | string | null,\n }> = {}) {\n this._targetEl = getElement(element);\n this._rotateControl = new RotateControl({ ...rotate, element: rotate.element || this._targetEl });\n this._translateControl = new TranslateControl({ ...translate, element: translate.element || this._targetEl });\n this._distanceControl = new DistanceControl({ ...distance, element: distance.element || this._targetEl });\n }\n\n /**\n * Destroy the instance and remove all event listeners attached\n * This also will reset CSS cursor to intial\n * @returns {void} Nothing\n */\n public destroy(): void {\n this._rotateControl.destroy();\n this._translateControl.destroy();\n this._distanceControl.destroy();\n }\n\n /**\n * Update control by given deltaTime\n * @param camera Camera to update position\n * @param deltaTime Number of milisec to update\n * @returns {void} Nothing\n */\n public update(camera: Camera, deltaTime: number): void {\n this._rotateControl.update(camera, deltaTime);\n this._translateControl.update(camera, deltaTime);\n this._distanceControl.update(camera, deltaTime);\n }\n\n /**\n * Resize control to match target size\n * @param size {@link https://threejs.org/docs/#api/en/math/Vector2 THREE.Vector2} instance of width(x), height(y)\n */\n public resize(size: THREE.Vector2) {\n this._rotateControl.resize(size);\n this._translateControl.resize(size);\n this._distanceControl.resize(size);\n }\n\n /**\n * Enable this control and add event listeners\n * @returns {void} Nothingß\n */\n public enable(): void {\n if (this._enabled) return;\n if (!this._targetEl) {\n throw new View3DError(ERROR.MESSAGES.ADD_CONTROL_FIRST, ERROR.CODES.ADD_CONTROL_FIRST);\n }\n\n this._rotateControl.enable();\n this._translateControl.enable();\n this._distanceControl.enable();\n\n this._enabled = true;\n }\n\n /**\n * Disable this control and remove all event handlers\n * @returns {void} Nothing\n */\n public disable(): void {\n if (!this._enabled || !this._targetEl) return;\n\n this._rotateControl.disable();\n this._translateControl.disable();\n this._distanceControl.disable();\n\n this._enabled = false;\n }\n\n /**\n * Synchronize this control's state to given camera position\n * @param camera Camera to match state\n * @returns {void} Nothing\n */\n public sync(camera: Camera): void {\n this._rotateControl.sync(camera);\n this._translateControl.sync(camera);\n this._distanceControl.sync(camera);\n }\n\n /**\n * Set target element to attach event listener\n * @param element target element\n * @returns {void} Nothing\n */\n public setElement(element: HTMLElement): void {\n this._targetEl = element;\n this._rotateControl.setElement(element);\n this._translateControl.setElement(element);\n this._distanceControl.setElement(element);\n }\n}\n\nexport default OrbitControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\nimport * as THREE from \"three\";\nimport { DRACOLoader } from \"three/examples/jsm/loaders/DRACOLoader\";\nimport Model from \"~/core/Model\";\nimport * as DEFAULT from \"~/consts/default\";\nimport { DracoLoadOption } from \"~/types/external\";\n\n/**\n * DracoLoader\n * @category Loaders\n */\nclass DracoLoader {\n /**\n * Load new DRC model from the given url\n * @param url URL to fetch .drc file\n * @param options Options for a loaded model\n * @returns Promise that resolves {@link Model}\n */\n public load(url: string, options: Partial<DracoLoadOption> = {}): Promise<Model> {\n const loader = new DRACOLoader();\n loader.setCrossOrigin(\"anonymous\");\n loader.setDecoderPath(DEFAULT.DRACO_DECODER_URL);\n loader.manager = new THREE.LoadingManager();\n\n return new Promise((resolve, reject) => {\n loader.load(url, geometry => {\n const model = this._parseToModel(geometry, options);\n loader.dispose();\n resolve(model);\n }, undefined, err => {\n loader.dispose();\n reject(err);\n });\n });\n }\n\n private _parseToModel(geometry: THREE.BufferGeometry, {\n fixSkinnedBbox = false,\n color = 0xffffff,\n point = false,\n pointOptions = {}\n }: Partial<DracoLoadOption> = {}): Model {\n geometry.computeVertexNormals();\n\n\t\tconst material = point\n ? new THREE.PointsMaterial({ color, ...pointOptions })\n : new THREE.MeshStandardMaterial({ color });\n\t\tconst mesh = point\n ? new THREE.Points(geometry, material)\n : new THREE.Mesh(geometry, material);\n\n const model = new Model({\n scenes: [mesh],\n fixSkinnedBbox,\n });\n\n return model;\n }\n}\n\nexport default DracoLoader;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Environment from \"./Environment\";\nimport Model from \"~/core/Model\";\nimport { getBoxPoints } from \"~/utils\";\n\n/**\n * THREE.DirectionalLight wrapper that will automatically update its shadow size to model\n * Shadow is enabled by default, use {@link AutoDirectionalLight#disableShadow disableShadow} to disable it\n * @category Environment\n */\nclass AutoDirectionalLight implements Environment {\n private _light: THREE.DirectionalLight;\n private _direction: THREE.Vector3; // Direction to light, from (0, 0, 0)\n\n /**\n * Array of lights that used in this preset\n * @see https://threejs.org/docs/#api/en/lights/Light\n */\n public get objects(): THREE.Object3D[] {\n return [this._light, this._light.target];\n }\n\n /**\n * The actual THREE.DirectionalLight\n * @type THREE#DirectionalLight\n * @see https://threejs.org/docs/#api/en/lights/DirectionalLight\n */\n public get light() { return this._light; }\n\n /**\n * Position of the light\n * @type THREE#Vector3\n * @see https://threejs.org/docs/#api/en/math/Vector3\n */\n public get position() { return this._light.position; }\n\n public get direction() { return this._direction; }\n\n /**\n * Create new instance of AutoDirectionalLight\n * @param [color=\"#ffffff\"] Color of the light\n * @param [intensity=1] Intensity of the light\n * @param {object} [options={}] Additional options\n * @param {THREE.Vector3} [options.direction=new THREE.Vector3(-1, -1, -1)] Direction of the light\n */\n constructor(color: string | number | THREE.Color = \"#ffffff\", intensity: number = 1, {\n direction = new THREE.Vector3(-1, -1, -1),\n } = {}) {\n this._light = new THREE.DirectionalLight(color, intensity);\n\n // Set the default position ratio of the directional light\n const light = this._light;\n light.castShadow = true; // Is enabled by default\n light.shadow.mapSize.width = 2048;\n light.shadow.mapSize.height = 2048;\n light.matrixAutoUpdate = false;\n\n this._direction = direction.clone().normalize();\n }\n\n /**\n * Make light cast a shadow\n */\n public enableShadow() {\n this._light.castShadow = true;\n }\n\n /**\n * Make light don't cast a shadow\n */\n public disableShadow() {\n this._light.castShadow = false;\n }\n\n /**\n * Modify light's position & shadow camera size from model's bounding box\n * @param model Model to fit size\n * @param scale Scale factor for shadow camera size\n */\n public fit(model: Model, {\n scale = 1.5,\n } = {}) {\n const bbox = model.bbox;\n const light = this._light;\n const direction = this._direction;\n const boxSize = bbox.getSize(new THREE.Vector3()).length();\n const boxCenter = bbox.getCenter(new THREE.Vector3());\n\n // Position fitting\n const newPos = new THREE.Vector3().addVectors(boxCenter, direction.clone().negate().multiplyScalar(boxSize * 0.5));\n light.position.copy(newPos);\n light.target.position.copy(boxCenter);\n light.updateMatrix();\n\n // Shadowcam fitting\n const shadowCam = light.shadow.camera;\n shadowCam.near = 0;\n shadowCam.far = 2 * boxSize;\n shadowCam.position.copy(newPos);\n shadowCam.lookAt(boxCenter);\n\n shadowCam.left = -1;\n shadowCam.right = 1;\n shadowCam.top = 1;\n shadowCam.bottom = -1;\n\n shadowCam.updateMatrixWorld();\n shadowCam.updateProjectionMatrix();\n\n const bboxPoints = getBoxPoints(bbox);\n const projectedPoints = bboxPoints.map(position => position.project(shadowCam));\n const screenBbox = new THREE.Box3().setFromPoints(projectedPoints);\n\n shadowCam.left *= -scale * screenBbox.min.x;\n shadowCam.right *= scale * screenBbox.max.x;\n shadowCam.top *= scale * screenBbox.max.y;\n shadowCam.bottom *= -scale * screenBbox.min.y;\n\n shadowCam.updateProjectionMatrix();\n }\n}\n\nexport default AutoDirectionalLight;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Model from \"~/core/Model\";\nimport Environment from \"./Environment\";\n\n/**\n * Helper class to easily add shadow plane under your 3D model\n * @category Environment\n * @example\n * import View3D, { ShadowPlane } from \"@egjs/view3d\";\n *\n * const view3d = new View3D(\"#view3d-canvas\");\n * const shadowPlane = new ShadowPlane();\n * view3d.scene.addEnv(shadowPlane);\n */\nclass ShadowPlane implements Environment {\n // Developers can change those values if they know what they're doing\n // So I'm leaving those values public\n\n /**\n * Geometry of the shadow plane\n * @see https://threejs.org/docs/#api/en/geometries/PlaneGeometry\n */\n public geometry: THREE.PlaneGeometry;\n /**\n * Material of the shadow plane\n * @see https://threejs.org/docs/#api/en/materials/ShadowMaterial\n */\n public material: THREE.ShadowMaterial;\n /**\n * Mesh of the shadow plane\n * @see https://threejs.org/docs/#api/en/objects/Mesh\n */\n public mesh: THREE.Mesh;\n\n public get objects() { return [this.mesh]; }\n\n /**\n * Shadow opacity, value can be between 0(invisible) and 1(solid)\n * @type number\n */\n public get opacity() {\n return this.material.opacity;\n }\n\n public set opacity(val: number) {\n this.material.opacity = val;\n }\n\n /**\n * Create new shadow plane\n * @param {object} options Options\n * @param {number} [options.size=10000] Size of the shadow plane\n * @param {number} [options.opacity=0.3] Opacity of the shadow\n */\n constructor({\n size = 10000,\n opacity = 0.3,\n } = {}) {\n this.geometry = new THREE.PlaneGeometry(size, size, 100, 100);\n this.material = new THREE.ShadowMaterial({ opacity });\n this.mesh = new THREE.Mesh(this.geometry, this.material);\n\n const mesh = this.mesh;\n mesh.rotateX(-Math.PI / 2);\n mesh.receiveShadow = true;\n }\n\n /**\n * Fit shadow plane's size & position to given model\n * @param model Model to fit\n */\n public fit(model: Model, {\n floorPosition,\n floorRotation = new THREE.Quaternion(0, 0, 0, 1),\n }: Partial<{\n floorPosition: THREE.Vector3,\n floorRotation: THREE.Quaternion,\n }> = {}): void {\n const modelPosition = model.scene.position;\n const localYAxis = new THREE.Vector3(0, 1, 0).applyQuaternion(floorRotation);\n\n // Apply position\n if (floorPosition) {\n // Apply a tiny offset to prevent z-fighting with original model\n this.mesh.position.copy(floorPosition.clone().add(localYAxis.clone().multiplyScalar(0.001)));\n } else {\n const modelBbox = model.bbox;\n const modelBboxYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y;\n const modelFloor = new THREE.Vector3().addVectors(\n modelPosition,\n // Apply a tiny offset to prevent z-fighting with original model\n localYAxis.multiplyScalar(-modelBboxYOffset + 0.0001),\n );\n this.mesh.position.copy(modelFloor);\n }\n\n // Apply rotation\n const rotX90 = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0));\n const shadowRotation = new THREE.Quaternion().multiplyQuaternions(floorRotation, rotX90);\n\n this.mesh.quaternion.copy(shadowRotation);\n this.mesh.updateMatrix();\n }\n}\n\nexport default ShadowPlane;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport { GLTFLoader as ThreeGLTFLoader, GLTF } from \"three/examples/jsm/loaders/GLTFLoader\";\nimport { DRACOLoader } from \"three/examples/jsm/loaders/DRACOLoader\";\nimport Model from \"~/core/Model\";\nimport * as DEFAULT from \"~/consts/default\";\nimport View3D from \"~/View3D\";\nimport { ShadowPlane, AutoDirectionalLight } from \"~/environments\";\nimport { ModelLoadOption } from \"~/types/external\";\n\n/**\n * GLTFLoader\n * @category Loaders\n */\nclass GLTFLoader {\n private _loader: ThreeGLTFLoader;\n private _dracoLoader: DRACOLoader;\n\n public get loader() { return this._loader; }\n public get dracoLoader() { return this._dracoLoader; }\n\n /**\n * Create a new instance of GLTFLoader\n */\n constructor() {\n this._loader = new ThreeGLTFLoader();\n this._dracoLoader = new DRACOLoader();\n\n const loader = this._loader;\n loader.setCrossOrigin(\"anonymous\");\n\n const dracoLoader = this._dracoLoader;\n dracoLoader.setDecoderPath(DEFAULT.DRACO_DECODER_URL);\n loader.setDRACOLoader(dracoLoader);\n }\n\n /**\n * Load new GLTF model from the given url\n * @param url URL to fetch glTF/glb file\n * @param options Options for a loaded model\n * @returns Promise that resolves {@link Model}\n */\n public load(url: string, options: Partial<ModelLoadOption> = {}): Promise<Model> {\n const loader = this._loader;\n loader.manager = new THREE.LoadingManager();\n\n return new Promise((resolve, reject) => {\n loader.load(url, gltf => {\n const model = this._parseToModel(gltf, options);\n resolve(model);\n }, undefined, err => {\n reject(err);\n });\n });\n }\n\n /**\n * Load preset generated from View3D editor.\n * @param viewer Instance of the {@link View3D}.\n * @param url Preset url\n * @param {object} options Options\n * @param {string} [options.path] Base path for additional files.\n * @param {function} [options.onLoad] Callback which called after each model LOD is loaded.\n * @returns {Model} Model instance with highest LOD\n */\n public loadPreset(viewer: View3D, url: string, options: Partial<{\n path: string;\n onLoad: (model: Model, lodIndex: number) => any;\n }> = {}): Promise<Model> {\n const loader = this._loader;\n const fileLoader = new THREE.FileLoader();\n\n return fileLoader.loadAsync(url)\n .then(jsonRaw => {\n return new Promise((resolve, reject) => {\n const json = JSON.parse(jsonRaw);\n const baseURL = THREE.LoaderUtils.extractUrlBase(url);\n\n // Reset\n viewer.scene.reset();\n viewer.camera.reset();\n viewer.animator.reset();\n\n const modelOptions = json.model;\n const cameraOptions = json.camera;\n const environmentOptions = json.env;\n\n viewer.camera.setDefaultPose({\n yaw: cameraOptions.yaw,\n pitch: cameraOptions.pitch,\n });\n viewer.camera.minDistance = cameraOptions.distanceRange[0];\n viewer.camera.maxDistance = cameraOptions.distanceRange[1];\n\n if (environmentOptions.background) {\n viewer.scene.setBackground(new THREE.Color(environmentOptions.background));\n }\n\n const shadowPlane = new ShadowPlane();\n shadowPlane.opacity = environmentOptions.shadow.opacity;\n viewer.scene.addEnv(shadowPlane);\n\n const ambientOptions = environmentOptions.ambient;\n const ambient = new THREE.AmbientLight(new THREE.Color(ambientOptions.color), ambientOptions.intensity);\n viewer.scene.addEnv(ambient);\n\n const lightOptions = [environmentOptions.light1, environmentOptions.light2, environmentOptions.light3];\n lightOptions.forEach(lightOption => {\n const lightDirection = new THREE.Vector3(lightOption.x, lightOption.y, lightOption.z).negate();\n const directional = new AutoDirectionalLight(new THREE.Color(lightOption.color), lightOption.intensity, {\n direction: lightDirection,\n });\n directional.light.castShadow = lightOption.castShadow;\n directional.light.updateMatrixWorld();\n viewer.scene.addEnv(directional);\n });\n\n let isFirstLoad = true;\n const loadFlags = json.LOD.map(() => false) as boolean[];\n json.LOD.forEach((fileName: string, lodIndex: number) => {\n const glbURL = this._resolveURL(`${baseURL}${fileName}`, options.path || \"\");\n\n loader.load(glbURL, gltf => {\n loadFlags[lodIndex] = true;\n const higherLODLoaded = loadFlags.slice(lodIndex + 1).some(loaded => loaded);\n if (higherLODLoaded) return;\n\n const model = this._parseToModel(gltf);\n\n viewer.display(model, {\n size: modelOptions.size,\n resetView: isFirstLoad,\n });\n isFirstLoad = false;\n\n model.castShadow = modelOptions.castShadow;\n model.receiveShadow = modelOptions.receiveShadow;\n\n if (options.onLoad) {\n options.onLoad(model, lodIndex);\n }\n if (lodIndex === json.LOD.length - 1) {\n resolve(model);\n }\n }, undefined, err => {\n reject(err);\n });\n });\n });\n });\n }\n\n /**\n * Load new GLTF model from the given files\n * @param files Files that has glTF/glb and all its associated resources like textures and .bin data files\n * @param options Options for a loaded model\n * @returns Promise that resolves {@link Model}\n */\n public loadFromFiles(files: File[], options: Partial<ModelLoadOption> = {}): Promise<Model> {\n const objectURLs: string[] = [];\n const revokeURLs = () => {\n objectURLs.forEach(url => {\n URL.revokeObjectURL(url);\n });\n };\n\n return new Promise((resolve, reject) => {\n if (files.length <= 0) {\n reject(new Error(\"No files found\"));\n return;\n }\n\n const gltfFile = files.find(file => /\\.(gltf|glb)$/i.test(file.name));\n if (!gltfFile) {\n reject(new Error(\"No glTF file found\"));\n return;\n }\n\n const filesMap = new Map<string, File>();\n files.forEach(file => {\n filesMap.set(file.name, file);\n });\n\n const gltfURL = URL.createObjectURL(gltfFile);\n\n objectURLs.push(gltfURL);\n\n const manager = new THREE.LoadingManager();\n manager.setURLModifier(fileURL => {\n const fileNameResult = /[^\\/|\\\\]+$/.exec(fileURL);\n const fileName = (fileNameResult && fileNameResult[0]) || \"\";\n\n if (filesMap.has(fileName)) {\n const blob = filesMap.get(fileName);\n const blobURL = URL.createObjectURL(blob);\n objectURLs.push(blobURL);\n\n return blobURL;\n }\n\n return fileURL;\n });\n\n const loader = this._loader;\n loader.manager = manager;\n loader.load(gltfURL, gltf => {\n const model = this._parseToModel(gltf, options);\n resolve(model);\n revokeURLs();\n }, undefined, err => {\n reject(err);\n revokeURLs();\n });\n });\n }\n\n /**\n * Parse from array buffer\n * @param data glTF asset to parse, as an ArrayBuffer or JSON string.\n * @param path The base path from which to find subsequent glTF resources such as textures and .bin data files.\n * @param options Options for a loaded model\n * @returns Promise that resolves {@link Model}\n */\n public parse(data: ArrayBuffer, path: string, options: Partial<ModelLoadOption> = {}): Promise<Model> {\n const loader = this._loader;\n loader.manager = new THREE.LoadingManager();\n\n return new Promise((resolve, reject) => {\n loader.parse(data, path, gltf => {\n const model = this._parseToModel(gltf, options);\n resolve(model);\n }, err => {\n reject(err);\n });\n });\n }\n\n private _parseToModel(gltf: GLTF, {\n fixSkinnedBbox = false,\n }: Partial<ModelLoadOption> = {}): Model {\n const model = new Model({\n scenes: gltf.scenes,\n animations: gltf.animations,\n fixSkinnedBbox,\n });\n\n model.meshes.forEach(mesh => {\n const materials = Array.isArray(mesh.material)\n ? mesh.material\n : [mesh.material];\n\n materials.forEach((mat: THREE.MeshStandardMaterial) => {\n if (mat.map) {\n mat.map.encoding = THREE.sRGBEncoding;\n }\n });\n });\n\n return model;\n }\n\n // Grabbed from three.js/GLTFLoader\n // Original code: https://github.com/mrdoob/three.js/blob/master/examples/jsm/loaders/GLTFLoader.js#L1221\n // License: MIT\n private _resolveURL(url: string, path: string): string {\n // Invalid URL\n if ( typeof url !== \"string\" || url === \"\" ) return \"\";\n\n // Host Relative URL\n if ( /^https?:\\/\\//i.test( path ) && /^\\//.test( url ) ) {\n\n path = path.replace( /(^https?:\\/\\/[^\\/]+).*/i, \"$1\" );\n\n }\n\n // Absolute URL http://,https://,//\n if ( /^(https?:)?\\/\\//i.test( url ) ) return url;\n\n // Data URI\n if ( /^data:.*,.*$/i.test( url ) ) return url;\n\n // Blob URL\n if ( /^blob:.*$/i.test( url ) ) return url;\n\n // Relative URL\n return path + url;\n }\n}\n\nexport default GLTFLoader;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport { RGBELoader } from \"three/examples/jsm/loaders/RGBELoader\";\nimport Renderer from \"~/core/Renderer\";\n\n/**\n * Texture loader\n * @category Loaders\n */\nclass TextureLoader {\n private _renderer: Renderer;\n\n /**\n * Create new TextureLoader instance\n * @param renderer {@link Renderer} instance of View3D\n */\n constructor(renderer: Renderer) {\n this._renderer = renderer;\n }\n\n /**\n * Create new {@link https://threejs.org/docs/index.html#api/en/textures/Texture Texture} with given url\n * Texture's {@link https://threejs.org/docs/index.html#api/en/textures/Texture.flipY flipY} property is `true` by Three.js's policy, so be careful when using it as a map texture.\n * @param url url to fetch image\n */\n public load(url: string): Promise<THREE.Texture> {\n return new Promise((resolve, reject) => {\n const loader = new THREE.TextureLoader();\n loader.load(url, resolve, undefined, reject);\n });\n }\n\n /**\n * Create new {@link https://threejs.org/docs/#api/en/renderers/WebGLCubeRenderTarget WebGLCubeRenderTarget} with given equirectangular image url\n * Be sure that equirectangular image has height of power of 2, as it will be resized if it isn't\n * @param url url to fetch equirectangular image\n * @returns WebGLCubeRenderTarget created\n */\n public loadEquirectagularTexture(url: string): Promise<THREE.WebGLCubeRenderTarget> {\n return new Promise((resolve, reject) => {\n const loader = new THREE.TextureLoader();\n loader.load(url, skyboxTexture => {\n resolve(this._equirectToCubemap(skyboxTexture));\n }, undefined, reject);\n });\n }\n\n /**\n * Create new {@link https://threejs.org/docs/#api/en/textures/CubeTexture CubeTexture} with given cubemap image urls\n * Image order should be: px, nx, py, ny, pz, nz\n * @param urls cubemap image urls\n * @returns CubeTexture created\n */\n public loadCubeTexture(urls: string[]): Promise<THREE.CubeTexture> {\n return new Promise((resolve, reject) => {\n const loader = new THREE.CubeTextureLoader();\n loader.load(urls, resolve, undefined, reject);\n });\n }\n\n public loadHDRTexture(url: string, isEquirectangular: false): Promise<THREE.DataTexture>;\n\n public loadHDRTexture(url: string, isEquirectangular: true): Promise<THREE.WebGLCubeRenderTarget>;\n\n /**\n * Create new texture with given HDR(RGBE) image url\n * @param url image url\n * @param isEquirectangular Whether to read this image as a equirectangular texture\n */\n public loadHDRTexture(url: string, isEquirectangular: boolean = true): Promise<THREE.DataTexture | THREE.WebGLCubeRenderTarget> {\n return new Promise((resolve, reject) => {\n const loader = new RGBELoader();\n loader.load(url, texture => {\n if (isEquirectangular) {\n resolve(this._equirectToCubemap(texture));\n } else {\n resolve(texture);\n }\n }, undefined, reject);\n });\n }\n\n private _equirectToCubemap(texture: THREE.Texture): THREE.WebGLCubeRenderTarget {\n return new THREE.WebGLCubeRenderTarget(texture.image.height)\n .fromEquirectangularTexture(this._renderer.threeRenderer, texture);\n }\n}\n\nexport default TextureLoader;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\ndeclare global {\n interface Window {\n XRSession: any;\n XRDOMOverlayState: any;\n }\n}\n\nexport const QUICKLOOK_SUPPORTED = (() => {\n const anchorEl = document.createElement(\"a\");\n return anchorEl.relList && anchorEl.relList.supports && anchorEl.relList.supports(\"ar\");\n})();\nexport const WEBXR_SUPPORTED = navigator.xr && navigator.xr.isSessionSupported;\nexport const HIT_TEST_SUPPORTED = window.XRSession && window.XRSession.prototype.requestHitTestSource;\nexport const DOM_OVERLAY_SUPPORTED = window.XRDOMOverlayState != null;\n\nexport const SESSION = {\n AR: \"immersive-ar\",\n VR: \"immersive-ar\",\n};\n\nexport const REFERENCE_SPACE = {\n LOCAL: \"local\",\n LOCAL_FLOOR: \"local-floor\",\n VIEWER: \"viewer\",\n};\n\nexport const EVENTS = {\n SELECT_START: \"selectstart\",\n SELECT: \"select\",\n SELECT_END: \"selectend\",\n};\n\nexport const INPUT_PROFILE = {\n TOUCH: \"generic-touchscreen\",\n};\n\nexport const FEATURES = {\n HIT_TEST: { requiredFeatures: [\"hit-test\"] },\n DOM_OVERLAY: (root: HTMLElement) => ({\n optionalFeatures: [\"dom-overlay\"],\n domOverlay: { root },\n }),\n};\n\n// For type definition\nexport const EMPTY_FEATURES: {\n requiredFeatures?: any[],\n optionalFeatures?: any[],\n [key: string]: any,\n} = {};\n\nexport const SCENE_VIEWER = {\n INTENT_AR_CORE: (params: string, fallback?: string) => `intent://arvr.google.com/scene-viewer/1.1?${params}#Intent;scheme=https;package=com.google.ar.core;action=android.intent.action.VIEW;${fallback ? `S.browser_fallback_url=${fallback};` : \"\"}end;`,\n INTENT_SEARCHBOX: (params: string, fallback: string) => `intent://arvr.google.com/scene-viewer/1.1?${params}#Intent;scheme=https;package=com.google.android.googlequicksearchbox;action=android.intent.action.VIEW;${fallback ? `S.browser_fallback_url=${fallback};` : \"\"}end;`,\n FALLBACK_DEFAULT: (params: string) => `https://arvr.google.com/scene-viewer?${params}`,\n};\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Motion from \"../../Motion\";\nimport * as DEFAULT from \"~/consts/default\";\nimport * as EASING from \"~/consts/easing\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\nimport ARControl from \"../common/ARControl\";\n\nenum STATE {\n WAITING,\n TRANSLATING,\n BOUNCING,\n}\n\n/**\n * Options for {@link ARFloorTranslateControl}\n * @category Controls-AR\n * @interface\n * @property {number} [threshold=0.05] Threshold until translation works, this value is relative to screen size.\n * @property {number} [hoverAmplitude=0.01] How much model will hover up and down, in meter. Default value is 0.01(1cm).\n * @property {number} [hoverHeight=0.1] How much model will float from the floor, in meter. Default value is 0.1(10cm).\n * @property {number} [hoverPeriod=1000] Hover cycle's period, in milisecond.\n * @property {function} [hoverEasing=EASING.SINE_WAVE] Hover animation's easing function.\n * @property {number} [bounceDuration=1000] Bounce-to-floor animation's duration, in milisecond.\n * @property {number} [bounceEasing=EASING.EASE_OUT_BOUNCE] Bounce-to-floor animation's easing function.\n */\nexport interface ARFloorTranslateControlOption {\n threshold: number;\n hoverAmplitude: number;\n hoverHeight: number;\n hoverPeriod: number;\n hoverEasing: (x: number) => number;\n bounceDuration: number;\n bounceEasing: (x: number) => number;\n}\n\n/**\n * Model's translation(position) control for {@link ARFloorControl}\n * @category Controls-AR\n */\nclass ARFloorTranslateControl implements ARControl {\n // Options\n private _hoverAmplitude: number;\n private _hoverHeight: number;\n\n // Internal states\n private _modelPosition = new THREE.Vector3();\n private _hoverPosition = new THREE.Vector3();\n private _floorPosition = new THREE.Vector3();\n private _dragPlane = new THREE.Plane();\n private _enabled = true;\n private _state = STATE.WAITING;\n private _initialPos = new THREE.Vector2();\n private _hoverMotion: Motion;\n private _bounceMotion: Motion;\n\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n /**\n * Position including hover/bounce animation offset from the floor.\n * @readonly\n */\n public get modelPosition() { return this._modelPosition.clone(); }\n /**\n * Last detected floor position\n * @readonly\n */\n public get floorPosition() { return this._floorPosition.clone(); }\n /**\n * How much model will hover up and down, in meter.\n */\n public get hoverAmplitude() { return this._hoverAmplitude; }\n /**\n * How much model will float from the floor, in meter.\n */\n public get hoverHeight() { return this._hoverHeight; }\n\n public set hoverAmplitude(val: number) { this._hoverAmplitude = val; }\n public set hoverHeight(val: number) { this._hoverHeight = val; }\n\n /**\n * Create new instance of ARTranslateControl\n * @param {ARFloorTranslateControlOption} [options={}] Options\n */\n constructor({\n hoverAmplitude = 0.01,\n hoverHeight = 0.1,\n hoverPeriod = 1000,\n hoverEasing = EASING.SINE_WAVE,\n bounceDuration = 1000,\n bounceEasing = EASING.EASE_OUT_BOUNCE,\n }: Partial<ARFloorTranslateControlOption> = {}) {\n this._hoverAmplitude = hoverAmplitude;\n this._hoverHeight = hoverHeight;\n this._hoverMotion = new Motion({\n loop: true,\n duration: hoverPeriod,\n easing: hoverEasing,\n });\n this._bounceMotion = new Motion({\n duration: bounceDuration,\n easing: bounceEasing,\n range: DEFAULT.INFINITE_RANGE,\n });\n }\n\n public initFloorPosition(position: THREE.Vector3) {\n this._modelPosition.copy(position);\n this._floorPosition.copy(position);\n this._hoverPosition.copy(position);\n this._hoverPosition.setY(position.y + this._hoverHeight);\n }\n\n // tslint:disable-next-line no-empty\n public init(ctx: XRRenderContext) {}\n\n // tslint:disable-next-line no-empty\n public destroy(ctx: XRContext) {}\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n this.deactivate();\n }\n\n public activate({ model }: XRRenderContext, gesture: TOUCH.GESTURE) {\n if (!this._enabled) return;\n\n const modelBbox = model.bbox;\n const modelBboxYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y;\n this._dragPlane.set(new THREE.Vector3(0, 1, 0), -(this._floorPosition.y + this._hoverHeight + modelBboxYOffset));\n\n this._hoverMotion.reset(0);\n this._hoverMotion.setEndDelta(1);\n this._state = STATE.TRANSLATING;\n }\n\n public deactivate() {\n if (!this._enabled || this._state === STATE.WAITING) {\n this._state = STATE.WAITING;\n return;\n }\n\n this._state = STATE.BOUNCING;\n\n const floorPosition = this._floorPosition;\n const modelPosition = this._modelPosition;\n const hoverPosition = this._hoverPosition;\n const bounceMotion = this._bounceMotion;\n\n const hoveringAmount = modelPosition.y - floorPosition.y;\n bounceMotion.reset(modelPosition.y);\n bounceMotion.setEndDelta(-hoveringAmount);\n\n // Restore hover pos\n hoverPosition.copy(floorPosition);\n hoverPosition.setY(floorPosition.y + this._hoverHeight);\n }\n\n public setInitialPos(coords: THREE.Vector2[]) {\n this._initialPos.copy(coords[0]);\n }\n\n public process({ view3d, model, frame, referenceSpace, xrCam }: XRRenderContext, { hitResults }: XRInputs) {\n const state = this._state;\n const notActive = state === STATE.WAITING || state === STATE.BOUNCING;\n if (!hitResults || hitResults.length !== 1 || notActive) return;\n\n const hitResult = hitResults[0];\n\n const prevFloorPosition = this._floorPosition.clone();\n const floorPosition = this._floorPosition;\n const hoverPosition = this._hoverPosition;\n const hoverHeight = this._hoverHeight;\n const dragPlane = this._dragPlane;\n\n const modelBbox = model.bbox;\n const modelBboxYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y;\n\n const hitPose = hitResult.results[0] && hitResult.results[0].getPose(referenceSpace);\n const isFloorHit = hitPose && hitPose.transform.matrix[5] >= 0.75;\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n\n if (!hitPose || !isFloorHit) {\n // Use previous drag plane if no hit plane is found\n const targetRayPose = frame.getPose(hitResult.inputSource.targetRaySpace, view3d.renderer.threeRenderer.xr.getReferenceSpace());\n const fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();\n\n const fingerRay = new THREE.Ray(camPos, fingerDir);\n const intersection = fingerRay.intersectPlane(dragPlane, new THREE.Vector3());\n\n if (intersection) {\n floorPosition.copy(intersection);\n floorPosition.setY(prevFloorPosition.y);\n hoverPosition.copy(intersection);\n hoverPosition.setY(intersection.y - modelBboxYOffset);\n }\n return;\n }\n\n const hitMatrix = new THREE.Matrix4().fromArray(hitPose.transform.matrix);\n const hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix);\n\n // Set new floor level when it's increased at least 10cm\n const currentDragPlaneHeight = -dragPlane.constant;\n const hitDragPlaneHeight = hitPosition.y + hoverHeight + modelBboxYOffset;\n\n if (hitDragPlaneHeight - currentDragPlaneHeight > 0.1) {\n dragPlane.constant = -hitDragPlaneHeight;\n }\n\n const camToHitDir = new THREE.Vector3().subVectors(hitPosition, camPos).normalize();\n const camToHitRay = new THREE.Ray(camPos, camToHitDir);\n const hitOnDragPlane = camToHitRay.intersectPlane(dragPlane, new THREE.Vector3());\n\n if (!hitOnDragPlane) return;\n\n floorPosition.copy(hitOnDragPlane);\n floorPosition.setY(hitPosition.y);\n hoverPosition.copy(hitOnDragPlane);\n hoverPosition.setY(hitOnDragPlane.y - modelBboxYOffset);\n }\n\n public update({ model }: XRRenderContext, delta: number) {\n const state = this._state;\n const modelPosition = this._modelPosition;\n const hoverPosition = this._hoverPosition;\n if (state === STATE.WAITING) return;\n\n if (state !== STATE.BOUNCING) {\n // Hover\n const hoverMotion = this._hoverMotion;\n hoverMotion.update(delta);\n\n // Change only x, y component of position\n const hoverOffset = hoverMotion.val * this._hoverAmplitude;\n modelPosition.copy(hoverPosition);\n modelPosition.setY(hoverPosition.y + hoverOffset);\n } else {\n // Bounce\n const bounceMotion = this._bounceMotion;\n bounceMotion.update(delta);\n\n modelPosition.setY(bounceMotion.val);\n\n if (bounceMotion.progress >= 1) {\n this._state = STATE.WAITING;\n }\n }\n\n const modelBbox = model.bbox;\n const modelYOffset = modelBbox.getCenter(new THREE.Vector3()).y - modelBbox.min.y;\n\n // modelPosition = where model.bbox.min.y should be\n model.scene.position.copy(modelPosition.clone().setY(modelPosition.y + modelYOffset));\n }\n}\n\nexport default ARFloorTranslateControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as XR from \"~/consts/xr\";\n\n/**\n * Manager for WebXR dom-overlay feature\n * @category XR\n */\nclass DOMOverlay {\n private _root: HTMLElement;\n private _loadingEl: HTMLElement | null;\n\n /**\n * Overlay root element\n */\n public get root() { return this._root; }\n /**\n * Loading indicator element, if there's any\n */\n public get loadingElement() { return this._loadingEl; }\n /**\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit} object for dom-overlay feature\n */\n public get features() { return XR.FEATURES.DOM_OVERLAY(this._root); }\n\n /**\n * Create new DOMOverlay instance\n * @param {object} [options] Options\n * @param {HTMLElement} [options.root] Overlay root element\n * @param {HTMLElement | null} [options.loadingEl] Model loading indicator element which will be invisible after placing model on the floor.\n */\n constructor(options: {\n root: HTMLElement,\n loadingEl: HTMLElement | null,\n }) {\n this._root = options.root;\n this._loadingEl = options.loadingEl;\n }\n\n /**\n * Return whether dom-overlay feature is available\n */\n public isAvailable() {\n return XR.DOM_OVERLAY_SUPPORTED;\n }\n\n /**\n * Show loading indicator, if there's any\n */\n public showLoading() {\n if (!this._loadingEl) return;\n\n this._loadingEl.style.visibility = \"visible\";\n }\n\n /**\n * Hide loading indicator, if there's any\n */\n public hideLoading() {\n if (!this._loadingEl) return;\n\n this._loadingEl.style.visibility = \"hidden\";\n }\n}\n\nexport default DOMOverlay;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport View3D from \"~/View3D\";\nimport XRSession from \"./XRSession\";\nimport DOMOverlay from \"./features/DOMOverlay\";\nimport EventEmitter from \"~/core/EventEmitter\";\nimport { getElement, merge } from \"~/utils\";\nimport * as DEFAULT from \"~/consts/default\";\nimport * as XR from \"~/consts/xr\";\nimport { XRContext, XRRenderContext } from \"~/types/internal\";\n\ndeclare global {\n interface Navigator { xr: any; }\n}\n\n/**\n * Options for WebARSession\n * @category XR\n * @interface\n * @property {object} [features={}] You can set additional features(see {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit}) with this option.\n * @property {number} [maxModelSize=Infinity] If model's size is too big to show on AR, you can restrict it's size with this option. Model with size bigger than this value will clamped to this value.\n * @property {HTMLElement|string|null} [overlayRoot=null] If this value is set, dom-overlay feature will be automatically added for this session. And this value will be used as dom-overlay's root element. You can set either HTMLElement or query selector for that element.\n * @property {HTMLElement|string|null} [loadingEl=null] This will be used for loading indicator element, which will automatically invisible after placing 3D model by setting `visibility: hidden`. This element must be placed under `overlayRoot`. You can set either HTMLElement or query selector for that element.\n * @property {boolean} [forceOverlay=false] Whether to apply `dom-overlay` feature as required. If set to false, `dom-overlay` will be optional feature.\n */\nexport interface WebARSessionOption {\n features: typeof XR.EMPTY_FEATURES;\n maxModelSize: number;\n overlayRoot: HTMLElement | string | null;\n loadingEl: HTMLElement | string | null;\n forceOverlay: boolean;\n}\n\n/**\n * WebXR based abstract AR session class\n * @category XR\n * @fires WebARSession#start\n * @fires WebARSession#end\n * @fires WebARSession#canPlace\n * @fires WebARSession#modelPlaced\n */\nabstract class WebARSession extends EventEmitter<{\n start: void;\n end: void;\n canPlace: void;\n modelPlaced: void;\n}> implements XRSession {\n /**\n * Whether it's webxr-based session or not\n * @type true\n */\n public readonly isWebXRSession = true;\n\n protected _session: any = null;\n protected _domOverlay: DOMOverlay | null = null;\n // As \"dom-overlay\" is an optional feature by default,\n // user can choose whether to show XR only when this feature is available\n protected _forceOverlay: boolean;\n protected _features: typeof XR.EMPTY_FEATURES;\n protected _maxModelSize: number;\n\n /**\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSession XRSession} of this session\n * This value is only available after calling enter\n */\n public get session() { return this._session; }\n /**\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit} object for this session.\n */\n public get features() { return this._features; }\n\n /**\n * Emitted when session is started.\n * @event start\n * @category XR\n * @memberof WebARSession\n * @type void\n */\n /**\n * Emitted when session is ended.\n * @event end\n * @category XR\n * @memberof WebARSession\n * @type void\n */\n /**\n * Emitted when model can be placed on the space.\n * @event canPlace\n * @category XR\n * @memberof WebARSession\n * @type void\n */\n /**\n * Emitted when model is placed.\n * @event modelPlaced\n * @category XR\n * @memberof WebARSession\n * @type void\n */\n\n /**\n * Create new instance of WebARSession\n * @param {object} [options={}] Options\n * @param {object} [options.features={}] You can set additional features(see {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit}) with this option.\n * @param {number} [options.maxModelSize=Infinity] If model's size is too big to show on AR, you can restrict it's size with this option. Model with size bigger than this value will clamped to this value.\n * @param {HTMLElement|string|null} [options.overlayRoot=null] If this value is set, dom-overlay feature will be automatically added for this session. And this value will be used as dom-overlay's root element. You can set either HTMLElement or query selector for that element.\n * @param {HTMLElement|string|null} [options.loadingEl=null] This will be used for loading indicator element, which will automatically invisible after placing 3D model by setting `visibility: hidden`. This element must be placed under `overlayRoot`. You can set either HTMLElement or query selector for that element.\n * @param {boolean} [options.forceOverlay=false] Whether to apply `dom-overlay` feature as required. If set to false, `dom-overlay` will be optional feature.\n */\n constructor({\n features: userFeatures = XR.EMPTY_FEATURES, // https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit\n maxModelSize = Infinity,\n overlayRoot = DEFAULT.NULL_ELEMENT,\n loadingEl = DEFAULT.NULL_ELEMENT,\n forceOverlay = false,\n }: Partial<WebARSessionOption> = {}) {\n super();\n const overlayEl = getElement(overlayRoot);\n\n const features: (typeof XR.EMPTY_FEATURES)[] = [];\n if (overlayEl) {\n this._domOverlay = new DOMOverlay({\n root: overlayEl,\n loadingEl: getElement(loadingEl, overlayEl),\n });\n features.push(this._domOverlay.features);\n }\n\n this._features = merge({}, ...features, userFeatures);\n this._maxModelSize = maxModelSize;\n this._forceOverlay = forceOverlay;\n }\n\n /**\n * Return availability of this session\n * @returns {Promise} A Promise that resolves availability of this session(boolean).\n */\n public isAvailable() {\n const domOverlay = this._domOverlay;\n\n if (!XR.WEBXR_SUPPORTED || !XR.HIT_TEST_SUPPORTED) return Promise.resolve(false);\n if (this._forceOverlay) {\n if (domOverlay && !domOverlay.isAvailable()) return Promise.resolve(false);\n }\n\n return navigator.xr.isSessionSupported(XR.SESSION.AR);\n }\n\n /**\n * Enter session\n * @param view3d Instance of the View3D\n * @returns {Promise}\n */\n public enter(view3d: View3D) {\n // Model not loaded yet\n if (!view3d.model) return Promise.reject(\"3D Model is not loaded\");\n\n const model = view3d.model;\n\n return navigator.xr.requestSession(XR.SESSION.AR, this._features)\n .then(session => {\n const renderer = view3d.renderer;\n const threeRenderer = renderer.threeRenderer;\n const xrContext = {\n view3d,\n model,\n session,\n };\n\n // Cache original values\n const originalMatrix = model.scene.matrix.clone();\n const originalModelSize = model.size;\n const originalBackground = view3d.scene.root.background;\n\n const arModelSize = Math.min(model.originalSize, this._maxModelSize);\n model.size = arModelSize;\n model.moveToOrigin();\n view3d.scene.setBackground(null);\n\n // Cache original model rotation\n threeRenderer.xr.setReferenceSpaceType(XR.REFERENCE_SPACE.LOCAL);\n threeRenderer.xr.setSession(session);\n threeRenderer.setPixelRatio(1);\n\n this.onStart(xrContext);\n session.addEventListener(\"end\", () => {\n this.onEnd(xrContext);\n\n // Restore original values\n model.scene.matrix.copy(originalMatrix);\n model.scene.matrix.decompose(model.scene.position, model.scene.quaternion, model.scene.scale);\n model.size = originalModelSize;\n model.moveToOrigin();\n\n view3d.scene.update(model);\n view3d.scene.setBackground(originalBackground);\n\n // Restore renderer values\n threeRenderer.xr.setSession(null);\n threeRenderer.setPixelRatio(window.devicePixelRatio);\n\n // Restore render loop\n renderer.stopAnimationLoop();\n renderer.setAnimationLoop(view3d.renderLoop);\n }, { once: true });\n\n // Set XR session render loop\n renderer.stopAnimationLoop();\n renderer.setAnimationLoop((delta, frame) => {\n const xrCam = threeRenderer.xr.getCamera(new THREE.PerspectiveCamera()) as THREE.PerspectiveCamera;\n const referenceSpace = threeRenderer.xr.getReferenceSpace();\n const glLayer = session.renderState.baseLayer;\n const size = {\n width: glLayer.framebufferWidth,\n height: glLayer.framebufferHeight,\n };\n const renderContext: XRRenderContext = {\n ...xrContext,\n delta,\n frame,\n referenceSpace,\n xrCam,\n size,\n };\n\n this._beforeRender(renderContext);\n view3d.renderLoop(delta);\n });\n });\n }\n\n /**\n * Exit this session\n * @param view3d Instance of the View3D\n */\n public exit(view3d: View3D) {\n const session = view3d.renderer.threeRenderer.xr.getSession();\n session.end();\n }\n\n public onStart(ctx: XRContext) {\n this._session = ctx.session;\n this._domOverlay?.showLoading();\n this.emit(\"start\");\n }\n\n public onEnd(ctx: XRContext) {\n this._session = null;\n this._domOverlay?.hideLoading();\n this.emit(\"end\");\n }\n\n protected abstract _beforeRender(ctx: XRRenderContext): void;\n}\n\nexport default WebARSession;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as XR from \"~/consts/xr\";\n\n/**\n * Manager for WebXR hit-test feature\n * @category XR\n */\nclass HitTest {\n private _source: any = null;\n\n /**\n * Return whether hit-test is ready\n */\n public get ready() { return this._source != null; }\n /**\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/XRSessionInit XRSessionInit} object for hit-test feature\n */\n public get features() { return XR.FEATURES.HIT_TEST; }\n\n /**\n * Destroy instance\n */\n public destroy() {\n if (this._source) {\n this._source.cancel();\n this._source = null;\n }\n }\n\n /**\n * Initialize hit-test feature\n * @param {XRSession} session XRSession instance\n */\n public init(session: any) {\n session.requestReferenceSpace(XR.REFERENCE_SPACE.VIEWER).then(referenceSpace => {\n session.requestHitTestSource({ space: referenceSpace }).then(source => {\n this._source = source;\n });\n });\n }\n\n /**\n * Return whether hit-test feature is available\n */\n public isAvailable() {\n return XR.HIT_TEST_SUPPORTED;\n }\n\n /**\n * Get hit-test results\n * @param {XRFrame} frame XRFrame instance\n */\n public getResults(frame: any) {\n return frame.getHitTestResults(this._source);\n }\n}\n\nexport default HitTest;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport EventEmitter from \"./EventEmitter\";\nimport * as DEFAULT from \"~/consts/default\";\nimport * as EASING from \"~/consts/easing\";\nimport { circulate } from \"~/utils\";\n\n/**\n * Fires for every animation frame when animation is active.\n * @type object\n * @property {object} event Event object.\n * @property {number} [event.progress] Current animation progress value.\n * Value is ranged from 0(start) to 1(end).\n * @property {number} [event.easedProgress] Eased progress value.\n * @event Animation#progress\n */\n\n/**\n * Fires for every animation loop except for the last loop\n * This will be triggered only when repeat > 0\n * @type object\n * @property {object} event Event object.\n * @property {number} [event.progress] Current animation progress value.\n * Value is ranged from 0(start) to 1(end).\n * @property {number} [event.easedProgress] Eased progress value.\n * @property {number} [event.loopIndex] Index of the current loop.\n * @event Animation#loop\n */\n\n/**\n * Fires when animation ends.\n * @type void\n * @event Animation#finish\n */\n\n/**\n * Self-running animation\n * @category Core\n */\nclass Animation extends EventEmitter<{\n progress: (event: { progress: number, easedProgress: number }) => any,\n loop: (event: { progress: number, easedProgress: number, loopIndex: number }) => any,\n finish: void,\n}> {\n // Options\n private _ctx: any; // Window or XRSession\n private _repeat: number;\n private _duration: number;\n private _easing: (x: number) => number;\n\n // Internal state\n private _rafId: number;\n private _loopCount: number;\n private _time: number;\n private _clock: number;\n\n /**\n * Create new instance of the Animation\n * @param {object} [options={}] Options\n */\n constructor({\n context = window,\n repeat = 0,\n duration = DEFAULT.ANIMATION_DURATION,\n easing = EASING.EASE_OUT_CUBIC,\n }: Partial<{\n context: any,\n repeat: number,\n duration: number,\n easing: (x: number) => number;\n }> = {}) {\n super();\n\n // Options\n this._repeat = repeat;\n this._duration = duration;\n this._easing = easing;\n\n // Internal States\n this._ctx = context;\n this._rafId = -1;\n this._time = 0;\n this._clock = 0;\n this._loopCount = 0;\n }\n\n public start() {\n if (this._rafId >= 0) return;\n\n // This guarantees \"progress\" event with progress = 0 on first start\n this._updateClock();\n this._loop();\n }\n\n public stop() {\n if (this._rafId < 0) return;\n\n this._time = 0;\n this._loopCount = 0;\n this._stopLoop();\n }\n\n public pause() {\n if (this._rafId < 0) return;\n\n this._stopLoop();\n }\n\n private _loop = () => {\n const delta = this._getDeltaTime();\n const duration = this._duration;\n this._time += delta;\n\n const loopIncrease = Math.floor(this._time / duration);\n this._time = circulate(this._time, 0, duration);\n\n const progress = this._time / duration;\n const progressEvent = {\n progress,\n easedProgress: this._easing(progress),\n };\n this.emit(\"progress\", progressEvent);\n\n for (let loopIdx = 0; loopIdx < loopIncrease; loopIdx++) {\n this._loopCount++;\n if (this._loopCount > this._repeat) {\n this.emit(\"finish\");\n this.stop();\n return;\n } else {\n this.emit(\"loop\", {\n ...progressEvent,\n loopIndex: this._loopCount,\n });\n }\n }\n\n this._rafId = this._ctx.requestAnimationFrame(this._loop);\n }\n\n private _stopLoop() {\n this._ctx.cancelAnimationFrame(this._rafId);\n this._rafId = -1;\n }\n\n private _getDeltaTime() {\n const lastTime = this._clock;\n this._updateClock();\n return this._clock - lastTime;\n }\n\n private _updateClock() {\n this._clock = Date.now();\n }\n}\n\nexport default Animation;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Options for {@link RotationIndicator}\n * @category Controls-AR\n * @interface\n * @property {string | number | THREE.Color} [ringColor=0xffffff] Ring color\n * @property {string | number | THREE.Color} [axisColor=0xffffff] Axis color\n */\nexport interface RotationIndicatorOption {\n ringColor: string | number | THREE.Color;\n axisColor: string | number | THREE.Color;\n}\n\n/**\n * Rotation indicator for ARHoverSession\n * @category Controls-AR\n */\nclass RotationIndicator {\n private _ring: THREE.Mesh;\n private _axis: THREE.Line;\n private _obj: THREE.Group;\n\n /**\n * {@link https://threejs.org/docs/index.html#api/en/objects/Group THREE.Group} object that contains ring & axis.\n */\n public get object() { return this._obj; }\n\n /**\n * Create new RotationIndicator\n * @param {RotationIndicatorOption} [options={}] Options\n */\n constructor({\n ringColor = 0xffffff,\n axisColor = 0xffffff,\n }: Partial<RotationIndicatorOption> = {}) {\n const ringGeometry = new THREE.RingGeometry(0.99, 1, 150, 1, 0, Math.PI * 2);\n const ringMaterial = new THREE.MeshBasicMaterial({ color: ringColor, side: THREE.DoubleSide });\n\n this._ring = new THREE.Mesh(ringGeometry, ringMaterial);\n\n const axisVertices = [\n new THREE.Vector3(0, 0, -1000),\n new THREE.Vector3(0, 0, +1000),\n ];\n const axisGeometry = new THREE.BufferGeometry().setFromPoints(axisVertices);\n const axisMaterial = new THREE.LineBasicMaterial({ color: axisColor });\n\n this._axis = new THREE.Line(axisGeometry, axisMaterial);\n\n this._obj = new THREE.Group();\n this._obj.add(this._ring);\n this._obj.add(this._axis);\n\n this.hide();\n }\n\n /**\n * Show indicator\n */\n public show() {\n this._obj.visible = true;\n }\n\n /**\n * Hide indicator\n */\n public hide() {\n this._obj.visible = false;\n }\n\n /**\n * Change the position of the indicator\n * @param position New position\n */\n public updatePosition(position: THREE.Vector3) {\n this._obj.position.copy(position);\n }\n\n /**\n * Update scale of the ring\n * @param scale New scale\n */\n public updateScale(scale: number) {\n this._ring.scale.setScalar(scale);\n }\n\n /**\n * Update indicator's rotation\n * @param rotation Quaternion value set as new rotation.\n */\n public updateRotation(rotation: THREE.Quaternion) {\n this._obj.quaternion.copy(rotation);\n }\n}\n\nexport default RotationIndicator;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Motion from \"~/controls/Motion\";\nimport RotationIndicator from \"../ui/RotationIndicator\";\nimport * as DEFAULT from \"~/consts/default\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\nimport { getRotationAngle } from \"~/utils\";\nimport ARControl from \"./ARControl\";\n\n/**\n * Options for {@link ARSwirlControl}\n * @category Controls-AR\n * @interface\n * @property {number} [scale=1] Scale(speed) factor of the rotation\n * @property {boolean} [showIndicator=true] Whether to show rotation indicator or not.\n */\nexport interface ARSwirlControlOption {\n scale: number;\n showIndicator: boolean;\n}\n\n/**\n * One finger swirl control on single axis\n * @category Controls-AR\n */\nclass ARSwirlControl implements ARControl {\n /**\n * Current rotation value\n */\n public readonly rotation = new THREE.Quaternion();\n\n // Options\n private _userScale: number;\n\n // Internal States\n private _axis = new THREE.Vector3(0, 1, 0);\n private _enabled = true;\n private _active = false;\n\n private _prevPos = new THREE.Vector2();\n private _fromQuat = new THREE.Quaternion();\n private _toQuat = new THREE.Quaternion();\n\n private _motion: Motion;\n private _rotationIndicator: RotationIndicator | null;\n\n /**\n * Whether this control is enabled or not.\n * @readonly\n */\n public get enabled() { return this._enabled; }\n /**\n * Scale(speed) factor of this control.\n */\n public get scale() { return this._userScale; }\n\n public set scale(val: number) { this._userScale = val; }\n\n /**\n * Create new ARSwirlControl\n * @param {ARSwirlControlOption} [options={}] Options\n */\n constructor({\n scale = 1,\n showIndicator = true,\n }: Partial<ARSwirlControlOption> = {}) {\n this._motion = new Motion({ range: DEFAULT.INFINITE_RANGE });\n this._userScale = scale;\n\n if (showIndicator) {\n this._rotationIndicator = new RotationIndicator();\n }\n }\n\n public init({ view3d }: XRRenderContext) {\n const initialRotation = view3d.model!.scene.quaternion;\n this.updateRotation(initialRotation);\n\n if (this._rotationIndicator) {\n view3d.scene.add(this._rotationIndicator.object);\n }\n }\n\n public destroy({ view3d }: XRContext) {\n if (this._rotationIndicator) {\n view3d.scene.remove(this._rotationIndicator.object);\n }\n }\n\n public updateRotation(rotation: THREE.Quaternion) {\n this.rotation.copy(rotation);\n this._fromQuat.copy(rotation);\n this._toQuat.copy(rotation);\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n }\n\n public activate({ view3d }: XRRenderContext, gesture: TOUCH.GESTURE) {\n if (!this._enabled) return;\n\n this._active = true;\n\n const model = view3d.model!;\n const rotationIndicator = this._rotationIndicator;\n\n if (rotationIndicator) {\n rotationIndicator.show();\n rotationIndicator.updatePosition(model.bbox.getCenter(new THREE.Vector3()));\n rotationIndicator.updateScale(model.size / 2);\n rotationIndicator.updateRotation(model.scene.quaternion);\n }\n }\n\n public deactivate() {\n this._active = false;\n\n if (this._rotationIndicator) {\n this._rotationIndicator.hide();\n }\n }\n\n public updateAxis(axis: THREE.Vector3) {\n this._axis.copy(axis);\n }\n\n public setInitialPos(coords: THREE.Vector2[]) {\n this._prevPos.copy(coords[0]);\n }\n\n public process({ view3d, xrCam }: XRRenderContext, { coords }: XRInputs) {\n if (!this._active || coords.length !== 1) return;\n\n const prevPos = this._prevPos;\n const motion = this._motion;\n\n const model = view3d.model!;\n const coord = coords[0];\n\n const modelPos = model.scene.position.clone();\n const ndcModelPos = new THREE.Vector2().fromArray(modelPos.project(xrCam).toArray());\n\n // Get the rotation angle with the model's NDC coordinates as the center.\n const rotationAngle = getRotationAngle(ndcModelPos, prevPos, coord) * this._userScale;\n const rotation = new THREE.Quaternion().setFromAxisAngle(this._axis, rotationAngle);\n const interpolated = this._getInterpolatedQuaternion();\n\n this._fromQuat.copy(interpolated);\n this._toQuat.premultiply(rotation);\n\n motion.reset(0);\n motion.setEndDelta(1);\n\n prevPos.copy(coord);\n }\n\n public update({ model }: XRRenderContext, deltaTime: number) {\n if (!this._active) return;\n\n const motion = this._motion;\n motion.update(deltaTime);\n\n const interpolated = this._getInterpolatedQuaternion();\n\n this.rotation.copy(interpolated);\n model.scene.quaternion.copy(interpolated);\n }\n\n private _getInterpolatedQuaternion(): THREE.Quaternion {\n const motion = this._motion;\n const toEuler = this._toQuat;\n const fromEuler = this._fromQuat;\n\n const progress = motion.val;\n\n return new THREE.Quaternion().copy(fromEuler).slerp(toEuler, progress);\n }\n}\n\nexport default ARSwirlControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nexport enum GESTURE {\n NONE = 0,\n ONE_FINGER_HORIZONTAL = 1,\n ONE_FINGER_VERTICAL = 2,\n ONE_FINGER = 1 | 2,\n TWO_FINGER_HORIZONTAL = 4,\n TWO_FINGER_VERTICAL = 8,\n TWO_FINGER = 4 | 8,\n PINCH = 16,\n}\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport * as TOUCH from \"~/consts/touch\";\n\nenum STATE {\n WAITING,\n IN_DEADZONE,\n OUT_OF_DEADZONE,\n}\n\n/**\n * Options for {@link DeadzoneChecker}\n * @category Controls-AR\n * @interface\n * @property {number} size Size of the deadzone circle.\n */\nexport interface DeadzoneCheckerOption {\n size: number;\n}\n\n/**\n * Deadzone checker for deadzone-based controls\n * @category Controls-AR\n */\nclass DeadzoneChecker {\n // Options\n private _size: number;\n\n // Internal States\n private _state = STATE.WAITING;\n private _detectedGesture = TOUCH.GESTURE.NONE;\n private _testingGestures = TOUCH.GESTURE.NONE;\n private _lastFingerCount = 0;\n private _aspect: number = 1;\n\n // Store two prev positions, as it should be maintained separately\n private _prevOneFingerPos = new THREE.Vector2();\n private _prevTwoFingerPos = new THREE.Vector2();\n private _initialTwoFingerDistance = 0;\n private _prevOneFingerPosInitialized = false;\n private _prevTwoFingerPosInitialized = false;\n\n /**\n * Size of the deadzone.\n * @type number\n */\n public get size() { return this._size; }\n public get inDeadzone() { return this._state === STATE.IN_DEADZONE; }\n\n public set size(val: number) { this._size = val; }\n\n /**\n * Create new DeadzoneChecker\n * @param {DeadzoneCheckerOption} [options={}] Options\n */\n constructor({\n size = 0.1,\n }: Partial<DeadzoneCheckerOption> = {}) {\n this._size = size;\n }\n\n /**\n * Set screen aspect(height / width)\n * @param aspect Screen aspect value\n */\n public setAspect(aspect: number) {\n this._aspect = aspect;\n }\n\n public setFirstInput(inputs: THREE.Vector2[]) {\n const fingerCount = inputs.length;\n\n if (fingerCount === 1 && !this._prevOneFingerPosInitialized) {\n this._prevOneFingerPos.copy(inputs[0]);\n this._prevOneFingerPosInitialized = true;\n } else if (fingerCount === 2 && !this._prevTwoFingerPosInitialized) {\n this._prevTwoFingerPos.copy(new THREE.Vector2().addVectors(inputs[0], inputs[1]).multiplyScalar(0.5));\n this._initialTwoFingerDistance = new THREE.Vector2().subVectors(inputs[0], inputs[1]).length();\n this._prevTwoFingerPosInitialized = true;\n }\n\n this._lastFingerCount = fingerCount;\n this._state = STATE.IN_DEADZONE;\n }\n\n public addTestingGestures(...gestures: TOUCH.GESTURE[]) {\n this._testingGestures = this._testingGestures | gestures.reduce((gesture, accumulated) => gesture | accumulated, TOUCH.GESTURE.NONE);\n }\n\n public cleanup() {\n this._testingGestures = TOUCH.GESTURE.NONE;\n this._lastFingerCount = 0;\n this._prevOneFingerPosInitialized = false;\n this._prevTwoFingerPosInitialized = false;\n this._initialTwoFingerDistance = 0;\n this._detectedGesture = TOUCH.GESTURE.NONE;\n this._state = STATE.WAITING;\n }\n\n public applyScreenAspect(inputs: THREE.Vector2[]) {\n const aspect = this._aspect;\n\n inputs.forEach(input => {\n if (aspect > 1) {\n input.setY(input.y * aspect);\n } else {\n input.setX(input.x / aspect);\n }\n });\n }\n\n public check(inputs: THREE.Vector2[]): TOUCH.GESTURE {\n const state = this._state;\n const deadzone = this._size;\n const testingGestures = this._testingGestures;\n const lastFingerCount = this._lastFingerCount;\n const fingerCount = inputs.length;\n\n if (state === STATE.OUT_OF_DEADZONE) {\n return this._detectedGesture;\n }\n\n this._lastFingerCount = fingerCount;\n this.applyScreenAspect(inputs);\n\n if (fingerCount !== lastFingerCount) {\n this.setFirstInput(inputs);\n return TOUCH.GESTURE.NONE;\n }\n\n if (fingerCount === 1) {\n const input = inputs[0];\n const prevPos = this._prevOneFingerPos.clone();\n\n const diff = new THREE.Vector2().subVectors(input, prevPos);\n if (diff.length() > deadzone) {\n if (Math.abs(diff.x) > Math.abs(diff.y)) {\n if (TOUCH.GESTURE.ONE_FINGER_HORIZONTAL & testingGestures) {\n this._detectedGesture = TOUCH.GESTURE.ONE_FINGER_HORIZONTAL;\n }\n } else {\n if (TOUCH.GESTURE.ONE_FINGER_VERTICAL & testingGestures) {\n this._detectedGesture = TOUCH.GESTURE.ONE_FINGER_VERTICAL;\n }\n }\n }\n } else if (fingerCount === 2) {\n const middle = new THREE.Vector2().addVectors(inputs[1], inputs[0]).multiplyScalar(0.5);\n const prevPos = this._prevTwoFingerPos.clone();\n\n const diff = new THREE.Vector2().subVectors(middle, prevPos);\n if (diff.length() > deadzone) {\n if (Math.abs(diff.x) > Math.abs(diff.y)) {\n if (TOUCH.GESTURE.TWO_FINGER_HORIZONTAL & testingGestures) {\n this._detectedGesture = TOUCH.GESTURE.TWO_FINGER_HORIZONTAL;\n }\n } else {\n if (TOUCH.GESTURE.TWO_FINGER_VERTICAL & testingGestures) {\n this._detectedGesture = TOUCH.GESTURE.TWO_FINGER_VERTICAL;\n }\n }\n }\n\n const distance = new THREE.Vector2().subVectors(inputs[1], inputs[0]).length();\n\n if (Math.abs(distance - this._initialTwoFingerDistance) > deadzone) {\n if (TOUCH.GESTURE.PINCH & testingGestures) {\n this._detectedGesture = TOUCH.GESTURE.PINCH;\n }\n }\n }\n\n if (this._detectedGesture !== TOUCH.GESTURE.NONE) {\n this._state = STATE.OUT_OF_DEADZONE;\n }\n\n return this._detectedGesture;\n }\n}\n\nexport default DeadzoneChecker;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport { toPowerOfTwo } from \"~/utils\";\n\n/**\n * Options for {@link ScaleUI}\n * @category Controls-AR\n * @interface\n * @property {number} [width=0.1] UI width, in meter.\n * @property {number} [padding=20] UI's padding value, in px.\n * @property {number} [offset=0.05] UI's Y-axis offset from model's bbox max y, in meter.\n * @property {number} [font=\"64px sans-serif\"] UI's font. See {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/font CanvasRenderingContext2D#font}\n * @property {number} [color=\"white\"] UI's font color. See {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle CanvasRenderingContext2D#fillStyle}\n */\nexport interface ScaleUIOption {\n width: number;\n padding: number;\n offset: number;\n font: CanvasRenderingContext2D[\"font\"];\n color: CanvasRenderingContext2D[\"fillStyle\"];\n}\n\n/**\n * UI element displaying model's scale percentage info when user chaning model's scale.\n * @category Controls-AR\n */\nclass ScaleUI {\n private _canvas: HTMLCanvasElement;\n private _ctx: CanvasRenderingContext2D;\n private _mesh: THREE.Mesh;\n private _texture: THREE.CanvasTexture;\n private _font: CanvasRenderingContext2D[\"font\"];\n private _color: CanvasRenderingContext2D[\"fillStyle\"];\n private _padding: number;\n private _offset: number;\n private _height: number;\n\n /**\n * Scale UI's plane mesh\n * @readonly\n */\n public get mesh() { return this._mesh; }\n /**\n * Scale UI's height value\n * @readonly\n */\n public get height() { return this._height; }\n /**\n * Whether UI is visible or not.\n * @readonly\n */\n public get visible() { return this._mesh.visible; }\n\n /**\n * Create new instance of ScaleUI\n * @param {ScaleUIOption} [options={}] Options\n */\n constructor({\n width = 0.1,\n padding = 20,\n offset = 0.05,\n font = \"64px sans-serif\",\n color = \"white\",\n }: Partial<ScaleUIOption> = {}) {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\")!;\n\n ctx.font = font;\n\n // Maximum canvas width should be equal to this\n const maxText = ctx.measureText(\"100%\");\n\n // Following APIs won't work on IE, but it's WebXR so I think it's okay\n const maxWidth = maxText.actualBoundingBoxLeft + maxText.actualBoundingBoxRight;\n const maxHeight = maxText.actualBoundingBoxAscent + maxText.actualBoundingBoxDescent;\n const widthPowerOfTwo = toPowerOfTwo(maxWidth);\n\n canvas.width = widthPowerOfTwo;\n canvas.height = widthPowerOfTwo;\n\n // This considers increased amount by making width to power of two\n const planeWidth = width * (widthPowerOfTwo / maxWidth);\n\n this._ctx = ctx;\n this._canvas = canvas;\n this._height = planeWidth * maxHeight / maxWidth; // Text height inside plane\n this._texture = new THREE.CanvasTexture(canvas);\n\n // Plane is square\n const uiGeometry = new THREE.PlaneGeometry(planeWidth, planeWidth);\n const mesh = new THREE.Mesh(\n uiGeometry,\n new THREE.MeshBasicMaterial({\n map: this._texture,\n transparent: true,\n }),\n );\n mesh.matrixAutoUpdate = false;\n\n this._mesh = mesh;\n this._font = font;\n this._color = color;\n this._padding = padding;\n this._offset = offset;\n }\n\n public updatePosition(position: THREE.Vector3, focus: THREE.Vector3) {\n // Update mesh\n const mesh = this._mesh;\n mesh.lookAt(focus);\n mesh.position.copy(position);\n mesh.position.setY(position.y + this._height / 2 + this._offset);\n mesh.updateMatrix();\n }\n\n public updateScale(scale: number) {\n const ctx = this._ctx;\n const canvas = this._canvas;\n const padding = this._padding;\n const scalePercentage = (scale * 100).toFixed(0);\n\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n const centerX = canvas.width / 2;\n const centerY = canvas.height / 2;\n\n // Draw round rect\n const textSize = ctx.measureText(`${scalePercentage}%`);\n const halfWidth = (textSize.actualBoundingBoxLeft + textSize.actualBoundingBoxRight) / 2;\n const halfHeight = (textSize.actualBoundingBoxAscent + textSize.actualBoundingBoxDescent) / 2;\n\n ctx.beginPath();\n\n ctx.moveTo(centerX - halfWidth, centerY - halfHeight - padding);\n ctx.lineTo(centerX + halfWidth, centerY - halfHeight - padding);\n ctx.quadraticCurveTo(centerX + halfWidth + padding, centerY - halfHeight - padding, centerX + halfWidth + padding, centerY - halfHeight);\n ctx.lineTo(centerX + halfWidth + padding, centerY + halfHeight);\n ctx.quadraticCurveTo(centerX + halfWidth + padding, centerY + halfHeight + padding, centerX + halfWidth, centerY + halfHeight + padding);\n ctx.lineTo(centerX - halfWidth, centerY + halfHeight + padding);\n ctx.quadraticCurveTo(centerX - halfWidth - padding, centerY + halfHeight + padding, centerX - halfWidth - padding, centerY + halfHeight);\n ctx.lineTo(centerX - halfWidth - padding, centerY - halfHeight);\n ctx.quadraticCurveTo(centerX - halfWidth - padding, centerY - halfHeight - padding, centerX - halfWidth, centerY - halfHeight - padding);\n\n ctx.closePath();\n\n ctx.lineWidth = 5;\n ctx.fillStyle = \"rgba(0, 0, 0, 0.3)\";\n ctx.fill();\n ctx.stroke();\n\n // Draw text\n ctx.font = this._font;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.strokeStyle = this._color;\n ctx.fillStyle = this._color;\n\n ctx.fillText(`${scalePercentage}%`, centerX, centerY);\n\n this._texture.needsUpdate = true;\n }\n\n /**\n * Show UI\n */\n public show() {\n this._mesh.visible = true;\n }\n\n /**\n * Hide UI\n */\n public hide() {\n this._mesh.visible = false;\n }\n}\n\nexport default ScaleUI;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARControl from \"./ARControl\";\nimport Motion from \"~/controls/Motion\";\nimport ScaleUI from \"../ui/ScaleUI\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\n\n/**\n * Options for {@link ARScaleControl}\n * @category Controls-AR\n * @interface\n * @property {number} [min=0.05] Minimum scale, default is 0.05(5%)\n * @property {number} [max=2] Maximum scale, default is 2(200%)\n */\nexport interface ARScaleControlOption {\n min: number;\n max: number;\n}\n\n/**\n * Model's scale controller which works on AR(WebXR) mode.\n * @category Controls-AR\n */\nclass ARScaleControl implements ARControl {\n // TODO: add option for \"user scale\"\n\n // Internal states\n private _motion: Motion;\n private _enabled = true;\n private _active = false;\n private _prevCoordDistance = -1;\n private _scaleMultiplier = 1;\n private _initialScale = new THREE.Vector3();\n private _ui = new ScaleUI();\n\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n public get scale() {\n return this._initialScale.clone().multiplyScalar(this._scaleMultiplier);\n }\n public get scaleMultiplier() { return this._scaleMultiplier; }\n /**\n * Range of the scale\n * @readonly\n */\n public get range() { return this._motion.range; }\n\n /**\n * Create new instance of ARScaleControl\n * @param {ARScaleControlOption} [options={}] Options\n */\n constructor({\n min = 0.05,\n max = 2,\n } = {}) {\n this._motion = new Motion({ duration: 0, range: { min, max } });\n this._motion.reset(1); // default scale is 1(100%)\n this._ui = new ScaleUI();\n }\n\n public init({ view3d }: XRRenderContext) {\n this._initialScale.copy(view3d.model!.scene.scale);\n view3d.scene.add(this._ui.mesh);\n }\n\n public destroy({ view3d }: XRContext) {\n view3d.scene.remove(this._ui.mesh);\n }\n\n public setInitialPos(coords: THREE.Vector2[]) {\n this._prevCoordDistance = new THREE.Vector2().subVectors(coords[0], coords[1]).length();\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n this.deactivate();\n }\n\n public activate(ctx: XRRenderContext, gesture: TOUCH.GESTURE) {\n this._active = true;\n this._ui.show();\n this._updateUIPosition(ctx);\n }\n\n public deactivate() {\n this._active = false;\n this._ui.hide();\n this._prevCoordDistance = -1;\n }\n\n /**\n * Update scale range\n * @param min Minimum scale\n * @param max Maximum scale\n */\n public setRange(min: number, max: number) {\n this._motion.range = { min, max };\n }\n\n public process(ctx: XRRenderContext, { coords }: XRInputs) {\n if (coords.length !== 2 || !this._enabled || !this._active) return;\n\n const motion = this._motion;\n const distance = new THREE.Vector2().subVectors(coords[0], coords[1]).length();\n const delta = (distance - this._prevCoordDistance);\n\n motion.setEndDelta(delta);\n this._prevCoordDistance = distance;\n\n this._updateUIPosition(ctx);\n }\n\n public update({ model }: XRRenderContext, deltaTime: number) {\n if (!this._enabled || !this._active) return;\n\n const motion = this._motion;\n motion.update(deltaTime);\n\n this._scaleMultiplier = motion.val;\n this._ui.updateScale(this._scaleMultiplier);\n\n model.scene.scale.copy(this.scale);\n }\n\n private _updateUIPosition({ view3d, xrCam }: XRRenderContext) {\n // Update UI\n const model = view3d.model!;\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n const uiPos = model.scene.position.clone().setY(model.bbox.max.y);\n\n this._ui.updatePosition(uiPos, camPos);\n }\n}\n\nexport default ARScaleControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Motion from \"../../Motion\";\nimport { Range } from \"~/types/internal\";\n\n/**\n * Options for {@link FloorIndicator}\n * @category Controls-AR\n * @interface\n * @property {number} [ringOpacity=0.3] Ring's opacity.\n * @property {number} [dirIndicatorOpacity=1] Direction indicator's opacity.\n * @property {number} [fadeoutDuration=1000] Fadeout animation's duration.\n */\nexport interface FloorIndicatorOption {\n opacityMin: number;\n opacityMax: number;\n fadeoutDuration: number;\n}\n\n/**\n * Ring type indicator for showing where the model's at.\n * @category Controls-AR\n */\nclass FloorIndicator {\n private _mesh: THREE.Mesh;\n private _animator: Motion;\n private _opacityRange: Range;\n\n /**\n * Ring mesh\n */\n public get mesh() { return this._mesh; }\n\n /**\n * Create new instance of FloorIndicator\n * @param {FloorIndicatorOption} [options={}] Options\n */\n constructor({\n ringOpacity = 0.3,\n dirIndicatorOpacity = 1,\n fadeoutDuration = 1000,\n } = {}) {\n const deg10 = Math.PI / 18;\n\n const dimmedRingGeomtry = new THREE.RingGeometry(0.975, 1, 150, 1, -6 * deg10, 30 * deg10);\n const reticle = new THREE.CircleGeometry(0.1, 30, 0, Math.PI * 2);\n dimmedRingGeomtry.merge(reticle);\n\n const highlightedRingGeometry = new THREE.RingGeometry(0.96, 1.015, 30, 1, 25 * deg10, 4 * deg10);\n\n // Create little triangle in ring\n const ringVertices = highlightedRingGeometry.vertices;\n const trianglePart = ringVertices.slice(Math.floor(11 * ringVertices.length / 16), Math.floor(13 * ringVertices.length / 16));\n const firstY = trianglePart[0].y;\n const midIndex = Math.floor(trianglePart.length / 2);\n trianglePart.forEach((vec, vecIdx) => {\n const offsetAmount = 0.025 * (midIndex - Math.abs(vecIdx - midIndex));\n vec.setY(firstY - offsetAmount);\n });\n\n const indicatorMat = new THREE.Matrix4().makeRotationX(-Math.PI / 2);\n const mergedGeometry = new THREE.Geometry();\n\n mergedGeometry.merge(dimmedRingGeomtry, indicatorMat, 0);\n mergedGeometry.merge(highlightedRingGeometry, indicatorMat, 1);\n\n const dimmedMaterial = new THREE.MeshBasicMaterial({\n transparent: true,\n opacity: ringOpacity,\n color: 0xffffff,\n });\n const highlightMaterial = new THREE.MeshBasicMaterial({\n transparent: true,\n opacity: dirIndicatorOpacity,\n color: 0xffffff,\n });\n const materials = [dimmedMaterial, highlightMaterial];\n\n this._mesh = new THREE.Mesh(mergedGeometry, materials);\n this._mesh.matrixAutoUpdate = false;\n this._animator = new Motion({ duration: fadeoutDuration });\n this._opacityRange = {\n min: ringOpacity,\n max: dirIndicatorOpacity,\n };\n }\n\n public update({\n delta,\n scale,\n position,\n rotation,\n }: {\n delta: number,\n scale: number,\n position: THREE.Vector3,\n rotation: THREE.Quaternion,\n }) {\n const mesh = this._mesh;\n const animator = this._animator;\n\n if (!this._mesh.visible) return;\n\n animator.update(delta);\n\n const materials = this._mesh.material as THREE.Material[];\n const minOpacityMat = materials[0];\n const maxOpacityMat = materials[1];\n const opacityRange = this._opacityRange;\n\n minOpacityMat.opacity = animator.val * opacityRange.min;\n maxOpacityMat.opacity = animator.val * opacityRange.max;\n\n if (animator.val <= 0) {\n mesh.visible = false;\n }\n\n // Update mesh\n mesh.scale.setScalar(scale);\n mesh.position.copy(position);\n mesh.quaternion.copy(rotation);\n mesh.updateMatrix();\n }\n\n public show() {\n this._mesh.visible = true;\n this._animator.reset(1);\n }\n\n public fadeout() {\n this._animator.setEndDelta(-1);\n }\n}\n\nexport default FloorIndicator;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARControl from \"./ARControl\";\nimport Motion from \"~/controls/Motion\";\nimport RotationIndicator from \"../ui/RotationIndicator\";\nimport * as DEFAULT from \"~/consts/default\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\nimport * as TOUCH from \"~/consts/touch\";\n\nenum STATE {\n WAITING,\n ROTATE_HORIZONTAL,\n ROTATE_VERTICAL,\n}\n\n/**\n * Options for {@link ARSwipeControl}\n * @category Controls-AR\n * @interface\n * @property {number} [scale=1] Scale(speed) factor of the rotation\n */\nexport interface ARSwipeControlOption {\n scale: number;\n}\n\n/**\n * Two finger swipe control\n * @category Controls-AR\n */\nclass ARSwipeControl implements ARControl {\n /**\n * Current rotation value\n */\n public readonly rotation = new THREE.Quaternion();\n\n // Options\n private _userScale: number;\n\n // Internal States\n private _state = STATE.WAITING;\n private _enabled = true;\n private _active = false;\n\n private _prevPos = new THREE.Vector2();\n private _fromQuat = new THREE.Quaternion();\n private _toQuat = new THREE.Quaternion();\n\n private _horizontalAxis = new THREE.Vector3();\n private _verticalAxis = new THREE.Vector3();\n\n private _motion: Motion;\n private _rotationIndicator: RotationIndicator;\n\n /**\n * Whether this control is enabled or not.\n * @readonly\n */\n public get enabled() { return this._enabled; }\n /**\n * Scale(speed) factor of this control.\n */\n public get scale() { return this._userScale; }\n public get horizontalAxis() { return this._horizontalAxis; }\n public get verticalAxis() { return this._verticalAxis; }\n\n public set scale(val: number) { this._userScale = val; }\n\n /**\n * Create new ARSwipeControl\n * @param {ARSwipeControlOption} [options={}] Options\n */\n constructor({\n scale = 1,\n }: Partial<{\n scale: number,\n }> = {}) {\n this._motion = new Motion({ range: DEFAULT.INFINITE_RANGE });\n this._rotationIndicator = new RotationIndicator();\n this._userScale = scale;\n }\n\n public init({ view3d }: XRRenderContext) {\n const initialRotation = view3d.model!.scene.quaternion;\n this.updateRotation(initialRotation);\n view3d.scene.add(this._rotationIndicator.object);\n }\n\n public destroy({ view3d }: XRContext) {\n view3d.scene.remove(this._rotationIndicator.object);\n }\n\n public updateRotation(rotation: THREE.Quaternion) {\n this.rotation.copy(rotation);\n this._fromQuat.copy(rotation);\n this._toQuat.copy(rotation);\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n }\n\n public updateAxis(horizontal: THREE.Vector3, vertical: THREE.Vector3) {\n this._horizontalAxis.copy(horizontal);\n this._verticalAxis.copy(vertical);\n }\n\n public activate({ view3d }: XRRenderContext, gesture: TOUCH.GESTURE) {\n if (!this._enabled) return;\n\n const model = view3d.model!;\n const rotationIndicator = this._rotationIndicator;\n\n this._active = true;\n rotationIndicator.show();\n rotationIndicator.updatePosition(model.bbox.getCenter(new THREE.Vector3()));\n rotationIndicator.updateScale(model.size / 2);\n\n if (gesture === TOUCH.GESTURE.TWO_FINGER_HORIZONTAL) {\n rotationIndicator.updateRotation(\n model.scene.quaternion.clone()\n .multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0))),\n );\n this._state = STATE.ROTATE_HORIZONTAL;\n } else if (gesture === TOUCH.GESTURE.TWO_FINGER_VERTICAL) {\n rotationIndicator.updateRotation(\n model.scene.quaternion.clone()\n .multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, 0))),\n );\n this._state = STATE.ROTATE_VERTICAL;\n }\n }\n\n public deactivate() {\n this._active = false;\n this._rotationIndicator.hide();\n this._state = STATE.WAITING;\n }\n\n public setInitialPos(coords: THREE.Vector2[]) {\n if (coords.length < 2) return;\n this._prevPos.set(\n (coords[0].x + coords[1].x) / 2,\n (coords[0].y + coords[1].y) / 2,\n );\n }\n\n public process(ctx: XRRenderContext, { coords }: XRInputs) {\n if (!this._active || coords.length !== 2) return;\n\n const state = this._state;\n const prevPos = this._prevPos;\n const motion = this._motion;\n const scale = this._userScale;\n\n const middlePos = new THREE.Vector2(\n (coords[0].x + coords[1].x) / 2,\n (coords[0].y + coords[1].y) / 2,\n );\n const posDiff = new THREE.Vector2().subVectors(prevPos, middlePos);\n\n const rotationAxis = state === STATE.ROTATE_HORIZONTAL\n ? this._horizontalAxis\n : this._verticalAxis;\n const rotationAngle = state === STATE.ROTATE_HORIZONTAL\n ? posDiff.x * scale\n : -posDiff.y * scale;\n\n const rotation = new THREE.Quaternion().setFromAxisAngle(rotationAxis, rotationAngle);\n const interpolated = this._getInterpolatedQuaternion();\n\n this._fromQuat.copy(interpolated);\n this._toQuat.premultiply(rotation);\n\n motion.reset(0);\n motion.setEndDelta(1);\n\n prevPos.copy(middlePos);\n }\n\n public update({ model }: XRRenderContext, deltaTime: number) {\n const motion = this._motion;\n motion.update(deltaTime);\n\n const interpolated = this._getInterpolatedQuaternion();\n\n this.rotation.copy(interpolated);\n model.scene.quaternion.copy(this.rotation);\n }\n\n private _getInterpolatedQuaternion(): THREE.Quaternion {\n const motion = this._motion;\n const toEuler = this._toQuat;\n const fromEuler = this._fromQuat;\n\n const progress = motion.val;\n\n return new THREE.Quaternion().copy(fromEuler).slerp(toEuler, progress);\n }\n}\n\nexport default ARSwipeControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARSwirlControl, { ARSwirlControlOption } from \"../common/ARSwirlControl\";\nimport ARFloorTranslateControl, { ARFloorTranslateControlOption } from \"./ARFloorTranslateControl\";\nimport ARScaleControl, { ARScaleControlOption } from \"../common/ARScaleControl\";\nimport FloorIndicator, { FloorIndicatorOption } from \"../ui/FloorIndicator\";\nimport * as XR from \"~/consts/xr\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\nimport DeadzoneChecker, { DeadzoneCheckerOption } from \"../common/DeadzoneChecker\";\n\n/**\n * Options for the {@link ARFloorControl}\n * @category Controls-AR\n * @interface\n * @property {ARSwirlControlOptions} rotate Options for {@link ARSwirlControl}\n * @property {ARFloorTranslateControlOption} translate Options for {@link ARFloorTranslateControl}\n * @property {ARScaleControlOption} scale Options for {@link ARScaleControl}\n * @property {FloorIndicatorOption} floorIndicator Options for {@link FloorIndicator}\n * @property {DeadzoneCheckerOption} deadzone Options for {@link DeadzoneChecker}\n */\nexport interface ARFloorControlOption {\n rotate: Partial<ARSwirlControlOption>;\n translate: Partial<ARFloorTranslateControlOption>;\n scale: Partial<ARScaleControlOption>;\n floorIndicator: Partial<FloorIndicatorOption>;\n deadzone: Partial<DeadzoneCheckerOption>;\n}\n\n/**\n * AR control for {@link FloorARSession}\n * @category Controls-AR\n */\nclass ARFloorControl {\n private _enabled = true;\n private _initialized = false;\n private _modelHit = false;\n private _hitTestSource: any = null;\n private _deadzoneChecker: DeadzoneChecker;\n private _rotateControl: ARSwirlControl;\n private _translateControl: ARFloorTranslateControl;\n private _scaleControl: ARScaleControl;\n private _floorIndicator: FloorIndicator;\n\n /**\n * Return whether this control is enabled or not\n */\n public get enabled() { return this._enabled; }\n /**\n * {@link ARSwirlControl} in this control\n */\n public get rotate() { return this._rotateControl; }\n /**\n * {@link ARFloorTranslateControl} in this control\n */\n public get translate() { return this._translateControl; }\n /**\n * {@link ARScaleControl} in this control\n */\n public get scale() { return this._scaleControl; }\n public get controls() {\n return [this._rotateControl, this._translateControl, this._scaleControl];\n }\n\n /**\n * Create new instance of ARFloorControl\n * @param {ARFloorControlOption} options Options\n */\n constructor(options: Partial<ARFloorControlOption> = {}) {\n this._rotateControl = new ARSwirlControl({\n showIndicator: false,\n ...options.rotate,\n });\n this._translateControl = new ARFloorTranslateControl(options.translate);\n this._scaleControl = new ARScaleControl(options.scale);\n this._floorIndicator = new FloorIndicator(options.floorIndicator);\n this._deadzoneChecker = new DeadzoneChecker(options.deadzone);\n }\n\n public init(ctx: XRRenderContext, initialFloorPos: THREE.Vector3) {\n const { session, view3d, size } = ctx;\n\n this.controls.forEach(control => control.init(ctx));\n this._translateControl.initFloorPosition(initialFloorPos);\n this._deadzoneChecker.setAspect(size.height / size.width);\n\n view3d.scene.add(this._floorIndicator.mesh);\n\n this._initialized = true;\n\n session.requestHitTestSourceForTransientInput({ profile: XR.INPUT_PROFILE.TOUCH })\n .then((transientHitTestSource: any) => {\n this._hitTestSource = transientHitTestSource;\n });\n }\n\n /**\n * Destroy this control and deactivate it\n * @param view3d Instance of the {@link View3D}\n */\n public destroy(ctx: XRContext) {\n if (!this._initialized) return;\n\n if (this._hitTestSource) {\n this._hitTestSource.cancel();\n this._hitTestSource = null;\n }\n\n ctx.view3d.scene.remove(this._floorIndicator.mesh);\n\n this.deactivate();\n this.controls.forEach(control => control.destroy(ctx));\n\n this._initialized = false;\n }\n\n public deactivate() {\n this._modelHit = false;\n this._deadzoneChecker.cleanup();\n this.controls.forEach(control => control.deactivate());\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n this.deactivate();\n }\n\n public update(ctx: XRRenderContext) {\n const { view3d, session, frame } = ctx;\n const hitTestSource = this._hitTestSource;\n\n if (!hitTestSource || !view3d.model) return;\n\n const deadzoneChecker = this._deadzoneChecker;\n const inputSources = session.inputSources;\n const hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);\n const coords = this._hitResultToVector(hitResults);\n const xrInputs = {\n coords,\n inputSources,\n hitResults,\n };\n\n if (deadzoneChecker.inDeadzone) {\n this._checkDeadzone(ctx, xrInputs);\n } else {\n this._processInput(ctx, xrInputs);\n }\n this._updateControls(ctx);\n }\n\n public onSelectStart = (ctx: XRRenderContext) => {\n const { view3d, frame, xrCam, referenceSpace } = ctx;\n const hitTestSource = this._hitTestSource;\n\n if (!hitTestSource || !this._enabled) return;\n\n const deadzoneChecker = this._deadzoneChecker;\n const rotateControl = this._rotateControl;\n const translateControl = this._translateControl;\n const scaleControl = this._scaleControl;\n\n // Update deadzone testing gestures\n if (rotateControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.ONE_FINGER);\n }\n if (translateControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.ONE_FINGER);\n }\n if (scaleControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.PINCH);\n }\n\n const hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);\n const coords = this._hitResultToVector(hitResults);\n deadzoneChecker.applyScreenAspect(coords);\n deadzoneChecker.setFirstInput(coords);\n\n if (coords.length === 1) {\n // Check finger is on the model\n const modelBbox = view3d.model!.bbox;\n\n const targetRayPose = frame.getPose(hitResults[0].inputSource.targetRaySpace, referenceSpace);\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n\n const fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();\n const fingerRay = new THREE.Ray(camPos, fingerDir);\n const intersection = fingerRay.intersectBox(modelBbox, new THREE.Vector3());\n\n if (intersection) {\n // Touch point intersected with model\n this._modelHit = true;\n }\n }\n\n this._floorIndicator.show();\n }\n\n public onSelectEnd = () => {\n this.deactivate();\n this._floorIndicator.fadeout();\n }\n\n private _checkDeadzone(ctx: XRRenderContext, { coords }: XRInputs) {\n const gesture = this._deadzoneChecker.check(coords.map(coord => coord.clone()));\n const rotateControl = this._rotateControl;\n const translateControl = this._translateControl;\n const scaleControl = this._scaleControl;\n\n if (gesture === TOUCH.GESTURE.NONE) return;\n\n switch (gesture) {\n case TOUCH.GESTURE.ONE_FINGER_HORIZONTAL:\n case TOUCH.GESTURE.ONE_FINGER_VERTICAL:\n if (this._modelHit) {\n translateControl.activate(ctx, gesture);\n translateControl.setInitialPos(coords);\n } else {\n rotateControl.activate(ctx, gesture);\n rotateControl.setInitialPos(coords);\n }\n break;\n case TOUCH.GESTURE.PINCH:\n scaleControl.activate(ctx, gesture);\n scaleControl.setInitialPos(coords);\n break;\n }\n }\n\n private _processInput(ctx: XRRenderContext, inputs: XRInputs) {\n this.controls.forEach(control => control.process(ctx, inputs));\n }\n\n private _updateControls(ctx: XRRenderContext) {\n const { view3d, model, delta } = ctx;\n const deltaMilisec = delta * 1000;\n\n this.controls.forEach(control => control.update(ctx, deltaMilisec));\n\n model.scene.updateMatrix();\n\n const modelRotation = this._rotateControl.rotation;\n const floorPosition = this._translateControl.floorPosition;\n view3d.scene.update(model, {\n floorPosition,\n });\n\n // Get a scaled bbox, which only has scale applied on it.\n const scaleControl = this._scaleControl;\n const scaledBbox = model.initialBbox;\n scaledBbox.min.multiply(scaleControl.scale);\n scaledBbox.max.multiply(scaleControl.scale);\n\n const floorIndicator = this._floorIndicator;\n const boundingSphere = scaledBbox.getBoundingSphere(new THREE.Sphere());\n\n floorIndicator.update({\n delta: deltaMilisec,\n scale: boundingSphere.radius,\n position: floorPosition,\n rotation: modelRotation,\n });\n }\n\n private _hitResultToVector(hitResults: any[]) {\n return hitResults.map(input => {\n return new THREE.Vector2().set(\n input.inputSource.gamepad.axes[0],\n -input.inputSource.gamepad.axes[1],\n );\n });\n }\n}\n\nexport default ARFloorControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport WebARSession, { WebARSessionOption } from \"./WebARSession\";\nimport HitTest from \"./features/HitTest\";\nimport Animation from \"~/core/Animation\";\nimport ARFloorControl, { ARFloorControlOption } from \"~/controls/ar/floor/ARFloorControl\";\nimport { merge } from \"~/utils\";\nimport * as XR from \"~/consts/xr\";\nimport { XRRenderContext, XRContext } from \"~/types/internal\";\n\n/**\n * Options for {@link FloorARSession}.\n * This type is intersection of {@link WebARSessionOption} and {@link ARControlOption}\n * @interface\n * @extends WebARSessionOption\n * @extends ARFloorControlOption\n */\ninterface FloorARSessionOption extends WebARSessionOption, ARFloorControlOption {}\n\n/**\n * WebXR based AR session which puts model on the detected floor.\n * @category XR\n * @fires WebARSession#start\n * @fires WebARSession#end\n * @fires WebARSession#canPlace\n * @fires WebARSession#modelPlaced\n */\nclass FloorARSession extends WebARSession {\n private _options: Partial<FloorARSessionOption>;\n private _control: ARFloorControl | null;\n private _renderContext: XRRenderContext | null;\n private _modelPlaced: boolean;\n private _hitTest: HitTest;\n\n /**\n * {@link ARControl} instance of this session\n * @type ARFloorControl | null\n */\n public get control() { return this._control; }\n\n /**\n * Create new instance of FloorARSession\n * @param {FloorARSessionOption} options Options\n */\n constructor(options: Partial<FloorARSessionOption> = {}) {\n super(options);\n\n this._control = null;\n this._renderContext = null;\n this._modelPlaced = false;\n\n this._hitTest = new HitTest();\n\n this._features = merge(this._features, this._hitTest.features);\n this._options = options;\n }\n\n public onStart = (ctx: XRContext) => {\n const { view3d, session } = ctx;\n\n super.onStart(ctx);\n\n this._control = new ARFloorControl(this._options);\n\n view3d.scene.hide();\n this._hitTest.init(session);\n }\n\n public onEnd = (ctx: XRContext) => {\n const { view3d, session } = ctx;\n\n super.onEnd(ctx);\n\n this._renderContext = null;\n this._modelPlaced = false;\n\n session.removeEventListener(XR.EVENTS.SELECT_START, this._onSelectStart);\n session.removeEventListener(XR.EVENTS.SELECT_END, this._onSelectEnd);\n\n this._hitTest.destroy();\n this._control!.destroy(ctx);\n this._control = null;\n\n view3d.scene.show();\n }\n\n protected _beforeRender = (ctx: XRRenderContext) => {\n this._renderContext = ctx;\n if (!this._modelPlaced) {\n this._initModelPosition(ctx);\n } else {\n this._control!.update(ctx);\n }\n }\n\n private _initModelPosition(ctx: XRRenderContext) {\n const {view3d, frame, session} = ctx;\n const model = view3d.model;\n const hitTest = this._hitTest;\n\n // Make sure the model is loaded\n if (!hitTest.ready || !model) return;\n\n const control = this._control!;\n const referenceSpace = view3d.renderer.threeRenderer.xr.getReferenceSpace();\n const hitTestResults = hitTest.getResults(frame);\n\n if (hitTestResults.length <= 0) return;\n\n const hit = hitTestResults[0];\n const hitMatrix = new THREE.Matrix4().fromArray(hit.getPose(referenceSpace).transform.matrix);\n\n // If transformed coords space's y axis is not facing up, don't use it.\n if (hitMatrix.elements[5] < 0.75) return;\n\n const modelRoot = model.scene;\n const hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix);\n\n // Reset rotation & update position\n modelRoot.quaternion.set(0, 0, 0, 1);\n modelRoot.position.copy(hitPosition);\n\n modelRoot.position.setY(modelRoot.position.y - model.bbox.min.y);\n modelRoot.updateMatrix();\n\n view3d.scene.update(model);\n view3d.scene.show();\n this.emit(\"canPlace\");\n\n // Don't need it\n hitTest.destroy();\n\n session.addEventListener(XR.EVENTS.SELECT_START, this._onSelectStart);\n session.addEventListener(XR.EVENTS.SELECT_END, this._onSelectEnd);\n\n this._domOverlay?.hideLoading();\n this._modelPlaced = true;\n this.emit(\"modelPlaced\");\n\n // Show scale up animation\n const originalModelScale = modelRoot.scale.clone();\n const scaleUpAnimation = new Animation({ context: session });\n\n scaleUpAnimation.on(\"progress\", evt => {\n const newScale = originalModelScale.clone().multiplyScalar(evt.easedProgress);\n modelRoot.scale.copy(newScale);\n });\n scaleUpAnimation.on(\"finish\", () => {\n modelRoot.scale.copy(originalModelScale);\n control.init(ctx, hitPosition);\n });\n scaleUpAnimation.start();\n }\n\n private _onSelectStart = (e) => {\n this._control!.onSelectStart({\n ...this._renderContext!,\n frame: e.frame,\n });\n }\n\n private _onSelectEnd = () => {\n this._control!.onSelectEnd();\n }\n}\n\nexport default FloorARSession;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport { range } from \"~/utils\";\n\n/**\n * Options for {@link ArrowIndicator}\n * @category Controls-AR\n * @interface\n * @property {string | number | THREE.Color} [color=0xffffff] Arrow color\n */\nexport interface ArrowIndicatorOption {\n color: string | number | THREE.Color;\n}\n\n/**\n * Arrow indicator for AR model translatioon.\n * @category Controls-AR\n */\nclass ArrowIndicator {\n private _arrows: THREE.Group[];\n private _obj: THREE.Group;\n\n /**\n * {@link https://threejs.org/docs/index.html#api/en/objects/Group THREE.Group} object that contains arrows.\n */\n public get object() { return this._obj; }\n\n /**\n * Create new ArrowIndicator\n * @param {ArrowIndicatorOption} [options={}] Options\n */\n constructor({\n color = 0xffffff,\n }: Partial<ArrowIndicatorOption> = {}) {\n const bodyGeometry = new THREE.CylinderBufferGeometry(0.1, 0.1, 1);\n const coneGeometry = new THREE.CylinderBufferGeometry(0, 0.5, 1, 30, 1);\n\n bodyGeometry.translate(0, 0.5, 0);\n coneGeometry.translate(0, 1.5, 0);\n\n const body = new THREE.Mesh(bodyGeometry, new THREE.MeshBasicMaterial({ color }));\n const cone = new THREE.Mesh(coneGeometry, new THREE.MeshBasicMaterial({ color }));\n const arrow = new THREE.Group();\n\n arrow.add(body);\n arrow.add(cone);\n\n this._arrows = [arrow];\n\n this._obj = new THREE.Group();\n this._obj.add(arrow);\n\n range(3).forEach(idx => {\n const copied = arrow.clone(true);\n copied.rotateZ(Math.PI / 2 * (idx + 1));\n this._obj.add(copied);\n this._arrows.push(copied);\n });\n\n this.hide();\n }\n\n /**\n * Show indicator\n */\n public show() {\n this._obj.visible = true;\n }\n\n /**\n * Hide indicator\n */\n public hide() {\n this._obj.visible = false;\n }\n\n /**\n * Change the center of the arrows to a given position\n * @param position Position to set as center of the arrows\n */\n public updatePosition(position: THREE.Vector3) {\n this._obj.position.copy(position);\n }\n\n /**\n * Update the arrow's offset from the center\n * @param offset Offset vector.\n */\n public updateOffset(offset: THREE.Vector3) {\n this._arrows.forEach((arrow, idx) => {\n const facingDirection = new THREE.Vector3(0, 1, 0).applyQuaternion(arrow.quaternion);\n const facingOffset = facingDirection.multiply(offset);\n\n arrow.position.copy(facingOffset);\n });\n }\n\n /**\n * Update arrow's scale\n * @param scale Scale vector\n */\n public updateScale(scale: number) {\n this._arrows.forEach(arrow => arrow.scale.setScalar(scale));\n }\n\n /**\n * Update arrow's rotation.\n * @param rotation Quaternion value to rotate arrows.\n */\n public updateRotation(rotation: THREE.Quaternion) {\n this._obj.quaternion.copy(rotation);\n }\n}\n\nexport default ArrowIndicator;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARControl from \"../common/ARControl\";\nimport ArrowIndicator, { ArrowIndicatorOption } from \"../ui/ArrowIndicator\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\n/**\n * Options for {@link ARTranslateControl}\n * @category Controls-AR\n * @interface\n * @property {ArrowIndicatorOption} arrow Options for {@link ArrowIndicator}\n */\nexport interface ARWallTranslateControlOption {\n arrow: Partial<ArrowIndicatorOption>;\n}\n\n/**\n * Model's translation(position) control for {@link ARWallControl}\n * @category Controls-AR\n */\nclass ARWallTranslateControl implements ARControl {\n public readonly position = new THREE.Vector3();\n public readonly wallPosition = new THREE.Vector3();\n public readonly hitRotation = new THREE.Quaternion();\n // Global Y guaranteed rotation matrix\n public readonly wallRotation = new THREE.Quaternion();\n private _arrowIndicator: ArrowIndicator;\n\n // Options\n\n // Internal states\n private _dragPlane = new THREE.Plane();\n private _enabled = true;\n private _active = false;\n private _initialPos = new THREE.Vector2();\n\n /**\n * Whether this control is enabled or not\n * @readonly\n */\n public get enabled() { return this._enabled; }\n\n /**\n * Create new instance of ARTranslateControl\n * @param {ARWallTranslateControlOption} [options={}] Options\n */\n constructor(options: Partial<ARWallTranslateControlOption> = {}) {\n this._arrowIndicator = new ArrowIndicator(options.arrow);\n }\n\n public initWallTransform({ hitPosition, hitRotation, modelPosition, wallRotation }: {\n hitPosition: THREE.Vector3,\n hitRotation: THREE.Quaternion,\n modelPosition: THREE.Vector3,\n wallRotation: THREE.Quaternion,\n }) {\n this.position.copy(modelPosition);\n this.hitRotation.copy(hitRotation);\n this.wallPosition.copy(hitPosition);\n this.wallRotation.copy(wallRotation);\n\n const wallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(wallRotation);\n\n this._dragPlane.set(wallNormal, -wallNormal.dot(modelPosition));\n }\n\n public init({ view3d }: XRRenderContext) {\n view3d.scene.add(this._arrowIndicator.object);\n }\n\n public destroy({ view3d }: XRContext) {\n view3d.scene.remove(this._arrowIndicator.object);\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n this.deactivate();\n }\n\n public activate({ model }: XRRenderContext, gesture: TOUCH.GESTURE) {\n if (!this._enabled) return;\n\n this._active = true;\n\n // Update arrows\n const arrowIndicator = this._arrowIndicator;\n const modelBbox = model.initialBbox;\n modelBbox.min.multiply(model.scene.scale);\n modelBbox.max.multiply(model.scene.scale);\n modelBbox.translate(model.scene.position);\n\n arrowIndicator.show();\n arrowIndicator.updatePosition(modelBbox.getCenter(new THREE.Vector3()));\n arrowIndicator.updateScale(model.size / 16);\n\n const arrowPlaneRotation = model.scene.quaternion.clone();\n\n arrowIndicator.updateRotation(arrowPlaneRotation);\n arrowIndicator.updateOffset(new THREE.Vector3().subVectors(modelBbox.max, modelBbox.min).multiplyScalar(0.5));\n }\n\n public deactivate() {\n this._active = false;\n this._arrowIndicator.hide();\n }\n\n public setInitialPos(coords: THREE.Vector2[]) {\n this._initialPos.copy(coords[0]);\n }\n\n public process({ view3d, model, frame, referenceSpace, xrCam }: XRRenderContext, { hitResults }: XRInputs) {\n if (!hitResults || hitResults.length !== 1 || !this._active) return;\n\n const dragPlane = this._dragPlane;\n\n const modelRoot = model.scene;\n const modelZOffset = -model.initialBbox.min.z * modelRoot.scale.z;\n\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n const hitResult = hitResults[0];\n const hitPose = hitResult.results[0] && hitResult.results[0].getPose(referenceSpace);\n\n const isWallHit = hitPose && hitPose.transform.matrix[5] < 0.25;\n\n if (!hitPose || !isWallHit) {\n // Use previous drag plane if no hit plane is found\n const targetRayPose = frame.getPose(hitResult.inputSource.targetRaySpace, view3d.renderer.threeRenderer.xr.getReferenceSpace());\n const fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();\n\n const fingerRay = new THREE.Ray(camPos, fingerDir);\n const intersection = fingerRay.intersectPlane(dragPlane, new THREE.Vector3());\n\n if (intersection) {\n this.wallPosition.copy(intersection.clone().sub(dragPlane.normal.clone().multiplyScalar(modelZOffset)));\n this.position.copy(intersection);\n }\n return;\n }\n\n const hitMatrix = new THREE.Matrix4().fromArray(hitPose.transform.matrix);\n const hitOrientation = new THREE.Quaternion().copy(hitPose.transform.orientation);\n const hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix);\n const worldYAxis = new THREE.Vector3(0, 1, 0);\n /*\n * ^ wallU\n * |\n * ⨀---> wallV\n * wallNormal\n */\n const wallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(hitOrientation).normalize();\n const wallU = new THREE.Vector3().crossVectors(worldYAxis, wallNormal);\n const wallV = wallNormal.clone().applyAxisAngle(wallU, -Math.PI / 2);\n\n // Reconstruct wall matrix with prev Y(normal) direction as Z axis\n const wallMatrix = new THREE.Matrix4().makeBasis(wallU, wallV, wallNormal);\n const modelPosition = hitPosition.clone().add(wallNormal.clone().multiplyScalar(modelZOffset));\n\n // Update position\n this.position.copy(modelPosition);\n this.wallPosition.copy(hitPosition);\n\n // Update rotation if it differs more than 10deg\n const prevWallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(this.hitRotation).normalize();\n if (Math.acos(Math.abs(prevWallNormal.dot(wallNormal))) >= Math.PI / 18) {\n const prevWallRotation = this.wallRotation.clone();\n const wallRotation = new THREE.Quaternion().setFromRotationMatrix(wallMatrix);\n const rotationDiff = prevWallRotation.inverse().premultiply(wallRotation);\n\n modelRoot.quaternion.premultiply(rotationDiff);\n this.wallRotation.copy(wallRotation);\n this.hitRotation.copy(hitOrientation);\n\n this._arrowIndicator.updateRotation(modelRoot.quaternion);\n\n // Update drag plane\n dragPlane.set(wallNormal, -modelPosition.dot(wallNormal));\n }\n }\n\n public update({ model }: XRRenderContext, delta: number) {\n model.scene.position.copy(this.position);\n this._arrowIndicator.updatePosition(this.position);\n model.scene.updateMatrix();\n }\n}\n\nexport default ARWallTranslateControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARWallTranslateControl, { ARWallTranslateControlOption } from \"./ARWallTranslateControl\";\nimport ARScaleControl, { ARScaleControlOption } from \"../common/ARScaleControl\";\nimport DeadzoneChecker, { DeadzoneCheckerOption } from \"../common/DeadzoneChecker\";\nimport ARSwirlControl, { ARSwirlControlOption } from \"../common/ARSwirlControl\";\nimport FloorIndicator, { FloorIndicatorOption } from \"../ui/FloorIndicator\";\nimport * as XR from \"~/consts/xr\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\n\n/**\n * Options for the {@link ARWallControl}\n * @category Controls-AR\n * @interface\n * @property {ARSwirlControlOptions} rotate Options for {@link ARSwirlControl}\n * @property {ARTranslateControlOption} translate Options for {@link ARWallTranslateControl}\n * @property {ARScaleControlOption} scale Options for {@link ARScaleControl}\n * @property {FloorIndicatorOption} floorIndicator Options for {@link FloorIndicator}\n * @property {DeadzoneCheckerOption} deadzone Options for {@link DeadzoneChecker}\n */\nexport interface ARWallControlOption {\n rotate: Partial<ARSwirlControlOption>;\n translate: Partial<ARWallTranslateControlOption>;\n scale: Partial<ARScaleControlOption>;\n floorIndicator: Partial<FloorIndicatorOption>;\n deadzone: Partial<DeadzoneCheckerOption>;\n}\n\n/**\n * AR control for {@link WallARSession}.\n * @category Controls-AR\n */\nclass ARWallControl {\n private _enabled = true;\n private _initialized = false;\n private _modelHit = false;\n private _hitTestSource: any = null;\n private _deadzoneChecker: DeadzoneChecker;\n private _rotateControl: ARSwirlControl;\n private _translateControl: ARWallTranslateControl;\n private _scaleControl: ARScaleControl;\n private _floorIndicator: FloorIndicator;\n\n /**\n * Return whether this control is enabled or not\n */\n public get enabled() { return this._enabled; }\n /**\n * {@link ARSwirlControlOptions} in this control\n */\n public get rotate() { return this._rotateControl; }\n /**\n * {@link ARTranslateControl} in this control\n */\n public get translate() { return this._translateControl; }\n /**\n * {@link ARScaleControl} in this control\n */\n public get scale() { return this._scaleControl; }\n public get controls() {\n return [this._rotateControl, this._translateControl, this._scaleControl];\n }\n\n /**\n * Create new instance of ARControl\n * @param {ARWallControlOption} options Options\n */\n constructor(options: Partial<ARWallControlOption> = {}) {\n // TODO: bind options\n this._rotateControl = new ARSwirlControl({\n ...options.rotate,\n showIndicator: false,\n });\n this._translateControl = new ARWallTranslateControl(options.translate);\n this._scaleControl = new ARScaleControl(options.scale);\n this._floorIndicator = new FloorIndicator(options.floorIndicator);\n this._deadzoneChecker = new DeadzoneChecker(options.deadzone);\n }\n\n public init(ctx: XRRenderContext, initialTransform: {\n hitPosition: THREE.Vector3,\n hitRotation: THREE.Quaternion,\n wallRotation: THREE.Quaternion,\n modelPosition: THREE.Vector3,\n }) {\n const { session, view3d, size } = ctx;\n\n this.controls.forEach(control => control.init(ctx));\n this._translateControl.initWallTransform(initialTransform);\n this._deadzoneChecker.setAspect(size.height / size.width);\n\n view3d.scene.add(this._floorIndicator.mesh);\n\n this._initialized = true;\n\n session.requestHitTestSourceForTransientInput({ profile: XR.INPUT_PROFILE.TOUCH })\n .then((transientHitTestSource: any) => {\n this._hitTestSource = transientHitTestSource;\n });\n }\n\n /**\n * Destroy this control and deactivate it\n * @param view3d Instance of the {@link View3D}\n */\n public destroy(ctx: XRContext) {\n if (!this._initialized) return;\n\n if (this._hitTestSource) {\n this._hitTestSource.cancel();\n this._hitTestSource = null;\n }\n\n ctx.view3d.scene.remove(this._floorIndicator.mesh);\n\n this.deactivate();\n this.controls.forEach(control => control.destroy(ctx));\n\n this._initialized = false;\n }\n\n public deactivate() {\n this._modelHit = false;\n this._deadzoneChecker.cleanup();\n this.controls.forEach(control => control.deactivate());\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n this.deactivate();\n }\n\n public update(ctx: XRRenderContext) {\n const { view3d, session, frame } = ctx;\n const hitTestSource = this._hitTestSource;\n\n if (!hitTestSource || !view3d.model) return;\n\n const deadzoneChecker = this._deadzoneChecker;\n const inputSources = session.inputSources;\n const hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);\n const coords = this._hitResultToVector(hitResults);\n const xrInputs = {\n coords,\n inputSources,\n hitResults,\n };\n\n if (deadzoneChecker.inDeadzone) {\n this._checkDeadzone(ctx, xrInputs);\n } else {\n this._processInput(ctx, xrInputs);\n }\n this._updateControls(ctx);\n }\n\n public onSelectStart = (ctx: XRRenderContext) => {\n const { view3d, session, frame, referenceSpace, xrCam } = ctx;\n const hitTestSource = this._hitTestSource;\n\n if (!hitTestSource || !this._enabled) return;\n\n const deadzoneChecker = this._deadzoneChecker;\n const rotateControl = this._rotateControl;\n const translateControl = this._translateControl;\n const scaleControl = this._scaleControl;\n\n // Update deadzone testing gestures\n if (rotateControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.ONE_FINGER);\n }\n if (translateControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.ONE_FINGER);\n }\n if (scaleControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.PINCH);\n }\n\n const hitResults = frame.getHitTestResultsForTransientInput(hitTestSource);\n const coords = this._hitResultToVector(hitResults);\n deadzoneChecker.applyScreenAspect(coords);\n deadzoneChecker.setFirstInput(coords);\n\n if (coords.length === 1) {\n // Check finger is on the model\n const modelBbox = view3d.model!.bbox;\n\n const targetRayPose = frame.getPose(session.inputSources[0].targetRaySpace, referenceSpace);\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n\n const fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();\n const fingerRay = new THREE.Ray(camPos, fingerDir);\n const intersection = fingerRay.intersectBox(modelBbox, new THREE.Vector3());\n\n if (intersection) {\n // Touch point intersected with model\n this._modelHit = true;\n }\n }\n\n this._floorIndicator.show();\n }\n\n public onSelectEnd = () => {\n this.deactivate();\n this._floorIndicator.fadeout();\n }\n\n private _checkDeadzone(ctx: XRRenderContext, { coords }: XRInputs) {\n const { model } = ctx;\n const gesture = this._deadzoneChecker.check(coords.map(coord => coord.clone()));\n const rotateControl = this._rotateControl;\n const translateControl = this._translateControl;\n const scaleControl = this._scaleControl;\n\n if (gesture === TOUCH.GESTURE.NONE) return;\n\n switch (gesture) {\n case TOUCH.GESTURE.ONE_FINGER_HORIZONTAL:\n case TOUCH.GESTURE.ONE_FINGER_VERTICAL:\n if (this._modelHit) {\n translateControl.activate(ctx, gesture);\n translateControl.setInitialPos(coords);\n } else {\n rotateControl.activate(ctx, gesture);\n rotateControl.updateAxis(new THREE.Vector3(0, 1, 0).applyQuaternion(translateControl.hitRotation));\n rotateControl.updateRotation(model.scene.quaternion);\n rotateControl.setInitialPos(coords);\n }\n break;\n case TOUCH.GESTURE.PINCH:\n scaleControl.activate(ctx, gesture);\n scaleControl.setInitialPos(coords);\n break;\n }\n }\n\n private _processInput(ctx: XRRenderContext, inputs: XRInputs) {\n this.controls.forEach(control => control.process(ctx, inputs));\n }\n\n private _updateControls(ctx: XRRenderContext) {\n const { view3d, model, delta } = ctx;\n const deltaMilisec = delta * 1000;\n\n this.controls.forEach(control => control.update(ctx, deltaMilisec));\n model.scene.updateMatrix();\n\n const translateControl = this._translateControl;\n const floorPosition = translateControl.wallPosition;\n view3d.scene.update(model, {\n floorPosition,\n floorRotation: translateControl.hitRotation,\n });\n\n // Get a scaled bbox, which only has scale applied on it.\n const scaleControl = this._scaleControl;\n const scaledBbox = model.initialBbox;\n scaledBbox.min.multiply(scaleControl.scale);\n scaledBbox.max.multiply(scaleControl.scale);\n\n const floorIndicator = this._floorIndicator;\n const boundingSphere = scaledBbox.getBoundingSphere(new THREE.Sphere());\n const rotX90 = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, 0));\n const floorRotation = model.scene.quaternion.clone().multiply(rotX90);\n\n floorIndicator.update({\n delta: deltaMilisec,\n scale: boundingSphere.radius,\n position: floorPosition,\n rotation: floorRotation,\n });\n }\n\n private _hitResultToVector(hitResults: any[]) {\n return hitResults.map(input => {\n return new THREE.Vector2().set(\n input.inputSource.gamepad.axes[0],\n -input.inputSource.gamepad.axes[1],\n );\n });\n }\n}\n\nexport default ARWallControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport WebARSession, { WebARSessionOption } from \"./WebARSession\";\nimport HitTest from \"./features/HitTest\";\nimport ARWallControl, { ARWallControlOption } from \"~/controls/ar/wall/ARWallControl\";\nimport Animation from \"~/core/Animation\";\nimport { merge } from \"~/utils\";\nimport * as XR from \"~/consts/xr\";\nimport { XRRenderContext, XRContext } from \"~/types/internal\";\n\n/**\n * Options for {@link WallARSession}.\n * This type is intersection of {@link WebARSessionOption} and {@link ARWallControlOption}\n * @category XR\n * @interface\n * @extends WebARSessionOption\n * @extends ARWallControlOption\n */\ninterface WallARSessionOption extends WebARSessionOption, ARWallControlOption {}\n\n/**\n * AR session which places model on the wall\n * @category XR\n * @fires WebARSession#start\n * @fires WebARSession#end\n * @fires WebARSession#canPlace\n * @fires WebARSession#modelPlaced\n */\nclass WallARSession extends WebARSession {\n private _options: Partial<WallARSessionOption>;\n private _control: ARWallControl | null;\n private _renderContext: XRRenderContext | null;\n private _modelPlaced: boolean;\n private _hitTest: HitTest;\n\n /**\n * {@link ARWallControl} instance of this session\n * @type ARWallControl | null\n */\n public get control() { return this._control; }\n\n /**\n * Create new instance of WallARSession\n * @param {WallARSessionOption} [options={}] Options\n */\n constructor(options: Partial<WallARSessionOption> = {}) {\n super(options);\n\n this._control = null;\n this._renderContext = null;\n this._modelPlaced = false;\n\n this._hitTest = new HitTest();\n\n this._features = merge(this._features, this._hitTest.features);\n this._options = options;\n }\n\n public onStart = (ctx: XRContext) => {\n const { view3d, session } = ctx;\n\n super.onStart(ctx);\n\n this._control = new ARWallControl(this._options);\n\n view3d.scene.hide();\n this._hitTest.init(session);\n }\n\n public onEnd = (ctx: XRContext) => {\n const { view3d, session } = ctx;\n\n super.onEnd(ctx);\n\n this._renderContext = null;\n this._modelPlaced = false;\n\n session.removeEventListener(XR.EVENTS.SELECT_START, this._onSelectStart);\n session.removeEventListener(XR.EVENTS.SELECT_END, this._onSelectEnd);\n\n this._hitTest.destroy();\n this._control!.destroy(ctx);\n this._control = null;\n\n view3d.scene.show();\n }\n\n protected _beforeRender = (ctx: XRRenderContext) => {\n this._renderContext = ctx;\n if (!this._modelPlaced) {\n this._initModelPosition(ctx);\n } else {\n this._control!.update(ctx);\n }\n }\n\n private _initModelPosition(ctx: XRRenderContext) {\n const {view3d, frame, session} = ctx;\n const model = view3d.model;\n const hitTest = this._hitTest;\n\n // Make sure the model is loaded\n if (!hitTest.ready || !model) return;\n\n const control = this._control!;\n const referenceSpace = view3d.renderer.threeRenderer.xr.getReferenceSpace();\n const hitTestResults = hitTest.getResults(frame);\n\n if (hitTestResults.length <= 0) return;\n\n const hit = hitTestResults[0];\n const hitPose = hit.getPose(referenceSpace);\n const hitMatrix = new THREE.Matrix4().fromArray(hitPose.transform.matrix);\n\n // If transformed coord space's y axis is facing up or down, don't use it.\n if (hitMatrix.elements[5] >= 0.25 || hitMatrix.elements[5] <= -0.25) return;\n\n const modelRoot = model.scene;\n const hitRotation = new THREE.Quaternion().copy(hitPose.transform.orientation);\n const hitPosition = new THREE.Vector3().setFromMatrixPosition(hitMatrix);\n const modelZOffset = -model.initialBbox.min.z * modelRoot.scale.z;\n const modelPosition = hitPosition.clone().setZ(hitPosition.z + modelZOffset);\n\n const worldYAxis = new THREE.Vector3(0, 1, 0);\n /*\n * ^ wallU\n * |\n * ⨀---> wallV\n * wallNormal\n */\n const wallNormal = new THREE.Vector3(0, 1, 0).applyQuaternion(hitRotation).normalize();\n const wallU = new THREE.Vector3().crossVectors(worldYAxis, wallNormal);\n const wallV = wallNormal.clone().applyAxisAngle(wallU, -Math.PI / 2);\n\n // Reconstruct wall matrix with prev Y(normal) direction as Z axis\n const wallMatrix = new THREE.Matrix4().makeBasis(wallU, wallV, wallNormal);\n const wallRotation = new THREE.Quaternion().setFromRotationMatrix(wallMatrix);\n const modelRotation = model.scene.quaternion.clone()\n .premultiply(wallRotation);\n\n // Update rotation & position\n modelRoot.quaternion.copy(modelRotation);\n modelRoot.position.copy(modelPosition);\n modelRoot.updateMatrix();\n\n view3d.scene.update(model);\n view3d.scene.show();\n\n // Don't need it\n hitTest.destroy();\n\n session.addEventListener(XR.EVENTS.SELECT_START, this._onSelectStart);\n session.addEventListener(XR.EVENTS.SELECT_END, this._onSelectEnd);\n\n this._domOverlay?.hideLoading();\n this._modelPlaced = true;\n\n // Show scale up animation\n const originalModelScale = model.scene.scale.clone();\n const scaleUpAnimation = new Animation({ context: session });\n\n scaleUpAnimation.on(\"progress\", evt => {\n const newScale = originalModelScale.clone().multiplyScalar(evt.easedProgress);\n model.scene.scale.copy(newScale);\n });\n scaleUpAnimation.on(\"finish\", () => {\n model.scene.scale.copy(originalModelScale);\n control.init(ctx, {\n hitPosition,\n hitRotation,\n wallRotation,\n modelPosition,\n });\n });\n scaleUpAnimation.start();\n }\n\n private _onSelectStart = (e) => {\n this._control!.onSelectStart({\n ...this._renderContext!,\n frame: e.frame,\n });\n }\n\n private _onSelectEnd = () => {\n this._control!.onSelectEnd();\n }\n}\n\nexport default WallARSession;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARSwirlControl, { ARSwirlControlOption } from \"../common/ARSwirlControl\";\nimport ARSwipeControl, { ARSwipeControlOption } from \"../common/ARSwipeControl\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\nimport * as TOUCH from \"~/consts/touch\";\nimport ARControl from \"../common/ARControl\";\n\n/**\n * Options for {@link ARHoverRotateControl}\n * @category Controls-AR\n * @interface\n * @property {ARSwirlControlOption} swirl Options for {@link ARSwirlControl}\n * @property {ARSwipeControlOption} swipe Options for {@link ARSwipeControl}\n */\nexport interface ARHoverRotateControlOption {\n swirl: Partial<ARSwirlControlOption>;\n swipe: Partial<ARSwipeControlOption>;\n}\n\n/**\n * Model's yaw(local y-axis rotation) controller which works on AR(WebXR) mode.\n * @category Controls-AR\n */\nclass ARHoverRotateControl implements ARControl {\n /**\n * Current rotation value\n */\n public readonly rotation = new THREE.Quaternion();\n\n // Internal States\n private _zRotationControl: ARSwirlControl;\n private _xyRotationControl: ARSwipeControl;\n private _activatedControl: ARSwirlControl | ARSwipeControl | null;\n\n /**\n * Whether this control is enabled or not.\n * This returns true when either one finger control or two finger control is enabled.\n * @readonly\n */\n public get enabled() { return this._zRotationControl.enabled || this._xyRotationControl.enabled; }\n\n /**\n * {@link ARSwirlControl} of this control.\n */\n public get swirl() { return this._zRotationControl; }\n /**\n * {@link ARSwipeControl} of this control.\n */\n public get swipe() { return this._xyRotationControl; }\n\n /**\n * Create new instance of ARRotateControl\n * @param {ARHoverRotateControlOption} options Options\n */\n constructor(options: Partial<ARHoverRotateControlOption> = {}) {\n this._zRotationControl = new ARSwirlControl(options.swirl);\n this._xyRotationControl = new ARSwipeControl(options.swipe);\n this._activatedControl = null;\n }\n\n public init(ctx: XRRenderContext) {\n const initialRotation = ctx.view3d.model!.scene.quaternion;\n\n this.rotation.copy(initialRotation);\n this._zRotationControl.init(ctx);\n this._xyRotationControl.init(ctx);\n }\n\n public destroy(ctx: XRContext) {\n this._zRotationControl.destroy(ctx);\n this._xyRotationControl.destroy(ctx);\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._zRotationControl.enable();\n this._xyRotationControl.enable();\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._zRotationControl.disable();\n this._xyRotationControl.disable();\n }\n\n public activate(ctx: XRRenderContext, gesture: TOUCH.GESTURE) {\n const zRotationControl = this._zRotationControl;\n const xyRotationControl = this._xyRotationControl;\n\n if (gesture & TOUCH.GESTURE.ONE_FINGER) {\n zRotationControl.activate(ctx, gesture);\n zRotationControl.updateRotation(this.rotation);\n this._activatedControl = zRotationControl;\n } else if (gesture & TOUCH.GESTURE.TWO_FINGER) {\n xyRotationControl.activate(ctx, gesture);\n xyRotationControl.updateRotation(this.rotation);\n this._activatedControl = xyRotationControl;\n }\n }\n\n public deactivate() {\n this._zRotationControl.deactivate();\n this._xyRotationControl.deactivate();\n }\n\n public process(ctx: XRRenderContext, inputs: XRInputs) {\n this._zRotationControl.process(ctx, inputs);\n this._xyRotationControl.process(ctx, inputs);\n }\n\n public setInitialPos(coords: THREE.Vector2[]) {\n this._zRotationControl.setInitialPos(coords);\n this._xyRotationControl.setInitialPos(coords);\n }\n\n public update(ctx: XRRenderContext, deltaTime: number) {\n if (this._activatedControl) {\n this._activatedControl.update(ctx, deltaTime);\n this.rotation.copy(this._activatedControl.rotation);\n }\n }\n\n public updateRotateAxis({ view3d, xrCam }: XRRenderContext) {\n const model = view3d.model!;\n const zRotateAxis = new THREE.Vector3();\n const horizontalRotateAxis = new THREE.Vector3();\n const verticalRotateAxis = new THREE.Vector3();\n\n const cameraRotation = new THREE.Quaternion().setFromRotationMatrix(xrCam.matrixWorld);\n\n const cameraBasis = [\n new THREE.Vector3(1, 0, 0),\n new THREE.Vector3(0, 1, 0),\n new THREE.Vector3(0, 0, 1),\n ].map(axis => axis.applyQuaternion(cameraRotation).normalize());\n\n const modelBasis = [\n new THREE.Vector3(1, 0, 0),\n new THREE.Vector3(0, 1, 0),\n new THREE.Vector3(0, 0, 1),\n ].map(axis => axis.applyQuaternion(model.scene.quaternion));\n\n // Always use z-rotation\n zRotateAxis.copy(modelBasis[2]);\n // Use more appropriate one between x/y axis\n horizontalRotateAxis.copy(modelBasis[1]);\n verticalRotateAxis.copy(modelBasis[0]);\n\n // If it's facing other direction, negate it to face correct direction\n if (zRotateAxis.dot(cameraBasis[2]) < 0) {\n zRotateAxis.negate();\n }\n if (horizontalRotateAxis.dot(cameraBasis[1]) > 0) {\n horizontalRotateAxis.negate();\n }\n if (verticalRotateAxis.dot(cameraBasis[0]) > 0) {\n verticalRotateAxis.negate();\n }\n\n this._zRotationControl.updateAxis(zRotateAxis);\n this._xyRotationControl.updateAxis(horizontalRotateAxis, verticalRotateAxis);\n }\n}\n\nexport default ARHoverRotateControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARControl from \"../common/ARControl\";\nimport ArrowIndicator, { ArrowIndicatorOption } from \"../ui/ArrowIndicator\";\nimport { getPrimaryAxisIndex } from \"~/utils\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext, XRInputs } from \"~/types/internal\";\n\n/**\n * Options for {@link ARHoverTranslateControl}\n * @category Controls-AR\n * @interface\n * @property {ArrowIndicatorOption} arrow Options for {@link ArrowIndicator}\n */\nexport interface ARHoverTranslateControlOption {\n arrow: ArrowIndicatorOption;\n}\n\n/**\n * Model's translation(position) control for {@link ARHoverControl}\n * @category Controls-AR\n */\nclass ARHoverTranslateControl implements ARControl {\n // Internal states\n private _position = new THREE.Vector3();\n private _dragPlane = new THREE.Plane();\n private _enabled = true;\n private _active = false;\n private _initialPos = new THREE.Vector2();\n private _arrowIndicator: ArrowIndicator;\n\n public get enabled() { return this._enabled; }\n public get position() { return this._position.clone(); }\n\n /**\n * Create new instance of ARTranslateControl\n * @param {ARHoverTranslateControlOption} [options={}] Options\n */\n constructor(options: Partial<ARHoverTranslateControlOption> = {}) {\n this._arrowIndicator = new ArrowIndicator(options.arrow);\n }\n\n public init({ view3d }: XRRenderContext) {\n this._position.copy(view3d.model!.scene.position);\n view3d.scene.add(this._arrowIndicator.object);\n }\n\n public destroy({ view3d }: XRContext) {\n view3d.scene.remove(this._arrowIndicator.object);\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n this.deactivate();\n }\n\n public activate({ model, xrCam }: XRRenderContext, gesture: TOUCH.GESTURE) {\n if (!this._enabled) return;\n\n const modelPos = model.scene.position;\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n\n const modelBasis = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()];\n model.scene.matrixWorld.extractBasis(modelBasis[0], modelBasis[1], modelBasis[2]);\n modelBasis.forEach(axes => axes.normalize());\n\n const camToModelDir = new THREE.Vector3().subVectors(modelPos, camPos).clone().normalize();\n const primaryAxisIdx = getPrimaryAxisIndex(modelBasis, camToModelDir);\n const primaryAxis = modelBasis[primaryAxisIdx];\n\n // If axes is facing the opposite of camera, negate it\n if (primaryAxis.dot(camToModelDir) < 0) {\n primaryAxis.negate();\n }\n\n const originToDragPlane = new THREE.Plane(primaryAxis, 0).distanceToPoint(modelPos);\n this._dragPlane.set(primaryAxis, -originToDragPlane);\n\n this._active = true;\n\n // Update arrows\n const arrowIndicator = this._arrowIndicator;\n const modelBbox = model.initialBbox;\n modelBbox.min.multiply(model.scene.scale);\n modelBbox.max.multiply(model.scene.scale);\n modelBbox.translate(modelPos);\n\n arrowIndicator.show();\n arrowIndicator.updatePosition(modelBbox.getCenter(new THREE.Vector3()));\n arrowIndicator.updateScale(model.size / 16);\n\n const arrowPlaneRotation = model.scene.quaternion.clone();\n if (primaryAxisIdx === 0) {\n arrowPlaneRotation.multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, 0)));\n } else if (primaryAxisIdx === 1) {\n arrowPlaneRotation.multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, 0)));\n }\n\n arrowIndicator.updateRotation(arrowPlaneRotation);\n arrowIndicator.updateOffset(new THREE.Vector3().subVectors(modelBbox.max, modelBbox.min).multiplyScalar(0.5));\n }\n\n public deactivate() {\n this._active = false;\n this._arrowIndicator.hide();\n }\n\n public setInitialPos(coords: THREE.Vector2[]) {\n this._initialPos.copy(coords[0]);\n }\n\n public process({ view3d, frame, referenceSpace, xrCam }: XRRenderContext, { inputSources }: XRInputs) {\n if (inputSources.length !== 1 || !this._active) return;\n\n const inputSource = inputSources[0];\n const dragPlane = this._dragPlane;\n\n const targetRayPose = frame.getPose(inputSource.targetRaySpace, referenceSpace);\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n\n const fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();\n const fingerRay = new THREE.Ray(camPos, fingerDir);\n const intersection = fingerRay.intersectPlane(dragPlane, new THREE.Vector3());\n\n if (intersection) {\n this._position.copy(intersection);\n\n // Update arrow position. As position is not a center of model, we should apply offset from it\n const model = view3d.model!;\n const centerYOffset = model.initialBbox.getCenter(new THREE.Vector3()).multiply(model.scene.scale).y;\n const modelLocalYDir = new THREE.Vector3().applyQuaternion(model.scene.quaternion);\n const newCenter = intersection.add(modelLocalYDir.multiplyScalar(centerYOffset));\n\n this._arrowIndicator.updatePosition(newCenter);\n }\n }\n\n public update({ model }: XRRenderContext, delta: number) {\n model.scene.position.copy(this._position);\n }\n}\n\nexport default ARHoverTranslateControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport ARHoverRotateControl, { ARHoverRotateControlOption } from \"./ARHoverRotateControl\";\nimport ARHoverTranslateControl, { ARHoverTranslateControlOption } from \"./ARHoverTranslateControl\";\nimport ARScaleControl, { ARScaleControlOption } from \"../common/ARScaleControl\";\nimport DeadzoneChecker from \"../common/DeadzoneChecker\";\nimport * as TOUCH from \"~/consts/touch\";\nimport { XRRenderContext, XRContext } from \"~/types/internal\";\n\n/**\n * Options for the {@link ARHoverControl}\n * @category Controls-AR\n * @interface\n * @property {ARHoverRotateControlOption} rotate Options for {@link ARHoverRotateControl}\n * @property {ARHoverTranslateControlOption} translate Options for {@link ARHoverTranslateControl}\n * @property {ARScaleControlOption} scale Options for {@link ARScaleControl}\n * @property {DeadzoneCheckerOption} deadzone Options for {@link DeadzoneChecker}\n */\nexport interface ARHoverControlOption {\n rotate: Partial<ARHoverRotateControlOption>;\n translate: Partial<ARHoverTranslateControlOption>;\n scale: Partial<ARScaleControlOption>;\n}\n\n/**\n * AR control for {@link HoverARSession}\n * @category Controls-AR\n */\nclass ARHoverControl {\n private _enabled = true;\n private _initialized = false;\n private _modelHit = false;\n private _deadzoneChecker: DeadzoneChecker;\n private _rotateControl: ARHoverRotateControl;\n private _translateControl: ARHoverTranslateControl;\n private _scaleControl: ARScaleControl;\n\n /**\n * Return whether this control is enabled or not\n */\n public get enabled() { return this._enabled; }\n /**\n * {@link ARHoverRotateControlOption} in this control\n */\n public get rotate() { return this._rotateControl; }\n /**\n * {@link ARHoverTranslateControlOption} in this control\n */\n public get translate() { return this._translateControl; }\n /**\n * {@link ARScaleControl} in this control\n */\n public get scale() { return this._scaleControl; }\n public get controls() {\n return [this._rotateControl, this._translateControl, this._scaleControl];\n }\n\n /**\n * Create new instance of ARHoverControl\n * @param {ARHoverControlOption} options Options\n */\n constructor(options: Partial<ARHoverControlOption> = {}) {\n this._rotateControl = new ARHoverRotateControl(options.rotate);\n this._translateControl = new ARHoverTranslateControl(options.translate);\n this._scaleControl = new ARScaleControl(options.scale);\n this._deadzoneChecker = new DeadzoneChecker();\n }\n\n public init(ctx: XRRenderContext) {\n const { size } = ctx;\n\n this.controls.forEach(control => control.init(ctx));\n this._deadzoneChecker.setAspect(size.height / size.width);\n\n this._initialized = true;\n }\n\n /**\n * Destroy this control and deactivate it\n * @param view3d Instance of the {@link View3D}\n */\n public destroy(ctx: XRContext) {\n if (!this._initialized) return;\n\n this.deactivate();\n this.controls.forEach(control => control.destroy(ctx));\n\n this._initialized = false;\n }\n\n public deactivate() {\n this._modelHit = false;\n this._deadzoneChecker.cleanup();\n this.controls.forEach(control => control.deactivate());\n }\n\n /**\n * Enable this control\n */\n public enable() {\n this._enabled = true;\n }\n\n /**\n * Disable this control\n */\n public disable() {\n this._enabled = false;\n this.deactivate();\n }\n\n public update(ctx: XRRenderContext) {\n const { session } = ctx;\n\n if (!this._initialized) return;\n\n const deadzoneChecker = this._deadzoneChecker;\n const inputSources = session.inputSources;\n\n if (deadzoneChecker.inDeadzone) {\n this._checkDeadzone(ctx, inputSources);\n } else {\n this._processInput(ctx, inputSources);\n }\n this._updateControls(ctx);\n }\n\n public onSelectStart = (ctx: XRRenderContext) => {\n const { view3d, session, frame, referenceSpace, xrCam } = ctx;\n if (!this._enabled) return;\n\n const deadzoneChecker = this._deadzoneChecker;\n const rotateControl = this._rotateControl;\n const translateControl = this._translateControl;\n const scaleControl = this._scaleControl;\n\n // Update rotation axis\n if (rotateControl.enabled) {\n rotateControl.updateRotateAxis(ctx);\n }\n\n // Update deadzone testing gestures\n if (rotateControl.swirl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.ONE_FINGER);\n }\n if (rotateControl.swipe.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.TWO_FINGER);\n }\n if (translateControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.ONE_FINGER);\n }\n if (scaleControl.enabled) {\n deadzoneChecker.addTestingGestures(TOUCH.GESTURE.PINCH);\n }\n\n const coords = this._inputSourceToVector(session.inputSources);\n deadzoneChecker.applyScreenAspect(coords);\n deadzoneChecker.setFirstInput(coords);\n\n if (coords.length === 1) {\n // Check finger is on the model\n const modelBbox = view3d.model!.bbox;\n\n const targetRayPose = frame.getPose(session.inputSources[0].targetRaySpace, referenceSpace);\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n\n const fingerDir = new THREE.Vector3().copy(targetRayPose.transform.position).sub(camPos).normalize();\n const fingerRay = new THREE.Ray(camPos, fingerDir);\n const intersection = fingerRay.intersectBox(modelBbox, new THREE.Vector3());\n\n if (intersection) {\n // Touch point intersected with model\n this._modelHit = true;\n }\n }\n }\n\n public onSelectEnd = () => {\n this.deactivate();\n }\n\n private _checkDeadzone(ctx: XRRenderContext, inputSources: any[]) {\n const coords = this._inputSourceToVector(inputSources);\n const gesture = this._deadzoneChecker.check(coords.map(coord => coord.clone()));\n const rotateControl = this._rotateControl;\n const translateControl = this._translateControl;\n const scaleControl = this._scaleControl;\n\n if (gesture === TOUCH.GESTURE.NONE) return;\n\n switch (gesture) {\n case TOUCH.GESTURE.ONE_FINGER_HORIZONTAL:\n case TOUCH.GESTURE.ONE_FINGER_VERTICAL:\n if (this._modelHit) {\n translateControl.activate(ctx, gesture);\n translateControl.setInitialPos(coords);\n } else {\n rotateControl.activate(ctx, gesture);\n rotateControl.setInitialPos(coords);\n }\n break;\n case TOUCH.GESTURE.TWO_FINGER_HORIZONTAL:\n case TOUCH.GESTURE.TWO_FINGER_VERTICAL:\n rotateControl.activate(ctx, gesture);\n rotateControl.setInitialPos(coords);\n break;\n case TOUCH.GESTURE.PINCH:\n scaleControl.activate(ctx, gesture);\n scaleControl.setInitialPos(coords);\n break;\n }\n }\n\n private _processInput(ctx: XRRenderContext, inputSources: any[]) {\n const coords = this._inputSourceToVector(inputSources);\n\n this.controls.forEach(control => control.process(ctx, { coords, inputSources }));\n }\n\n private _updateControls(ctx: XRRenderContext) {\n const { view3d, model, delta } = ctx;\n const deltaMilisec = delta * 1000;\n\n this.controls.forEach(control => control.update(ctx, deltaMilisec));\n\n model.scene.updateMatrix();\n view3d.scene.update(model);\n }\n\n private _inputSourceToVector(inputSources: any[]) {\n return Array.from(inputSources).map(inputSource => {\n const axes = inputSource.gamepad.axes;\n return new THREE.Vector2(axes[0], -axes[1]);\n });\n }\n}\n\nexport default ARHoverControl;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport WebARSession, { WebARSessionOption } from \"./WebARSession\";\nimport ARHoverControl, { ARHoverControlOption } from \"~/controls/ar/hover/ARHoverControl\";\nimport Animation from \"~/core/Animation\";\nimport * as XR from \"~/consts/xr\";\nimport { XRRenderContext, XRContext } from \"~/types/internal\";\nimport { clamp } from \"~/utils\";\n\n/**\n * Options for {@link HoverARSession}.\n * This type is intersection of {@link WebARSessionOption} and {@link ARHoverControlOption}\n * @category XR\n * @interface\n * @extends WebARSessionOption\n * @extends ARHoverControlOption\n */\ninterface HoverARSessionOption extends WebARSessionOption, ARHoverControlOption {\n initialDistance: number;\n}\n\n/**\n * WebXR based AR session which puts model at the space front of camera.\n * @category XR\n * @fires WebARSession#start\n * @fires WebARSession#end\n * @fires WebARSession#canPlace\n * @fires WebARSession#modelPlaced\n */\nclass HoverARSession extends WebARSession {\n private _options: Partial<HoverARSessionOption>;\n private _control: ARHoverControl | null;\n private _renderContext: XRRenderContext | null;\n private _modelPlaced: boolean;\n\n /**\n * {@link ARControl} instance of this session\n * @type ARHoverControl | null\n */\n public get control() { return this._control; }\n\n /**\n * Create new instance of HoverARSession\n * @param {HoverARSessionOption} options Options\n */\n constructor(options: Partial<HoverARSessionOption> = {}) {\n super(options);\n\n this._control = null;\n this._renderContext = null;\n this._modelPlaced = false;\n this._options = options;\n }\n\n /**\n * Place model on the current position\n */\n public placeModel() {\n const ctx = this._renderContext;\n\n // Not ready to place model yet\n if (!ctx || !ctx.view3d.scene.visible || this._modelPlaced) return;\n\n const { session, view3d } = ctx;\n const modelRoot = view3d.model!.scene;\n const control = this._control!;\n\n session.addEventListener(XR.EVENTS.SELECT_START, this._onSelectStart);\n session.addEventListener(XR.EVENTS.SELECT_END, this._onSelectEnd);\n\n this._modelPlaced = true;\n this.emit(\"modelPlaced\");\n\n // Show scale up animation\n const originalModelScale = modelRoot.scale.clone();\n const scaleUpAnimation = new Animation({ context: session });\n\n scaleUpAnimation.on(\"progress\", evt => {\n const newScale = originalModelScale.clone().multiplyScalar(evt.easedProgress);\n modelRoot.scale.copy(newScale);\n });\n scaleUpAnimation.on(\"finish\", () => {\n modelRoot.scale.copy(originalModelScale);\n control.init(ctx);\n });\n scaleUpAnimation.start();\n }\n\n public onStart = (ctx: XRContext) => {\n const { view3d } = ctx;\n\n super.onStart(ctx);\n\n this._control = new ARHoverControl(this._options);\n\n view3d.scene.hide();\n }\n\n public onEnd = (ctx: XRContext) => {\n const { view3d, session } = ctx;\n\n super.onEnd(ctx);\n\n this._renderContext = null;\n this._modelPlaced = false;\n\n session.removeEventListener(XR.EVENTS.SELECT_START, this._onSelectStart);\n session.removeEventListener(XR.EVENTS.SELECT_END, this._onSelectEnd);\n\n this._control!.destroy(ctx);\n this._control = null;\n\n view3d.scene.show();\n }\n\n protected _beforeRender = (ctx: XRRenderContext) => {\n this._renderContext = ctx;\n\n if (!this._modelPlaced) {\n this._initModelPosition(ctx);\n } else {\n this._control!.update(ctx);\n }\n }\n\n private _initModelPosition(ctx: XRRenderContext) {\n const {view3d, xrCam} = ctx;\n const model = view3d.model;\n\n // Make sure the model exist\n if (!model) return;\n\n const modelRoot = model.scene;\n const camPos = new THREE.Vector3().setFromMatrixPosition(xrCam.matrixWorld);\n const camQuat = new THREE.Quaternion().setFromRotationMatrix(xrCam.matrixWorld);\n const viewDir = new THREE.Vector3(0, 0, -1).applyQuaternion(camQuat);\n\n const modelBbox = model.bbox;\n const bboxDiff = new THREE.Vector3().subVectors(modelBbox.max, modelBbox.min);\n const maxComponent = Math.max(bboxDiff.x, bboxDiff.y, bboxDiff.z);\n\n // Reset rotation & update position\n modelRoot.position.copy(camPos);\n modelRoot.position.add(viewDir.multiplyScalar(clamp(maxComponent, 0.5, 3))); // Place at 1m from camera\n modelRoot.lookAt(camPos.setY(modelRoot.position.y));\n modelRoot.updateMatrix();\n\n view3d.scene.update(model);\n\n if (!view3d.scene.visible) {\n view3d.scene.show();\n this.emit(\"canPlace\");\n }\n }\n\n private _onSelectStart = (e) => {\n this._control!.onSelectStart({\n ...this._renderContext!,\n frame: e.frame,\n });\n }\n\n private _onSelectEnd = () => {\n this._control!.onSelectEnd();\n }\n}\n\nexport default HoverARSession;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\n// Browser related constants\n\nexport const IS_IOS = /iPad|iPhone|iPod/.test(navigator.userAgent)\n || (navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1);\n\nexport const IS_ANDROID = /android/i.test(navigator.userAgent);\n\nexport const IS_SAFARI = /safari/i.test(navigator.userAgent);\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport XRSession from \"./XRSession\";\nimport { IS_ANDROID } from \"~/consts/browser\";\nimport * as XR from \"~/consts/xr\";\n\n/**\n * AR session using Google's scene-viewer\n * @category XR\n * @see https://developers.google.com/ar/develop/java/scene-viewer\n */\nclass SceneViewerSession implements XRSession {\n public readonly isWebXRSession = false;\n\n /**\n * Create new instance of SceneViewerSession\n * @see https://developers.google.com/ar/develop/java/scene-viewer\n * @param params Session params\n * @param {string} [params.file] This URL specifies the glTF or glb file that should be loaded into Scene Viewer. This should be URL-escaped.\n * @param {string} [params.browser_fallback_url] This is a Google Chrome feature supported only for web-based implementations. When the Google app com.google.android.googlequicksearchbox is not present on the device, this is the URL that Google Chrome navigates to.\n * @param {string} [params.mode=\"ar_only\"] See {@link https://developers.google.com/ar/develop/java/scene-viewer} for available modes.\n * @param {string} [params.title] A name for the model. If present, it will be displayed in the UI. The name will be truncated with ellipses after 60 characters.\n * @param {string} [params.link] A URL for an external webpage. If present, a button will be surfaced in the UI that intents to this URL when clicked.\n * @param {string} [params.sound] A URL to a looping audio track that is synchronized with the first animation embedded in a glTF file. It should be provided alongside a glTF with an animation of matching length. If present, the sound is looped after the model is loaded. This should be URL-escaped.\n * @param {string} [params.resizable=true] When set to false, users will not be able to scale the model in the AR experience. Scaling works normally in the 3D experience.\n */\n constructor(public params: {\n file: string,\n browser_fallback_url?: string,\n mode?: \"3d_preferred\" | \"3d_only\" | \"ar_preferred\" | \"ar_only\" | string,\n title?: string,\n link?: string,\n sound?: string,\n resizable?: \"true\" | \"false\" | boolean,\n [key: string]: any,\n }) {\n if (!this.params.mode) {\n // Default mode is \"ar_only\", which should use com.google.ar.core package\n this.params.mode = \"ar_only\";\n }\n }\n\n /**\n * Return the availability of SceneViewerSession.\n * Scene-viewer is available on all android devices with google ARCore installed.\n * @returns {Promise} A Promise that resolves availability of this session(boolean).\n */\n public isAvailable() {\n return Promise.resolve(IS_ANDROID);\n }\n\n /**\n * Enter Scene-viewer AR session\n */\n public enter() {\n const params = Object.assign({}, this.params);\n const fallback = params.browser_fallback_url;\n delete params.browser_fallback_url;\n\n const resizable = params.resizable;\n delete params.resizable;\n if (resizable === true) {\n params.resizable = \"true\";\n } else if (resizable === false) {\n params.resizable = \"false\";\n } else if (resizable) {\n params.resizable = resizable;\n }\n\n const queryString = Object.keys(params)\n .filter(key => params[key] != null)\n .map(key => `${key}=${params[key]}`).join(\"&\");\n\n const intentURL = params.mode === \"ar_only\"\n ? XR.SCENE_VIEWER.INTENT_AR_CORE(queryString, fallback)\n : XR.SCENE_VIEWER.INTENT_SEARCHBOX(queryString, fallback || XR.SCENE_VIEWER.FALLBACK_DEFAULT(queryString));\n\n const anchor = document.createElement(\"a\") as HTMLAnchorElement;\n anchor.href = intentURL;\n anchor.click();\n\n return Promise.resolve();\n }\n\n public exit() {\n // DO NOTHING\n }\n}\n\nexport default SceneViewerSession;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport XRSession from \"./XRSession\";\nimport { IS_IOS, IS_SAFARI } from \"~/consts/browser\";\nimport { QUICKLOOK_SUPPORTED } from \"~/consts/xr\";\n\n/**\n * AR Session using Apple AR Quick Look Viewer\n * @category XR\n * @see https://developer.apple.com/augmented-reality/quick-look/\n */\nclass QuickLookSession implements XRSession {\n /**\n * Whether it's webxr-based session or not\n * @type false\n */\n public readonly isWebXRSession = false;\n\n private _file: string;\n private _allowsContentScaling: boolean;\n\n /**\n * Create new instance of QuickLookSession\n * @param {object} [options] Quick Look options\n * @param {string} [options.file] USDZ file's location URL.\n * @param {boolean} [options.allowsContentScaling=true] Whether to allow content scaling.\n */\n constructor({\n file,\n allowsContentScaling = true,\n }: {\n file: string,\n allowsContentScaling?: boolean,\n }) {\n this._file = file;\n this._allowsContentScaling = allowsContentScaling;\n }\n\n /**\n * Return the availability of QuickLookSession.\n * QuickLook AR is available on iOS12+ on Safari & Chrome browser\n * Note that iOS Chrome won't show up QuickLook AR when it's local dev environment\n * @returns {Promise} A Promise that resolves availability of this session(boolean).\n */\n public isAvailable() {\n // This can handle all WebKit based browsers including iOS Safari & iOS Chrome\n return Promise.resolve(QUICKLOOK_SUPPORTED && IS_IOS && IS_SAFARI);\n }\n\n /**\n * Enter QuickLook AR Session\n */\n public enter() {\n const anchor = document.createElement(\"a\") as HTMLAnchorElement;\n anchor.setAttribute(\"rel\", \"ar\");\n anchor.appendChild(document.createElement(\"img\"));\n\n const usdzURL = new URL(this._file, window.location.toString());\n if (!this._allowsContentScaling) {\n usdzURL.hash = \"allowsContentScaling=0\";\n }\n\n anchor.setAttribute(\"href\", usdzURL.toString());\n anchor.click();\n\n return Promise.resolve();\n }\n\n public exit() {\n // DO NOTHING\n }\n}\n\nexport default QuickLookSession;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport * as THREE from \"three\";\nimport Model from \"~/core/Model\";\nimport View3DError from \"~/View3DError\";\nimport * as ERR from \"~/consts/error\";\n\n/**\n * Texture(image) model\n * @category Extra\n */\nclass TextureModel extends Model {\n private _texture: THREE.Texture;\n private _mesh: THREE.Mesh;\n\n /**\n * Texture that used for this model\n * @see https://threejs.org/docs/index.html#api/en/textures/Texture\n * @type THREE.Texture\n */\n public get texture() { return this._texture; }\n /**\n * Model's mesh object\n * @see https://threejs.org/docs/index.html#api/en/objects/Mesh\n * @type THREE.Mesh\n */\n public get mesh() { return this._mesh; }\n\n /**\n * Create new TextureModel\n * @param {object} options Options\n * @param {number} [options.width] Width of the model.\n * @param {number} [options.height] Height of the model.\n * @param {boolean} [options.billboard=false] When set to true, model will keep rotate to show its front face to camera. Only Y-axis rotation is considered.\n * @throws {View3DError} `CODES.PROVIDE_WIDTH_OR_HEIGHT` When both width and height are not given.\n */\n constructor({\n image,\n width,\n height,\n billboard = false,\n }: {\n image: THREE.Texture | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement;\n width?: number;\n height?: number;\n billboard?: boolean;\n }) {\n const texture = (image as THREE.Texture).isTexture\n ? image as THREE.Texture\n : new THREE.Texture(image as HTMLImageElement);\n const aspect = texture.image.width / texture.image.height;\n if (width == null && height == null) {\n throw new View3DError(ERR.MESSAGES.PROVIDE_WIDTH_OR_HEIGHT, ERR.CODES.PROVIDE_WIDTH_OR_HEIGHT);\n }\n if (width == null) {\n width = height! * aspect;\n } else if (height == null) {\n height = width! / aspect;\n }\n texture.encoding = THREE.sRGBEncoding;\n const geometry = new THREE.PlaneGeometry(width, height);\n const material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide });\n const mesh = new THREE.Mesh(geometry, material);\n\n super({ scenes: [mesh] });\n\n this._texture = texture;\n this._mesh = mesh;\n\n if (billboard) {\n const root = mesh;\n root.onBeforeRender = (renderer, scene, camera) => {\n const pos = root.getWorldPosition(new THREE.Vector3());\n const camPos = new THREE.Vector3().setFromMatrixPosition(camera.matrixWorld);\n\n root.lookAt(camPos.setY(pos.y));\n mesh.updateMatrix();\n };\n }\n }\n}\n\nexport default TextureModel;\n","/*\n * Copyright (c) 2020 NAVER Corp.\n * egjs projects are licensed under the MIT license\n */\n\nimport View3D from \"./View3D\";\nimport View3DError from \"./View3DError\";\nimport * as Core from \"./core\";\nimport * as Controls from \"./controls\";\nimport * as Loaders from \"./loaders\";\nimport * as Environments from \"./environments\";\nimport * as XR from \"./xr\";\nimport * as Extra from \"./extra\";\nimport * as Externals from \"./consts/external\";\nimport * as EASING from \"./consts/easing\";\nimport { CODES } from \"./consts/error\";\nimport { merge } from \"./utils\";\n\nmerge(View3D, Core);\nmerge(View3D, Environments);\nmerge(View3D, Controls);\nmerge(View3D, Loaders);\nmerge(View3D, XR);\nmerge(View3D, Extra);\nmerge(View3D, Externals);\n(View3D as any).View3DError = View3DError;\n(View3D as any).ERROR_CODES = CODES;\n(View3D as any).EASING = EASING;\nexport default View3D;\n"],"names":["_listenerMap","eventName","callback","listenerMap","this","listeners","indexOf","push","callbackIdx","splice","_i","event","forEach","canvas","_canvas","_renderer","THREE","alpha","antialias","preserveDrawingBuffer","xr","enabled","outputEncoding","_clock","enableShadow","Object","context","getSize","val","setSize","x","y","renderer","isPresenting","setPixelRatio","window","devicePixelRatio","offsetWidth","offsetHeight","scene","camera","render","root","threeCamera","start","setAnimationLoop","timestamp","frame","delta","_this","getDelta","stop","threeRenderer","shadowMap","type","STANDARD_MAPS","message","code","_super","setPrototypeOf","View3DError","prototype","name","__extends","Error","CODES","WRONG_TYPE","ELEMENT_NOT_FOUND","ELEMENT_NOT_CANVAS","WEBGL_NOT_SUPPORTED","ADD_CONTROL_FIRST","PROVIDE_WIDTH_OR_HEIGHT","MESSAGES","types","map","join","query","el","tagName","getElement","parent","targetEl","queryResult","document","querySelector","ERROR","nodeType","Node","ELEMENT_NODE","range","end","Array","apply","undef","idx","toRadian","Math","PI","clamp","min","max","findIndex","target","list","index","_b","__values","length","itemIndex","mix","a","b","t","circulate","size","abs","merge","srcs","source","keys","key","value","isArray","SINE_WAVE","sin","EASE_OUT_CUBIC","pow","EASE_OUT_BOUNCE","n1","MOUSE_BUTTON","_root","_userObjects","_envObjects","_envs","userObjects","envObjects","add","visible","model","override","env","fit","resetModel","resetEnv","_removeChildsOf","background","environment","object","_a","envs","isObject3D","objects","remove","envIndex","envmap","texture","obj","traverse","child","isMesh","mesh","geometry","dispose","material","mat","children","_camera","_controls","control","destroy","element","setElement","sync","enable","controls","controlIndex","removedControl","disable","syncToCamera","resize","deltaMiliSec","update","updatePosition","yaw","pitch","distance","pivot","Pose","clone","EASING","ANIMATION_RANGE","CAMERA_POSE","INFINITE_RANGE","Infinity","PITCH_RANGE","DISTANCE_RANGE","NULL_ELEMENT","DRACO_DECODER_URL","_c","duration","_d","loop","_e","DEFAULT","_f","easing","_duration","_loop","_range","_easing","_activated","reset","_val","_start","_end","_progress","deltaTime","prev","nextProgress","easedProgress","defaultVal","from","to","_motion","Motion","_from","_to","_enabled","motion","progress","lerp","_finishCallbacks","setEndDelta","_defaultPose","_threeCamera","_controller","Controller","_currentPose","_minDistance","_maxDistance","fov","updateProjectionMatrix","renderHeight","aspect","tan","controller","currentPose","defaultPose","Promise","resolve","resetControl_1","AnimationControl","onFinished","cam","newDefaultPose","_clampCurrentPose","pose","newCamPos","z","cos","position","copy","lookAt","_mixer","_clips","_actions","clips","mixer","clip","clipAction","action","play","timeScale","uncacheRoot","getRoot","view3d","_view3d","_sessions","_currentSession","all","session","isAvailable","some","result","xrSession","_enterSession","exit","sessionIdx","errors","sessions","reject","enter","then","isWebXRSession","addEventListener","catch","e","EVENTS","newSize","emit","_scene","_animator","test","getCanvas","Renderer","Camera","Scene","ModelAnimator","_xr","XRManager","_model","clear","removeEventListener","applySize","resetView","animator","setClips","animations","stopAnimationLoop","renderLoop","View3D","EventEmitter","scenes","fixSkinnedBbox","castShadow","receiveShadow","_animations","_fixSkinnedBbox","_cachedLights","_cachedMeshes","_setInitialBbox","bboxCenter","_initialBbox","getCenter","negate","_moveInitialBboxToCenter","_originalSize","_getAllLights","_getAllMeshes","_getTransformedBbox","scale","setScalar","updateMatrix","meshes","initialBbox","multiply","updateMatrixWorld","_hasSkinnedMesh","_getSkeletonBbox","setFromObject","bbox","isSkinnedMesh","positions","attributes","skinIndicies","skinIndex","skinWeights","skinWeight","skeleton","boneMatricies","boneMatrices","finalMatrix","posIdx","identity","skinned","set","skinVertex","getX","getY","getZ","applyMatrix4","bindMatrix","weights","getW","indicies","weight","boneMatrix","fromArray","multiplyScalar","transformed","bindMatrixInverse","toArray","matrixWorld","expandByPoint","count","expandByObject","translate","lights","isLight","matrix","delay","delayOnMouseLeave","speed","_g","pauseOnHover","_h","canInterrupt","_j","disableOnInterrupt","evt","_canInterrupt","button","LEFT","RIGHT","_interrupted","_clearTimeout","_onMouseUp","_setUninterruptedAfterDelay","_delay","_pauseOnHover","_hovering","_delayOnMouseLeave","_speed","_disableOnInterrupt","_targetEl","_onMouseDown","_onTouchStart","_onTouchEnd","_onMouseEnter","_onMouseLeave","_onWheel","_interruptionTimer","setTimeout","clearTimeout","CURSOR","useGrabCursor","scaleToElement","preventDefault","focus","_prevPos","clientX","clientY","_onMouseMove","_setCursor","prevPos","rotateDelta","sub","_userScale","_scaleToElement","_screenScale","_xMotion","_yMotion","touch","touches","cancelable","stopPropagation","_useGrabCursor","xMotion","yMotion","_onTouchMove","style","cursor","_getTouchesMiddle","_touchInitialized","middlePoint","subVectors","screenSize","_screenSize","viewXDir","applyQuaternion","quaternion","viewYDir","screenScale","renderWidth","divide","_onContextMenu","deltaY","animation","_scale","_scaleModifier","prevTouchDistance","_prevTouchDistance","touchPoint1","pageX","pageY","touchPoint2","touchDistance","minDistance","maxDistance","rotate","_rotateControl","RotateControl","_translateControl","TranslateControl","_distanceControl","DistanceControl","url","options","loader","DRACOLoader","setCrossOrigin","setDecoderPath","manager","load","_parseToModel","undefined","err","color","point","pointOptions","computeVertexNormals","Model","intensity","direction","_light","light","shadow","mapSize","width","height","matrixAutoUpdate","_direction","normalize","boxSize","boxCenter","newPos","addVectors","shadowCam","near","far","left","right","top","bottom","box","projectedPoints","project","screenBbox","setFromPoints","opacity","rotateX","floorPosition","floorRotation","modelPosition","localYAxis","modelBbox","modelBboxYOffset","modelFloor","rotX90","setFromEuler","shadowRotation","multiplyQuaternions","_loader","ThreeGLTFLoader","_dracoLoader","dracoLoader","setDRACOLoader","gltf","viewer","loadAsync","jsonRaw","json","JSON","parse","baseURL","extractUrlBase","modelOptions","cameraOptions","environmentOptions","setDefaultPose","distanceRange","setBackground","shadowPlane","ShadowPlane","addEnv","ambientOptions","ambient","light1","light2","light3","lightOption","lightDirection","directional","AutoDirectionalLight","isFirstLoad","loadFlags","LOD","fileName","lodIndex","glbURL","_resolveURL","path","slice","loaded","display","onLoad","files","revokeURLs","objectURLs","URL","revokeObjectURL","gltfFile","find","file","filesMap","Map","gltfURL","createObjectURL","setURLModifier","fileURL","fileNameResult","exec","has","blob","get","blobURL","data","encoding","replace","anchorEl","STATE","skyboxTexture","_equirectToCubemap","urls","isEquirectangular","RGBELoader","image","fromEquirectangularTexture","QUICKLOOK_SUPPORTED","createElement","relList","supports","WEBXR_SUPPORTED","navigator","isSessionSupported","HIT_TEST_SUPPORTED","XRSession","requestHitTestSource","DOM_OVERLAY_SUPPORTED","XRDOMOverlayState","SESSION","REFERENCE_SPACE","INPUT_PROFILE","FEATURES","requiredFeatures","optionalFeatures","domOverlay","EMPTY_FEATURES","SCENE_VIEWER","params","fallback","_loadingEl","loadingEl","XR","visibility","userFeatures","maxModelSize","overlayRoot","forceOverlay","overlayEl","features","_domOverlay","DOMOverlay","_features","_maxModelSize","_forceOverlay","_session","requestSession","xrContext","originalMatrix","originalModelSize","originalBackground","arModelSize","originalSize","moveToOrigin","setReferenceSpaceType","setSession","onStart","onEnd","decompose","once","xrCam","getCamera","referenceSpace","getReferenceSpace","glLayer","renderState","baseLayer","framebufferWidth","framebufferHeight","renderContext","_beforeRender","getSession","ctx","showLoading","hideLoading","_source","cancel","requestReferenceSpace","space","getHitTestResults","repeat","_getDeltaTime","_time","loopIncrease","floor","progressEvent","loopIdx","_loopCount","_repeat","loopIndex","_rafId","_ctx","requestAnimationFrame","_updateClock","_stopLoop","cancelAnimationFrame","lastTime","Date","now","ringColor","axisColor","ringGeometry","ringMaterial","side","_ring","axisVertices","axisGeometry","axisMaterial","_axis","_obj","hide","rotation","showIndicator","_rotationIndicator","RotationIndicator","initialRotation","updateRotation","_fromQuat","_toQuat","gesture","_active","rotationIndicator","show","updateScale","axis","coords","center","v1","v2","centerToV1","deg","compDeg","coord","modelPos","ndcModelPos","rotationAngle","angle","sign","setFromAxisAngle","interpolated","_getInterpolatedQuaternion","premultiply","toEuler","fromEuler","slerp","GESTURE","hoverAmplitude","hoverHeight","hoverPeriod","hoverEasing","bounceDuration","bounceEasing","WAITING","_hoverAmplitude","_hoverHeight","_hoverMotion","_bounceMotion","_modelPosition","_floorPosition","_hoverPosition","setY","deactivate","_dragPlane","_state","TRANSLATING","BOUNCING","hoverPosition","bounceMotion","hoveringAmount","_initialPos","hitResults","state","notActive","hitResult","prevFloorPosition","dragPlane","hitPose","results","getPose","isFloorHit","transform","camPos","setFromMatrixPosition","hitMatrix","hitPosition","currentDragPlaneHeight","constant","hitDragPlaneHeight","hitOnDragPlane","intersectPlane","targetRayPose","inputSource","targetRaySpace","intersection","hoverMotion","hoverOffset","modelYOffset","padding","offset","font","getContext","maxText","measureText","maxWidth","actualBoundingBoxLeft","actualBoundingBoxRight","maxHeight","actualBoundingBoxAscent","actualBoundingBoxDescent","widthPowerOfTwo","toPowerOfTwo","planeWidth","_height","_texture","transparent","_mesh","_font","_color","_padding","_offset","scalePercentage","toFixed","clearRect","centerX","centerY","textSize","halfWidth","halfHeight","beginPath","moveTo","lineTo","quadraticCurveTo","closePath","lineWidth","fillStyle","fill","stroke","textAlign","textBaseline","strokeStyle","fillText","needsUpdate","ScaleUI","_ui","_initialScale","_scaleMultiplier","_prevCoordDistance","_updateUIPosition","uiPos","ringOpacity","dirIndicatorOpacity","fadeoutDuration","deg10","dimmedRingGeomtry","reticle","highlightedRingGeometry","ringVertices","vertices","trianglePart","firstY","midIndex","vec","vecIdx","offsetAmount","indicatorMat","makeRotationX","mergedGeometry","materials","_opacityRange","minOpacityMat","maxOpacityMat","opacityRange","TOUCH","NONE","_size","IN_DEADZONE","_aspect","inputs","fingerCount","_prevOneFingerPosInitialized","_prevTwoFingerPosInitialized","_prevTwoFingerPos","_initialTwoFingerDistance","_prevOneFingerPos","_lastFingerCount","gestures","_testingGestures","reduce","accumulated","_detectedGesture","input","setX","deadzone","testingGestures","lastFingerCount","OUT_OF_DEADZONE","applyScreenAspect","setFirstInput","diff","ONE_FINGER_HORIZONTAL","ONE_FINGER_VERTICAL","middle","TWO_FINGER_HORIZONTAL","TWO_FINGER_VERTICAL","PINCH","hitTestSource","_hitTestSource","deadzoneChecker","_deadzoneChecker","rotateControl","translateControl","scaleControl","_scaleControl","addTestingGestures","ONE_FINGER","getHitTestResultsForTransientInput","_hitResultToVector","intersectBox","_modelHit","_floorIndicator","fadeout","ARSwirlControl","ARFloorTranslateControl","ARScaleControl","FloorIndicator","floorIndicator","DeadzoneChecker","initialFloorPos","init","initFloorPosition","setAspect","_initialized","requestHitTestSourceForTransientInput","profile","transientHitTestSource","cleanup","inputSources","xrInputs","inDeadzone","_checkDeadzone","_processInput","_updateControls","check","activate","setInitialPos","process","deltaMilisec","modelRotation","scaledBbox","boundingSphere","getBoundingSphere","radius","gamepad","axes","_control","ARFloorControl","_options","_hitTest","_renderContext","_modelPlaced","_onSelectStart","_onSelectEnd","_initModelPosition","onSelectStart","onSelectEnd","HitTest","hitTest","ready","hitTestResults","getResults","hit","elements","modelRoot","originalModelScale","scaleUpAnimation","Animation","on","newScale","WebARSession","bodyGeometry","coneGeometry","body","cone","arrow","_arrows","copied","rotateZ","facingOffset","_arrowIndicator","ArrowIndicator","hitRotation","wallRotation","wallPosition","wallNormal","dot","arrowIndicator","arrowPlaneRotation","updateOffset","modelZOffset","isWallHit","hitOrientation","orientation","worldYAxis","wallU","crossVectors","wallV","applyAxisAngle","wallMatrix","makeBasis","prevWallNormal","acos","prevWallRotation","setFromRotationMatrix","rotationDiff","inverse","normal","ARWallTranslateControl","initialTransform","initWallTransform","updateAxis","ARWallControl","setZ","_horizontalAxis","_verticalAxis","horizontal","vertical","ROTATE_HORIZONTAL","ROTATE_VERTICAL","middlePos","posDiff","rotationAxis","_zRotationControl","swirl","_xyRotationControl","ARSwipeControl","swipe","_activatedControl","zRotationControl","xyRotationControl","TWO_FINGER","zRotateAxis","horizontalRotateAxis","verticalRotateAxis","cameraRotation","cameraBasis","modelBasis","_position","extractBasis","viewDir","primaryIdx","maxDot","camToModelDir","primaryAxisIdx","axesIdx","dotProduct","primaryAxis","originToDragPlane","distanceToPoint","centerYOffset","modelLocalYDir","newCenter","updateRotateAxis","_inputSourceToVector","ARHoverRotateControl","ARHoverTranslateControl","ARHoverControl","camQuat","bboxDiff","maxComponent","IS_IOS","userAgent","platform","maxTouchPoints","IS_ANDROID","IS_SAFARI","mode","assign","browser_fallback_url","resizable","queryString","filter","intentURL","anchor","href","click","allowsContentScaling","_file","_allowsContentScaling","setAttribute","appendChild","usdzURL","location","toString","hash","billboard","isTexture","ERR","root_1","onBeforeRender","pos","getWorldPosition","Core","Environments","Controls","Loaders","Extra","Externals","ERROR_CODES"],"mappings":"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"}
\No newline at end of file