mirror of https://github.com/bjornbytes/lovr.git
Clean up WebXR;
- Pointer lock - wasPressed/wasReleased - Cleanup
This commit is contained in:
parent
6cadcea65d
commit
e50835260a
|
@ -6,7 +6,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define EVENT_TARGET "#canvas"
|
||||
#define CANVAS "#canvas"
|
||||
|
||||
static struct {
|
||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context;
|
||||
|
@ -17,6 +17,7 @@ static struct {
|
|||
keyboardCallback onKeyboardEvent;
|
||||
bool keyMap[KEY_COUNT];
|
||||
bool mouseMap[2];
|
||||
MouseMode mouseMode;
|
||||
long mouseX;
|
||||
long mouseY;
|
||||
int width;
|
||||
|
@ -45,7 +46,7 @@ static EM_BOOL onResize(int type, const EmscriptenUiEvent* data, void* userdata)
|
|||
emscripten_webgl_get_drawing_buffer_size(state.context, &state.framebufferWidth, &state.framebufferHeight);
|
||||
|
||||
int newWidth, newHeight;
|
||||
emscripten_get_canvas_element_size(EVENT_TARGET, &newWidth, &newHeight);
|
||||
emscripten_get_canvas_element_size(CANVAS, &newWidth, &newHeight);
|
||||
if (state.width != newWidth || state.height != newHeight) {
|
||||
state.width = newWidth;
|
||||
state.height = newHeight;
|
||||
|
@ -77,8 +78,13 @@ static EM_BOOL onMouseButton(int type, const EmscriptenMouseEvent* data, void* u
|
|||
}
|
||||
|
||||
static EM_BOOL onMouseMove(int type, const EmscriptenMouseEvent* data, void* userdata) {
|
||||
state.mouseX = data->clientX;
|
||||
state.mouseY = data->clientY;
|
||||
if (state.mouseMode == MOUSE_MODE_GRABBED) {
|
||||
state.mouseX += data->movementX;
|
||||
state.mouseY += data->movementY;
|
||||
} else {
|
||||
state.mouseX = data->clientX;
|
||||
state.mouseY = data->clientY;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -168,8 +174,8 @@ static EM_BOOL onKeyEvent(int type, const EmscriptenKeyboardEvent* data, void* u
|
|||
case DOM_PK_PAGE_DOWN: key = KEY_PAGE_DOWN; break;
|
||||
case DOM_PK_INSERT: key = KEY_INSERT; break;
|
||||
case DOM_PK_DELETE: key = KEY_DELETE; break;
|
||||
case DOM_PK_OS_LEFT: key = KEY_LEFT_SUPER; break;
|
||||
case DOM_PK_OS_RIGHT: key = KEY_RIGHT_SUPER; break;
|
||||
case DOM_PK_OS_LEFT: key = KEY_LEFT_OS; break;
|
||||
case DOM_PK_OS_RIGHT: key = KEY_RIGHT_OS; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
|
@ -185,14 +191,14 @@ static EM_BOOL onKeyEvent(int type, const EmscriptenKeyboardEvent* data, void* u
|
|||
|
||||
bool lovrPlatformInit() {
|
||||
emscripten_set_beforeunload_callback(NULL, onBeforeUnload);
|
||||
emscripten_set_focus_callback(EVENT_TARGET, NULL, true, onFocusChanged);
|
||||
emscripten_set_blur_callback(EVENT_TARGET, NULL, true, onFocusChanged);
|
||||
emscripten_set_focus_callback(CANVAS, NULL, true, onFocusChanged);
|
||||
emscripten_set_blur_callback(CANVAS, NULL, true, onFocusChanged);
|
||||
emscripten_set_resize_callback(0, NULL, true, onResize);
|
||||
emscripten_set_mousedown_callback(EVENT_TARGET, NULL, true, onMouseButton);
|
||||
emscripten_set_mouseup_callback(EVENT_TARGET, NULL, true, onMouseButton);
|
||||
emscripten_set_mousemove_callback(EVENT_TARGET, NULL, true, onMouseMove);
|
||||
emscripten_set_keydown_callback(EVENT_TARGET, NULL, true, onKeyEvent);
|
||||
emscripten_set_keyup_callback(EVENT_TARGET, NULL, true, onKeyEvent);
|
||||
emscripten_set_mousedown_callback(CANVAS, NULL, true, onMouseButton);
|
||||
emscripten_set_mouseup_callback(CANVAS, NULL, true, onMouseButton);
|
||||
emscripten_set_mousemove_callback(CANVAS, NULL, true, onMouseMove);
|
||||
emscripten_set_keydown_callback(CANVAS, NULL, true, onKeyEvent);
|
||||
emscripten_set_keyup_callback(CANVAS, NULL, true, onKeyEvent);
|
||||
state.epoch = emscripten_get_now();
|
||||
return true;
|
||||
}
|
||||
|
@ -270,7 +276,7 @@ bool lovrPlatformCreateWindow(const WindowFlags* flags) {
|
|||
attributes.preserveDrawingBuffer = false;
|
||||
attributes.majorVersion = 2;
|
||||
attributes.minorVersion = 0;
|
||||
state.context = emscripten_webgl_create_context(EVENT_TARGET, &attributes);
|
||||
state.context = emscripten_webgl_create_context(CANVAS, &attributes);
|
||||
if (state.context < 0) {
|
||||
state.context = 0;
|
||||
return false;
|
||||
|
@ -278,7 +284,7 @@ bool lovrPlatformCreateWindow(const WindowFlags* flags) {
|
|||
|
||||
emscripten_webgl_make_context_current(state.context);
|
||||
emscripten_webgl_get_drawing_buffer_size(state.context, &state.framebufferWidth, &state.framebufferHeight);
|
||||
emscripten_get_canvas_element_size(EVENT_TARGET, &state.width, &state.height);
|
||||
emscripten_get_canvas_element_size(CANVAS, &state.width, &state.height);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -339,7 +345,14 @@ void lovrPlatformGetMousePosition(double* x, double* y) {
|
|||
}
|
||||
|
||||
void lovrPlatformSetMouseMode(MouseMode mode) {
|
||||
//
|
||||
if (state.mouseMode != mode) {
|
||||
state.mouseMode = mode;
|
||||
if (mode == MOUSE_MODE_GRABBED) {
|
||||
EM_ASM(Module['canvas'].requestPointerLock());
|
||||
} else {
|
||||
EM_ASM(document.exitPointerLock());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool lovrPlatformIsMouseDown(MouseButton button) {
|
||||
|
|
|
@ -26,27 +26,24 @@ extern bool webxr_animate(Device device, struct Model* model);
|
|||
extern void webxr_renderTo(void (*callback)(void*), void* userdata);
|
||||
extern void webxr_update(float dt);
|
||||
|
||||
static HeadsetInterface* oldHeadsetDriver;
|
||||
bool webxrAttached = false;
|
||||
static bool webxrAttached = false;
|
||||
static HeadsetInterface* previousHeadsetDriver;
|
||||
|
||||
static void setDriver(HeadsetInterface* newDriver) {
|
||||
HeadsetInterface* prev = lovrHeadsetDriver;
|
||||
lovrHeadsetDriver = newDriver;
|
||||
|
||||
HeadsetInterface* driver = lovrHeadsetTrackingDrivers;
|
||||
HeadsetInterface* lastDriver = NULL;
|
||||
while (driver) {
|
||||
if (driver == prev) {
|
||||
if (lastDriver) {
|
||||
lastDriver->next = lovrHeadsetDriver;
|
||||
static void setDriver(HeadsetInterface* new) {
|
||||
if (lovrHeadsetTrackingDrivers == lovrHeadsetDriver) {
|
||||
lovrHeadsetTrackingDrivers = new;
|
||||
} else {
|
||||
FOREACH_TRACKING_DRIVER(driver) {
|
||||
if (driver->next == lovrHeadsetDriver) {
|
||||
driver->next = new;
|
||||
break;
|
||||
}
|
||||
lovrHeadsetDriver->next = driver->next;
|
||||
driver->next = NULL;
|
||||
driver = lovrHeadsetDriver;
|
||||
}
|
||||
lastDriver = driver;
|
||||
driver = driver->next;
|
||||
}
|
||||
|
||||
new->next = lovrHeadsetDriver->next;
|
||||
lovrHeadsetDriver->next = NULL;
|
||||
lovrHeadsetDriver = new;
|
||||
}
|
||||
|
||||
void webxr_attach() {
|
||||
|
@ -54,7 +51,7 @@ void webxr_attach() {
|
|||
return;
|
||||
}
|
||||
|
||||
oldHeadsetDriver = lovrHeadsetDriver;
|
||||
previousHeadsetDriver = lovrHeadsetDriver;
|
||||
setDriver(&lovrHeadsetWebXRDriver);
|
||||
webxrAttached = true;
|
||||
}
|
||||
|
@ -64,8 +61,8 @@ void webxr_detach() {
|
|||
return;
|
||||
}
|
||||
|
||||
setDriver(oldHeadsetDriver);
|
||||
oldHeadsetDriver = NULL;
|
||||
setDriver(previousHeadsetDriver);
|
||||
previousHeadsetDriver = NULL;
|
||||
webxrAttached = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
display: block;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
max-width: 800px;
|
||||
max-width: 1080px;
|
||||
width: 80%;
|
||||
height: auto;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
|
||||
|
@ -37,7 +37,7 @@
|
|||
|
||||
<body>
|
||||
<div class="container">
|
||||
<canvas id="canvas" width="800" height="600" tabIndex="1"></canvas>
|
||||
<canvas id="canvas" width="1080" height="600" tabIndex="1"></canvas>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
|
|
@ -1,34 +1,58 @@
|
|||
var webxr = {
|
||||
$state: {},
|
||||
|
||||
// Derived from github:immersive-web/webxr-input-profiles#5052b76
|
||||
$buttons: {
|
||||
'oculus-touch': {
|
||||
left: [0, 3, null, 1, null, null, null, 4, 5],
|
||||
right: [0, 3, null, 1, null, 4, 5, null, null],
|
||||
},
|
||||
'valve-index': [0, 3, 2, 1, null, 4, null, 4, null],
|
||||
'microsoft-mixed-reality': [0, 3, 2, 1],
|
||||
'htc-vive': [0, null, 2, 1],
|
||||
'generic-trigger': [0],
|
||||
'generic-trigger-touchpad': [0, null, 2],
|
||||
'generic-trigger-thumbstick': [0, 3],
|
||||
'generic-trigger-touchpad-thumbstick': [0, 3, 2],
|
||||
'generic-trigger-squeeze': [0, null, null, 1],
|
||||
'generic-trigger-squeeze-touchpad': [0, null, 2, 1],
|
||||
'generic-trigger-squeeze-touchpad-thumbstick': [0, 3, 2, 1],
|
||||
'generic-trigger-squeeze-thumbstick': [0, 3, null, 1],
|
||||
'generic-hand-select': [0]
|
||||
},
|
||||
$axes: {
|
||||
'oculus-touch': { touchpad: false, thumbstick: true },
|
||||
'valve-index': { touchpad: true, thumbstick: true },
|
||||
'microsoft-mixed-reality': { touchpad: true, thumbstick: true },
|
||||
'htc-vive': { touchpad: true, thumbstick: false },
|
||||
'generic-trigger': { touchpad: false, thumbstick: false },
|
||||
'generic-trigger-touchpad': { touchpad: true, thumbstick: false },
|
||||
'generic-trigger-thumbstick': { touchpad: false, thumbstick: true },
|
||||
'generic-trigger-touchpad-thumbstick': { touchpad: true, thumbstick: true },
|
||||
'generic-trigger-squeeze': { touchpad: false, thumbstick: false },
|
||||
'generic-trigger-squeeze-touchpad': { touchpad: true, thumbstick: false },
|
||||
'generic-trigger-squeeze-touchpad-thumbstick': { touchpad: true, thumbstick: true },
|
||||
'generic-trigger-squeeze-thumbstick': { touchpad: false, thumbstick: true },
|
||||
'generic-hand-select': { touchpad: false, thumbstick: false },
|
||||
},
|
||||
|
||||
$writePose: function(transform, position, orientation) {
|
||||
HEAPF32[(position >> 2) + 0] = transform.position.x;
|
||||
HEAPF32[(position >> 2) + 1] = transform.position.y;
|
||||
HEAPF32[(position >> 2) + 2] = transform.position.z;
|
||||
HEAPF32[(position >> 2) + 3] = transform.position.w;
|
||||
HEAPF32[(orientation >> 2) + 0] = transform.orientation.x;
|
||||
HEAPF32[(orientation >> 2) + 1] = transform.orientation.y;
|
||||
HEAPF32[(orientation >> 2) + 2] = transform.orientation.z;
|
||||
HEAPF32[(orientation >> 2) + 3] = transform.orientation.w;
|
||||
},
|
||||
|
||||
webxr_init__deps: ['$buttons', '$axes'],
|
||||
webxr_init: function(offset, msaa) {
|
||||
if (!navigator.xr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state.session = null;
|
||||
state.clipNear = .1;
|
||||
state.clipFar = 1000.0;
|
||||
state.boundsGeometry = 0; /* NULL */
|
||||
state.boundsGeometryCount = 0;
|
||||
|
||||
var mappings = {
|
||||
'oculus-touch-left': [0, 3, null, 1, null, null, null, 4, 5],
|
||||
'oculus-touch-right': [0, 3, null, 1, null, 4, 5, null, null],
|
||||
'valve-index': [0, 3, 2, 1, null, 4, null, 4, null],
|
||||
'microsoft-mixed-reality': [0, 3, 2, 1],
|
||||
'htc-vive': [0, null, 2, 1],
|
||||
'generic-trigger': [0],
|
||||
'generic-trigger-touchpad': [0, null, 2],
|
||||
'generic-trigger-thumbstick': [0, 3],
|
||||
'generic-trigger-touchpad-thumbstick': [0, 3, 2],
|
||||
'generic-trigger-squeeze': [0, null, null, 1],
|
||||
'generic-trigger-squeeze-touchpad': [0, null, 2, 1],
|
||||
'generic-trigger-squeeze-touchpad-thumbstick': [0, 3, 2, 1],
|
||||
'generic-trigger-squeeze-thumbstick': [0, 3, null, 1],
|
||||
'generic-hand-select': [0]
|
||||
};
|
||||
|
||||
Module.lovr = Module.lovr || {};
|
||||
Module.lovr.enterVR = function() {
|
||||
var options = {
|
||||
|
@ -43,59 +67,67 @@ var webxr = {
|
|||
|
||||
return Promise.all([space, Module.ctx.makeXRCompatible()]).then(function(data) {
|
||||
state.session = session;
|
||||
|
||||
session.space = data[0];
|
||||
session.layer = new XRWebGLLayer(session, Module.ctx);
|
||||
session.updateRenderState({ baseLayer: session.layer });
|
||||
session.framebufferId = GL.getNewId(GL.framebuffers);
|
||||
GL.framebuffers[session.framebufferId] = session.layer.framebuffer;
|
||||
state.space = data[0];
|
||||
state.clipNear = .1;
|
||||
state.clipFar = 1000.0;
|
||||
state.boundsGeometry = 0; /* NULL */
|
||||
state.boundsGeometryCount = 0;
|
||||
state.layer = new XRWebGLLayer(session, Module.ctx);
|
||||
state.updateRenderState({ baseLayer: state.layer });
|
||||
state.fbo = GL.getNewId(GL.framebuffers);
|
||||
GL.framebuffers[state.fbo] = state.layer.framebuffer;
|
||||
|
||||
// Canvas
|
||||
var sizeof_Camera = 264;
|
||||
var sizeof_CanvasFlags = 16;
|
||||
var width = session.layer.framebufferWidth;
|
||||
var height = session.layer.framebufferHeight;
|
||||
var width = state.layer.framebufferWidth;
|
||||
var height = state.layer.framebufferHeight;
|
||||
var flags = Module.stackAlloc(sizeof_CanvasFlags);
|
||||
HEAPU8.fill(0, flags, flags + sizeof_CanvasFlags); // memset(&flags, 0, sizeof(CanvasFlags));
|
||||
HEAPU8[flags + 12] = 1; // flags.stereo
|
||||
session.canvas = Module['_lovrCanvasCreateFromHandle'](width, height, flags, session.framebufferId, 0, 0, 1, true);
|
||||
session.camera = Module._malloc(sizeof_Camera);
|
||||
state.canvas = Module['_lovrCanvasCreateFromHandle'](width, height, flags, state.fbo, 0, 0, 1, true);
|
||||
Module.stackRestore(flags);
|
||||
|
||||
session.deviceMap = [];
|
||||
// Camera
|
||||
var sizeof_Camera = 264;
|
||||
state.camera = Module._malloc(sizeof_Camera);
|
||||
HEAPU8[state.camera + 0] = 1; // state.camera.stereo = true
|
||||
HEAPU32[(state.camera + 4) >> 2] = state.canvas; // state.camera.canvas = state.canvas
|
||||
|
||||
state.hands = [];
|
||||
state.lastButtonState = [];
|
||||
session.addEventListener('inputsourceschange', function(event) {
|
||||
session.deviceMap.splice(0, session.deviceMap.length);
|
||||
for (var i = 0; i < session.inputSources.length; i++) {
|
||||
var hands = { left: 1, right: 2 };
|
||||
session.deviceMap[hands[inputSource.handedness]] = inputSource;
|
||||
state.hands.splice(0, state.hands.length);
|
||||
session.inputSources.forEach(function(inputSource) {
|
||||
state.hands[({ left: 1, right: 2 })[inputSource.handedness]] = inputSource;
|
||||
|
||||
for (var i = 0; i < inputSource.profiles.length; i++) {
|
||||
var profile = inputSource.profiles[i];
|
||||
var profile = inputSource.profiles.find(function(profile) { return mappings[profile]; });
|
||||
|
||||
// So far Oculus touch controllers are the only "meaningfully handed" controllers
|
||||
// If more appear, a more general approach should be used
|
||||
if (profile === 'oculus-touch') {
|
||||
profile = profile + '-' + inputSource.handedness;
|
||||
}
|
||||
|
||||
if (mappings[profile]) {
|
||||
inputSource.mapping = mappings[profile];
|
||||
break;
|
||||
}
|
||||
if (!inputSource.gamepad || !profile) {
|
||||
inputSource.buttons = [];
|
||||
inputSource.axes = {};
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inputSource.axes = axes[profile];
|
||||
var mapping = buttons[profile][inputSource.handedness] || buttons[profile] || [];
|
||||
inputSource.buttons = mapping.map(function(buttonIndex) {
|
||||
return inputSource.gamepad.buttons[buttonIndex];
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
session.addEventListener('end', function() {
|
||||
if (session.canvas) {
|
||||
Module['_lovrCanvasDestroy'](session.canvas);
|
||||
Module._free(session.canvas - 4);
|
||||
Module._free(session.camera|0);
|
||||
Module._free(state.boundsGeometry|0);
|
||||
Module._free(state.camera|0);
|
||||
|
||||
if (state.canvas) {
|
||||
Module['_lovrCanvasDestroy'](state.canvas);
|
||||
Module._free(state.canvas - 4);
|
||||
}
|
||||
|
||||
if (session.framebufferId) {
|
||||
GL.framebuffers[session.framebufferId].name = 0;
|
||||
GL.framebuffers[session.framebufferId] = null;
|
||||
if (state.fbo) {
|
||||
GL.framebuffers[state.fbo].name = 0;
|
||||
GL.framebuffers[state.fbo] = null;
|
||||
}
|
||||
|
||||
Browser.mainLoop.pause();
|
||||
|
@ -105,15 +137,22 @@ var webxr = {
|
|||
state.session = null;
|
||||
});
|
||||
|
||||
// Trick emscripten into using the session's requestAnimationFrame
|
||||
// Trick emscripten into using the session's requestAnimationFrame, also make ourselves
|
||||
// the headset driver using webxr_attach. These are both undone when the session ends
|
||||
// so that the mouse/keyboard driver can be used when the session is inactive.
|
||||
Browser.mainLoop.pause();
|
||||
Module['_webxr_attach']();
|
||||
Browser.requestAnimationFrame = function(fn) {
|
||||
return session.requestAnimationFrame(function(t, frame) {
|
||||
session.displayTime = t;
|
||||
session.frame = frame;
|
||||
session.viewer = session.frame.getViewerPose(session.space);
|
||||
state.displayTime = t;
|
||||
state.frame = frame;
|
||||
state.viewer = state.frame.getViewerPose(state.space);
|
||||
fn();
|
||||
state.hands.forEach(function(inputSource, i) {
|
||||
state.lastButtonState[i] = inputSource && inputSource.buttons.map(function(button) {
|
||||
return button.pressed;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
Browser.mainLoop.resume();
|
||||
|
@ -123,12 +162,11 @@ var webxr = {
|
|||
};
|
||||
|
||||
Module.lovr.exitVR = function() {
|
||||
return state.session ? state.session.end() : Promise.resolve();
|
||||
return session ? session.end() : Promise.resolve();
|
||||
};
|
||||
|
||||
// WebXR is not set as the display driver at initialization time, so that the VR simulator can
|
||||
// be used on the DOM's canvas before the session starts. When the session starts, it uses the
|
||||
// webxr_attach function to make itself the display driver for the duration of the session.
|
||||
// WebXR is not set as the display driver immediately, it uses webxr_attach to make itself the
|
||||
// headset driver when a session starts.
|
||||
return false;
|
||||
},
|
||||
|
||||
|
@ -136,8 +174,6 @@ var webxr = {
|
|||
if (state.session) {
|
||||
state.session.end();
|
||||
}
|
||||
|
||||
Module._free(state.boundsGeometry|0);
|
||||
},
|
||||
|
||||
webxr_getName: function(name, size) {
|
||||
|
@ -149,12 +185,12 @@ var webxr = {
|
|||
},
|
||||
|
||||
webxr_getDisplayTime: function() {
|
||||
return state.session.displayTime / 1000.0;
|
||||
return state.displayTime / 1000.0;
|
||||
},
|
||||
|
||||
webxr_getDisplayDimensions: function(width, height) {
|
||||
HEAPU32[width >> 2] = state.session.layer.framebufferWidth;
|
||||
HEAPU32[height >> 2] = state.session.layer.framebufferHeight;
|
||||
HEAPU32[width >> 2] = state.layer.framebufferWidth;
|
||||
HEAPU32[height >> 2] = state.layer.framebufferHeight;
|
||||
},
|
||||
|
||||
webxr_getDisplayFrequency: function() {
|
||||
|
@ -166,25 +202,14 @@ var webxr = {
|
|||
},
|
||||
|
||||
webxr_getViewCount: function() {
|
||||
return state.session.viewer.views.length;
|
||||
return state.viewer.views.length;
|
||||
},
|
||||
|
||||
webxr_getViewPose__deps: ['$writePose'],
|
||||
webxr_getViewPose: function(index, position, orientation) {
|
||||
var view = state.session.viewer.views[index];
|
||||
if (view) {
|
||||
var transform = view.transform;
|
||||
HEAPF32[(position >> 2) + 0] = transform.position.x;
|
||||
HEAPF32[(position >> 2) + 1] = transform.position.y;
|
||||
HEAPF32[(position >> 2) + 2] = transform.position.z;
|
||||
HEAPF32[(position >> 2) + 3] = transform.position.w;
|
||||
HEAPF32[(orientation >> 2) + 0] = transform.orientation.x;
|
||||
HEAPF32[(orientation >> 2) + 1] = transform.orientation.y;
|
||||
HEAPF32[(orientation >> 2) + 2] = transform.orientation.z;
|
||||
HEAPF32[(orientation >> 2) + 3] = transform.orientation.w;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
var view = state.viewer && state.viewer.views[index];
|
||||
view && writePose(view.transform, position, orientation);
|
||||
return !!view;
|
||||
},
|
||||
|
||||
webxr_getViewAngles: function(index, left, right, up, down) {
|
||||
|
@ -199,7 +224,7 @@ var webxr = {
|
|||
webxr_setClipDistance: function(clipNear, clipFar) {
|
||||
state.clipNear = clipNear;
|
||||
state.clipFar = clipFar;
|
||||
state.session.updateRenderState({
|
||||
state.updateRenderState({
|
||||
clipNear: clipNear,
|
||||
clipFar: clipFar
|
||||
});
|
||||
|
@ -211,18 +236,18 @@ var webxr = {
|
|||
},
|
||||
|
||||
webxr_getBoundsGeometry: function(count) {
|
||||
if (!(state.session.space instanceof XRBoundedReferenceSpace)) {
|
||||
if (!(state.space instanceof XRBoundedReferenceSpace)) {
|
||||
return 0; /* NULL */
|
||||
}
|
||||
|
||||
var points = state.session.space.boundsGeometry;
|
||||
var points = state.space.boundsGeometry;
|
||||
|
||||
if (state.boundsGeometryCount < points.length) {
|
||||
Module._free(state.boundsGeometry|0);
|
||||
state.boundsGeometryCount = points.length;
|
||||
state.boundsGeometry = Module._malloc(4 * 4 * state.boundsGeometryCount);
|
||||
if (state.boundsGeometry === 0) {
|
||||
return state.boundsGeometry;
|
||||
return 0; /* NULL */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,35 +262,18 @@ var webxr = {
|
|||
return state.boundsGeometry;
|
||||
},
|
||||
|
||||
webxr_getPose__deps: ['$writePose'],
|
||||
webxr_getPose: function(device, position, orientation) {
|
||||
if (device === 0 /* DEVICE_HEAD */) {
|
||||
var transform = state.session.viewer.transform;
|
||||
HEAPF32[(position >> 2) + 0] = transform.position.x;
|
||||
HEAPF32[(position >> 2) + 1] = transform.position.y;
|
||||
HEAPF32[(position >> 2) + 2] = transform.position.z;
|
||||
HEAPF32[(position >> 2) + 3] = transform.position.w;
|
||||
HEAPF32[(orientation >> 2) + 0] = transform.orientation.x;
|
||||
HEAPF32[(orientation >> 2) + 1] = transform.orientation.y;
|
||||
HEAPF32[(orientation >> 2) + 2] = transform.orientation.z;
|
||||
HEAPF32[(orientation >> 2) + 3] = transform.orientation.w;
|
||||
writePose(state.viewer.transform, position, orientation);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (state.session.deviceMap[device]) {
|
||||
var inputSource = state.session.deviceMap[device];
|
||||
var space = inputSource.gripSpace || inputSource.targetRaySpace;
|
||||
var pose = state.session.frame.getPose(space, state.session.space);
|
||||
if (pose) {
|
||||
HEAPF32[(position >> 2) + 0] = pose.transform.position.x;
|
||||
HEAPF32[(position >> 2) + 1] = pose.transform.position.y;
|
||||
HEAPF32[(position >> 2) + 2] = pose.transform.position.z;
|
||||
HEAPF32[(position >> 2) + 3] = pose.transform.position.w;
|
||||
HEAPF32[(orientation >> 2) + 0] = pose.transform.orientation.x;
|
||||
HEAPF32[(orientation >> 2) + 1] = pose.transform.orientation.y;
|
||||
HEAPF32[(orientation >> 2) + 2] = pose.transform.orientation.z;
|
||||
HEAPF32[(orientation >> 2) + 3] = pose.transform.orientation.w;
|
||||
return true;
|
||||
}
|
||||
if (state.hands[device]) {
|
||||
var space = state.hands[device].gripSpace || state.hands[device].targetRaySpace;
|
||||
var pose = state.frame.getPose(space, state.space);
|
||||
pose && writePose(pose.transform, position, orientation);
|
||||
return !!pose;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -276,77 +284,63 @@ var webxr = {
|
|||
},
|
||||
|
||||
webxr_isDown: function(device, button, down, changed) {
|
||||
var inputSource = state.session.deviceMap[device];
|
||||
if (!inputSource || !inputSource.gamepad || !inputSource.mapping) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HEAPU32[down >> 2] = inputSource.gamepad.buttons[inputSource.mapping[button]].pressed ? 1 : 0;
|
||||
HEAPU32[changed >> 2] = 0; // TODO
|
||||
return true;
|
||||
var button = state.hands[device] && state.hands[device].button;
|
||||
HEAPU32[down >> 2] = button && button.pressed;
|
||||
HEAPU32[changed >> 2] = button && (state.lastButtonState[device][button] ^ button.pressed);
|
||||
return !!button;
|
||||
},
|
||||
|
||||
webxr_isTouched: function(device, button, touched) {
|
||||
var inputSource = state.session.deviceMap[device];
|
||||
if (!inputSource || !inputSource.gamepad || !inputSource.mapping) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HEAPU32[touched >> 2] = inputSource.gamepad.buttons[inputSource.mapping[button]].touched ? 1 : 0;
|
||||
return true;
|
||||
var button = state.hands[device] && state.hands[device].button;
|
||||
HEAPU32[touched >> 2] = button && button.touched;
|
||||
return !!button;
|
||||
},
|
||||
|
||||
webxr_getAxis: function(device, axis, value) {
|
||||
var inputSource = state.session.deviceMap[device];
|
||||
if (!inputSource || !inputSource.gamepad || !inputSource.mapping) {
|
||||
var hand = state.hands[device];
|
||||
|
||||
if (!hand || !hand.gamepad) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (axis) {
|
||||
// These 1D axes are queried as buttons in the Gamepad API
|
||||
// The DeviceAxis enumerants match the DeviceButton ones, so they're interchangeable
|
||||
case 0: /* AXIS_TRIGGER */
|
||||
case 3: /* AXIS_GRIP */
|
||||
HEAPF32[value >> 2] = inputSource.gamepad.buttons[inputSource.mapping[axis]].value;
|
||||
return true;
|
||||
HEAPF32[value >> 2] = hand.buttons[axis] && hand.buttons[axis].value;
|
||||
return !!hand.buttons[axis];
|
||||
|
||||
case 1: /* AXIS_THUMBSTICK */
|
||||
HEAPF32[value >> 2 + 0] = inputSource.gamepad.axes[2];
|
||||
HEAPF32[value >> 2 + 1] = inputSource.gamepad.axes[3];
|
||||
return true;
|
||||
HEAPF32[value >> 2 + 0] = hand.gamepad.axes[2];
|
||||
HEAPF32[value >> 2 + 1] = hand.gamepad.axes[3];
|
||||
return hand.axes.thumbstick;
|
||||
|
||||
case 2: /* AXIS_TOUCHPAD */
|
||||
HEAPF32[value >> 2 + 0] = inputSource.gamepad.axes[0];
|
||||
HEAPF32[value >> 2 + 1] = inputSource.gamepad.axes[1];
|
||||
return true;
|
||||
HEAPF32[value >> 2 + 0] = hand.gamepad.axes[0];
|
||||
HEAPF32[value >> 2 + 1] = hand.gamepad.axes[1];
|
||||
return hand.axes.touchpad;
|
||||
|
||||
default:
|
||||
return false;
|
||||
default: return false;
|
||||
}
|
||||
},
|
||||
|
||||
webxr_getSkeleton__deps: ['$writePose'],
|
||||
webxr_getSkeleton: function(device, poses) {
|
||||
var inputSource = state.session.deviceMap[device];
|
||||
var inputSource = state.hands[device];
|
||||
|
||||
if (!inputSource || !inputSource.hand) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There are 26 total hand joints, each with an 8-float pose
|
||||
HEAPF32.fill(0, poses >> 2, (poses >> 2) + 26 * 8);
|
||||
// WebXR does not have a palm joint but the skeleton otherwise matches up
|
||||
HEAPF32.fill(0, poses >> 2, (poses >> 2) + 8 * 26 /* HAND_JOINT_COUNT */);
|
||||
poses += 32;
|
||||
|
||||
// WebXR has 25 joints, it's missing JOINT_PALM but otherwise it matches up perfectly
|
||||
for (var i = 0; i < 25; i++) {
|
||||
if (inputSource.hand[i]) {
|
||||
var jointPose = state.session.frame.getJointPose(inputSource.hand[i], state.session.space);
|
||||
if (jointPose) {
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 0] = jointPose.transform.position.x;
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 1] = jointPose.transform.position.y;
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 2] = jointPose.transform.position.z;
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 3] = jointPose.transform.position.w;
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 4] = jointPose.transform.orientation.x;
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 5] = jointPose.transform.orientation.y;
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 6] = jointPose.transform.orientation.z;
|
||||
HEAPF32[(poses >> 2) + (i + 1) * 8 + 7] = jointPose.transform.orientation.w;
|
||||
var pose = state.frame.getJointPose(inputSource.hand[i], state.space);
|
||||
if (pose) {
|
||||
var position = poses + i * 32;
|
||||
writePose(pose.transform, position, position + 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -354,15 +348,12 @@ var webxr = {
|
|||
return true;
|
||||
},
|
||||
|
||||
// Not an official WebXR feature, but widely supported
|
||||
webxr_vibrate: function(device, strength, duration, frequency) {
|
||||
var inputSource = state.session.deviceMap[device];
|
||||
if (!inputSource || !inputSource.gamepad || !inputSource.gamepad.hapticActuators || !inputSource.gamepad.hapticActuators[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not technically an official WebXR feature, but widely supported
|
||||
inputSource.gamepad.hapticActuators[0].pulse(strength, duration * 1000);
|
||||
return true;
|
||||
var hand = state.deviceMap[device];
|
||||
var actuator = hand && hand.gamepad && hand.gamepad.hapticActuators && hand.gamepad.hapticActuators[0];
|
||||
actuator && actuator.pulse(strength, duration * 1000);
|
||||
return !!actuator;
|
||||
},
|
||||
|
||||
webxr_newModelData: function(device, animated) {
|
||||
|
@ -374,20 +365,14 @@ var webxr = {
|
|||
},
|
||||
|
||||
webxr_renderTo: function(callback, userdata) {
|
||||
var views = state.session.viewer.views;
|
||||
var camera = state.session.camera;
|
||||
var stereo = views.length > 1;
|
||||
var matrices = (camera + 8) >> 2;
|
||||
HEAPU8[camera + 0] = stereo; // camera.stereo = stereo
|
||||
HEAPU32[(camera + 4) >> 2] = state.session.canvas; // camera.canvas = session.canvas
|
||||
var views = state.viewer.views;
|
||||
var matrices = (state.camera + 8) >> 2;
|
||||
HEAPF32.set(views[0].transform.inverse.matrix, matrices + 0);
|
||||
HEAPF32.set(views[1].transform.inverse.matrix, matrices + 16);
|
||||
HEAPF32.set(views[0].projectionMatrix, matrices + 32);
|
||||
if (stereo) {
|
||||
HEAPF32.set(views[1].transform.inverse.matrix, matrices + 16);
|
||||
HEAPF32.set(views[1].projectionMatrix, matrices + 48);
|
||||
}
|
||||
HEAPF32.set(views[1].projectionMatrix, matrices + 48);
|
||||
|
||||
Module['_lovrGraphicsSetCamera'](camera, true);
|
||||
Module['_lovrGraphicsSetCamera'](state.camera, true);
|
||||
Module['dynCall_vi'](callback, userdata);
|
||||
Module['_lovrGraphicsSetCamera'](0, false);
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue