Somewhat working camera controller
This commit is contained in:
@@ -1,27 +1,23 @@
|
||||
use winit::event::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct IsPressed(bool);
|
||||
|
||||
impl From<bool> for IsPressed {
|
||||
fn from(item: bool) -> Self {
|
||||
IsPressed(item)
|
||||
}
|
||||
}
|
||||
use cgmath::Vector2;
|
||||
use cgmath::Point3;
|
||||
use winit::{dpi::PhysicalPosition, event::*};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ButtonPress {
|
||||
Up(IsPressed),
|
||||
Down(IsPressed),
|
||||
Left(IsPressed),
|
||||
Right(IsPressed),
|
||||
Forward(IsPressed),
|
||||
Backward(IsPressed),
|
||||
Up(ElementState),
|
||||
Down(ElementState),
|
||||
Left(ElementState),
|
||||
Right(ElementState),
|
||||
Forward(ElementState),
|
||||
Backward(ElementState),
|
||||
Reset(ElementState),
|
||||
}
|
||||
|
||||
pub struct CameraController {
|
||||
speed: f32,
|
||||
button_press: Option<ButtonPress>,
|
||||
old_mouse: PhysicalPosition<f64>,
|
||||
mouse_movement: Vector2<f64>,
|
||||
}
|
||||
|
||||
impl CameraController {
|
||||
@@ -29,10 +25,12 @@ impl CameraController {
|
||||
Self {
|
||||
speed,
|
||||
button_press: None,
|
||||
old_mouse: PhysicalPosition::new(0.0, 0.0),
|
||||
mouse_movement: Vector2::new(0.0, 0.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_events(&mut self, event: &WindowEvent) -> bool {
|
||||
pub fn input(&mut self, event: &WindowEvent) {
|
||||
match event {
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
@@ -42,55 +40,103 @@ impl CameraController {
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
let pressed = (*state == ElementState::Pressed).into();
|
||||
match key {
|
||||
} => match key {
|
||||
VirtualKeyCode::W => {
|
||||
self.button_press = Some(ButtonPress::Forward(pressed));
|
||||
true
|
||||
self.button_press = Some(ButtonPress::Forward(*state));
|
||||
}
|
||||
VirtualKeyCode::A => {
|
||||
self.button_press = Some(ButtonPress::Left(pressed));
|
||||
true
|
||||
self.button_press = Some(ButtonPress::Left(*state));
|
||||
}
|
||||
VirtualKeyCode::S => {
|
||||
self.button_press = Some(ButtonPress::Backward(pressed));
|
||||
true
|
||||
self.button_press = Some(ButtonPress::Backward(*state));
|
||||
}
|
||||
VirtualKeyCode::D => {
|
||||
self.button_press = Some(ButtonPress::Right(pressed));
|
||||
true
|
||||
self.button_press = Some(ButtonPress::Right(*state));
|
||||
}
|
||||
VirtualKeyCode::Space => {
|
||||
self.button_press = Some(ButtonPress::Up(pressed));
|
||||
true
|
||||
self.button_press = Some(ButtonPress::Up(*state));
|
||||
}
|
||||
VirtualKeyCode::LShift => {
|
||||
self.button_press = Some(ButtonPress::Down(pressed));
|
||||
true
|
||||
self.button_press = Some(ButtonPress::Down(*state));
|
||||
}
|
||||
_ => false,
|
||||
VirtualKeyCode::Return => {
|
||||
self.button_press = Some(ButtonPress::Reset(*state));
|
||||
}
|
||||
_ => {},
|
||||
},
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
self.mouse_movement = Vector2 {
|
||||
x: (*position).x - self.old_mouse.x,
|
||||
y: (*position).y - self.old_mouse.y,
|
||||
};
|
||||
|
||||
self.old_mouse = *position;
|
||||
}
|
||||
_ => false,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_camera(&self, camera: &mut crate::camera::Camera) {
|
||||
/// Update the camera vectors
|
||||
/// Vectors are casted from (0, 0, 0) to both the target and the eye
|
||||
pub fn update_camera(&mut self, camera: &mut crate::camera::Camera) {
|
||||
// TODO what about delta time?
|
||||
use cgmath::InnerSpace;
|
||||
// Casted eye -> target
|
||||
let forward = camera.target - camera.eye;
|
||||
let forward_norm = forward.normalize();
|
||||
let forward_mag = forward.magnitude();
|
||||
|
||||
// cross product of forwards and up => perpendicular right
|
||||
let right = forward_norm.cross(camera.up);
|
||||
let right_norm = right.normalize();
|
||||
|
||||
match self.button_press {
|
||||
Some(ButtonPress::Forward(IsPressed(true))) if forward_mag > self.speed => {
|
||||
// keyboard buttons:
|
||||
// target stays in place
|
||||
// eye moves
|
||||
// check movement vector, if too close
|
||||
Some(ButtonPress::Forward(ElementState::Pressed)) if forward_mag > self.speed => {
|
||||
camera.eye += forward_norm * self.speed;
|
||||
}
|
||||
Some(ButtonPress::Backward(IsPressed(true))) => {
|
||||
Some(ButtonPress::Backward(ElementState::Pressed)) => {
|
||||
camera.eye -= forward_norm * self.speed;
|
||||
}
|
||||
Some(ButtonPress::Right(ElementState::Pressed)) => {
|
||||
let vector = right_norm * self.speed;
|
||||
camera.eye += vector;
|
||||
camera.target += vector;
|
||||
}
|
||||
Some(ButtonPress::Left(ElementState::Pressed)) => {
|
||||
let vector = right_norm * self.speed;
|
||||
camera.eye -= vector;
|
||||
camera.target -= vector;
|
||||
}
|
||||
Some(ButtonPress::Up(ElementState::Pressed)) => {
|
||||
let vector = camera.up.normalize() * self.speed;
|
||||
camera.eye += vector;
|
||||
camera.target += vector;
|
||||
}
|
||||
Some(ButtonPress::Down(ElementState::Pressed)) => {
|
||||
let vector = camera.up.normalize() * self.speed;
|
||||
camera.eye -= vector;
|
||||
camera.target -= vector;
|
||||
}
|
||||
Some(ButtonPress::Reset(ElementState::Pressed)) => {
|
||||
camera.target = Point3::new(0.0, 0.0, 0.0);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// TODO add rest of the movement
|
||||
|
||||
// mouse movement:
|
||||
// target moves
|
||||
// eye stays in place
|
||||
let decr = 200.0;
|
||||
camera.target.x += (self.mouse_movement.x as f32) / decr;
|
||||
camera.target.y -= (self.mouse_movement.y as f32) / decr;
|
||||
self.mouse_movement = Vector2 { x: 0.0, y: 0.0 };
|
||||
|
||||
dbg!(&camera.eye);
|
||||
dbg!(&camera.target);
|
||||
dbg!(self.mouse_movement);
|
||||
}
|
||||
}
|
||||
|
||||
44
src/main.rs
44
src/main.rs
@@ -1,8 +1,4 @@
|
||||
use winit::{
|
||||
event::*,
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::WindowBuilder,
|
||||
};
|
||||
use winit::{dpi::PhysicalPosition, event::*, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder};
|
||||
|
||||
mod state;
|
||||
mod vertex;
|
||||
@@ -16,7 +12,12 @@ use crate::state::State;
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
let mut window = WindowBuilder::new()
|
||||
.build(&event_loop)
|
||||
.unwrap();
|
||||
//window.set_cursor_visible(false);
|
||||
//window.set_cursor_grab(true).unwrap();
|
||||
|
||||
// wait until Future is ready
|
||||
let mut state = pollster::block_on(State::new(&window));
|
||||
|
||||
@@ -24,33 +25,14 @@ fn main() {
|
||||
Event::WindowEvent {
|
||||
ref event, // forward event
|
||||
window_id
|
||||
} if window_id == window.id() // be sure to only use the current one
|
||||
=> if !state.input(event) { // don't continue if input hasn't been processed yet
|
||||
match event {
|
||||
// TODO can't this be moved to state.input()
|
||||
WindowEvent::CloseRequested |
|
||||
WindowEvent::KeyboardInput {
|
||||
input: KeyboardInput {
|
||||
state: ElementState::Pressed,
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
// ignore the other entries
|
||||
..
|
||||
},
|
||||
// ignore the other entries
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::Resized(physical_size) => {
|
||||
state.resize(*physical_size)
|
||||
},
|
||||
WindowEvent::ScaleFactorChanged {new_inner_size, ..} => {
|
||||
state.resize(**new_inner_size);
|
||||
},
|
||||
// Discard all other WindowEvents
|
||||
_ => {}
|
||||
} if window_id == window.id() => {
|
||||
state.input(event, control_flow);
|
||||
}
|
||||
},
|
||||
Event::RedrawRequested(_) => {
|
||||
state.update();
|
||||
// update the entire scene
|
||||
state.update(&mut window);
|
||||
|
||||
// render the update
|
||||
match state.render() {
|
||||
Ok(_) => {},
|
||||
// recreate swap_chain
|
||||
|
||||
38
src/state.rs
38
src/state.rs
@@ -2,10 +2,7 @@ use wgpu::{
|
||||
PrimitiveTopology,
|
||||
util::DeviceExt,
|
||||
};
|
||||
use winit::{
|
||||
event::*,
|
||||
window::Window,
|
||||
};
|
||||
use winit::{dpi::PhysicalPosition, event::*, window::Window, event_loop::{ControlFlow}};
|
||||
|
||||
/// Hold state with important information
|
||||
pub struct State {
|
||||
@@ -135,7 +132,7 @@ impl State {
|
||||
// x, y, z
|
||||
// 1 up, 2 back
|
||||
// +z is out of the screen
|
||||
eye: (0.0, 1.0, 2.0).into(),
|
||||
eye: (0.0, 0.0, 2.0).into(),
|
||||
// look at the center
|
||||
target: (0.0, 0.0, 0.0).into(),
|
||||
// which way is up
|
||||
@@ -307,9 +304,26 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
/// Idicate, whether an event has been fully processed
|
||||
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
||||
/// Process input of the WindowEvent
|
||||
pub fn input(&mut self, event: &WindowEvent, control_flow: &mut ControlFlow) {
|
||||
match event {
|
||||
WindowEvent::CloseRequested |
|
||||
WindowEvent::KeyboardInput {
|
||||
input: KeyboardInput {
|
||||
state: ElementState::Pressed,
|
||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||
// ignore the other entries
|
||||
..
|
||||
},
|
||||
// ignore the other entries
|
||||
..
|
||||
} => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::Resized(physical_size) => {
|
||||
self.resize(*physical_size)
|
||||
},
|
||||
WindowEvent::ScaleFactorChanged {new_inner_size, ..} => {
|
||||
self.resize(**new_inner_size);
|
||||
},
|
||||
// WindowEvent::CursorMoved { position, .. } => {
|
||||
// let x = (position.x as f64) / self.size.width as f64;
|
||||
// let y = (position.y as f64) / self.size.height as f64;
|
||||
@@ -327,14 +341,20 @@ impl State {
|
||||
// self.use_pentagon = !self.use_pentagon;
|
||||
// true
|
||||
// }
|
||||
_ => self.camera_controller.process_events(event)
|
||||
_ => self.camera_controller.input(event)
|
||||
}
|
||||
}
|
||||
|
||||
/// Update State before render()
|
||||
pub fn update(&mut self) {
|
||||
pub fn update(&mut self, window: &mut winit::window::Window) {
|
||||
// reposition camera
|
||||
self.camera_controller.update_camera(&mut self.camera);
|
||||
// always move cursor back to center after controller update,
|
||||
// so we don't loose it
|
||||
window.set_cursor_position(PhysicalPosition::new(
|
||||
self.size.width / 2,
|
||||
self.size.height / 2,
|
||||
)).unwrap();
|
||||
// update projection for uniform buffer
|
||||
self.uniform.update_view_proj(&self.camera);
|
||||
// write uniform buffer to queue
|
||||
|
||||
Reference in New Issue
Block a user