Added camera panning and cursor trapping

This commit is contained in:
Joshua Barretto 2019-01-12 13:56:34 +00:00
parent 45d5a0a396
commit 979f47420d
8 changed files with 73 additions and 24 deletions

View File

@ -21,12 +21,14 @@ use crate::{
window::Window, 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 { pub struct GlobalState {
window: Window, window: Window,
} }
impl GlobalState { 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) { pub fn on_play_state_changed(&mut self) {
self.window.untrap_cursor(); self.window.untrap_cursor();
} }

View File

@ -31,14 +31,23 @@ use gfx_device_gl as gfx_backend;
// Library // Library
use gfx; 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)] #[derive(Debug)]
pub enum RenderError { pub enum RenderError {
PipelineError(gfx::PipelineStateError<String>), PipelineError(gfx::PipelineStateError<String>),
UpdateError(gfx::UpdateError<usize>), UpdateError(gfx::UpdateError<usize>),
} }
/// 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 { pub trait Pipeline {
type Vertex: type Vertex:
Clone + Clone +

View File

@ -66,10 +66,10 @@ pub fn create_mesh() -> Mesh<SkyboxPipeline> {
// +x // +x
#[rustfmt::skip] #[rustfmt::skip]
mesh.push_quad(Quad::new( 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] },
Vertex { pos: [ 1.0, -1.0, 1.0] }, Vertex { pos: [ 1.0, -1.0, -1.0] },
)); ));
// -y // -y
#[rustfmt::skip] #[rustfmt::skip]
@ -82,10 +82,10 @@ pub fn create_mesh() -> Mesh<SkyboxPipeline> {
// +y // +y
#[rustfmt::skip] #[rustfmt::skip]
mesh.push_quad(Quad::new( 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] },
Vertex { pos: [ 1.0, 1.0, 1.0] }, Vertex { pos: [ 1.0, 1.0, -1.0] },
)); ));
// -z // -z
#[rustfmt::skip] #[rustfmt::skip]
@ -98,10 +98,10 @@ pub fn create_mesh() -> Mesh<SkyboxPipeline> {
// +z // +z
#[rustfmt::skip] #[rustfmt::skip]
mesh.push_quad(Quad::new( 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] },
Vertex { pos: [-1.0, 1.0, 1.0] }, Vertex { pos: [-1.0, -1.0, 1.0] },
)); ));
mesh mesh

View File

@ -32,7 +32,7 @@ pub type TgtDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, Tg
/// A type that encapsulates rendering state. `Renderer` is central to Voxygen's rendering /// A type that encapsulates rendering state. `Renderer` is central to Voxygen's rendering
/// subsystem and contains any state necessary to interact with the GPU, along with pipeline state /// subsystem and contains any state necessary to interact with the GPU, along with pipeline state
/// objects (PSOs) needed to renderer different kinds of model to the screen. /// objects (PSOs) needed to renderer different kinds of models to the screen.
pub struct Renderer { pub struct Renderer {
device: gfx_backend::Device, device: gfx_backend::Device,
encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>, encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
@ -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( pub fn render_skybox(
&mut self, &mut self,
model: &Model<skybox::SkyboxPipeline>, model: &Model<skybox::SkyboxPipeline>,
@ -152,7 +152,7 @@ struct GfxPipeline<P: gfx::pso::PipelineInit> {
pso: gfx::pso::PipelineState<gfx_backend::Resources, P::Meta>, pso: gfx::pso::PipelineState<gfx_backend::Resources, P::Meta>,
} }
/// 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>( fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
factory: &mut gfx_backend::Factory, factory: &mut gfx_backend::Factory,
pipe: P, pipe: P,

View File

@ -50,6 +50,15 @@ impl Camera {
(view_mat, proj_mat, cam_pos) (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<f32>) {
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. /// Get the focus position of the camera.
pub fn get_focus_pos(&self) -> Vec3<f32> { self.focus } pub fn get_focus_pos(&self) -> Vec3<f32> { self.focus }
/// Set the focus position of the camera. /// Set the focus position of the camera.

View File

@ -1,14 +1,20 @@
pub mod camera; pub mod camera;
// Library
use vek::*;
// Crate // Crate
use crate::render::{ use crate::{
Consts, render::{
Globals, Consts,
Model, Globals,
Renderer, Model,
SkyboxPipeline, Renderer,
SkyboxLocals, SkyboxPipeline,
create_skybox_mesh, SkyboxLocals,
create_skybox_mesh,
},
window::Event,
}; };
// Local // Local
@ -19,6 +25,9 @@ struct Skybox {
locals: Consts<SkyboxLocals>, locals: Consts<SkyboxLocals>,
} }
// TODO: Don't hard-code this
const CURSOR_PAN_SCALE: f32 = 0.005;
pub struct Scene { pub struct Scene {
camera: Camera, camera: Camera,
globals: Consts<Globals>, globals: Consts<Globals>,
@ -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) { pub fn maintain_gpu_data(&mut self, renderer: &mut Renderer) {
// Compute camera matrices // Compute camera matrices
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(); let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();

View File

@ -38,13 +38,14 @@ impl PlayState for SessionState {
loop { loop {
// Handle window events // Handle window events
for event in global_state.window.fetch_events() { for event in global_state.window.fetch_events() {
match event { let _handled = match event {
Event::Close => return PlayStateResult::Shutdown, Event::Close => return PlayStateResult::Shutdown,
// When 'q' is pressed, exit the session // When 'q' is pressed, exit the session
Event::Char('q') => return PlayStateResult::Pop, 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 // Maintain scene GPU data

View File

@ -69,6 +69,11 @@ impl Window {
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)), 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 events