From 45d5a0a39615c42eda48bb40dce6a8c65bda2488 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sat, 12 Jan 2019 01:14:58 +0000 Subject: [PATCH] Added cursor trapping, more documentation --- voxygen/shaders/character.frag | 2 +- voxygen/shaders/character.vert | 2 +- voxygen/shaders/skybox.frag | 2 +- voxygen/shaders/skybox.vert | 2 +- voxygen/src/main.rs | 16 ++++++--- voxygen/src/menu/title.rs | 6 ++-- voxygen/src/render/mod.rs | 1 + voxygen/src/render/pipelines/mod.rs | 46 +++++++++++++++++--------- voxygen/src/render/pipelines/skybox.rs | 2 +- voxygen/src/render/renderer.rs | 30 ++++++++++++----- voxygen/src/render/util.rs | 10 ++++++ voxygen/src/scene/camera.rs | 18 +++++++--- voxygen/src/scene/mod.rs | 21 ++++++++++-- voxygen/src/session.rs | 11 ++++-- voxygen/src/window.rs | 20 ++++++++++- 15 files changed, 143 insertions(+), 46 deletions(-) create mode 100644 voxygen/src/render/util.rs diff --git a/voxygen/shaders/character.frag b/voxygen/shaders/character.frag index 12b2bbe12a..6caf3768ba 100644 --- a/voxygen/shaders/character.frag +++ b/voxygen/shaders/character.frag @@ -14,7 +14,7 @@ uniform u_globals { vec4 cam_pos; vec4 focus_pos; vec4 view_distance; - vec4 tod; + vec4 time_of_day; vec4 time; }; diff --git a/voxygen/shaders/character.vert b/voxygen/shaders/character.vert index 885d6b40ba..0fa6bc639b 100644 --- a/voxygen/shaders/character.vert +++ b/voxygen/shaders/character.vert @@ -16,7 +16,7 @@ uniform u_globals { vec4 cam_pos; vec4 focus_pos; vec4 view_distance; - vec4 tod; + vec4 time_of_day; vec4 time; }; diff --git a/voxygen/shaders/skybox.frag b/voxygen/shaders/skybox.frag index fbca11d0ea..b39330e15e 100644 --- a/voxygen/shaders/skybox.frag +++ b/voxygen/shaders/skybox.frag @@ -14,7 +14,7 @@ uniform u_globals { vec4 cam_pos; vec4 focus_pos; vec4 view_distance; - vec4 tod; + vec4 time_of_day; vec4 time; }; diff --git a/voxygen/shaders/skybox.vert b/voxygen/shaders/skybox.vert index f3243ebadb..3b58fcfd18 100644 --- a/voxygen/shaders/skybox.vert +++ b/voxygen/shaders/skybox.vert @@ -14,7 +14,7 @@ uniform u_globals { vec4 cam_pos; vec4 focus_pos; vec4 view_distance; - vec4 tod; + vec4 time_of_day; vec4 time; }; diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 38d2005d37..0cc40a4c79 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -12,8 +12,6 @@ pub use crate::error::Error; use std::mem; // Library -use glutin; -use failure; use log; use pretty_env_logger; @@ -28,6 +26,12 @@ pub struct GlobalState { window: Window, } +impl GlobalState { + pub fn on_play_state_changed(&mut self) { + self.window.untrap_cursor(); + } +} + // States can either close (and revert to a previous state), push a new state on top of themselves, // or switch to a totally different state pub enum PlayStateResult { @@ -82,23 +86,27 @@ fn main() { log::info!("Shutting down all states..."); while states.last().is_some() { states.pop().map(|old_state| { - log::info!("Popped state '{}'", old_state.name()) + log::info!("Popped state '{}'", old_state.name()); + global_state.on_play_state_changed(); }); } }, PlayStateResult::Pop => { states.pop().map(|old_state| { - log::info!("Popped state '{}'", old_state.name()) + log::info!("Popped state '{}'", old_state.name()); + global_state.on_play_state_changed(); }); }, PlayStateResult::Push(new_state) => { log::info!("Pushed state '{}'", new_state.name()); states.push(new_state); + global_state.on_play_state_changed(); }, PlayStateResult::Switch(mut new_state) => { states.last_mut().map(|old_state| { log::info!("Switching to state '{}' from state '{}'", new_state.name(), old_state.name()); mem::swap(old_state, &mut new_state); + global_state.on_play_state_changed(); }); }, } diff --git a/voxygen/src/menu/title.rs b/voxygen/src/menu/title.rs index 1586d882aa..91c647f993 100644 --- a/voxygen/src/menu/title.rs +++ b/voxygen/src/menu/title.rs @@ -7,7 +7,6 @@ use crate::{ PlayStateResult, GlobalState, window::Event, - render, session::SessionState, }; @@ -44,8 +43,9 @@ impl PlayState for TitleState { // Finish the frame global_state.window.renderer_mut().flush(); - global_state.window.display() - .expect("Failed to display window"); + global_state.window + .swap_buffers() + .expect("Failed to swap window buffers"); } } diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index e8ad2f52ac..459be2ac0e 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -3,6 +3,7 @@ pub mod mesh; pub mod model; pub mod pipelines; pub mod renderer; +mod util; // Reexports pub use self::{ diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs index ba8d1581c9..1283c0bab6 100644 --- a/voxygen/src/render/pipelines/mod.rs +++ b/voxygen/src/render/pipelines/mod.rs @@ -11,6 +11,9 @@ use gfx::{ }; use vek::*; +// Local +use super::util::arr_to_mat; + gfx_defines! { constant Globals { view_mat: [[f32; 4]; 4] = "view_mat", @@ -18,32 +21,43 @@ gfx_defines! { cam_pos: [f32; 4] = "cam_pos", focus_pos: [f32; 4] = "focus_pos", view_distance: [f32; 4] = "view_distance", - tod: [f32; 4] = "tod", + time_of_day: [f32; 4] = "time_of_day", time: [f32; 4] = "time", } } impl Globals { - pub fn new() -> Self { - // TODO: Get rid of this ugliness - #[rustfmt::skip] - fn f32_arr_to_mat(arr: [f32; 16]) -> [[f32; 4]; 4] { - [ - [arr[ 0], arr[ 1], arr[ 2], arr[ 3]], - [arr[ 4], arr[ 5], arr[ 6], arr[ 7]], - [arr[ 8], arr[ 9], arr[10], arr[11]], - [arr[12], arr[13], arr[14], arr[15]], - ] - } - + /// Create global consts with default values. + pub fn default() -> Self { Self { - view_mat: f32_arr_to_mat(Mat4::identity().into_col_array()), - proj_mat: f32_arr_to_mat(Mat4::identity().into_col_array()), + view_mat: arr_to_mat(Mat4::identity().into_col_array()), + proj_mat: arr_to_mat(Mat4::identity().into_col_array()), cam_pos: [0.0; 4], focus_pos: [0.0; 4], view_distance: [0.0; 4], - tod: [0.0; 4], + time_of_day: [0.0; 4], time: [0.0; 4], } } + + /// Create global consts from the provided parameters. + pub fn new( + view_mat: Mat4, + proj_mat: Mat4, + cam_pos: Vec3, + focus_pos: Vec3, + view_distance: f32, + time_of_day: f32, + time: f32, + ) -> Self { + Self { + view_mat: arr_to_mat(view_mat.into_col_array()), + proj_mat: arr_to_mat(proj_mat.into_col_array()), + cam_pos: Vec4::from(cam_pos).into_array(), + focus_pos: Vec4::from(focus_pos).into_array(), + view_distance: [view_distance; 4], + time_of_day: [time_of_day; 4], + time: [time; 4], + } + } } diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index c6d0bd3205..2e6c4c1856 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -41,7 +41,7 @@ gfx_defines! { } impl Locals { - pub fn new() -> Self { + pub fn default() -> Self { Self { nul: [0.0; 4] } } } diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 7410a2072c..7388bdfc61 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -46,7 +46,8 @@ pub struct Renderer { } impl Renderer { - /// Create a new `Renderer` from a variety of backend-specific components and the window targets. + /// Create a new `Renderer` from a variety of backend-specific components and the window + /// targets. pub fn new( device: gfx_backend::Device, mut factory: gfx_backend::Factory, @@ -99,13 +100,25 @@ impl Renderer { Ok(Consts::new(&mut self.factory)) } - /// Create a new set of constants and update then with a value. - pub fn create_consts_with(&mut self, val: T) -> Result, RenderError> { + /// Create a new set of constants with a value. + pub fn create_consts_with( + &mut self, + val: T + ) -> Result, RenderError> { let mut consts = self.create_consts()?; consts.update(&mut self.encoder, val)?; Ok(consts) } + /// Update a set of constants with a new value. + pub fn update_consts( + &mut self, + consts: &mut Consts, + val: T + ) -> Result<(), RenderError> { + consts.update(&mut self.encoder, val) + } + /// Create a new model from the provided mesh. pub fn create_model(&mut self, mesh: &Mesh

) -> Result, RenderError> { Ok(Model::new( @@ -136,7 +149,6 @@ impl Renderer { } struct GfxPipeline { - program: gfx::handle::Program, pso: gfx::pso::PipelineState, } @@ -166,10 +178,12 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>( ) // Do some funky things to work around an oddity in gfx's error ownership rules .map_err(|err| RenderError::PipelineError(match err { - gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err), - gfx::PipelineStateError::DescriptorInit(err) => gfx::PipelineStateError::DescriptorInit(err.into()), - gfx::PipelineStateError::DeviceCreate(err) => gfx::PipelineStateError::DeviceCreate(err), + gfx::PipelineStateError::Program(err) => + gfx::PipelineStateError::Program(err), + gfx::PipelineStateError::DescriptorInit(err) => + gfx::PipelineStateError::DescriptorInit(err.into()), + gfx::PipelineStateError::DeviceCreate(err) => + gfx::PipelineStateError::DeviceCreate(err), }))?, - program, }) } diff --git a/voxygen/src/render/util.rs b/voxygen/src/render/util.rs new file mode 100644 index 0000000000..a1e64ecdb7 --- /dev/null +++ b/voxygen/src/render/util.rs @@ -0,0 +1,10 @@ +// TODO: Get rid of this ugliness +#[rustfmt::skip] +pub fn arr_to_mat(arr: [f32; 16]) -> [[f32; 4]; 4] { + [ + [arr[ 0], arr[ 1], arr[ 2], arr[ 3]], + [arr[ 4], arr[ 5], arr[ 6], arr[ 7]], + [arr[ 8], arr[ 9], arr[10], arr[11]], + [arr[12], arr[13], arr[14], arr[15]], + ] +} diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 503b51bd01..8aca51c840 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -21,15 +21,15 @@ impl Camera { Self { focus: Vec3::zero(), ori: Vec3::zero(), - dist: 10.0, + dist: 5.0, fov: 1.3, aspect: 1.618, } } /// Compute the transformation matrices (view matrix and projection matrix) for the camera. - pub fn compute_matrices(&self) -> (Mat4, Mat4) { - let view = Mat4::::identity() + pub fn compute_dependents(&self) -> (Mat4, Mat4, Vec3) { + let view_mat = Mat4::::identity() * Mat4::translation_3d(-Vec3::unit_z() * self.dist) * Mat4::rotation_z(self.ori.z) * Mat4::rotation_x(self.ori.y) @@ -37,13 +37,21 @@ impl Camera { * Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x()) * Mat4::translation_3d(-self.focus); - let proj = Mat4::perspective_rh_no( + let proj_mat = Mat4::perspective_rh_no( self.fov, self.aspect, NEAR_PLANE, FAR_PLANE, ); - (view, proj) + // TODO: Make this more efficient + let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w()); + + (view_mat, proj_mat, cam_pos) } + + /// Get the focus position of the camera. + pub fn get_focus_pos(&self) -> Vec3 { self.focus } + /// Set the focus position of the camera. + pub fn set_focus_pos(&mut self, focus: Vec3) { self.focus = focus; } } diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 27d2a6f0f0..a5cc55783f 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -31,19 +31,36 @@ impl Scene { Self { camera: Camera::new(), globals: renderer - .create_consts_with(Globals::new()) + .create_consts_with(Globals::default()) .unwrap(), skybox: Skybox { model: renderer .create_model(&create_skybox_mesh()) .unwrap(), locals: renderer - .create_consts_with(SkyboxLocals::new()) + .create_consts_with(SkyboxLocals::default()) .unwrap(), }, } } + pub fn maintain_gpu_data(&mut self, renderer: &mut Renderer) { + // Compute camera matrices + let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(); + + // Update global constants + renderer.update_consts(&mut self.globals, Globals::new( + view_mat, + proj_mat, + cam_pos, + self.camera.get_focus_pos(), + 10.0, + 0.0, + 0.0, + )) + .expect("Failed to update global constants"); + } + /// Render the scene using the provided `Renderer` pub fn render_to(&self, renderer: &mut Renderer) { // Render the skybox first (it appears over everything else so must be rendered first) diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index b02a7d0469..4aef16944a 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -31,6 +31,9 @@ const BG_COLOR: Rgba = Rgba { r: 0.0, g: 0.3, b: 1.0, a: 1.0 }; impl PlayState for SessionState { fn play(&mut self, global_state: &mut GlobalState) -> PlayStateResult { + // Trap the cursor + global_state.window.trap_cursor(); + // Game loop loop { // Handle window events @@ -44,6 +47,9 @@ impl PlayState for SessionState { } } + // Maintain scene GPU data + self.scene.maintain_gpu_data(global_state.window.renderer_mut()); + // Clear the screen global_state.window.renderer_mut().clear(BG_COLOR); @@ -52,8 +58,9 @@ impl PlayState for SessionState { // Finish the frame global_state.window.renderer_mut().flush(); - global_state.window.display() - .expect("Failed to display window"); + global_state.window + .swap_buffers() + .expect("Failed to swap window buffers"); } } diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index fc2eb059f7..8d70ce2a77 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -1,6 +1,7 @@ // Library use glutin; use gfx_window_glutin; +use vek::*; // Crate use crate::{ @@ -73,13 +74,30 @@ impl Window { events } - pub fn display(&self) -> Result<(), Error> { + pub fn swap_buffers(&self) -> Result<(), Error> { self.window.swap_buffers() .map_err(|err| Error::BackendError(Box::new(err))) } + + pub fn trap_cursor(&mut self) { + self.window.hide_cursor(true); + self.window.grab_cursor(true) + .expect("Failed to grab cursor"); + } + + pub fn untrap_cursor(&mut self) { + self.window.hide_cursor(false); + self.window.grab_cursor(false) + .expect("Failed to ungrab cursor"); + } } +/// Represents an incoming event from the window pub enum Event { + /// The window has been requested to close. Close, + /// A key has been typed that corresponds to a specific character. Char(char), + /// The cursor has been panned across the screen while trapped. + CursorPan(Vec2), }