Add XRSession::requestHitTestSource()

This commit is contained in:
Manish Goregaokar 2020-04-10 15:30:13 -07:00
parent f1d6a89150
commit 1b07b77323
9 changed files with 131 additions and 22 deletions

View file

@ -4,6 +4,17 @@
// https://immersive-web.github.io/hit-test/#xrhittestsource-interface
enum XRHitTestTrackableType {
"point",
"plane",
"mesh"
};
dictionary XRHitTestOptionsInit {
required XRSpace space;
sequence<XRHitTestTrackableType> entityTypes;
XRRay offsetRay;
};
[SecureContext, Exposed=Window]
interface XRHitTestSource {

View file

@ -36,6 +36,9 @@ interface XRSession : EventTarget {
Promise<void> end();
// hit test module
Promise<XRHitTestSource> requestHitTestSource(XRHitTestOptionsInit options);
// // Events
attribute EventHandler onend;
attribute EventHandler onselect;

View file

@ -82,6 +82,10 @@ impl XRRay {
Ok(Self::new(&window.global(), Ray { origin, direction }))
}
pub fn ray(&self) -> Ray<ApiSpace> {
self.ray
}
}
impl XRRayMethods for XRRay {

View file

@ -13,7 +13,7 @@ use crate::dom::xrsession::{cast_transform, ApiPose, ApiViewerPose, XRSession};
use crate::dom::xrspace::XRSpace;
use dom_struct::dom_struct;
use euclid::RigidTransform3D;
use webxr_api::Frame;
use webxr_api::{BaseSpace, Frame, Space};
#[dom_struct]
pub struct XRReferenceSpace {
@ -57,6 +57,17 @@ impl XRReferenceSpace {
global,
)
}
pub fn space(&self) -> Space {
let base = match self.ty {
XRReferenceSpaceType::Local => BaseSpace::Local,
XRReferenceSpaceType::Viewer => BaseSpace::Viewer,
XRReferenceSpaceType::Local_floor => BaseSpace::Floor,
_ => panic!("unsupported reference space found"),
};
let offset = self.offset.transform();
Space { base, offset }
}
}
impl XRReferenceSpaceMethods for XRReferenceSpace {

View file

@ -6,6 +6,8 @@ use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
use crate::dom::bindings::codegen::Bindings::XRHitTestSourceBinding::XRHitTestOptionsInit;
use crate::dom::bindings::codegen::Bindings::XRHitTestSourceBinding::XRHitTestTrackableType;
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateMethods;
@ -28,6 +30,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::performance::reduce_timing_resolution;
use crate::dom::promise::Promise;
use crate::dom::xrframe::XRFrame;
use crate::dom::xrhittestsource::XRHitTestSource;
use crate::dom::xrinputsourcearray::XRInputSourceArray;
use crate::dom::xrinputsourceevent::XRInputSourceEvent;
use crate::dom::xrreferencespace::XRReferenceSpace;
@ -37,18 +40,20 @@ use crate::dom::xrspace::XRSpace;
use crate::realms::InRealm;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use euclid::{Rect, RigidTransform3D, Transform3D};
use euclid::{Rect, RigidTransform3D, Transform3D, Vector3D};
use ipc_channel::ipc::IpcReceiver;
use ipc_channel::router::ROUTER;
use metrics::ToMs;
use profile_traits::ipc;
use std::cell::Cell;
use std::collections::HashMap;
use std::f64::consts::{FRAC_PI_2, PI};
use std::mem;
use std::rc::Rc;
use webxr_api::{
self, util, ApiSpace, Display, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent,
SelectKind, Session, SessionId, View, Viewer, Visibility,
self, util, ApiSpace, Display, EntityTypes, EnvironmentBlendMode, Event as XREvent, Frame,
FrameUpdateEvent, HitTestId, HitTestSource, Ray, SelectEvent, SelectKind, Session, SessionId,
View, Viewer, Visibility,
};
#[dom_struct]
@ -75,6 +80,10 @@ pub struct XRSession {
end_promises: DomRefCell<Vec<Rc<Promise>>>,
/// https://immersive-web.github.io/webxr/#ended
ended: Cell<bool>,
#[ignore_malloc_size_of = "defined in webxr"]
next_hit_test_id: Cell<HitTestId>,
#[ignore_malloc_size_of = "defined in webxr"]
pending_hit_test_promises: DomRefCell<HashMap<HitTestId, Rc<Promise>>>,
/// Opaque framebuffers need to know the session is "outside of a requestAnimationFrame"
/// https://immersive-web.github.io/webxr/#opaque-framebuffer
outside_raf: Cell<bool>,
@ -104,6 +113,8 @@ impl XRSession {
input_sources: Dom::from_ref(input_sources),
end_promises: DomRefCell::new(vec![]),
ended: Cell::new(false),
next_hit_test_id: Cell::new(HitTestId(0)),
pending_hit_test_promises: DomRefCell::new(HashMap::new()),
outside_raf: Cell::new(true),
}
}
@ -373,7 +384,7 @@ impl XRSession {
}
for event in frame.events.drain(..) {
self.session.borrow_mut().apply_event(event)
self.handle_frame_update(event);
}
// Step 2
@ -480,6 +491,22 @@ impl XRSession {
}
}
}
fn handle_frame_update(&self, event: FrameUpdateEvent) {
match event {
FrameUpdateEvent::HitTestSourceAdded(id) => {
if let Some(promise) = self.pending_hit_test_promises.borrow_mut().remove(&id) {
promise.resolve_native(&XRHitTestSource::new(&self.global(), id, &self));
} else {
warn!(
"received hit test add request for unknown hit test {:?}",
id
)
}
},
_ => self.session.borrow_mut().apply_event(event),
}
}
}
impl XRSessionMethods for XRSession {
@ -709,6 +736,52 @@ impl XRSessionMethods for XRSession {
self.session.borrow_mut().end_session();
p
}
// https://immersive-web.github.io/hit-test/#dom-xrsession-requesthittestsource
fn RequestHitTestSource(&self, options: &XRHitTestOptionsInit) -> Rc<Promise> {
let p = Promise::new(&self.global());
let id = self.next_hit_test_id.get();
self.next_hit_test_id.set(HitTestId(id.0 + 1));
let space = options.space.space();
let ray = if let Some(ref ray) = options.offsetRay {
ray.ray()
} else {
Ray {
origin: Vector3D::new(0., 0., 0.),
direction: Vector3D::new(0., 0., -1.),
}
};
let mut types = EntityTypes::default();
if let Some(ref tys) = options.entityTypes {
for ty in tys {
match ty {
XRHitTestTrackableType::Point => types.point = true,
XRHitTestTrackableType::Plane => types.plane = true,
XRHitTestTrackableType::Mesh => types.mesh = true,
}
}
} else {
types.plane = true;
}
let source = HitTestSource {
id,
space,
ray,
types,
};
self.pending_hit_test_promises
.borrow_mut()
.insert(id, p.clone());
self.session.borrow().request_hit_test(source);
p
}
}
// The pose of an object in native-space. Should never be exposed.

