diff --git a/dist/mr.js b/dist/mr.js index 2d91fdc9..6337e4c6 100644 --- a/dist/mr.js +++ b/dist/mr.js @@ -443,7 +443,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ MRApp: () => (/* binding */ MRApp)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var three_addons_controls_OrbitControls_js__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! three/addons/controls/OrbitControls.js */ \"./node_modules/three/examples/jsm/controls/OrbitControls.js\");\n/* harmony import */ var three_addons_webxr_XRButton_js__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! three/addons/webxr/XRButton.js */ \"./node_modules/three/examples/jsm/webxr/XRButton.js\");\n/* harmony import */ var stats_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! stats.js */ \"./node_modules/stats.js/build/stats.min.js\");\n/* harmony import */ var stats_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(stats_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var mrjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! mrjs */ \"./src/index.js\");\n/* harmony import */ var mrjs_core_MRElement__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! mrjs/core/MRElement */ \"./src/core/MRElement.js\");\n/* harmony import */ var mrjs_core_MREntity__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! mrjs/core/MREntity */ \"./src/core/MREntity.js\");\n/* harmony import */ var mrjs_core_MRSystem__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! mrjs/core/MRSystem */ \"./src/core/MRSystem.js\");\n/* harmony import */ var mrjs_core_user_MRUser__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! mrjs/core/user/MRUser */ \"./src/core/user/MRUser.js\");\n/* harmony import */ var mrjs_core_entities_MRSkyBoxEntity__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! mrjs/core/entities/MRSkyBoxEntity */ \"./src/core/entities/MRSkyBoxEntity.js\");\n/* harmony import */ var mrjs_core_entities_MRStatsEntity__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! mrjs/core/entities/MRStatsEntity */ \"./src/core/entities/MRStatsEntity.js\");\n/* harmony import */ var mrjs_core_componentSystems_AnchorSystem__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! mrjs/core/componentSystems/AnchorSystem */ \"./src/core/componentSystems/AnchorSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_AnimationSystem__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! mrjs/core/componentSystems/AnimationSystem */ \"./src/core/componentSystems/AnimationSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_AudioSystem__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! mrjs/core/componentSystems/AudioSystem */ \"./src/core/componentSystems/AudioSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_BoundaryVisibilitySystem__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! mrjs/core/componentSystems/BoundaryVisibilitySystem */ \"./src/core/componentSystems/BoundaryVisibilitySystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_ClippingSystem__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! mrjs/core/componentSystems/ClippingSystem */ \"./src/core/componentSystems/ClippingSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_ControlSystem__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! mrjs/core/componentSystems/ControlSystem */ \"./src/core/componentSystems/ControlSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_GeometryStyleSystem__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! mrjs/core/componentSystems/GeometryStyleSystem */ \"./src/core/componentSystems/GeometryStyleSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_LayoutSystem__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! mrjs/core/componentSystems/LayoutSystem */ \"./src/core/componentSystems/LayoutSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_MaskingSystem__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! mrjs/core/componentSystems/MaskingSystem */ \"./src/core/componentSystems/MaskingSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_MaterialStyleSystem__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! mrjs/core/componentSystems/MaterialStyleSystem */ \"./src/core/componentSystems/MaterialStyleSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_PanelSystem__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! mrjs/core/componentSystems/PanelSystem */ \"./src/core/componentSystems/PanelSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_PhysicsSystem__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! mrjs/core/componentSystems/PhysicsSystem */ \"./src/core/componentSystems/PhysicsSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_SkyBoxSystem__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! mrjs/core/componentSystems/SkyBoxSystem */ \"./src/core/componentSystems/SkyBoxSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_StatsSystem__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! mrjs/core/componentSystems/StatsSystem */ \"./src/core/componentSystems/StatsSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_TextSystem__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! mrjs/core/componentSystems/TextSystem */ \"./src/core/componentSystems/TextSystem.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n('use strict');\nwindow.mobileCheck = function () {\n return mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.display.mobileCheckFunction();\n};\n\n// events that trigger the eventUpdate call for all MRSystems\nconst GLOBAL_UPDATE_EVENTS = ['enterxr', 'exitxr', 'load', 'anchored', 'panelupdate', 'engine-started', 'resize'];\n\n/**\n * @class MRApp\n * @classdesc The engine handler for running MRjs as an App. `mr-app`\n * @augments MRElement\n */\nclass MRApp extends mrjs_core_MRElement__WEBPACK_IMPORTED_MODULE_2__.MRElement {\n /**\n * @class\n * @description Constructs the base information of the app including system, camera, engine, xr, and rendering defaults.\n */\n constructor() {\n super();\n Object.defineProperty(this, 'isApp', {\n value: true,\n writable: false,\n });\n\n this.xrsupport = false;\n this.isMobile = window.mobileCheck(); // resolves true/false\n\n this.inspect = false;\n\n this.clock = new three__WEBPACK_IMPORTED_MODULE_23__.Clock();\n this.systems = new Set();\n this.scene = new three__WEBPACK_IMPORTED_MODULE_23__.Scene();\n this.scene.matrixWorldAutoUpdate = false;\n this.anchor = null;\n this.origin = new three__WEBPACK_IMPORTED_MODULE_23__.Object3D();\n\n this.scene.add(this.origin);\n\n // The rest of the renderer is filled out in this.connectedCallback()-->this.init() since\n // the renderer relies on certain component flags attached to the itself.\n this.renderer = null;\n\n this.lighting = {\n enabled: true,\n color: 0xffffff,\n intensity: 1,\n radius: 5,\n shadows: true,\n };\n\n this.cameraOptions = {\n mode: 'orthographic',\n };\n this.render = this.render.bind(this);\n this.onWindowResize = this.onWindowResize.bind(this);\n }\n\n /**\n * @function\n * @memberof MRApp\n * @returns {number} width in 3d or pixel space (depending on if in xr) of the current open app\n */\n get appWidth() {\n let result = parseFloat(this.compStyle.width.split('px')[0]);\n if (mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.isPresenting) {\n result = (result / window.innerWidth) * mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.display.VIRTUAL_DISPLAY_RESOLUTION;\n }\n return result;\n }\n\n /**\n * @function\n * @memberof MRApp\n * @returns {number} height in 3d or pixel space (depending on if in xr) of the current open app\n */\n get appHeight() {\n let result = parseFloat(this.compStyle.height.split('px')[0]);\n if (mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.isPresenting) {\n result = (result / window.screen.height) * mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.display.VIRTUAL_DISPLAY_RESOLUTION;\n }\n return result;\n }\n\n /**\n * @function Connected\n * @memberof MRApp\n * @description The connectedCallback function that runs whenever this entity component becomes connected to something else.\n */\n connectedCallback() {\n this.compStyle = window.getComputedStyle(this);\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.physics.initializePhysics();\n this.init();\n\n this.observer = new MutationObserver(this.mutationCallback);\n this.observer.observe(this, { attributes: true, childList: true });\n\n // initialize built in Systems\n document.addEventListener('engine-started', (event) => {\n this.user = new mrjs_core_user_MRUser__WEBPACK_IMPORTED_MODULE_5__[\"default\"](this.camera, this.scene);\n\n if (this.dataset.occlusion == 'spotlight') {\n this.scene.add(this.user.initSpotlight());\n }\n\n // order matters for all the below system creation items\n this.panelSystem = new mrjs_core_componentSystems_PanelSystem__WEBPACK_IMPORTED_MODULE_18__.PanelSystem();\n this.layoutSystem = new mrjs_core_componentSystems_LayoutSystem__WEBPACK_IMPORTED_MODULE_15__.LayoutSystem();\n this.textSystem = new mrjs_core_componentSystems_TextSystem__WEBPACK_IMPORTED_MODULE_22__.TextSystem();\n this.geometryStyleSystem = new mrjs_core_componentSystems_GeometryStyleSystem__WEBPACK_IMPORTED_MODULE_14__.GeometryStyleSystem();\n this.materialStyleSystem = new mrjs_core_componentSystems_MaterialStyleSystem__WEBPACK_IMPORTED_MODULE_17__.MaterialStyleSystem();\n this.boundaryVisibilitySystem = new mrjs_core_componentSystems_BoundaryVisibilitySystem__WEBPACK_IMPORTED_MODULE_11__.BoundaryVisibilitySystem();\n this.statsSystem = new mrjs_core_componentSystems_StatsSystem__WEBPACK_IMPORTED_MODULE_21__.StatsSystem();\n this.physicsSystem = new mrjs_core_componentSystems_PhysicsSystem__WEBPACK_IMPORTED_MODULE_19__.PhysicsSystem();\n this.controlSystem = new mrjs_core_componentSystems_ControlSystem__WEBPACK_IMPORTED_MODULE_13__.ControlSystem();\n this.anchorSystem = new mrjs_core_componentSystems_AnchorSystem__WEBPACK_IMPORTED_MODULE_8__.AnchorSystem();\n this.animationSystem = new mrjs_core_componentSystems_AnimationSystem__WEBPACK_IMPORTED_MODULE_9__.AnimationSystem();\n this.skyBoxSystem = new mrjs_core_componentSystems_SkyBoxSystem__WEBPACK_IMPORTED_MODULE_20__.SkyBoxSystem();\n this.audioSystem = new mrjs_core_componentSystems_AudioSystem__WEBPACK_IMPORTED_MODULE_10__.AudioSystem();\n\n // These must be the last three systems since\n // they affect rendering. Clipping must happen\n // before masking. Rendering must be the last step.\n this.clippingSystem = new mrjs_core_componentSystems_ClippingSystem__WEBPACK_IMPORTED_MODULE_12__.ClippingSystem();\n this.maskingSystem = new mrjs_core_componentSystems_MaskingSystem__WEBPACK_IMPORTED_MODULE_16__.MaskingSystem();\n });\n\n this.addEventListener('entityadded', (event) => {\n for (const system of this.systems) {\n system._onNewEntity(event.target);\n }\n });\n\n document.addEventListener('entityremoved', async (event) => {\n for (const system of this.systems) {\n system._entityRemoved(event.detail.entity);\n }\n\n while (event.detail.entity.object3D.parent) {\n event.detail.entity.object3D.removeFromParent();\n }\n });\n\n // Call `eventUpdate` on all systems if any of the global events are triggered\n for (const eventType of GLOBAL_UPDATE_EVENTS) {\n document.addEventListener(eventType, (event) => {\n for (const system of this.systems) {\n system.eventUpdate();\n }\n });\n }\n }\n\n /**\n * @function Disconnected\n * @memberof MRApp\n * @description The disconnectedCallback function that runs whenever this entity component becomes connected to something else.\n */\n disconnectedCallback() {\n this.denit();\n this.observer.disconnect();\n }\n\n // TODO: These are for toggling debug and app level flags in realtime.\n // Currently only 'debug' is implemented. but we should add:\n // - stats\n // - lighting\n // - controllers\n // - ?\n /**\n * @function\n * @param {object} mutation - TODO\n */\n mutatedAttribute(mutation) {}\n\n /**\n * @function\n * @param {object} mutation - TODO\n */\n mutatedChildList(mutation) {}\n\n /**\n * @function\n * @description The mutationCallback function that runs whenever this entity component should be mutated.\n * @param {object} mutationList - the list of update/change/mutation(s) to be handled.\n * @param {object} observer - w3 standard object that watches for changes on the HTMLElement\n */\n mutationCallback = (mutationList, observer) => {\n for (const mutation of mutationList) {\n if (mutation.type === 'childList') {\n this.mutatedChildList(mutation);\n }\n if (mutation.type === 'attributes') {\n this.mutatedAttribute(mutation);\n }\n }\n };\n\n /**\n * @function\n * @description Initializes the engine state for the MRApp. This function is run whenever the MRApp is connected.\n */\n init() {\n window.addEventListener('resize', this.onWindowResize);\n\n this.debug = this.dataset.debug ?? false;\n\n /* --- Renderer Setup --- */\n\n this.renderer = new three__WEBPACK_IMPORTED_MODULE_23__.WebGLRenderer({\n antialias: true,\n alpha: true,\n // There's issues in the timing to enable taking screenshots of threejs scenes unless you have direct access to the code.\n // Using the preserveDrawingBuffer to ignore timing issues is the best approach instead. Though this has a performance hit,\n // we're allowing it to be enabled by users when necessary.\n //\n // References:\n // https://stackoverflow.com/questions/15558418/how-do-you-save-an-image-from-a-three-js-canvas\n // https://stackoverflow.com/questions/30628064/how-to-toggle-preservedrawingbuffer-in-three-js\n preserveDrawingBuffer: this.dataset.preserve_drawing_buffer ?? false,\n });\n this.renderer.setPixelRatio(window.devicePixelRatio);\n this.renderer.setSize(this.appWidth, this.appHeight);\n this.renderer.autoClear = false;\n this.renderer.shadowMap.enabled = true;\n this.renderer.xr.enabled = true;\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr = this.renderer.xr;\n this.renderer.toneMapping = three__WEBPACK_IMPORTED_MODULE_23__.ACESFilmicToneMapping;\n this.renderer.toneMappingExposure = 1;\n this.renderer.localClippingEnabled = true;\n\n this.appendChild(this.renderer.domElement);\n\n this.renderer.setAnimationLoop(this.render);\n\n /* --- Camera Setup --- */\n\n this.initCamera();\n\n const layersString = this.dataset.layers;\n if (layersString) {\n this.layers = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToVector(layersString);\n\n for (const layer of this.layers) {\n this.camera.layers.enable(layer);\n }\n }\n\n const orbitalOptionsString = this.dataset.orbital;\n let orbitalOptions = {};\n if (orbitalOptionsString) {\n orbitalOptions = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToJson(orbitalOptionsString);\n }\n this.orbital = orbitalOptions.mode ?? false;\n if (this.debug || this.orbital) {\n const orbitControls = new three_addons_controls_OrbitControls_js__WEBPACK_IMPORTED_MODULE_24__.OrbitControls(this.camera, this.renderer.domElement);\n orbitControls.minDistance = 1;\n orbitControls.maxDistance = 2;\n\n // set target location if requested\n if (orbitalOptions.targetPos) {\n if (orbitalOptions.targetPos.length !== 3) {\n console.error('Invalid orbital target position format. Please provide \"x y z\".');\n }\n orbitControls.target.set(orbitalOptions.targetPos[0], orbitalOptions.targetPos[1], orbitalOptions.targetPos[2]);\n orbitControls.update();\n }\n\n // Note: order of the two below if-statements matter.\n // Want if both debug=true and orbital=true for orbital to take priority.\n if (this.orbital) {\n // always allow orbital controls\n orbitControls.enabled = true;\n } else if (this.debug) {\n // only allow orbital controls on += keypress\n orbitControls.enabled = false;\n document.addEventListener('keydown', (event) => {\n if (event.key == '=') {\n orbitControls.enabled = true;\n }\n });\n document.addEventListener('keyup', (event) => {\n if (event.key == '=') {\n orbitControls.enabled = false;\n }\n });\n }\n }\n\n /* --- Lighting Setup --- */\n\n if (this.dataset.lighting ?? false) {\n this.lighting = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToJson(this.lighting);\n }\n this.initLights(this.lighting);\n\n /* --- Stats Setup --- */\n\n if (this.dataset.stats ?? false) {\n // Old version of stats using the Stats.js visual\n // setup. Leaving to allow for top left quick visual of stats.\n // Is /not/ performant in headset. Documentation notes this.\n //\n this.stats = new (stats_js__WEBPACK_IMPORTED_MODULE_0___default())();\n this.stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom\n document.body.appendChild(this.stats.dom);\n }\n\n /* --- Background Setup --- */\n\n // allows for mr-app style to have background:value to set the skybox\n if (this.compStyle.backgroundImage !== 'none') {\n let skybox = new mrjs_core_entities_MRSkyBoxEntity__WEBPACK_IMPORTED_MODULE_6__.MRSkyBoxEntity();\n let imageUrl = this.compStyle.backgroundImage.match(/url\\(\"?(.+?)\"?\\)/)[1];\n skybox.setAttribute('src', imageUrl);\n this.appendChild(skybox);\n\n // Need to zero out the background-image property otherwise\n // we'll end up with a canvas background as well as the skybox\n // when the canvas background is not needed in this 3d setup.\n //\n // We can do this because panel backgrounds are actual webpage\n // backgrounds and the app itself's background is separate from\n // that, being understood as the skybox of the entire app itself.\n this.style.setProperty('background-image', 'none', 'important');\n this.compStyle = window.getComputedStyle(this);\n }\n\n /* --- Mobile VS XR Setup --- */\n\n // We don't support mobile XR yet\n if (!this.isMobile) {\n navigator.xr?.isSessionSupported('immersive-ar').then((supported) => {\n this.xrsupport = supported;\n\n if (this.xrsupport) {\n this.XRButton = three_addons_webxr_XRButton_js__WEBPACK_IMPORTED_MODULE_25__.XRButton.createButton(this.renderer, {\n requiredFeatures: ['local', 'hand-tracking'],\n optionalFeatures: ['hit-test', 'anchors', 'plane-detection'],\n });\n\n this.XRButton.addEventListener('click', () => {\n this.classList.add('inXR');\n this.XRButton.blur();\n });\n document.body.appendChild(this.XRButton);\n\n this.XRButton.style.position = 'fixed';\n this.XRButton.style.zIndex = 10000;\n }\n });\n }\n }\n\n /**\n * @function\n * @description Initializes the user information for the MRApp including appropriate HMD direction and camera information and the default scene anchor location.\n */\n initCamera = () => {\n const cameraOptionsString = this.dataset.camera ?? '';\n if (cameraOptionsString) {\n Object.assign(this.cameraOptions, mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToJson(this.cameraOptionString) ?? {});\n }\n\n __webpack_require__.g.appWidth = this.appWidth;\n __webpack_require__.g.appHeight = this.appHeight;\n\n switch (this.cameraOptions.mode) {\n case 'orthographic':\n __webpack_require__.g.viewPortWidth = this.appWidth / 1000;\n __webpack_require__.g.viewPortHeight = this.appHeight / 1000;\n\n // In an orthographic camera, unlike perspective, objects are rendered at the same scale regardless of their\n // distance from the camera, meaning near and far clipping planes are more about what objects are visible in\n // terms of their distance from the camera, rather than affecting the size of the objects.\n this.camera = new three__WEBPACK_IMPORTED_MODULE_23__.OrthographicCamera(__webpack_require__.g.viewPortWidth / -2, __webpack_require__.g.viewPortWidth / 2, __webpack_require__.g.viewPortHeight / 2, __webpack_require__.g.viewPortHeight / -2, 0.01, 1000);\n break;\n case 'perspective':\n default:\n this.camera = new three__WEBPACK_IMPORTED_MODULE_23__.PerspectiveCamera(70, this.appWidth / this.appHeight, 0.01, 20);\n this.vFOV = three__WEBPACK_IMPORTED_MODULE_23__.MathUtils.degToRad(this.camera.fov);\n __webpack_require__.g.viewPortHeight = 2 * Math.tan(this.vFOV / 2);\n __webpack_require__.g.viewPortWidth = __webpack_require__.g.viewPortHeight * this.camera.aspect;\n break;\n }\n this.camera.matrixWorldAutoUpdate = false;\n\n let posUpdated = false;\n if (this.cameraOptions.hasOwnProperty('startPos')) {\n const startPosString = comp.startPos;\n if (startPosString) {\n const startPosArray = startPosString.split(' ').map(parseFloat);\n if (startPosArray.length === 3) {\n const [x, y, z] = startPosArray;\n this.camera.position.set(x, y, z);\n posUpdated = true;\n } else {\n console.error('Invalid camera starting position format. Please provide \"x y z\".');\n }\n }\n }\n if (!posUpdated) {\n // default\n this.camera.position.set(0, 0, 1);\n }\n };\n\n /**\n * @function\n * @description Initializes default lighting and shadows for the main scene.\n * @param {object} data - the lights data (color, intensity, shadows, etc)\n */\n initLights = (data) => {\n if (!data.enabled) {\n return;\n }\n this.globalLight = new three__WEBPACK_IMPORTED_MODULE_23__.AmbientLight(data.color);\n this.globalLight.intensity = data.intensity;\n this.globalLight.position.set(0, 5, 0);\n this.scene.add(this.globalLight);\n\n if (!this.isMobile) {\n if (data.shadows) {\n this.shadowLight = new three__WEBPACK_IMPORTED_MODULE_23__.PointLight(data.color);\n this.shadowLight.position.set(-1, 1, 1);\n this.shadowLight.intensity = data.intensity;\n this.shadowLight.castShadow = data.shadows;\n this.shadowLight.shadow.radius = data.radius;\n this.shadowLight.shadow.camera.near = 0.01; // default\n this.shadowLight.shadow.camera.far = 20; // default\n this.shadowLight.shadow.mapSize.set(2048, 2048);\n this.scene.add(this.shadowLight);\n }\n }\n };\n\n /**\n * @function\n * @description De-initializes rendering and MR\n */\n denit() {\n document.body.removeChild(this.renderer.domElement);\n this.removeChild(this.XRButton);\n window.removeEventListener('resize', this.onWindowResize);\n }\n\n /**\n * @function\n * @description Registers a new system addition to the MRApp engine.\n * @param {MRSystem} system - the system to be added.\n */\n registerSystem(system) {\n this.systems.add(system);\n }\n\n /**\n * @function\n * @description Unregisters a system from the MRApp engine.\n * @param {MRSystem} system - the system to be removed.\n */\n unregisterSystem(system) {\n this.systems.delete(system);\n }\n\n /**\n * @function\n * @description Adding an entity as an object in this MRApp engine's scene.\n * @param {MREntity} entity - the entity to be added.\n */\n add(entity) {\n this.origin.add(entity.object3D);\n }\n\n /**\n * @function\n * @description Removing an entity as an object in this MRApp engine's scene.\n * @param {MREntity} entity - the entity to be removed.\n */\n removeEntity(entity) {\n this.origin.remove(entity.object3D);\n }\n\n /**\n * @function\n * @description Handles what is necessary rendering, camera, and user-wise when the viewing window is resized.\n */\n onWindowResize() {\n __webpack_require__.g.appWidth = this.appWidth;\n __webpack_require__.g.appHeight = this.appHeight;\n switch (this.cameraOptions.mode) {\n case 'orthographic':\n __webpack_require__.g.viewPortWidth = this.appWidth / 1000;\n __webpack_require__.g.viewPortHeight = this.appHeight / 1000;\n\n this.camera.left = __webpack_require__.g.viewPortWidth / -2;\n this.camera.right = __webpack_require__.g.viewPortWidth / 2;\n this.camera.top = __webpack_require__.g.viewPortHeight / 2;\n this.camera.bottom = __webpack_require__.g.viewPortHeight / -2;\n break;\n case 'perspective':\n default:\n this.camera.aspect = this.appWidth / this.appHeight;\n __webpack_require__.g.viewPortWidth = __webpack_require__.g.viewPortHeight * this.camera.aspect;\n break;\n }\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(this.appWidth, this.appHeight);\n }\n\n /**\n * @function\n * @description Default function header needed by threejs. The render function that is called during ever frame. Calls every systems' update function.\n * @param {number} timeStamp - timeStamp of the current frame.\n * @param {object} frame - given frame information to be used for any feature changes\n */\n render(timeStamp, frame) {\n // ----- grab important vars ----- //\n\n const deltaTime = this.clock.getDelta();\n\n // ----- If using the threejs stats for 'stats=true' ---- //\n\n if (this.stats) {\n this.stats.update();\n }\n\n // ----- Update needed items ----- //\n\n if (mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.isPresenting && !mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session) {\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session = this.renderer.xr.getSession();\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.referenceSpace = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.getReferenceSpace();\n\n this.dispatchEvent(new CustomEvent('enterxr', { bubbles: true }));\n\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session.addEventListener('end', () => {\n this.camera.position.set(0, 0, 1);\n this.camera.quaternion.set(0, 0, 0, 1);\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session = undefined;\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.referenceSpace = undefined;\n this.classList.remove('inXR');\n\n this.onWindowResize();\n this.dispatchEvent(new CustomEvent('exitxr', { bubbles: true }));\n });\n }\n\n this.user?.update();\n\n // ----- System Updates ----- //\n\n for (const system of this.systems) {\n system._update(deltaTime, frame);\n }\n\n // ----- Actually Render ----- //\n\n // TODO (in future) - once this gets more complicated, it will be nice to have a render system separate\n // from the pure loop but it is okay as is here for now.\n\n this.scene.updateMatrixWorld();\n if (this.camera.parent === null) {\n this.camera.updateMatrixWorld();\n }\n this.renderer.clear();\n\n // Need to wait until we have all needed rendering-associated systems loaded.\n if (this.maskingSystem !== undefined) {\n this.maskingSystem.sync();\n const currentShadowEnabled = this.renderer.shadowMap.enabled;\n this.renderer.shadowMap.enabled = false;\n this.renderer.render(this.maskingSystem.scene, this.camera);\n this.renderer.shadowMap.enabled = currentShadowEnabled;\n }\n\n this.renderer.render(this.scene, this.camera);\n }\n}\n\ncustomElements.get('mr-app') || customElements.define('mr-app', MRApp);\n\n\n//# sourceURL=webpack://mrjs/./src/core/MRApp.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ MRApp: () => (/* binding */ MRApp)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! three */ \"./node_modules/three/build/three.module.js\");\n/* harmony import */ var three_addons_controls_OrbitControls_js__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! three/addons/controls/OrbitControls.js */ \"./node_modules/three/examples/jsm/controls/OrbitControls.js\");\n/* harmony import */ var three_addons_webxr_XRButton_js__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! three/addons/webxr/XRButton.js */ \"./node_modules/three/examples/jsm/webxr/XRButton.js\");\n/* harmony import */ var stats_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! stats.js */ \"./node_modules/stats.js/build/stats.min.js\");\n/* harmony import */ var stats_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(stats_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var mrjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! mrjs */ \"./src/index.js\");\n/* harmony import */ var mrjs_core_MRElement__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! mrjs/core/MRElement */ \"./src/core/MRElement.js\");\n/* harmony import */ var mrjs_core_MREntity__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! mrjs/core/MREntity */ \"./src/core/MREntity.js\");\n/* harmony import */ var mrjs_core_MRSystem__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! mrjs/core/MRSystem */ \"./src/core/MRSystem.js\");\n/* harmony import */ var mrjs_core_user_MRUser__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! mrjs/core/user/MRUser */ \"./src/core/user/MRUser.js\");\n/* harmony import */ var mrjs_core_entities_MRSkyBoxEntity__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! mrjs/core/entities/MRSkyBoxEntity */ \"./src/core/entities/MRSkyBoxEntity.js\");\n/* harmony import */ var mrjs_core_entities_MRStatsEntity__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! mrjs/core/entities/MRStatsEntity */ \"./src/core/entities/MRStatsEntity.js\");\n/* harmony import */ var mrjs_core_componentSystems_AnchorSystem__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! mrjs/core/componentSystems/AnchorSystem */ \"./src/core/componentSystems/AnchorSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_AnimationSystem__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! mrjs/core/componentSystems/AnimationSystem */ \"./src/core/componentSystems/AnimationSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_AudioSystem__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! mrjs/core/componentSystems/AudioSystem */ \"./src/core/componentSystems/AudioSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_BoundaryVisibilitySystem__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! mrjs/core/componentSystems/BoundaryVisibilitySystem */ \"./src/core/componentSystems/BoundaryVisibilitySystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_ClippingSystem__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! mrjs/core/componentSystems/ClippingSystem */ \"./src/core/componentSystems/ClippingSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_ControlSystem__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! mrjs/core/componentSystems/ControlSystem */ \"./src/core/componentSystems/ControlSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_GeometryStyleSystem__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! mrjs/core/componentSystems/GeometryStyleSystem */ \"./src/core/componentSystems/GeometryStyleSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_LayoutSystem__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! mrjs/core/componentSystems/LayoutSystem */ \"./src/core/componentSystems/LayoutSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_MaskingSystem__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! mrjs/core/componentSystems/MaskingSystem */ \"./src/core/componentSystems/MaskingSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_MaterialStyleSystem__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! mrjs/core/componentSystems/MaterialStyleSystem */ \"./src/core/componentSystems/MaterialStyleSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_PanelSystem__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! mrjs/core/componentSystems/PanelSystem */ \"./src/core/componentSystems/PanelSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_PhysicsSystem__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! mrjs/core/componentSystems/PhysicsSystem */ \"./src/core/componentSystems/PhysicsSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_SkyBoxSystem__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! mrjs/core/componentSystems/SkyBoxSystem */ \"./src/core/componentSystems/SkyBoxSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_StatsSystem__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! mrjs/core/componentSystems/StatsSystem */ \"./src/core/componentSystems/StatsSystem.js\");\n/* harmony import */ var mrjs_core_componentSystems_TextSystem__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! mrjs/core/componentSystems/TextSystem */ \"./src/core/componentSystems/TextSystem.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n('use strict');\nwindow.mobileCheck = function () {\n return mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.display.mobileCheckFunction();\n};\n\n// events that trigger the eventUpdate call for all MRSystems\nconst GLOBAL_UPDATE_EVENTS = ['enterxr', 'exitxr', 'load', 'anchored', 'panelupdate', 'engine-started', 'resize'];\n\n/**\n * @class MRApp\n * @classdesc The engine handler for running MRjs as an App. `mr-app`\n * @augments MRElement\n */\nclass MRApp extends mrjs_core_MRElement__WEBPACK_IMPORTED_MODULE_2__.MRElement {\n /**\n * @class\n * @description Constructs the base information of the app including system, camera, engine, xr, and rendering defaults.\n */\n constructor() {\n super();\n Object.defineProperty(this, 'isApp', {\n value: true,\n writable: false,\n });\n\n this.xrsupport = false;\n this.isMobile = window.mobileCheck(); // resolves true/false\n\n this.inspect = false;\n\n this.clock = new three__WEBPACK_IMPORTED_MODULE_23__.Clock();\n this.systems = new Set();\n this.scene = new three__WEBPACK_IMPORTED_MODULE_23__.Scene();\n this.scene.matrixWorldAutoUpdate = false;\n this.anchor = null;\n this.origin = new three__WEBPACK_IMPORTED_MODULE_23__.Object3D();\n\n this.scene.add(this.origin);\n\n // The rest of the renderer is filled out in this.connectedCallback()-->this.init() since\n // the renderer relies on certain component flags attached to the itself.\n this.renderer = null;\n\n this.lighting = {\n enabled: true,\n color: 0xffffff,\n intensity: 1,\n radius: 5,\n shadows: true,\n };\n\n this.cameraOptions = {\n mode: 'orthographic',\n };\n this.render = this.render.bind(this);\n this.onWindowResize = this.onWindowResize.bind(this);\n }\n\n /**\n * @function\n * @memberof MRApp\n * @returns {number} width in 3d or pixel space (depending on if in xr) of the current open app\n */\n get appWidth() {\n let result = parseFloat(this.compStyle.width.split('px')[0]);\n if (mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.isPresenting) {\n result = (result / window.innerWidth) * mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.display.VIRTUAL_DISPLAY_RESOLUTION;\n }\n return result;\n }\n\n /**\n * @function\n * @memberof MRApp\n * @returns {number} height in 3d or pixel space (depending on if in xr) of the current open app\n */\n get appHeight() {\n let result = parseFloat(this.compStyle.height.split('px')[0]);\n if (mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.isPresenting) {\n result = (result / window.screen.height) * mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.display.VIRTUAL_DISPLAY_RESOLUTION;\n }\n return result;\n }\n\n /**\n * @function Connected\n * @memberof MRApp\n * @description The connectedCallback function that runs whenever this entity component becomes connected to something else.\n */\n connectedCallback() {\n this.compStyle = window.getComputedStyle(this);\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.physics.initializePhysics();\n this.init();\n\n this.observer = new MutationObserver(this.mutationCallback);\n this.observer.observe(this, { attributes: true, childList: true });\n\n // initialize built in Systems\n document.addEventListener('engine-started', (event) => {\n this.user = new mrjs_core_user_MRUser__WEBPACK_IMPORTED_MODULE_5__[\"default\"](this.camera, this.scene);\n\n if (this.dataset.occlusion == 'spotlight') {\n this.scene.add(this.user.initSpotlight());\n }\n\n // order matters for all the below system creation items\n this.panelSystem = new mrjs_core_componentSystems_PanelSystem__WEBPACK_IMPORTED_MODULE_18__.PanelSystem();\n this.layoutSystem = new mrjs_core_componentSystems_LayoutSystem__WEBPACK_IMPORTED_MODULE_15__.LayoutSystem();\n this.textSystem = new mrjs_core_componentSystems_TextSystem__WEBPACK_IMPORTED_MODULE_22__.TextSystem();\n this.geometryStyleSystem = new mrjs_core_componentSystems_GeometryStyleSystem__WEBPACK_IMPORTED_MODULE_14__.GeometryStyleSystem();\n this.materialStyleSystem = new mrjs_core_componentSystems_MaterialStyleSystem__WEBPACK_IMPORTED_MODULE_17__.MaterialStyleSystem();\n this.boundaryVisibilitySystem = new mrjs_core_componentSystems_BoundaryVisibilitySystem__WEBPACK_IMPORTED_MODULE_11__.BoundaryVisibilitySystem();\n this.statsSystem = new mrjs_core_componentSystems_StatsSystem__WEBPACK_IMPORTED_MODULE_21__.StatsSystem();\n this.physicsSystem = new mrjs_core_componentSystems_PhysicsSystem__WEBPACK_IMPORTED_MODULE_19__.PhysicsSystem();\n this.controlSystem = new mrjs_core_componentSystems_ControlSystem__WEBPACK_IMPORTED_MODULE_13__.ControlSystem();\n this.anchorSystem = new mrjs_core_componentSystems_AnchorSystem__WEBPACK_IMPORTED_MODULE_8__.AnchorSystem();\n this.animationSystem = new mrjs_core_componentSystems_AnimationSystem__WEBPACK_IMPORTED_MODULE_9__.AnimationSystem();\n this.skyBoxSystem = new mrjs_core_componentSystems_SkyBoxSystem__WEBPACK_IMPORTED_MODULE_20__.SkyBoxSystem();\n this.audioSystem = new mrjs_core_componentSystems_AudioSystem__WEBPACK_IMPORTED_MODULE_10__.AudioSystem();\n\n // These must be the last three systems since\n // they affect rendering. Clipping must happen\n // before masking. Rendering must be the last step.\n this.clippingSystem = new mrjs_core_componentSystems_ClippingSystem__WEBPACK_IMPORTED_MODULE_12__.ClippingSystem();\n this.maskingSystem = new mrjs_core_componentSystems_MaskingSystem__WEBPACK_IMPORTED_MODULE_16__.MaskingSystem();\n });\n\n this.addEventListener('entityadded', (event) => {\n for (const system of this.systems) {\n system._onNewEntity(event.target);\n }\n });\n\n document.addEventListener('entityremoved', async (event) => {\n for (const system of this.systems) {\n system._entityRemoved(event.detail.entity);\n }\n\n while (event.detail.entity.object3D.parent) {\n event.detail.entity.object3D.removeFromParent();\n }\n });\n\n // Call `eventUpdate` on all systems if any of the global events are triggered\n for (const eventType of GLOBAL_UPDATE_EVENTS) {\n document.addEventListener(eventType, (event) => {\n for (const system of this.systems) {\n system.eventUpdate();\n }\n });\n }\n }\n\n /**\n * @function Disconnected\n * @memberof MRApp\n * @description The disconnectedCallback function that runs whenever this entity component becomes connected to something else.\n */\n disconnectedCallback() {\n this.denit();\n this.observer.disconnect();\n }\n\n // TODO: These are for toggling debug and app level flags in realtime.\n // Currently only 'debug' is implemented. but we should add:\n // - stats\n // - lighting\n // - controllers\n // - ?\n /**\n * @function\n * @param {object} mutation - TODO\n */\n mutatedAttribute(mutation) {}\n\n /**\n * @function\n * @param {object} mutation - TODO\n */\n mutatedChildList(mutation) {}\n\n /**\n * @function\n * @description The mutationCallback function that runs whenever this entity component should be mutated.\n * @param {object} mutationList - the list of update/change/mutation(s) to be handled.\n * @param {object} observer - w3 standard object that watches for changes on the HTMLElement\n */\n mutationCallback = (mutationList, observer) => {\n for (const mutation of mutationList) {\n if (mutation.type === 'childList') {\n this.mutatedChildList(mutation);\n }\n if (mutation.type === 'attributes') {\n this.mutatedAttribute(mutation);\n }\n }\n };\n\n /**\n * @function\n * @description Initializes the engine state for the MRApp. This function is run whenever the MRApp is connected.\n */\n init() {\n window.addEventListener('resize', this.onWindowResize);\n\n this.debug = this.dataset.debug ?? false;\n\n /* --- Renderer Setup --- */\n\n this.renderer = new three__WEBPACK_IMPORTED_MODULE_23__.WebGLRenderer({\n antialias: true,\n alpha: true,\n // There's issues in the timing to enable taking screenshots of threejs scenes unless you have direct access to the code.\n // Using the preserveDrawingBuffer to ignore timing issues is the best approach instead. Though this has a performance hit,\n // we're allowing it to be enabled by users when necessary.\n //\n // References:\n // https://stackoverflow.com/questions/15558418/how-do-you-save-an-image-from-a-three-js-canvas\n // https://stackoverflow.com/questions/30628064/how-to-toggle-preservedrawingbuffer-in-three-js\n preserveDrawingBuffer: this.dataset.preserveDrawingBuffer ?? false,\n });\n this.renderer.setPixelRatio(window.devicePixelRatio);\n this.renderer.setSize(this.appWidth, this.appHeight);\n this.renderer.autoClear = false;\n this.renderer.shadowMap.enabled = true;\n this.renderer.xr.enabled = true;\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr = this.renderer.xr;\n this.renderer.toneMapping = three__WEBPACK_IMPORTED_MODULE_23__.ACESFilmicToneMapping;\n this.renderer.toneMappingExposure = 1;\n this.renderer.localClippingEnabled = true;\n\n this.appendChild(this.renderer.domElement);\n\n this.renderer.setAnimationLoop(this.render);\n\n /* --- Camera Setup --- */\n\n this.initCamera();\n\n const layersString = this.dataset.layers;\n if (layersString) {\n this.layers = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToVector(layersString);\n\n for (const layer of this.layers) {\n this.camera.layers.enable(layer);\n }\n }\n\n const orbitalOptionsString = this.dataset.orbital;\n let orbitalOptions = {};\n if (orbitalOptionsString) {\n orbitalOptions = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToJson(orbitalOptionsString);\n }\n this.orbital = orbitalOptions.mode ?? false;\n if (this.debug || this.orbital) {\n const orbitControls = new three_addons_controls_OrbitControls_js__WEBPACK_IMPORTED_MODULE_24__.OrbitControls(this.camera, this.renderer.domElement);\n orbitControls.minDistance = 1;\n orbitControls.maxDistance = 2;\n\n // set target location if requested\n if (orbitalOptions.targetPos) {\n if (orbitalOptions.targetPos.length !== 3) {\n console.error('Invalid orbital target position format. Please provide \"x y z\".');\n }\n orbitControls.target.set(orbitalOptions.targetPos[0], orbitalOptions.targetPos[1], orbitalOptions.targetPos[2]);\n orbitControls.update();\n }\n\n // Note: order of the two below if-statements matter.\n // Want if both debug=true and orbital=true for orbital to take priority.\n if (this.orbital) {\n // always allow orbital controls\n orbitControls.enabled = true;\n } else if (this.debug) {\n // only allow orbital controls on += keypress\n orbitControls.enabled = false;\n document.addEventListener('keydown', (event) => {\n if (event.key == '=') {\n orbitControls.enabled = true;\n }\n });\n document.addEventListener('keyup', (event) => {\n if (event.key == '=') {\n orbitControls.enabled = false;\n }\n });\n }\n }\n\n /* --- Lighting Setup --- */\n\n if (this.dataset.lighting ?? false) {\n this.lighting = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToJson(this.dataset.lighting);\n }\n this.initLights(this.lighting);\n\n /* --- Stats Setup --- */\n\n if (this.dataset.stats ?? false) {\n // Old version of stats using the Stats.js visual\n // setup. Leaving to allow for top left quick visual of stats.\n // Is /not/ performant in headset. Documentation notes this.\n //\n this.stats = new (stats_js__WEBPACK_IMPORTED_MODULE_0___default())();\n this.stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom\n document.body.appendChild(this.stats.dom);\n }\n\n /* --- Background Setup --- */\n\n // allows for mr-app style to have background:value to set the skybox\n if (this.compStyle.backgroundImage !== 'none') {\n let skybox = new mrjs_core_entities_MRSkyBoxEntity__WEBPACK_IMPORTED_MODULE_6__.MRSkyBoxEntity();\n let imageUrl = this.compStyle.backgroundImage.match(/url\\(\"?(.+?)\"?\\)/)[1];\n skybox.setAttribute('src', imageUrl);\n this.appendChild(skybox);\n\n // Need to zero out the background-image property otherwise\n // we'll end up with a canvas background as well as the skybox\n // when the canvas background is not needed in this 3d setup.\n //\n // We can do this because panel backgrounds are actual webpage\n // backgrounds and the app itself's background is separate from\n // that, being understood as the skybox of the entire app itself.\n this.style.setProperty('background-image', 'none', 'important');\n this.compStyle = window.getComputedStyle(this);\n }\n\n /* --- Mobile VS XR Setup --- */\n\n // We don't support mobile XR yet\n if (!this.isMobile) {\n navigator.xr?.isSessionSupported('immersive-ar').then((supported) => {\n this.xrsupport = supported;\n\n if (this.xrsupport) {\n this.XRButton = three_addons_webxr_XRButton_js__WEBPACK_IMPORTED_MODULE_25__.XRButton.createButton(this.renderer, {\n requiredFeatures: ['local', 'hand-tracking'],\n optionalFeatures: ['hit-test', 'anchors', 'plane-detection'],\n });\n\n this.XRButton.addEventListener('click', () => {\n this.classList.add('inXR');\n this.XRButton.blur();\n });\n document.body.appendChild(this.XRButton);\n\n this.XRButton.style.position = 'fixed';\n this.XRButton.style.zIndex = 10000;\n }\n });\n }\n }\n\n /**\n * @function\n * @description Initializes the user information for the MRApp including appropriate HMD direction and camera information and the default scene anchor location.\n */\n initCamera = () => {\n const cameraOptionsString = this.dataset.camera ?? '';\n if (cameraOptionsString) {\n Object.assign(this.cameraOptions, mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.string.stringToJson(this.cameraOptionString) ?? {});\n }\n\n __webpack_require__.g.appWidth = this.appWidth;\n __webpack_require__.g.appHeight = this.appHeight;\n\n switch (this.cameraOptions.mode) {\n case 'orthographic':\n __webpack_require__.g.viewPortWidth = this.appWidth / 1000;\n __webpack_require__.g.viewPortHeight = this.appHeight / 1000;\n\n // In an orthographic camera, unlike perspective, objects are rendered at the same scale regardless of their\n // distance from the camera, meaning near and far clipping planes are more about what objects are visible in\n // terms of their distance from the camera, rather than affecting the size of the objects.\n this.camera = new three__WEBPACK_IMPORTED_MODULE_23__.OrthographicCamera(__webpack_require__.g.viewPortWidth / -2, __webpack_require__.g.viewPortWidth / 2, __webpack_require__.g.viewPortHeight / 2, __webpack_require__.g.viewPortHeight / -2, 0.01, 1000);\n break;\n case 'perspective':\n default:\n this.camera = new three__WEBPACK_IMPORTED_MODULE_23__.PerspectiveCamera(70, this.appWidth / this.appHeight, 0.01, 20);\n this.vFOV = three__WEBPACK_IMPORTED_MODULE_23__.MathUtils.degToRad(this.camera.fov);\n __webpack_require__.g.viewPortHeight = 2 * Math.tan(this.vFOV / 2);\n __webpack_require__.g.viewPortWidth = __webpack_require__.g.viewPortHeight * this.camera.aspect;\n break;\n }\n this.camera.matrixWorldAutoUpdate = false;\n\n let posUpdated = false;\n if (this.cameraOptions.hasOwnProperty('startPos')) {\n const startPosString = comp.startPos;\n if (startPosString) {\n const startPosArray = startPosString.split(' ').map(parseFloat);\n if (startPosArray.length === 3) {\n const [x, y, z] = startPosArray;\n this.camera.position.set(x, y, z);\n posUpdated = true;\n } else {\n console.error('Invalid camera starting position format. Please provide \"x y z\".');\n }\n }\n }\n if (!posUpdated) {\n // default\n this.camera.position.set(0, 0, 1);\n }\n };\n\n /**\n * @function\n * @description Initializes default lighting and shadows for the main scene.\n * @param {object} data - the lights data (color, intensity, shadows, etc)\n */\n initLights = (data) => {\n if (!data.enabled) {\n return;\n }\n this.globalLight = new three__WEBPACK_IMPORTED_MODULE_23__.AmbientLight(data.color);\n this.globalLight.intensity = data.intensity;\n this.globalLight.position.set(0, 5, 0);\n this.scene.add(this.globalLight);\n\n if (!this.isMobile) {\n if (data.shadows) {\n this.shadowLight = new three__WEBPACK_IMPORTED_MODULE_23__.PointLight(data.color);\n this.shadowLight.position.set(-1, 1, 1);\n this.shadowLight.intensity = data.intensity;\n this.shadowLight.castShadow = data.shadows;\n this.shadowLight.shadow.radius = data.radius;\n this.shadowLight.shadow.camera.near = 0.01; // default\n this.shadowLight.shadow.camera.far = 20; // default\n this.shadowLight.shadow.mapSize.set(2048, 2048);\n this.scene.add(this.shadowLight);\n }\n }\n };\n\n /**\n * @function\n * @description De-initializes rendering and MR\n */\n denit() {\n document.body.removeChild(this.renderer.domElement);\n this.removeChild(this.XRButton);\n window.removeEventListener('resize', this.onWindowResize);\n }\n\n /**\n * @function\n * @description Registers a new system addition to the MRApp engine.\n * @param {MRSystem} system - the system to be added.\n */\n registerSystem(system) {\n this.systems.add(system);\n }\n\n /**\n * @function\n * @description Unregisters a system from the MRApp engine.\n * @param {MRSystem} system - the system to be removed.\n */\n unregisterSystem(system) {\n this.systems.delete(system);\n }\n\n /**\n * @function\n * @description Adding an entity as an object in this MRApp engine's scene.\n * @param {MREntity} entity - the entity to be added.\n */\n add(entity) {\n this.origin.add(entity.object3D);\n }\n\n /**\n * @function\n * @description Removing an entity as an object in this MRApp engine's scene.\n * @param {MREntity} entity - the entity to be removed.\n */\n removeEntity(entity) {\n this.origin.remove(entity.object3D);\n }\n\n /**\n * @function\n * @description Handles what is necessary rendering, camera, and user-wise when the viewing window is resized.\n */\n onWindowResize() {\n __webpack_require__.g.appWidth = this.appWidth;\n __webpack_require__.g.appHeight = this.appHeight;\n switch (this.cameraOptions.mode) {\n case 'orthographic':\n __webpack_require__.g.viewPortWidth = this.appWidth / 1000;\n __webpack_require__.g.viewPortHeight = this.appHeight / 1000;\n\n this.camera.left = __webpack_require__.g.viewPortWidth / -2;\n this.camera.right = __webpack_require__.g.viewPortWidth / 2;\n this.camera.top = __webpack_require__.g.viewPortHeight / 2;\n this.camera.bottom = __webpack_require__.g.viewPortHeight / -2;\n break;\n case 'perspective':\n default:\n this.camera.aspect = this.appWidth / this.appHeight;\n __webpack_require__.g.viewPortWidth = __webpack_require__.g.viewPortHeight * this.camera.aspect;\n break;\n }\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(this.appWidth, this.appHeight);\n }\n\n /**\n * @function\n * @description Default function header needed by threejs. The render function that is called during ever frame. Calls every systems' update function.\n * @param {number} timeStamp - timeStamp of the current frame.\n * @param {object} frame - given frame information to be used for any feature changes\n */\n render(timeStamp, frame) {\n // ----- grab important vars ----- //\n\n const deltaTime = this.clock.getDelta();\n\n // ----- If using the threejs stats for 'stats=true' ---- //\n\n if (this.stats) {\n this.stats.update();\n }\n\n // ----- Update needed items ----- //\n\n if (mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.isPresenting && !mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session) {\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session = this.renderer.xr.getSession();\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.referenceSpace = mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.getReferenceSpace();\n\n this.dispatchEvent(new CustomEvent('enterxr', { bubbles: true }));\n\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session.addEventListener('end', () => {\n this.camera.position.set(0, 0, 1);\n this.camera.quaternion.set(0, 0, 0, 1);\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.session = undefined;\n mrjs__WEBPACK_IMPORTED_MODULE_1__.mrjsUtils.xr.referenceSpace = undefined;\n this.classList.remove('inXR');\n\n this.onWindowResize();\n this.dispatchEvent(new CustomEvent('exitxr', { bubbles: true }));\n });\n }\n\n this.user?.update();\n\n // ----- System Updates ----- //\n\n for (const system of this.systems) {\n system._update(deltaTime, frame);\n }\n\n // ----- Actually Render ----- //\n\n // TODO (in future) - once this gets more complicated, it will be nice to have a render system separate\n // from the pure loop but it is okay as is here for now.\n\n this.scene.updateMatrixWorld();\n if (this.camera.parent === null) {\n this.camera.updateMatrixWorld();\n }\n this.renderer.clear();\n\n // Need to wait until we have all needed rendering-associated systems loaded.\n if (this.maskingSystem !== undefined) {\n this.maskingSystem.sync();\n const currentShadowEnabled = this.renderer.shadowMap.enabled;\n this.renderer.shadowMap.enabled = false;\n this.renderer.render(this.maskingSystem.scene, this.camera);\n this.renderer.shadowMap.enabled = currentShadowEnabled;\n }\n\n this.renderer.render(this.scene, this.camera);\n }\n}\n\ncustomElements.get('mr-app') || customElements.define('mr-app', MRApp);\n\n\n//# sourceURL=webpack://mrjs/./src/core/MRApp.js?"); /***/ }), diff --git a/samples/examples/debug.html b/samples/examples/debug.html index eb788a62..9c629d07 100644 --- a/samples/examples/debug.html +++ b/samples/examples/debug.html @@ -9,7 +9,7 @@ - +