Auto merge of #23292 - Manishearth:input, r=asajeffrey

Add support for XRInputSource and target ray spaces

Untested, but compiles.

r? @jdm or @asajeffrey

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23292)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2019-05-07 19:23:55 -04:00 committed by GitHub
commit 670a32c9e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 315 additions and 37 deletions

16
Cargo.lock generated
View file

@ -3457,7 +3457,7 @@ dependencies = [
[[package]]
name = "rust-webvr"
version = "0.10.4"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bindgen 0.49.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3470,13 +3470,13 @@ dependencies = [
"libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ovr-mobile-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winit 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rust-webvr-api"
version = "0.10.4"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"android_injected_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3810,7 +3810,7 @@ dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"osmesa-src 0.1.0 (git+https://github.com/servo/osmesa-src)",
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sig 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tinyfiledialogs 3.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -5137,7 +5137,7 @@ dependencies = [
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1",
"rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1",
"servo_config 0.0.1",
"webvr_traits 0.0.1",
@ -5149,7 +5149,7 @@ version = "0.0.1"
dependencies = [
"ipc-channel 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1",
"rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -5647,8 +5647,8 @@ dependencies = [
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "da06feaa07f69125ab9ddc769b11de29090122170b402547f64b86fe16ebc399"
"checksum rust-webvr 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dd268264db4808e78ad1738ce1ff10a8bd53fb5ba408f595763174ca4a6fb875"
"checksum rust-webvr-api 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1b2af5c6c86fb79e70b5a34daa3d488411225707c73dc5467c7da7c83d557daf"
"checksum rust-webvr 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e9c827417035beccd02f5e1dde7866c80662efafb8bcfe659f0082d10def4faa"
"checksum rust-webvr-api 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5208a3b3f0b02abf17e66c0fe1e0cd3a4f5172c9bf6d1a3e1ac6338a3d218d3"
"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rusttype 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8eb11f5b0a98c8eca2fb1483f42646d8c340e83e46ab416f8a063a0fd0eeb20"

View file

@ -12,7 +12,7 @@ use std::fmt;
use std::num::NonZeroU32;
use std::ops::Deref;
use webrender_api::{DocumentId, ImageKey, PipelineId};
use webvr_traits::WebVRFutureFrameData;
use webvr_traits::WebVRPoseInformation;
/// Helper function that creates a WebGL channel (WebGLSender, WebGLReceiver) to be used in WebGLCommands.
pub use crate::webgl_channel::webgl_channel;
@ -508,9 +508,13 @@ pub enum WebVRCommand {
/// Synchronize the pose information to be used in the frame.
SyncPoses(
WebVRDeviceId,
// near
f64,
// far
f64,
WebGLSender<Result<WebVRFutureFrameData, ()>>,
// sync gamepads too
bool,
WebGLSender<Result<WebVRPoseInformation, ()>>,
),
/// Submit the frame to a VR device using the specified texture coordinates.
SubmitFrame(WebVRDeviceId, [f32; 4], [f32; 4]),

View file

@ -138,7 +138,7 @@ use tendril::{StrTendril, TendrilSink};
use time::{Duration, Timespec};
use uuid::Uuid;
use webrender_api::{DocumentId, ImageKey, RenderApiSender};
use webvr_traits::WebVRGamepadHand;
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState};
/// A trait to allow tracing (only) DOM objects.
pub unsafe trait JSTraceable {
@ -478,7 +478,7 @@ unsafe_no_jsmanaged_fields!(WebGLVertexArrayId);
unsafe_no_jsmanaged_fields!(WebGLVersion);
unsafe_no_jsmanaged_fields!(WebGLSLVersion);
unsafe_no_jsmanaged_fields!(MediaList);
unsafe_no_jsmanaged_fields!(WebVRGamepadHand);
unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand);
unsafe_no_jsmanaged_fields!(ScriptToConstellationChan);
unsafe_no_jsmanaged_fields!(InteractiveMetrics);
unsafe_no_jsmanaged_fields!(InteractiveWindow);

View file

@ -540,6 +540,7 @@ pub mod xmlhttprequestupload;
pub mod xmlserializer;
pub mod xr;
pub mod xrframe;
pub mod xrinputsource;
pub mod xrlayer;
pub mod xrpose;
pub mod xrreferencespace;

View file

@ -22,7 +22,7 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom};
use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
@ -36,6 +36,7 @@ use crate::dom::vrpose::VRPose;
use crate::dom::vrstageparameters::VRStageParameters;
use crate::dom::webglrenderingcontext::WebGLRenderingContext;
use crate::dom::xrframe::XRFrame;
use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrsession::XRSession;
use crate::dom::xrwebgllayer::XRWebGLLayer;
use crate::script_runtime::CommonScriptMsg;
@ -47,11 +48,12 @@ use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender;
use profile_traits::ipc;
use std::cell::Cell;
use std::collections::HashMap;
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use std::thread;
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRFutureFrameData};
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRPoseInformation};
use webvr_traits::{WebVRLayer, WebVRMsg};
#[dom_struct]
@ -86,12 +88,16 @@ pub struct VRDisplay {
// Compositor VRFrameData synchonization
frame_data_status: Cell<VRFrameDataStatus>,
#[ignore_malloc_size_of = "closures are hard"]
frame_data_receiver: DomRefCell<Option<WebGLReceiver<Result<WebVRFutureFrameData, ()>>>>,
frame_data_receiver: DomRefCell<Option<WebGLReceiver<Result<WebVRPoseInformation, ()>>>>,
running_display_raf: Cell<bool>,
paused: Cell<bool>,
stopped_on_pause: Cell<bool>,
/// Whether or not this is XR mode, and the session
xr_session: MutNullableDom<XRSession>,
/// Have inputs been initialized? (i.e, has getInputSources() been called?)
/// XR only
initialized_inputs: Cell<bool>,
input_sources: DomRefCell<HashMap<u32, Dom<XRInputSource>>>,
}
unsafe_no_jsmanaged_fields!(WebVRDisplayData);
@ -115,6 +121,8 @@ struct VRRAFUpdate {
/// Number uniquely identifying the WebGL context
/// so that we may setup/tear down VR compositors as things change
context_id: usize,
/// Do we need input data?
needs_inputs: bool,
}
type VRRAFUpdateSender = Sender<Result<VRRAFUpdate, ()>>;
@ -164,6 +172,8 @@ impl VRDisplay {
// When the VR Resume event is received and the flag is set, VR presentation automatically restarts.
stopped_on_pause: Cell::new(false),
xr_session: MutNullableDom::default(),
initialized_inputs: Cell::new(false),
input_sources: DomRefCell::new(HashMap::new()),
}
}
@ -627,6 +637,7 @@ impl VRDisplay {
depth_far: self.depth_far.get(),
api_sender: self.api_sender(),
context_id: self.context_id(),
needs_inputs: self.initialized_inputs.get(),
}
}
@ -690,6 +701,7 @@ impl VRDisplay {
let (raf_sender, raf_receiver) = unbounded();
let (wakeup_sender, wakeup_receiver) = unbounded();
*self.raf_wakeup_sender.borrow_mut() = Some(wakeup_sender);
let mut needs_inputs = false;
// The render loop at native headset frame rate is implemented using a dedicated thread.
// Every loop iteration syncs pose data with the HMD, submits the pixels to the display and waits for Vsync.
@ -726,8 +738,13 @@ impl VRDisplay {
.unwrap();
// Run Sync Poses in parallell on Render thread
let msg =
WebVRCommand::SyncPoses(display_id, near, far, sync_sender.clone());
let msg = WebVRCommand::SyncPoses(
display_id,
near,
far,
needs_inputs,
sync_sender.clone(),
);
api_sender.send_vr(msg).unwrap();
} else {
let _ = wakeup_receiver.recv();
@ -752,6 +769,7 @@ impl VRDisplay {
if let Ok(update) = raf_receiver.recv().unwrap() {
near = update.depth_near;
far = update.depth_far;
needs_inputs = update.needs_inputs;
if update.context_id != context_id {
if let Some(ref api_sender) = update.api_sender {
api_sender
@ -808,8 +826,16 @@ impl VRDisplay {
fn sync_frame_data(&self) {
let status = if let Some(receiver) = self.frame_data_receiver.borrow().as_ref() {
match receiver.recv().unwrap() {
Ok(future_data) => {
*self.frame_data.borrow_mut() = future_data.block();
Ok(pose) => {
*self.frame_data.borrow_mut() = pose.frame.block();
if self.initialized_inputs.get() {
let inputs = self.input_sources.borrow();
for (id, state) in pose.gamepads {
if let Some(input) = inputs.get(&id) {
input.update_state(state);
}
}
}
VRFrameDataStatus::Synced
},
Err(()) => VRFrameDataStatus::Exit,
@ -909,6 +935,53 @@ impl VRDisplay {
pair.1 = None;
}
}
/// Initialize XRInputSources
fn initialize_inputs(&self) {
if self.initialized_inputs.get() {
return;
}
self.initialized_inputs.set(true);
let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
let display = self.display.borrow().display_id;
self.webvr_thread()
.send(WebVRMsg::GetGamepadsForDisplay(display, sender))
.unwrap();
match receiver.recv().unwrap() {
Ok(gamepads) => {
let global = self.global();
let session = self
.xr_session
.get()
.expect("initialize_inputs called on a VR session");
let roots: Vec<_> = gamepads
.into_iter()
.map(|g| {
(
g.1.gamepad_id,
XRInputSource::new(&global, &session, g.0, g.1),
)
})
.collect();
let mut inputs = self.input_sources.borrow_mut();
for (id, root) in &roots {
inputs.insert(*id, Dom::from_ref(&root));
}
},
Err(_) => {},
}
}
pub fn get_input_sources(&self) -> Vec<DomRoot<XRInputSource>> {
self.initialize_inputs();
self.input_sources
.borrow()
.iter()
.map(|(_, x)| DomRoot::from_ref(&**x))
.collect()
}
}
// WebVR Spec: If the number of values in the leftBounds/rightBounds arrays

View file

@ -0,0 +1,26 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// https://immersive-web.github.io/webxr/#xrinputsource-interface
enum XRHandedness {
"none",
"left",
"right"
};
enum XRTargetRayMode {
"gaze",
"tracked-pointer",
"screen"
};
[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"]
interface XRInputSource {
readonly attribute XRHandedness handedness;
// [SameObject] readonly attribute XRTargetRayMode targetRayMode;
[SameObject] readonly attribute XRSpace targetRaySpace;
// [SameObject] readonly attribute XRSpace? gripSpace;
// [SameObject] readonly attribute Gamepad? gamepad;
};

View file

@ -20,12 +20,15 @@ interface XRSession : EventTarget {
readonly attribute XREnvironmentBlendMode environmentBlendMode;
readonly attribute XRRenderState renderState;
readonly attribute XRSpace viewerSpace;
[SameObject] readonly attribute XRSpace viewerSpace;
// // Methods
Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceOptions options);
// workaround until we have FrozenArray
// see https://github.com/servo/servo/issues/10427#issuecomment-449593626
// FrozenArray<XRInputSource> getInputSources();
sequence<XRInputSource> getInputSources();
Promise<void> updateRenderState(optional XRRenderStateInit state);
long requestAnimationFrame(XRFrameRequestCallback callback);

View file

@ -0,0 +1,83 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding;
use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
XRHandedness, XRInputSourceMethods,
};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrsession::XRSession;
use crate::dom::xrspace::XRSpace;
use dom_struct::dom_struct;
use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState, WebVRPose};
#[dom_struct]
pub struct XRInputSource {
reflector: Reflector,
session: Dom<XRSession>,
#[ignore_malloc_size_of = "Defined in rust-webvr"]
data: WebVRGamepadData,
#[ignore_malloc_size_of = "Defined in rust-webvr"]
state: DomRefCell<WebVRGamepadState>,
target_ray_space: MutNullableDom<XRSpace>,
}
impl XRInputSource {
pub fn new_inherited(
session: &XRSession,
data: WebVRGamepadData,
state: WebVRGamepadState,
) -> XRInputSource {
XRInputSource {
reflector: Reflector::new(),
session: Dom::from_ref(session),
data,
state: DomRefCell::new(state),
target_ray_space: Default::default(),
}
}
pub fn new(
global: &GlobalScope,
session: &XRSession,
data: WebVRGamepadData,
state: WebVRGamepadState,
) -> DomRoot<XRInputSource> {
reflect_dom_object(
Box::new(XRInputSource::new_inherited(session, data, state)),
global,
XRInputSourceBinding::Wrap,
)
}
pub fn update_state(&self, state: WebVRGamepadState) {
*self.state.borrow_mut() = state;
}
pub fn pose(&self) -> WebVRPose {
self.state.borrow().pose
}
}
impl XRInputSourceMethods for XRInputSource {
/// https://immersive-web.github.io/webxr/#dom-xrinputsource-handedness
fn Handedness(&self) -> XRHandedness {
match self.data.hand {
WebVRGamepadHand::Unknown => XRHandedness::None,
WebVRGamepadHand::Left => XRHandedness::Left,
WebVRGamepadHand::Right => XRHandedness::Right,
}
}
/// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace
fn TargetRaySpace(&self) -> DomRoot<XRSpace> {
self.target_ray_space.or_init(|| {
let global = self.global();
XRSpace::new_inputspace(&global, &self.session, &self)
})
}
}

View file

@ -110,7 +110,7 @@ impl XRReferenceSpace {
// non-subclassed XRReferenceSpaces exist, obtained via the "identity"
// type. These are equivalent to the viewer pose and follow the headset
// around
XRSpace::viewer_pose_from_frame_data(base_pose)
XRSpace::pose_to_transform(&base_pose.pose)
}
}
}

View file

@ -94,7 +94,7 @@ impl XRRigidTransformMethods for XRRigidTransform {
}
// https://immersive-web.github.io/webxr/#dom-xrrigidtransform-orientation
fn Orientation(&self) -> DomRoot<DOMPointReadOnly> {
self.position.or_init(|| {
self.orientation.or_init(|| {
let r = &self.transform.rotation;
DOMPointReadOnly::new(&self.global(), r.i, r.j, r.k, r.r)
})

View file

@ -19,6 +19,7 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::vrdisplay::VRDisplay;
use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrlayer::XRLayer;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrrenderstate::XRRenderState;
@ -33,6 +34,7 @@ pub struct XRSession {
display: Dom<VRDisplay>,
base_layer: MutNullableDom<XRLayer>,
blend_mode: XREnvironmentBlendMode,
viewer_space: MutNullableDom<XRSpace>,
}
impl XRSession {
@ -43,6 +45,7 @@ impl XRSession {
base_layer: Default::default(),
// we don't yet support any AR devices
blend_mode: XREnvironmentBlendMode::Opaque,
viewer_space: Default::default(),
}
}
@ -86,7 +89,8 @@ impl XRSessionMethods for XRSession {
// https://immersive-web.github.io/webxr/#dom-xrsession-viewerspace
fn ViewerSpace(&self) -> DomRoot<XRSpace> {
XRSpace::new_viewerspace(&self.global(), &self)
self.viewer_space
.or_init(|| XRSpace::new_viewerspace(&self.global(), &self))
}
/// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe
@ -153,4 +157,9 @@ impl XRSessionMethods for XRSession {
p
}
/// https://immersive-web.github.io/webxr/#dom-xrsession-getinputsources
fn GetInputSources(&self) -> Vec<DomRoot<XRInputSource>> {
self.display.get_input_sources()
}
}

View file

@ -5,20 +5,22 @@
use crate::dom::bindings::codegen::Bindings::XRSpaceBinding;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::reflect_dom_object;
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::XRSession;
use dom_struct::dom_struct;
use euclid::{RigidTransform3D, Rotation3D, Vector3D};
use webvr_traits::WebVRFrameData;
use webvr_traits::{WebVRFrameData, WebVRPose};
#[dom_struct]
pub struct XRSpace {
eventtarget: EventTarget,
session: Dom<XRSession>,
is_viewerspace: bool,
input_source: MutNullableDom<XRInputSource>,
}
impl XRSpace {
@ -27,6 +29,7 @@ impl XRSpace {
eventtarget: EventTarget::new_inherited(),
session: Dom::from_ref(session),
is_viewerspace: false,
input_source: Default::default(),
}
}
@ -35,6 +38,7 @@ impl XRSpace {
eventtarget: EventTarget::new_inherited(),
session: Dom::from_ref(session),
is_viewerspace: true,
input_source: Default::default(),
}
}
@ -45,6 +49,27 @@ impl XRSpace {
XRSpaceBinding::Wrap,
)
}
fn new_inputspace_inner(session: &XRSession, input: &XRInputSource) -> XRSpace {
XRSpace {
eventtarget: EventTarget::new_inherited(),
session: Dom::from_ref(session),
is_viewerspace: false,
input_source: MutNullableDom::new(Some(input)),
}
}
pub fn new_inputspace(
global: &GlobalScope,
session: &XRSession,
input: &XRInputSource,
) -> DomRoot<XRSpace> {
reflect_dom_object(
Box::new(XRSpace::new_inputspace_inner(session, input)),
global,
XRSpaceBinding::Wrap,
)
}
}
impl XRSpace {
@ -57,16 +82,18 @@ impl XRSpace {
if let Some(reference) = self.downcast::<XRReferenceSpace>() {
reference.get_pose(base_pose)
} else if self.is_viewerspace {
XRSpace::viewer_pose_from_frame_data(base_pose)
XRSpace::pose_to_transform(&base_pose.pose)
} else if let Some(source) = self.input_source.get() {
XRSpace::pose_to_transform(&source.pose())
} else {
unreachable!()
}
}
pub fn viewer_pose_from_frame_data(data: &WebVRFrameData) -> RigidTransform3D<f64> {
let pos = data.pose.position.unwrap_or([0., 0., 0.]);
pub fn pose_to_transform(pose: &WebVRPose) -> RigidTransform3D<f64> {
let pos = pose.position.unwrap_or([0., 0., 0.]);
let translation = Vector3D::new(pos[0] as f64, pos[1] as f64, pos[2] as f64);
let orient = data.pose.orientation.unwrap_or([0., 0., 0., 0.]);
let orient = pose.orientation.unwrap_or([0., 0., 0., 0.]);
let rotation = Rotation3D::quaternion(
orient[0] as f64,
orient[1] as f64,

View file

@ -55,7 +55,7 @@ impl XRStationaryReferenceSpace {
///
/// Does not apply originOffset, use get_viewer_pose on XRReferenceSpace instead
pub fn get_unoffset_viewer_pose(&self, viewer_pose: &WebVRFrameData) -> RigidTransform3D<f64> {
let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose);
let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose);
// all math is in column-vector notation
// we use the following equation to verify correctness here:
// get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space)
@ -113,7 +113,7 @@ impl XRStationaryReferenceSpace {
},
XRStationaryReferenceSpaceSubtype::Position_disabled => {
// This space follows the user around, but does not mirror the user's orientation
let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose);
let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose);
viewer_pose.translation.into()
},
}

View file

@ -22,7 +22,7 @@ gleam = "0.6"
ipc-channel = "0.11"
log = "0.4"
msg = {path = "../msg"}
rust-webvr = {version = "0.10.2", features = ["openvr", "vrexternal"]}
rust-webvr = {version = "=0.11.0", features = ["openvr", "vrexternal"]}
script_traits = {path = "../script_traits"}
servo_config = {path = "../config"}
webvr_traits = {path = "../webvr_traits" }

View file

@ -16,7 +16,7 @@ use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::{thread, time};
use webvr_traits::webvr::*;
use webvr_traits::{WebVRMsg, WebVRResult};
use webvr_traits::{WebVRMsg, WebVRPoseInformation, WebVRResult};
/// WebVRThread owns native VRDisplays, handles their life cycle inside Servo and
/// acts a doorman for untrusted VR requests from DOM Objects. These are the key components
@ -128,6 +128,9 @@ impl WebVRThread {
WebVRMsg::GetGamepads(synced_ids, sender) => {
self.handle_get_gamepads(synced_ids, sender);
},
WebVRMsg::GetGamepadsForDisplay(display_id, sender) => {
self.handle_get_gamepads_for_display(display_id, sender);
},
WebVRMsg::Exit => break,
}
}
@ -251,6 +254,32 @@ impl WebVRThread {
self.vr_compositor_chan.send(compositor).unwrap();
}
fn handle_get_gamepads_for_display(
&mut self,
display_id: u32,
sender: IpcSender<WebVRResult<Vec<(VRGamepadData, VRGamepadState)>>>,
) {
match self.service.get_display(display_id) {
Some(display) => {
let gamepads = display.borrow_mut().fetch_gamepads();
match gamepads {
Ok(gamepads) => {
let data = gamepads
.iter()
.map(|g| {
let g = g.borrow();
(g.data(), g.state())
})
.collect();
sender.send(Ok(data)).unwrap();
},
Err(e) => sender.send(Err(e)).unwrap(),
}
},
None => sender.send(Err("Device not found".into())).unwrap(),
}
}
fn handle_get_gamepads(
&mut self,
synced_ids: Vec<u32>,
@ -386,10 +415,23 @@ impl webgl::WebVRRenderHandler for WebVRCompositorHandler {
unsafe { (*compositor.0).start_present(None) };
}
},
webgl::WebVRCommand::SyncPoses(compositor_id, near, far, sender) => {
webgl::WebVRCommand::SyncPoses(compositor_id, near, far, get_gamepads, sender) => {
if let Some(compositor) = self.compositors.get(&compositor_id) {
let pose = unsafe { (*compositor.0).future_frame_data(near, far) };
let _ = sender.send(Ok(pose));
let mut pose_information = WebVRPoseInformation {
frame: pose,
gamepads: vec![],
};
if get_gamepads {
let gamepads = unsafe { (*compositor.0).fetch_gamepads() };
if let Ok(gamepads) = gamepads {
for gamepad in gamepads {
let g = gamepad.borrow();
pose_information.gamepads.push((g.id(), g.state()));
}
}
}
let _ = sender.send(Ok(pose_information));
} else {
let _ = sender.send(Err(()));
}

View file

@ -13,5 +13,5 @@ path = "lib.rs"
[dependencies]
ipc-channel = "0.11"
msg = {path = "../msg"}
rust-webvr-api = {version = "0.10.3", features = ["ipc"]}
rust-webvr-api = {version = "=0.11.0", features = ["ipc"]}
serde = "1.0"

View file

@ -30,3 +30,9 @@ pub use rust_webvr_api::VRLayer as WebVRLayer;
pub use rust_webvr_api::VRMainThreadHeartbeat as WebVRMainThreadHeartbeat;
pub use rust_webvr_api::VRPose as WebVRPose;
pub use rust_webvr_api::VRStageParameters as WebVRStageParameters;
#[derive(Deserialize, Serialize)]
pub struct WebVRPoseInformation {
pub frame: WebVRFutureFrameData,
pub gamepads: Vec<(u32, WebVRGamepadState)>,
}

View file

@ -30,5 +30,9 @@ pub enum WebVRMsg {
Vec<u32>,
IpcSender<WebVRResult<Vec<(Option<VRGamepadData>, VRGamepadState)>>>,
),
GetGamepadsForDisplay(
u32,
IpcSender<WebVRResult<Vec<(VRGamepadData, VRGamepadState)>>>,
),
Exit,
}

View file

@ -52,7 +52,7 @@ lazy_static = "1"
libservo = {path = "../../components/servo"}
libc = "0.2"
log = "0.4"
rust-webvr = { version = "0.10.2", features = ["glwindow"] }
rust-webvr = { version = "=0.11.0", features = ["glwindow"] }
tinyfiledialogs = "3.0"
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]