View file

@ -11,7 +11,8 @@ use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::{cast_transform, ApiPose, XRSession};
use dom_struct::dom_struct;
use webxr_api::Frame;
use euclid::RigidTransform3D;
use webxr_api::{BaseSpace, Frame, Space};
#[dom_struct]
pub struct XRSpace {
@ -56,6 +57,24 @@ impl XRSpace {
global,
)
}
pub fn space(&self) -> Space {
if let Some(rs) = self.downcast::<XRReferenceSpace>() {
rs.space()
} else if let Some(source) = self.input_source.get() {
let base = if self.is_grip_space {
BaseSpace::Grip(source.id())
} else {
BaseSpace::TargetRay(source.id())
};
Space {
base,
offset: RigidTransform3D::identity(),
}
} else {
panic!("invalid space found")
}
}
}
impl XRSpace {

View file

@ -1,7 +1,4 @@
[ar_hittest_subscription_refSpaces.https.html]
[Ensures subscription to hit test works with viewer space - straight up - no results]
expected: FAIL
[Ensures subscription to hit test works with viewer space - straight ahead - plane]
expected: FAIL

View file

@ -1,10 +0,0 @@
[ar_hittest_subscription_states_regular.https.html]
[Hit test subscription succeeds if the feature was requested]
expected: FAIL
[Hit test subscription fails if the feature was not requested]
expected: FAIL
[Hit test subscription fails if the feature was requested but the session already ended]
expected: FAIL

View file

@ -1,10 +1,11 @@
[ar_hittest_subscription_transientInputSources.https.html]
expected: ERROR
[Ensures subscription to transient hit test works with an XRSpace from input source - after move - 1 result]
expected: FAIL
expected: NOTRUN
[Ensures subscription to transient hit test works with an XRSpace from input source - after move - no results]
expected: FAIL
expected: NOTRUN
[Ensures subscription to transient hit test works with an XRSpace from input source - no move]
expected: FAIL
expected: TIMEOUT