UNPKG

363 kBSource Map (JSON)View Raw
1{"version":3,"file":"view3d.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/consts/xr.ts","../src/controls/ar/floor/ARFloorTranslateControl.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/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\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 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\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","d1","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_DURATION","ANIMATION_RANGE","CAMERA_POSE","INFINITE_RANGE","Infinity","PITCH_RANGE","DISTANCE_RANGE","NULL_ELEMENT","DRACO_DECODER_URL","_c","duration","DEFAULT","_d","loop","_e","_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","anchorEl","STATE","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","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","camToHitDir","hitOnDragPlane","intersectPlane","targetRayPose","inputSource","targetRaySpace","fingerDir","intersection","hoverMotion","hoverOffset","modelYOffset","padding","offset","font","getContext","maxText","measureText","maxWidth","actualBoundingBoxLeft","actualBoundingBoxRight","maxHeight","actualBoundingBoxAscent","actualBoundingBoxDescent","widthPowerOfTwo","toPowerOfTwo","planeWidth","_height","_texture","uiGeometry","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