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,
};
// 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();
}

View File

@ -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<String>),
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 {
type Vertex:
Clone +

View File

@ -66,10 +66,10 @@ pub fn create_mesh() -> Mesh<SkyboxPipeline> {
// +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<SkyboxPipeline> {
// +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<SkyboxPipeline> {
// +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

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
/// 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 {
device: gfx_backend::Device,
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(
&mut self,
model: &Model<skybox::SkyboxPipeline>,
@ -152,7 +152,7 @@ struct GfxPipeline<P: gfx::pso::PipelineInit> {
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>(
factory: &mut gfx_backend::Factory,
pipe: P,

View File

@ -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<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.
pub fn get_focus_pos(&self) -> Vec3<f32> { self.focus }
/// Set the focus position of the camera.

View File

@ -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<SkyboxLocals>,
}
// TODO: Don't hard-code this
const CURSOR_PAN_SCALE: f32 = 0.005;
pub struct Scene {
camera: Camera,
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) {
// Compute camera matrices
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();

View File

@ -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

View File

@ -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