From 84848af2ba3fae45e2ed9078f6a26d9bbc2c598f Mon Sep 17 00:00:00 2001 From: thiolliere Date: Sat, 18 Mar 2017 15:58:34 +0100 Subject: [PATCH 1/5] fix warnings --- src/api/emscripten/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/emscripten/mod.rs b/src/api/emscripten/mod.rs index 393527b134..473e7cc8bf 100644 --- a/src/api/emscripten/mod.rs +++ b/src/api/emscripten/mod.rs @@ -64,8 +64,8 @@ const DOCUMENT_NAME: &'static str = "#document\0"; impl Window { pub fn new(_: &WindowAttributes, - pf_reqs: &PixelFormatRequirements, - opengl: &GlAttributes<&Window>, + _pf_reqs: &PixelFormatRequirements, + _opengl: &GlAttributes<&Window>, _: &PlatformSpecificWindowBuilderAttributes, _: winit::WindowBuilder) -> Result { @@ -219,11 +219,11 @@ impl Window { } #[inline] - pub fn set_cursor(&self, cursor: MouseCursor) { + pub fn set_cursor(&self, _cursor: MouseCursor) { } #[inline] - pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { + pub fn set_cursor_state(&self, _state: CursorState) -> Result<(), String> { Ok(()) } @@ -233,7 +233,7 @@ impl Window { } #[inline] - pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> { + pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> { Ok(()) } From acd4405546818fcc48c44c985b0b584b35ebc7f1 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Sat, 18 Mar 2017 16:22:57 +0100 Subject: [PATCH 2/5] implement hidpi factor --- src/api/emscripten/ffi.rs | 2 ++ src/api/emscripten/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/emscripten/ffi.rs b/src/api/emscripten/ffi.rs index ebde37cae3..1102cf74c9 100644 --- a/src/api/emscripten/ffi.rs +++ b/src/api/emscripten/ffi.rs @@ -157,4 +157,6 @@ extern { pub fn emscripten_set_keydown_callback(target: *const libc::c_char, user_data: *mut libc::c_void, use_capture: EM_BOOL, callback: em_keyboard_callback_func) -> EMSCRIPTEN_RESULT; pub fn emscripten_set_keyup_callback(target: *const libc::c_char, user_data: *mut libc::c_void, use_capture: EM_BOOL, callback: em_keyboard_callback_func) -> EMSCRIPTEN_RESULT; + + pub fn emscripten_get_device_pixel_ratio() -> f64; } diff --git a/src/api/emscripten/mod.rs b/src/api/emscripten/mod.rs index 473e7cc8bf..a9f3b4a683 100644 --- a/src/api/emscripten/mod.rs +++ b/src/api/emscripten/mod.rs @@ -229,7 +229,7 @@ impl Window { #[inline] pub fn hidpi_factor(&self) -> f32 { - 1.0 + unsafe { ffi::emscripten_get_device_pixel_ratio() as f32 } } #[inline] @@ -259,7 +259,7 @@ impl Window { #[inline] pub fn hdpi_factor(&self) -> f32 { - unimplemented!(); + self.hidpi_factor() } } From 10b3b77a0204ef2c206f654b89f609b1ff1b6061 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Sat, 18 Mar 2017 17:04:51 +0100 Subject: [PATCH 3/5] impl get set size --- src/api/emscripten/ffi.rs | 10 ++++------ src/api/emscripten/mod.rs | 20 ++++++-------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/api/emscripten/ffi.rs b/src/api/emscripten/ffi.rs index 1102cf74c9..ffbf2db6eb 100644 --- a/src/api/emscripten/ffi.rs +++ b/src/api/emscripten/ffi.rs @@ -136,12 +136,6 @@ extern { pub fn emscripten_exit_fullscreen() -> EMSCRIPTEN_RESULT; - pub fn emscripten_set_element_css_size(target: *const libc::c_char, width: libc::c_double, - height: libc::c_double) -> EMSCRIPTEN_RESULT; - - pub fn emscripten_get_element_css_size(target: *const libc::c_char, width: *mut libc::c_double, - height: *mut libc::c_double) -> EMSCRIPTEN_RESULT; - pub fn emscripten_sleep(delay: libc::c_uint); pub fn emscripten_set_main_loop(func : em_callback_func, fps : libc::c_int, simulate_infinite_loop : libc::c_int); @@ -159,4 +153,8 @@ extern { pub fn emscripten_set_keyup_callback(target: *const libc::c_char, user_data: *mut libc::c_void, use_capture: EM_BOOL, callback: em_keyboard_callback_func) -> EMSCRIPTEN_RESULT; pub fn emscripten_get_device_pixel_ratio() -> f64; + + pub fn emscripten_set_canvas_size(width: libc::c_int, height: libc::c_int); + + pub fn emscripten_get_canvas_size(width: *mut libc::c_int, height: *mut libc::c_int, isFullscreen: *mut libc::c_int); } diff --git a/src/api/emscripten/mod.rs b/src/api/emscripten/mod.rs index a9f3b4a683..6cea9e058b 100644 --- a/src/api/emscripten/mod.rs +++ b/src/api/emscripten/mod.rs @@ -151,17 +151,13 @@ impl Window { pub fn get_inner_size(&self) -> Option<(u32, u32)> { unsafe { - use std::{mem, ptr}; + use std::mem; let mut width = mem::uninitialized(); let mut height = mem::uninitialized(); + let mut fullscreen = mem::uninitialized(); - if ffi::emscripten_get_element_css_size(ptr::null(), &mut width, &mut height) - != ffi::EMSCRIPTEN_RESULT_SUCCESS - { - None - } else { - Some((width as u32, height as u32)) - } + ffi::emscripten_get_canvas_size(&mut width, &mut height, &mut fullscreen); + Some((width as u32, height as u32)) } } @@ -172,11 +168,7 @@ impl Window { #[inline] pub fn set_inner_size(&self, width: u32, height: u32) { - unsafe { - use std::ptr; - ffi::emscripten_set_element_css_size(ptr::null(), width as libc::c_double, height - as libc::c_double); - } + unsafe { ffi::emscripten_set_canvas_size(width as i32, height as i32); } } #[inline] @@ -244,7 +236,7 @@ impl Window { #[inline] pub fn get_inner_size_pixels(&self) -> Option<(u32, u32)> { - unimplemented!() + self.get_inner_size() } #[inline] From b8cdab7aeeb2cc4ee557629ed878cac48ae32393 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Sat, 18 Mar 2017 17:56:16 +0100 Subject: [PATCH 4/5] impl fullscreen and window dimensions --- src/api/emscripten/ffi.rs | 24 ++++++++++++++++++++++++ src/api/emscripten/mod.rs | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/api/emscripten/ffi.rs b/src/api/emscripten/ffi.rs index ffbf2db6eb..dbfc84482c 100644 --- a/src/api/emscripten/ffi.rs +++ b/src/api/emscripten/ffi.rs @@ -17,6 +17,28 @@ pub type em_webgl_context_callback = extern fn(libc::c_int, *const libc::c_void, pub type em_callback_func = unsafe extern fn(); +pub type em_fullscreenchange_callback_func = Option EM_BOOL>; + +#[repr(C)] +pub struct EmscriptenFullscreenChangeEvent { + pub isFullscreen: ::libc::c_int, + pub fullscreenEnabled: ::libc::c_int, + pub nodeName: [::libc::c_char; 128usize], + pub id: [::libc::c_char; 128usize], + pub elementWidth: ::libc::c_int, + pub elementHeight: ::libc::c_int, + pub screenWidth: ::libc::c_int, + pub screenHeight: ::libc::c_int, +} +#[test] +fn bindgen_test_layout_EmscriptenFullscreenChangeEvent() { + assert_eq!(::std::mem::size_of::(), 280usize); + assert_eq!(::std::mem::align_of::(), 4usize); +} + pub const EMSCRIPTEN_EVENT_KEYDOWN: libc::c_int = 2; pub const EMSCRIPTEN_EVENT_KEYUP: libc::c_int = 3; @@ -157,4 +179,6 @@ extern { pub fn emscripten_set_canvas_size(width: libc::c_int, height: libc::c_int); pub fn emscripten_get_canvas_size(width: *mut libc::c_int, height: *mut libc::c_int, isFullscreen: *mut libc::c_int); + + pub fn emscripten_set_fullscreenchange_callback(target: *const libc::c_char, userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_fullscreenchange_callback_func) -> EMSCRIPTEN_RESULT; } diff --git a/src/api/emscripten/mod.rs b/src/api/emscripten/mod.rs index 6cea9e058b..009af4bef3 100644 --- a/src/api/emscripten/mod.rs +++ b/src/api/emscripten/mod.rs @@ -67,7 +67,7 @@ impl Window { _pf_reqs: &PixelFormatRequirements, _opengl: &GlAttributes<&Window>, _: &PlatformSpecificWindowBuilderAttributes, - _: winit::WindowBuilder) + window_builder: winit::WindowBuilder) -> Result { // getting the default values of attributes @@ -130,10 +130,24 @@ impl Window { // TODO: emscripten_set_webglcontextrestored_callback - Ok(Window { + let window = Window { context: context, events: events, - }) + }; + + if window_builder.window.monitor.is_some() { + use std::ptr; + unsafe { + em_try(ffi::emscripten_request_fullscreen(ptr::null(), ffi::EM_TRUE)) + .map_err(|e| ::CreationError::OsError(e))?; + em_try(ffi::emscripten_set_fullscreenchange_callback(ptr::null(), 0 as *mut libc::c_void, ffi::EM_FALSE, Some(fullscreen_callback))) + .map_err(|e| ::CreationError::OsError(e))?; + } + } else if let Some((w, h)) = window_builder.window.dimensions { + window.set_inner_size(w, h); + } + + Ok(window) } #[inline] @@ -295,7 +309,9 @@ impl GlContext for Window { impl Drop for Window { fn drop(&mut self) { + use std::ptr; unsafe { + ffi::emscripten_set_fullscreenchange_callback(ptr::null(), 0 as *mut libc::c_void, ffi::EM_FALSE, None); ffi::emscripten_exit_fullscreen(); ffi::emscripten_webgl_destroy_context(self.context); } @@ -319,6 +335,12 @@ fn error_to_str(code: ffi::EMSCRIPTEN_RESULT) -> &'static str { } } +fn em_try(res: ffi::EMSCRIPTEN_RESULT) -> Result<(), String> { + match res { + ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED => Ok(()), + r @ _ => Err(error_to_str(r).to_string()), + } +} extern fn mouse_callback( event_type: libc::c_int, @@ -390,3 +412,14 @@ extern fn keyboard_callback( ffi::EM_TRUE } +// In case of fullscreen window this method will request fullscreen on change +#[allow(non_snake_case)] +unsafe extern "C" fn fullscreen_callback( + _eventType: libc::c_int, + _fullscreenChangeEvent: *const ffi::EmscriptenFullscreenChangeEvent, + _userData: *mut libc::c_void) -> ffi::EM_BOOL +{ + use std::ptr; + ffi::emscripten_request_fullscreen(ptr::null(), ffi::EM_TRUE); + ffi::EM_FALSE +} From e84423590fde21f5a95d530da4f29754d2252421 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Sun, 19 Mar 2017 16:29:55 +0100 Subject: [PATCH 5/5] impl set_cursor_state grab mode use pointerlock https://www.w3.org/TR/pointerlock/ this behavior is not the same as other backend. I wanted this because as set_cursor_position is not available on emscripten backend. the only way to have a FPS camera is to use pointerlock. So you can use grab to have FPS camera on emscripten. also show_mouse is implement in javascript as in a pull request that hasn't been merged https://github.com/kripken/emscripten/pull/4616 --- src/api/emscripten/ffi.rs | 24 ++++++++++++++ src/api/emscripten/mod.rs | 70 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/api/emscripten/ffi.rs b/src/api/emscripten/ffi.rs index dbfc84482c..5ec6b60e21 100644 --- a/src/api/emscripten/ffi.rs +++ b/src/api/emscripten/ffi.rs @@ -39,6 +39,18 @@ fn bindgen_test_layout_EmscriptenFullscreenChangeEvent() { assert_eq!(::std::mem::align_of::(), 4usize); } +#[repr(C)] +pub struct EmscriptenPointerlockChangeEvent { + pub isActive: ::libc::c_int, + pub nodeName: [::libc::c_char; 128usize], + pub id: [::libc::c_char; 128usize], +} +#[test] +fn bindgen_test_layout_EmscriptenPointerlockChangeEvent() { + assert_eq!(::std::mem::size_of::(), 260usize); + assert_eq!(::std::mem::align_of::(), 4usize); +} + pub const EMSCRIPTEN_EVENT_KEYDOWN: libc::c_int = 2; pub const EMSCRIPTEN_EVENT_KEYUP: libc::c_int = 3; @@ -98,6 +110,8 @@ pub type em_mouse_callback_func = extern fn(libc::c_int, *const EmscriptenMouseE pub type em_keyboard_callback_func = extern fn(libc::c_int, *const EmscriptenKeyboardEvent, *mut libc::c_void) -> EM_BOOL; +pub type em_pointerlockchange_callback_func = Option EM_BOOL>; + #[repr(C)] pub struct EmscriptenWebGLContextAttributes { pub alpha: EM_BOOL, @@ -152,6 +166,10 @@ extern { // note: this function is not documented but is used by the ports of glfw, SDL and EGL pub fn emscripten_GetProcAddress(name: *const libc::c_char) -> *const libc::c_void; + pub fn emscripten_request_pointerlock(target: *const libc::c_char, + deferUntilInEventHandler: EM_BOOL) -> EMSCRIPTEN_RESULT; + + pub fn emscripten_exit_pointerlock() -> EMSCRIPTEN_RESULT; pub fn emscripten_request_fullscreen(target: *const libc::c_char, deferUntilInEventHandler: EM_BOOL) -> EMSCRIPTEN_RESULT; @@ -181,4 +199,10 @@ extern { pub fn emscripten_get_canvas_size(width: *mut libc::c_int, height: *mut libc::c_int, isFullscreen: *mut libc::c_int); pub fn emscripten_set_fullscreenchange_callback(target: *const libc::c_char, userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_fullscreenchange_callback_func) -> EMSCRIPTEN_RESULT; + + pub fn emscripten_set_pointerlockchange_callback(target: *const libc::c_char, userData: *mut libc::c_void, useCapture: EM_BOOL, callback: em_pointerlockchange_callback_func) -> EMSCRIPTEN_RESULT; + + pub fn emscripten_hide_mouse(); + + pub fn emscripten_asm_const(code: *const libc::c_char); } diff --git a/src/api/emscripten/mod.rs b/src/api/emscripten/mod.rs index 009af4bef3..f356715027 100644 --- a/src/api/emscripten/mod.rs +++ b/src/api/emscripten/mod.rs @@ -29,6 +29,7 @@ mod ffi; mod keyboard; pub struct Window { + cursor_state: RefCell<::CursorState>, context: ffi::EMSCRIPTEN_WEBGL_CONTEXT_HANDLE, events: Box>>, } @@ -131,6 +132,7 @@ impl Window { // TODO: emscripten_set_webglcontextrestored_callback let window = Window { + cursor_state: RefCell::new(::CursorState::Normal), context: context, events: events, }; @@ -229,8 +231,41 @@ impl Window { } #[inline] - pub fn set_cursor_state(&self, _state: CursorState) -> Result<(), String> { - Ok(()) + pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { + use std::ptr; + unsafe { + use ::CursorState::*; + + let mut old_state = self.cursor_state.borrow_mut(); + if state == *old_state { + return Ok(()); + } + + // Set or unset grab callback + match state { + Hide | Normal => em_try(ffi::emscripten_set_pointerlockchange_callback(ptr::null(), 0 as *mut libc::c_void, ffi::EM_FALSE, None))?, + Grab => em_try(ffi::emscripten_set_pointerlockchange_callback(ptr::null(), 0 as *mut libc::c_void, ffi::EM_FALSE, Some(pointerlockchange_callback)))?, + } + + // Go back to normal cursor state + match *old_state { + Hide => show_mouse(), + Grab => em_try(ffi::emscripten_exit_pointerlock())?, + Normal => (), + } + + // Set cursor from normal cursor state + match state { + Hide => ffi::emscripten_hide_mouse(), + Grab => em_try(ffi::emscripten_request_pointerlock(ptr::null(), ffi::EM_TRUE))?, + Normal => (), + } + + // Update + *old_state = state; + + Ok(()) + } } #[inline] @@ -423,3 +458,34 @@ unsafe extern "C" fn fullscreen_callback( ffi::emscripten_request_fullscreen(ptr::null(), ffi::EM_TRUE); ffi::EM_FALSE } + +// In case of pointer grabbed this method will request pointer lock on change +#[allow(non_snake_case)] +unsafe extern "C" fn pointerlockchange_callback( + _eventType: libc::c_int, + _pointerlockChangeEvent: *const ffi::EmscriptenPointerlockChangeEvent, + _userData: *mut libc::c_void) -> ffi::EM_BOOL +{ + use std::ptr; + ffi::emscripten_request_pointerlock(ptr::null(), ffi::EM_TRUE); + ffi::EM_FALSE +} + +fn show_mouse() { + // Hide mouse hasn't show mouse equivalent. + // There is a pull request on emscripten that hasn't been merged #4616 + // that contains: + // + // var styleSheet = document.styleSheets[0]; + // var rules = styleSheet.cssRules; + // for (var i = 0; i < rules.length; i++) { + // if (rules[i].cssText.substr(0, 6) == 'canvas') { + // styleSheet.deleteRule(i); + // i--; + // } + // } + // styleSheet.insertRule('canvas.emscripten { border: none; cursor: auto; }', 0); + unsafe { + ffi::emscripten_asm_const(b"var styleSheet = document.styleSheets[0]; var rules = styleSheet.cssRules; for (var i = 0; i < rules.length; i++) { if (rules[i].cssText.substr(0, 6) == 'canvas') { styleSheet.deleteRule(i); i--; } } styleSheet.insertRule('canvas.emscripten { border: none; cursor: auto; }', 0);\0" as *const u8); + } +}