Make it possible to rotate in webxr glwindow view

This commit is contained in:
Paul Rouget 2019-09-30 17:43:00 +02:00
parent 42d64d002a
commit e65f1c9dbf
5 changed files with 109 additions and 42 deletions

4
Cargo.lock generated
View file

@ -5646,7 +5646,7 @@ dependencies = [
[[package]] [[package]]
name = "webxr" name = "webxr"
version = "0.0.1" version = "0.0.1"
source = "git+https://github.com/servo/webxr#876424c9adbe4592518f76888452c0cdbb6adbed" source = "git+https://github.com/servo/webxr#72d85b8254f8ce5d10f91d59ed35cd5969d15ed8"
dependencies = [ dependencies = [
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)", "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -5664,7 +5664,7 @@ dependencies = [
[[package]] [[package]]
name = "webxr-api" name = "webxr-api"
version = "0.0.1" version = "0.0.1"
source = "git+https://github.com/servo/webxr#876424c9adbe4592518f76888452c0cdbb6adbed" source = "git+https://github.com/servo/webxr#72d85b8254f8ce5d10f91d59ed35cd5969d15ed8"
dependencies = [ dependencies = [
"euclid 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -9,19 +9,24 @@ use crate::embedder::EmbedderCallbacks;
use crate::window_trait::WindowPortsMethods; use crate::window_trait::WindowPortsMethods;
use crate::events_loop::EventsLoop; use crate::events_loop::EventsLoop;
use crate::{headed_window, headless_window}; use crate::{headed_window, headless_window};
use glutin::WindowId;
use servo::compositing::windowing::WindowEvent; use servo::compositing::windowing::WindowEvent;
use servo::config::opts::{self, parse_url_or_filename}; use servo::config::opts::{self, parse_url_or_filename};
use servo::servo_config::pref; use servo::servo_config::pref;
use servo::servo_url::ServoUrl; use servo::servo_url::ServoUrl;
use servo::{BrowserId, Servo}; use servo::{BrowserId, Servo};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::env; use std::env;
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
thread_local! {
pub static WINDOWS: RefCell<HashMap<WindowId, Rc<dyn WindowPortsMethods>>> = RefCell::new(HashMap::new());
}
pub struct App { pub struct App {
events_loop: Rc<RefCell<EventsLoop>>, events_loop: Rc<RefCell<EventsLoop>>,
window: Rc<dyn WindowPortsMethods>,
servo: RefCell<Servo<dyn WindowPortsMethods>>, servo: RefCell<Servo<dyn WindowPortsMethods>>,
browser: RefCell<Browser<dyn WindowPortsMethods>>, browser: RefCell<Browser<dyn WindowPortsMethods>>,
event_queue: RefCell<Vec<WindowEvent>>, event_queue: RefCell<Vec<WindowEvent>>,
@ -54,10 +59,11 @@ impl App {
servo.handle_events(vec![WindowEvent::NewBrowser(get_default_url(), browser_id)]); servo.handle_events(vec![WindowEvent::NewBrowser(get_default_url(), browser_id)]);
servo.setup_logging(); servo.setup_logging();
register_window(window);
let app = App { let app = App {
event_queue: RefCell::new(vec![]), event_queue: RefCell::new(vec![]),
events_loop, events_loop,
window: window,
browser: RefCell::new(browser), browser: RefCell::new(browser),
servo: RefCell::new(servo), servo: RefCell::new(servo),
suspended: Cell::new(false), suspended: Cell::new(false),
@ -89,18 +95,24 @@ impl App {
glutin::Event::WindowEvent { glutin::Event::WindowEvent {
window_id, event, .. window_id, event, ..
} => { } => {
if Some(window_id) != self.window.id() { return WINDOWS.with(|windows| {
match windows.borrow().get(&window_id) {
None => {
warn!("Got an event from unknown window"); warn!("Got an event from unknown window");
} else { glutin::ControlFlow::Break
},
Some(window) => {
// Resize events need to be handled during run_forever // Resize events need to be handled during run_forever
let cont = if let glutin::WindowEvent::Resized(_) = event { let cont = if let glutin::WindowEvent::Resized(_) = event {
glutin::ControlFlow::Continue glutin::ControlFlow::Continue
} else { } else {
glutin::ControlFlow::Break glutin::ControlFlow::Break
}; };
self.window.winit_event_to_servo_event(event); window.winit_event_to_servo_event(event);
return cont; return cont;
} }
}
});
}, },
} }
glutin::ControlFlow::Break glutin::ControlFlow::Break
@ -108,7 +120,10 @@ impl App {
fn run_loop(self) { fn run_loop(self) {
loop { loop {
if !self.window.is_animating() || self.suspended.get() { let animating = WINDOWS.with(|windows| {
windows.borrow().iter().any(|(_, window)| window.is_animating())
});
if !animating || self.suspended.get() {
// If there's no animations running then we block on the window event loop. // If there's no animations running then we block on the window event loop.
self.events_loop.borrow_mut().run_forever(|e| { self.events_loop.borrow_mut().run_forever(|e| {
let cont = self.winit_event_to_servo_event(e); let cont = self.winit_event_to_servo_event(e);
@ -141,18 +156,27 @@ impl App {
let mut browser = self.browser.borrow_mut(); let mut browser = self.browser.borrow_mut();
let mut servo = self.servo.borrow_mut(); let mut servo = self.servo.borrow_mut();
let win_events = self.window.get_events(); // FIXME:
// As of now, we support only one browser (self.browser)
// but have multiple windows (dom.webxr.glwindow). We forward
// the events of all the windows combined to that single
// browser instance. Pressing the "a" key on the glwindow
// will send a key event to the servo window.
let mut app_events = self.get_events();
WINDOWS.with(|windows| {
for (_win_id, window) in &*windows.borrow() {
app_events.extend(window.get_events());
}
});
// FIXME: this could be handled by Servo. We don't need // FIXME: this could be handled by Servo. We don't need
// a repaint_synchronously function exposed. // a repaint_synchronously function exposed.
let need_resize = win_events.iter().any(|e| match *e { let need_resize = app_events.iter().any(|e| match *e {
WindowEvent::Resize => true, WindowEvent::Resize => true,
_ => false, _ => false,
}); });
let mut app_events = self.get_events();
app_events.extend(win_events);
browser.handle_window_events(app_events); browser.handle_window_events(app_events);
let mut servo_events = servo.get_events(); let mut servo_events = servo.get_events();
@ -189,6 +213,12 @@ fn get_default_url() -> ServoUrl {
cmdline_url.or(pref_url).or(blank_url).unwrap() cmdline_url.or(pref_url).or(blank_url).unwrap()
} }
pub fn register_window(window: Rc<dyn WindowPortsMethods>) {
WINDOWS.with(|w| {
w.borrow_mut().insert(window.id(), window);
});
}
pub fn gl_version() -> glutin::GlRequest { pub fn gl_version() -> glutin::GlRequest {
if opts::get().angle { if opts::get().angle {
glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0)) glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0))

View file

@ -9,7 +9,7 @@ use crate::context::GlContext;
use crate::events_loop::EventsLoop; use crate::events_loop::EventsLoop;
use crate::keyutils::keyboard_event_from_winit; use crate::keyutils::keyboard_event_from_winit;
use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT}; use crate::window_trait::{WindowPortsMethods, LINE_HEIGHT};
use euclid::{default::Size2D as UntypedSize2D, Point2D, Scale, Size2D, Vector2D}; use euclid::{Angle, default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit, Vector2D};
use gleam::gl; use gleam::gl;
use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize}; use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@ -17,7 +17,7 @@ use glutin::os::macos::{ActivationPolicy, WindowBuilderExt};
use glutin::Api; use glutin::Api;
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
use glutin::Icon; use glutin::Icon;
use glutin::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase}; use glutin::{ElementState, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, VirtualKeyCode};
#[cfg(any(target_os = "linux", target_os = "windows"))] #[cfg(any(target_os = "linux", target_os = "windows"))]
use image; use image;
use keyboard_types::{Key, KeyState, KeyboardEvent}; use keyboard_types::{Key, KeyState, KeyboardEvent};
@ -68,6 +68,7 @@ pub struct Window {
animation_state: Cell<AnimationState>, animation_state: Cell<AnimationState>,
fullscreen: Cell<bool>, fullscreen: Cell<bool>,
gl: Rc<dyn gl::Gl>, gl: Rc<dyn gl::Gl>,
xr_rotation: Cell<Rotation3D<f32, UnknownUnit, UnknownUnit>>,
} }
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
@ -194,6 +195,7 @@ impl Window {
inner_size: Cell::new(inner_size), inner_size: Cell::new(inner_size),
primary_monitor, primary_monitor,
screen_size, screen_size,
xr_rotation: Cell::new(Rotation3D::identity()),
}; };
window.present(); window.present();
@ -235,12 +237,36 @@ impl Window {
self.last_pressed.set(Some(event)); self.last_pressed.set(Some(event));
} else if event.key != Key::Unidentified { } else if event.key != Key::Unidentified {
self.last_pressed.set(None); self.last_pressed.set(None);
self.handle_xr_rotation(&input);
self.event_queue self.event_queue
.borrow_mut() .borrow_mut()
.push(WindowEvent::Keyboard(event)); .push(WindowEvent::Keyboard(event));
} }
} }
fn handle_xr_rotation(&self, input: &KeyboardInput) {
if input.state != glutin::ElementState::Pressed {
return;
}
let mut x = 0.0;
let mut y = 0.0;
match input.virtual_keycode {
Some(VirtualKeyCode::Up) => x = 1.0,
Some(VirtualKeyCode::Down) => x = -1.0,
Some(VirtualKeyCode::Left) => y = 1.0,
Some(VirtualKeyCode::Right) => y = -1.0,
_ => return,
};
if input.modifiers.shift {
x = 10.0 * x;
y = 10.0 * y;
}
let x: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_x(Angle::degrees(x));
let y: Rotation3D<_, UnknownUnit, UnknownUnit> = Rotation3D::around_y(Angle::degrees(y));
let rotation = self.xr_rotation.get().post_rotate(&x).post_rotate(&y);
self.xr_rotation.set(rotation);
}
/// Helper function to handle a click /// Helper function to handle a click
fn handle_mouse( fn handle_mouse(
&self, &self,
@ -394,8 +420,8 @@ impl WindowPortsMethods for Window {
self.animation_state.get() == AnimationState::Animating self.animation_state.get() == AnimationState::Animating
} }
fn id(&self) -> Option<glutin::WindowId> { fn id(&self) -> glutin::WindowId {
Some(self.gl_context.borrow().window().id()) self.gl_context.borrow().window().id()
} }
fn winit_event_to_servo_event(&self, event: glutin::WindowEvent) { fn winit_event_to_servo_event(&self, event: glutin::WindowEvent) {
@ -486,15 +512,15 @@ impl WindowPortsMethods for Window {
} }
impl webxr::glwindow::GlWindow for Window { impl webxr::glwindow::GlWindow for Window {
fn make_current(&mut self) { fn make_current(&self) {
debug!("Making window {:?} current", self.gl_context.borrow().window().id()); debug!("Making window {:?} current", self.gl_context.borrow().window().id());
self.gl_context.get_mut().make_current(); self.gl_context.borrow_mut().make_current();
} }
fn swap_buffers(&mut self) { fn swap_buffers(&self) {
debug!("Swapping buffers on window {:?}", self.gl_context.borrow().window().id()); debug!("Swapping buffers on window {:?}", self.gl_context.borrow().window().id());
self.gl_context.get_mut().swap_buffers(); self.gl_context.borrow().swap_buffers();
self.gl_context.get_mut().make_not_current(); self.gl_context.borrow_mut().make_not_current();
} }
fn size(&self) -> UntypedSize2D<gl::GLsizei> { fn size(&self) -> UntypedSize2D<gl::GLsizei> {
@ -508,12 +534,18 @@ impl webxr::glwindow::GlWindow for Window {
Size2D::new(width * dpr, height *dpr).to_i32() Size2D::new(width * dpr, height *dpr).to_i32()
} }
fn new_window(&self) -> Result<Box<dyn webxr::glwindow::GlWindow>, ()> { fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
Ok(Box::new(Window::new( self.xr_rotation.get().clone()
}
fn new_window(&self) -> Result<Rc<dyn webxr::glwindow::GlWindow>, ()> {
let window = Rc::new(Window::new(
self.inner_size.get(), self.inner_size.get(),
Some(self), Some(self),
self.events_loop.clone(), self.events_loop.clone(),
))) ));
app::register_window(window.clone());
Ok(window)
} }
} }

View file

@ -6,7 +6,7 @@
use crate::window_trait::WindowPortsMethods; use crate::window_trait::WindowPortsMethods;
use glutin; use glutin;
use euclid::{default::Size2D as UntypedSize2D, Point2D, Scale, Size2D}; use euclid::{default::Size2D as UntypedSize2D, Point2D, Rotation3D, Scale, Size2D, UnknownUnit};
use gleam::gl; use gleam::gl;
use servo::compositing::windowing::{AnimationState, WindowEvent}; use servo::compositing::windowing::{AnimationState, WindowEvent};
use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods}; use servo::compositing::windowing::{EmbedderCoordinates, WindowMethods};
@ -132,8 +132,10 @@ impl WindowPortsMethods for Window {
false false
} }
fn id(&self) -> Option<glutin::WindowId> { fn id(&self) -> glutin::WindowId {
None unsafe {
glutin::WindowId::dummy()
}
} }
fn page_height(&self) -> f32 { fn page_height(&self) -> f32 {
@ -217,23 +219,26 @@ impl WindowMethods for Window {
} }
impl webxr::glwindow::GlWindow for Window { impl webxr::glwindow::GlWindow for Window {
fn make_current(&mut self) {} fn make_current(&self) {}
fn swap_buffers(&mut self) {} fn swap_buffers(&self) {}
fn size(&self) -> UntypedSize2D<gl::GLsizei> { fn size(&self) -> UntypedSize2D<gl::GLsizei> {
let dpr = self.servo_hidpi_factor().get(); let dpr = self.servo_hidpi_factor().get();
Size2D::new((self.context.width as f32 * dpr) as gl::GLsizei, (self.context.height as f32 * dpr) as gl::GLsizei) Size2D::new((self.context.width as f32 * dpr) as gl::GLsizei, (self.context.height as f32 * dpr) as gl::GLsizei)
} }
fn new_window(&self) -> Result<Box<dyn webxr::glwindow::GlWindow>, ()> { fn new_window(&self) -> Result<Rc<dyn webxr::glwindow::GlWindow>, ()> {
let width = self.context.width; let width = self.context.width;
let height = self.context.height; let height = self.context.height;
let share = Some(&self.context); let share = Some(&self.context);
let context = HeadlessContext::new(width, height, share); let context = HeadlessContext::new(width, height, share);
let gl = self.gl.clone(); let gl = self.gl.clone();
Ok(Box::new(Window { Ok(Rc::new(Window {
context, context,
gl, gl,
animation_state: Cell::new(AnimationState::Idle), animation_state: Cell::new(AnimationState::Idle),
fullscreen: Cell::new(false), fullscreen: Cell::new(false),
})) }))
} }
fn get_rotation(&self) -> Rotation3D<f32, UnknownUnit, UnknownUnit> {
Rotation3D::identity()
}
} }

View file

@ -15,7 +15,7 @@ pub const LINE_HEIGHT: f32 = 38.0;
pub trait WindowPortsMethods: WindowMethods + webxr::glwindow::GlWindow { pub trait WindowPortsMethods: WindowMethods + webxr::glwindow::GlWindow {
fn get_events(&self) -> Vec<WindowEvent>; fn get_events(&self) -> Vec<WindowEvent>;
fn id(&self) -> Option<glutin::WindowId>; fn id(&self) -> glutin::WindowId;
fn has_events(&self) -> bool; fn has_events(&self) -> bool;
fn page_height(&self) -> f32; fn page_height(&self) -> f32;
fn get_fullscreen(&self) -> bool; fn get_fullscreen(&self) -> bool;