-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from ir-engine/move-back-out-webxr-emulator
move back out webxr emulator
- Loading branch information
Showing
64 changed files
with
3,789 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/* | ||
CPAL-1.0 License | ||
The contents of this file are subject to the Common Public Attribution License | ||
Version 1.0. (the "License"); you may not use this file except in compliance | ||
with the License. You may obtain a copy of the License at | ||
https://github.com/ir-engine/ir-engine/blob/dev/LICENSE. | ||
The License is based on the Mozilla Public License Version 1.1, but Sections 14 | ||
and 15 have been added to cover use of software over a computer network and | ||
provide for limited attribution for the Original Developer. In addition, | ||
Exhibit A has been modified to be consistent with Exhibit B. | ||
Software distributed under the License is distributed on an "AS IS" basis, | ||
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the | ||
specific language governing rights and limitations under the License. | ||
The Original Code is Infinite Reality Engine. | ||
The Original Developer is the Initial Developer. The Initial Developer of the | ||
Original Code is the Infinite Reality Engine team. | ||
All portions of the code written by the Infinite Reality Engine team are Copyright © 2021-2023 | ||
Infinite Reality Engine. All Rights Reserved. | ||
*/ | ||
|
||
import { useHookstate, useImmediateEffect, useMutableState } from '@ir-engine/hyperflux' | ||
import { endXRSession, requestXRSession } from '@ir-engine/spatial/src/xr/XRSessionFunctions' | ||
import Button from '@ir-engine/ui/src/primitives/tailwind/Button' | ||
import React from 'react' | ||
|
||
import EmulatedDevice from './js/emulatedDevice' | ||
import { EmulatorSettings, emulatorStates } from './js/emulatorStates' | ||
import { syncDevicePose } from './js/messenger' | ||
import Devtool from './jsx/app' | ||
import devtoolCSS from './styles/index.css?inline' | ||
|
||
import { XRState } from '@ir-engine/spatial/src/xr/XRState' | ||
import 'bootstrap' | ||
import 'bootstrap/dist/css/bootstrap.min.css' | ||
import { WebXREventDispatcher } from '@ir-engine/spatial/tests/webxr/emulator/WebXREventDispatcher' | ||
import { POLYFILL_ACTIONS } from '@ir-engine/spatial/tests/webxr/emulator/actions' | ||
|
||
export async function overrideXR(args: { mode: 'immersive-vr' | 'immersive-ar' }) { | ||
// inject the webxr polyfill from the webxr emulator source - this is a script added by the bot | ||
// globalThis.WebXRPolyfillInjection() | ||
|
||
const { CustomWebXRPolyfill } = await import('@ir-engine/spatial/tests/webxr/emulator/CustomWebXRPolyfill') | ||
new CustomWebXRPolyfill() | ||
// override session supported request, it hangs indefinitely for some reason | ||
;(navigator as any).xr.isSessionSupported = () => { | ||
return true | ||
} | ||
|
||
const deviceDefinition = { | ||
id: 'Oculus Quest', | ||
name: 'Oculus Quest', | ||
modes: ['inline', 'immersive-vr', 'immersive-ar'], | ||
headset: { | ||
hasPosition: true, | ||
hasRotation: true | ||
}, | ||
controllers: [ | ||
{ | ||
id: 'Oculus Touch (Right)', | ||
buttonNum: 7, | ||
primaryButtonIndex: 0, | ||
primarySqueezeButtonIndex: 1, | ||
hasPosition: true, | ||
hasRotation: true, | ||
hasSqueezeButton: true, | ||
isComplex: true | ||
}, | ||
{ | ||
id: 'Oculus Touch (Left)', | ||
buttonNum: 7, | ||
primaryButtonIndex: 0, | ||
primarySqueezeButtonIndex: 1, | ||
hasPosition: true, | ||
hasRotation: true, | ||
hasSqueezeButton: true, | ||
isComplex: true | ||
} | ||
], | ||
environmentBlendMode: args.mode === 'immersive-vr' ? 'opaque' : 'additive' | ||
} | ||
|
||
// send our device info to the polyfill API so it knows our capabilities | ||
WebXREventDispatcher.instance.dispatchEvent({ | ||
type: POLYFILL_ACTIONS.DEVICE_INIT, | ||
detail: { stereoEffect: false, deviceDefinition } | ||
}) | ||
} | ||
|
||
const setup = async (mode: 'immersive-vr' | 'immersive-ar') => { | ||
await overrideXR({ mode }) | ||
await EmulatorSettings.instance.load() | ||
const device = new EmulatedDevice() | ||
device.on('pose', syncDevicePose) | ||
;(emulatorStates as any).emulatedDevice = device | ||
|
||
return device | ||
} | ||
|
||
export const EmulatorDevtools = (props: { mode: 'immersive-vr' | 'immersive-ar' }) => { | ||
const xrState = useMutableState(XRState) | ||
const xrActive = xrState.sessionActive.value && !xrState.requestingSession.value | ||
|
||
const deviceState = useHookstate(null as null | EmulatedDevice) | ||
useImmediateEffect(() => { | ||
setup(props.mode).then((device) => { | ||
deviceState.set(device) | ||
}) | ||
}, []) | ||
|
||
const toggleXR = async () => { | ||
if (xrActive) { | ||
endXRSession() | ||
} else { | ||
requestXRSession({ mode: props.mode }) | ||
} | ||
} | ||
|
||
const togglePlacement = () => { | ||
if (xrState.scenePlacementMode.value !== 'placing') { | ||
xrState.scenePlacementMode.set('placing') | ||
xrState.sceneScaleAutoMode.set(false) | ||
xrState.sceneScaleTarget.set(0.1) | ||
} else { | ||
xrState.scenePlacementMode.set('placed') | ||
} | ||
} | ||
|
||
return ( | ||
<> | ||
<style type="text/css">{devtoolCSS.toString()}</style> | ||
<div | ||
id="devtools" | ||
className="flex-no-wrap m-0 flex h-full h-full select-none flex-col overflow-hidden overflow-hidden bg-gray-900 text-xs text-gray-900" | ||
> | ||
<div className="flex-no-wrap flex h-10 select-none flex-row bg-gray-800 text-xs text-gray-900"> | ||
<Button className="my-1 ml-auto mr-6 px-10" onClick={toggleXR} disabled={xrState.requestingSession.value}> | ||
{(xrActive ? 'Exit ' : 'Enter ') + (props.mode === 'immersive-ar' ? 'AR' : 'VR')} | ||
</Button> | ||
{props.mode === 'immersive-ar' && ( | ||
<Button className="my-1 ml-auto mr-6 px-10" onClick={togglePlacement} disabled={!xrActive}> | ||
Place Scene | ||
</Button> | ||
)} | ||
</div> | ||
{deviceState.value && <Devtool device={deviceState.value} />} | ||
</div> | ||
</> | ||
) | ||
} |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
/** | ||
* Events triggered by the emulator UI and sent to the content script | ||
*/ | ||
export const EMULATOR_ACTIONS = { | ||
HEADSET_POSE_CHANGE: 'ea-headset-pose-change', | ||
CONTROLLER_POSE_CHANGE: 'ea-controller-pose-change', | ||
CONTROLLER_VISIBILITY_CHANGE: 'ea-controller-visibility-change', | ||
BUTTON_STATE_CHANGE: 'ea-button-state-change', | ||
ANALOG_VALUE_CHANGE: 'ea-analog-value-change', | ||
DEVICE_TYPE_CHANGE: 'ea-device-type-change', | ||
STEREO_TOGGLE: 'ea-stereo-toggle', | ||
KEYBOARD_EVENT: 'ea-keyboard-event', | ||
EXIT_IMMERSIVE: 'ea-exit-immersive', | ||
ROOM_DIMENSION_CHANGE: 'ea-room-dimension-change', | ||
EXCLUDE_POLYFILL: 'ea-exclude-polyfill', | ||
INPUT_MODE_CHANGE: 'ea-input-mode-change', | ||
HAND_POSE_CHANGE: 'ea-hand-pose-change', | ||
HAND_VISIBILITY_CHANGE: 'ea-hand-visibility-change', | ||
PINCH_VALUE_CHANGE: 'ea-pinch-value-change', | ||
USER_OBJECTS_CHANGE: 'ea-user-objects-change', | ||
}; | ||
|
||
/** | ||
* Events triggered by the content script and caught and processed by the custom WebXR Polyfill | ||
*/ | ||
export const POLYFILL_ACTIONS = EMULATOR_ACTIONS | ||
// { | ||
// HEADSET_POSE_CHANGE: 'pa-headset-pose-change', | ||
// CONTROLLER_POSE_CHANGE: 'pa-controller-pose-change', | ||
// CONTROLLER_VISIBILITY_CHANGE: 'pa-controller-visibility-change', | ||
// BUTTON_STATE_CHANGE: 'pa-button-state-change', | ||
// ANALOG_VALUE_CHANGE: 'pa-analog-value-change', | ||
// DEVICE_TYPE_CHANGE: 'pa-device-type-change', | ||
// STEREO_TOGGLE: 'pa-stereo-toggle', | ||
// KEYBOARD_EVENT: 'pa-keyboard-event', | ||
// EXIT_IMMERSIVE: 'pa-exit-immersive', | ||
// DEVICE_INIT: 'pa-device-init', | ||
// ROOM_DIMENSION_CHANGE: 'pa-room-dimension-change', | ||
// INPUT_MODE_CHANGE: 'pa-input-mode-change', | ||
// HAND_POSE_CHANGE: 'pa-hand-pose-change', | ||
// HAND_VISIBILITY_CHANGE: 'pa-hand-visibility-change', | ||
// PINCH_VALUE_CHANGE: 'pa-pinch-value-change', | ||
// USER_OBJECTS_CHANGE: 'pa-user-objects-change', | ||
// }; | ||
|
||
/** | ||
* Events triggered from the client side that are caught by the content script and then relayed back to the emulator side | ||
*/ | ||
export const CLIENT_ACTIONS = { | ||
ENTER_IMMERSIVE: 'ca-enter-immersive', | ||
EXIT_IMMERSIVE: 'ca-exit-immersive', | ||
PING: 'ca-ping', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
export const PRESS_AND_RELEASE_DURATION = 250; | ||
|
||
export const BUTTON_POLYFILL_INDEX_MAPPING = { | ||
joystick: 0, | ||
trigger: 1, | ||
grip: 2, | ||
button1: 3, | ||
button2: 4, | ||
}; | ||
|
||
export const DEVICE = { | ||
HEADSET: '0', | ||
INPUT_RIGHT: '2', | ||
INPUT_LEFT: '3', | ||
}; | ||
|
||
export const OBJECT_NAME = {}; | ||
OBJECT_NAME[DEVICE.HEADSET] = 'headset'; | ||
OBJECT_NAME[DEVICE.INPUT_LEFT] = 'left-controller'; | ||
OBJECT_NAME[DEVICE.INPUT_RIGHT] = 'right-controller'; | ||
|
||
export const DEFAULT_TRANSFORMS = {}; | ||
DEFAULT_TRANSFORMS[DEVICE.HEADSET] = { | ||
position: [0, 1.7, 0], | ||
rotation: [0, 0, 0, 'XYZ'], | ||
}; | ||
DEFAULT_TRANSFORMS[DEVICE.INPUT_RIGHT] = { | ||
position: [0.25, 1.5, -0.4], | ||
rotation: [0, 0, 0, 'XYZ'], | ||
}; | ||
DEFAULT_TRANSFORMS[DEVICE.INPUT_LEFT] = { | ||
position: [-0.25, 1.5, -0.4], | ||
rotation: [0, 0, 0, 'XYZ'], | ||
}; | ||
|
||
export const CONTROLLER_STRINGS = {}; | ||
CONTROLLER_STRINGS[DEVICE.INPUT_LEFT] = { | ||
name: 'left-controller', | ||
displayName: 'Left Controller', | ||
handedness: 'left', | ||
button1: 'ButtonX', | ||
button2: 'ButtonY', | ||
}; | ||
CONTROLLER_STRINGS[DEVICE.INPUT_RIGHT] = { | ||
name: 'right-controller', | ||
displayName: 'Right Controller', | ||
handedness: 'right', | ||
button1: 'ButtonA', | ||
button2: 'ButtonB', | ||
}; | ||
|
||
export const HAND_STRINGS = {}; | ||
HAND_STRINGS[DEVICE.INPUT_LEFT] = { | ||
name: 'left-hand', | ||
displayName: 'Left Hand', | ||
handedness: 'left', | ||
}; | ||
HAND_STRINGS[DEVICE.INPUT_RIGHT] = { | ||
name: 'right-hand', | ||
displayName: 'Right Hand', | ||
handedness: 'right', | ||
}; | ||
|
||
export const KEYBOARD_CONTROL_MAPPING = { | ||
left: { | ||
joystickLeft: 'a', | ||
joystickRight: 'd', | ||
joystickForward: 'w', | ||
joystickBackward: 's', | ||
trigger: 'e', | ||
grip: 'q', | ||
button1: 'x', | ||
button2: 'z', | ||
joystick: 'c', | ||
}, | ||
right: { | ||
joystickLeft: 'ArrowLeft', | ||
joystickRight: 'ArrowRight', | ||
joystickForward: 'ArrowUp', | ||
joystickBackward: 'ArrowDown', | ||
trigger: 'Enter', | ||
grip: 'Shift', | ||
button1: "'", | ||
button2: '/', | ||
joystick: '.', | ||
}, | ||
}; | ||
|
||
export const GAMEPAD_ID_TO_INPUT_ID_MAPPING = { | ||
3: 'joystick', | ||
5: 'button2', | ||
4: 'button1', | ||
0: 'trigger', | ||
1: 'grip', | ||
}; | ||
|
||
export const SEMANTIC_LABELS = { | ||
Desk: 'desk', | ||
Couch: 'couch', | ||
Floor: 'floor', | ||
Ceiling: 'ceiling', | ||
Wall: 'wall', | ||
Door: 'door', | ||
Window: 'window', | ||
Table: 'table', | ||
Shelf: 'shelf', | ||
Bed: 'bed', | ||
Screen: 'screen', | ||
Lamp: 'lamp', | ||
Plant: 'plant', | ||
WallArt: 'wall art', | ||
Other: 'other', | ||
}; | ||
|
||
export const TRIGGER_MODES = ['slow', 'normal', 'fast', 'turbo']; | ||
|
||
export const TRIGGER_CONFIG = { | ||
slow: { | ||
interval: 20, | ||
holdTime: 100, | ||
}, | ||
normal: { | ||
interval: 10, | ||
holdTime: 50, | ||
}, | ||
fast: { | ||
interval: 5, | ||
holdTime: 10, | ||
}, | ||
turbo: { | ||
interval: 1, | ||
holdTime: 1, | ||
}, | ||
}; |
Oops, something went wrong.