diff --git a/voxygen/src/main.rs b/voxygen/src/main.rs index 0cc40a4c79..223534fd77 100644 --- a/voxygen/src/main.rs +++ b/voxygen/src/main.rs @@ -21,12 +21,14 @@ use crate::{ window::Window, }; -// A type used to store state that is shared between all play states +/// A type used to store state that is shared between all play states pub struct GlobalState { window: Window, } impl GlobalState { + /// Called after a change in play state has occured (usually used to reverse any temporary + /// effects a state may have made). pub fn on_play_state_changed(&mut self) { self.window.untrap_cursor(); } diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 459be2ac0e..0faf4dc7b0 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -31,14 +31,23 @@ use gfx_device_gl as gfx_backend; // Library use gfx; -/// Used to represent one of many possible errors that may be omitted by the rendering code +/// Used to represent one of many possible errors that may be omitted by the rendering subsystem #[derive(Debug)] pub enum RenderError { PipelineError(gfx::PipelineStateError), UpdateError(gfx::UpdateError), } -/// Used to represent a specific rendering configuration +/// Used to represent a specific rendering configuration. +/// +/// Note that pipelines are tied to the +/// rendering backend, and as such it is necessary to modify the rendering subsystem when adding +/// new pipelines - custom pipelines are not currently an objective of the rendering subsystem. +/// +/// # Examples +/// +/// - `SkyboxPipeline` +/// - `CharacterPipeline` pub trait Pipeline { type Vertex: Clone + diff --git a/voxygen/src/render/pipelines/skybox.rs b/voxygen/src/render/pipelines/skybox.rs index 2e6c4c1856..c39a2b3ce6 100644 --- a/voxygen/src/render/pipelines/skybox.rs +++ b/voxygen/src/render/pipelines/skybox.rs @@ -66,10 +66,10 @@ pub fn create_mesh() -> Mesh { // +x #[rustfmt::skip] mesh.push_quad(Quad::new( - Vertex { pos: [ 1.0, -1.0, -1.0] }, + Vertex { pos: [ 1.0, -1.0, 1.0] }, Vertex { pos: [ 1.0, 1.0, 1.0] }, Vertex { pos: [ 1.0, 1.0, -1.0] }, - Vertex { pos: [ 1.0, -1.0, 1.0] }, + Vertex { pos: [ 1.0, -1.0, -1.0] }, )); // -y #[rustfmt::skip] @@ -82,10 +82,10 @@ pub fn create_mesh() -> Mesh { // +y #[rustfmt::skip] mesh.push_quad(Quad::new( - Vertex { pos: [ 1.0, 1.0, -1.0] }, + Vertex { pos: [ 1.0, 1.0, 1.0] }, Vertex { pos: [-1.0, 1.0, 1.0] }, Vertex { pos: [-1.0, 1.0, -1.0] }, - Vertex { pos: [ 1.0, 1.0, 1.0] }, + Vertex { pos: [ 1.0, 1.0, -1.0] }, )); // -z #[rustfmt::skip] @@ -98,10 +98,10 @@ pub fn create_mesh() -> Mesh { // +z #[rustfmt::skip] mesh.push_quad(Quad::new( - Vertex { pos: [-1.0, -1.0, 1.0] }, + Vertex { pos: [-1.0, 1.0, 1.0] }, Vertex { pos: [ 1.0, 1.0, 1.0] }, Vertex { pos: [ 1.0, -1.0, 1.0] }, - Vertex { pos: [-1.0, 1.0, 1.0] }, + Vertex { pos: [-1.0, -1.0, 1.0] }, )); mesh diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs index 7388bdfc61..dc9ed54109 100644 --- a/voxygen/src/render/renderer.rs +++ b/voxygen/src/render/renderer.rs @@ -32,7 +32,7 @@ pub type TgtDepthView = gfx::handle::DepthStencilView, @@ -127,7 +127,7 @@ impl Renderer { )) } - /// Queue the rendering of the provided skybox model in the upcoming frame + /// Queue the rendering of the provided skybox model in the upcoming frame. pub fn render_skybox( &mut self, model: &Model, @@ -152,7 +152,7 @@ struct GfxPipeline { pso: gfx::pso::PipelineState, } -/// Create a new pipeline from the provided vertex shader and fragment shader +/// Create a new pipeline from the provided vertex shader and fragment shader. fn create_pipeline<'a, P: gfx::pso::PipelineInit>( factory: &mut gfx_backend::Factory, pipe: P, diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 8aca51c840..5eca5669ce 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -50,6 +50,15 @@ impl Camera { (view_mat, proj_mat, cam_pos) } + /// Rotate the camera about its focus by the given delta, limiting the input accordingly. + pub fn rotate_by(&mut self, delta: Vec3) { + self.ori += delta; + // Clamp camera pitch to the vertical limits + self.ori.y = self.ori.y + .min(PI / 2.0) + .max(-PI / 2.0); + } + /// Get the focus position of the camera. pub fn get_focus_pos(&self) -> Vec3 { self.focus } /// Set the focus position of the camera. diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index a5cc55783f..86f9d62129 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -1,14 +1,20 @@ pub mod camera; +// Library +use vek::*; + // Crate -use crate::render::{ - Consts, - Globals, - Model, - Renderer, - SkyboxPipeline, - SkyboxLocals, - create_skybox_mesh, +use crate::{ + render::{ + Consts, + Globals, + Model, + Renderer, + SkyboxPipeline, + SkyboxLocals, + create_skybox_mesh, + }, + window::Event, }; // Local @@ -19,6 +25,9 @@ struct Skybox { locals: Consts, } +// TODO: Don't hard-code this +const CURSOR_PAN_SCALE: f32 = 0.005; + pub struct Scene { camera: Camera, globals: Consts, @@ -44,6 +53,20 @@ impl Scene { } } + /// Handle an incoming user input event (i.e: cursor moved, key pressed, window closed, etc.). + pub fn handle_input_event(&mut self, event: Event) -> bool { + match event { + // Panning the cursor makes the camera rotate + Event::CursorPan(delta) => { + self.camera.rotate_by(Vec3::from(delta) * CURSOR_PAN_SCALE); + true + }, + // All other events are unhandled + _ => false, + } + } + + /// Maintain and update GPU data such as constant buffers, models, etc. pub fn maintain_gpu_data(&mut self, renderer: &mut Renderer) { // Compute camera matrices let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(); diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 4aef16944a..e5f8968e17 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -38,13 +38,14 @@ impl PlayState for SessionState { loop { // Handle window events for event in global_state.window.fetch_events() { - match event { + let _handled = match event { Event::Close => return PlayStateResult::Shutdown, // When 'q' is pressed, exit the session Event::Char('q') => return PlayStateResult::Pop, - // Ignore all other events - _ => {}, - } + // Pass all other events to the scene + event => self.scene.handle_input_event(event), + }; + // TODO: Do something if the event wasn't handled? } // Maintain scene GPU data diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs index 8d70ce2a77..d2a88be1b5 100644 --- a/voxygen/src/window.rs +++ b/voxygen/src/window.rs @@ -69,6 +69,11 @@ impl Window { glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)), _ => {}, }, + glutin::Event::DeviceEvent { event, .. } => match event { + glutin::DeviceEvent::MouseMotion { delta: (dx, dy), .. } => + events.push(Event::CursorPan(Vec2::new(dx as f32, dy as f32))), + _ => {}, + }, _ => {}, }); events