model-converter/src/controls.rs

405 lines
12 KiB
Rust
Raw Normal View History

2018-04-10 15:25:01 +02:00
//! This models contains structs that help move the camera in a user-friendly way.
2018-07-23 10:12:37 +02:00
const EPSILON: f64 = 0.001;
2018-04-10 15:13:35 +02:00
2022-08-14 14:25:17 +02:00
use glium::glutin::dpi::{PhysicalPosition, PhysicalSize};
use glium::glutin::event::{
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, VirtualKeyCode, WindowEvent,
2018-09-18 15:23:51 +02:00
};
2018-04-10 15:13:35 +02:00
2018-04-17 10:45:44 +02:00
use camera::Camera;
2022-08-14 14:25:17 +02:00
use math::vector::{Vector2, Vector3};
2018-04-11 14:13:49 +02:00
use model::Model;
2022-08-14 14:25:17 +02:00
use renderer::Renderer;
2018-04-10 15:13:35 +02:00
/// The trait that all controls should implement.
pub trait Controls {
/// Modifies the camera depending on the event.
2022-08-14 14:25:17 +02:00
fn manage_event(&mut self, event: &Event<()>, camera: &mut Camera, renderer: &Renderer);
2018-04-12 17:23:40 +02:00
/// Updates the camera depending on time.
2018-04-17 10:45:44 +02:00
fn update(&mut self, camera: &mut Camera, renderer: &Renderer);
2018-04-10 15:13:35 +02:00
}
/// An orbit controls allowing to orbit around an object.
///
/// Only object centered are supported.
pub struct OrbitControls {
/// The last position of the mouse.
2018-07-23 10:12:37 +02:00
mouse_position: Vector2<f64>,
2018-04-10 15:13:35 +02:00
/// Wether the left click of the mouse is pressed or not.
pressed: bool,
/// The theta angle of the position of the camera in spheric coordinates.
2018-07-23 10:12:37 +02:00
theta: f64,
2018-04-10 15:13:35 +02:00
/// The phi angle of the position of the camera in spheric coordinates.
2018-07-23 10:12:37 +02:00
phi: f64,
2018-04-10 15:13:35 +02:00
/// The distance between the camera and the origin.
2018-07-23 10:12:37 +02:00
distance: f64,
2018-04-10 15:13:35 +02:00
/// The sensitiviy of the rotation of the mouse.
2018-07-23 10:12:37 +02:00
sensitivity: f64,
2018-04-11 14:13:49 +02:00
/// The center of the object.
2018-07-23 10:12:37 +02:00
center: Vector3<f64>,
2018-04-10 15:13:35 +02:00
}
impl OrbitControls {
/// Creates a new orbit controls, and initializes the camera.
2018-07-23 10:12:37 +02:00
pub fn new(center: Vector3<f64>, distance: f64, camera: &mut Camera) -> OrbitControls {
2018-04-10 15:13:35 +02:00
let controls = OrbitControls {
mouse_position: Vector2::new(0.0, 0.0),
pressed: false,
theta: 0.0,
phi: 0.0,
2018-04-11 14:13:49 +02:00
distance: distance,
2018-04-10 15:13:35 +02:00
sensitivity: 200.0,
2018-04-11 14:13:49 +02:00
center: center,
2018-04-10 15:13:35 +02:00
};
*camera.position.x_mut() = controls.distance * controls.theta.cos();
*camera.position.y_mut() = 0.0;
*camera.position.z_mut() = controls.distance * controls.phi.sin();
2018-04-11 14:13:49 +02:00
camera.position += controls.center;
camera.target = controls.center;
2018-04-10 15:13:35 +02:00
controls
}
2018-04-11 14:13:49 +02:00
/// Creates orbit controls that are mode to rotate around a model.
pub fn around(model: &Model, camera: &mut Camera) -> OrbitControls {
// Compute bounding box
let bounding_box = model.bounding_box();
let center = (bounding_box.min() + bounding_box.max()) / 2.0;
let distance = (bounding_box.max() - bounding_box.min()).norm();
OrbitControls::new(
2018-07-23 10:12:37 +02:00
Vector3::new(center.x() as f64, center.y() as f64, center.z() as f64),
distance as f64,
2022-08-14 14:25:17 +02:00
camera,
2018-04-11 14:13:49 +02:00
)
}
2018-04-10 15:13:35 +02:00
}
impl Controls for OrbitControls {
2022-08-14 14:25:17 +02:00
fn manage_event(&mut self, event: &Event<()>, camera: &mut Camera, _: &Renderer) {
2018-04-10 15:13:35 +02:00
match *event {
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::MouseInput {
button: MouseButton::Left,
state,
..
},
..
2018-04-10 15:13:35 +02:00
} => {
self.pressed = state == ElementState::Pressed;
2022-08-14 14:25:17 +02:00
}
2018-04-10 15:13:35 +02:00
2018-04-11 17:03:32 +02:00
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event: WindowEvent::Resized(PhysicalSize { width, height }),
..
2018-04-11 17:03:32 +02:00
} => {
2018-07-23 10:12:37 +02:00
camera.aspect_ratio = width as f64 / height as f64;
2022-08-14 14:25:17 +02:00
}
2018-04-11 17:03:32 +02:00
2018-04-10 15:13:35 +02:00
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::MouseWheel {
delta: MouseScrollDelta::LineDelta(_, y),
..
},
..
2018-04-10 15:13:35 +02:00
} => {
2018-07-23 10:12:37 +02:00
self.distance -= y as f64 / self.sensitivity;
2018-04-10 15:13:35 +02:00
*camera.position.x_mut() = self.distance * self.phi.cos() * self.theta.cos();
*camera.position.y_mut() = self.distance * self.phi.sin();
*camera.position.z_mut() = self.distance * self.phi.cos() * self.theta.sin();
2018-04-11 14:13:49 +02:00
camera.position += self.center;
camera.target = self.center;
2022-08-14 14:25:17 +02:00
}
2018-04-10 15:13:35 +02:00
2022-08-14 14:25:17 +02:00
Event::WindowEvent {
event:
WindowEvent::CursorMoved {
position: PhysicalPosition { x, y },
..
},
..
2018-04-10 15:13:35 +02:00
} => {
2018-07-23 10:12:37 +02:00
let current_position = Vector2::new(x as f64, y as f64);
2018-04-10 15:13:35 +02:00
if self.pressed {
let difference = (current_position - self.mouse_position) / self.sensitivity;
self.theta += difference.x();
2022-08-14 14:25:17 +02:00
self.phi += difference.y();
2018-04-10 15:13:35 +02:00
2018-07-23 10:12:37 +02:00
use std::f64::consts::PI;
2022-08-14 14:25:17 +02:00
self.phi = self.phi.max(-PI / 2.0 + EPSILON);
self.phi = self.phi.min(PI / 2.0 - EPSILON);
2018-04-10 15:13:35 +02:00
*camera.position.x_mut() = self.distance * self.phi.cos() * self.theta.cos();
*camera.position.y_mut() = self.distance * self.phi.sin();
*camera.position.z_mut() = self.distance * self.phi.cos() * self.theta.sin();
2018-04-11 14:13:49 +02:00
camera.position += self.center;
camera.target = self.center;
2018-04-10 15:13:35 +02:00
}
// Record new position
self.mouse_position = current_position;
2022-08-14 14:25:17 +02:00
}
2018-04-10 15:13:35 +02:00
_ => (),
}
}
2018-04-12 17:23:40 +02:00
2022-08-14 14:25:17 +02:00
fn update(&mut self, _: &mut Camera, _: &Renderer) {}
2018-04-12 17:23:40 +02:00
}
/// First person controls, just like in video games.
pub struct FirstPersonControls {
/// Theta angle of the spheric coordinates of the direction of the camera.
2018-07-23 10:12:37 +02:00
theta: f64,
2018-04-12 17:23:40 +02:00
/// Phi angle of the spheric coordinates of the direction of the camera.
2018-07-23 10:12:37 +02:00
phi: f64,
2018-04-12 17:23:40 +02:00
/// Current position of the camera.
2018-07-23 10:12:37 +02:00
position: Vector3<f64>,
2018-04-12 17:23:40 +02:00
/// Vector indicating the direction of the camera.
2018-07-23 10:12:37 +02:00
forward: Vector3<f64>,
2018-04-12 17:23:40 +02:00
2018-04-12 17:40:49 +02:00
/// Vector indicating the left of the camera.
2018-07-23 10:12:37 +02:00
left: Vector3<f64>,
2018-04-12 17:40:49 +02:00
2018-04-12 17:23:40 +02:00
/// Speed of the camera.
2018-07-23 10:12:37 +02:00
speed: f64,
2018-04-12 17:23:40 +02:00
/// Sensitivity of the mouse.
2018-07-23 10:12:37 +02:00
sensitivity: f64,
2018-04-12 17:23:40 +02:00
/// Wether the forward button is pressed or not.
forward_pressed: bool,
/// Wether the backward button is pressed or not.
backward_pressed: bool,
2018-04-12 17:40:49 +02:00
/// Wether the left button is pressed or not.
left_pressed: bool,
/// Wether the right button is pressed or not.
right_pressed: bool,
/// Wether the boost is active or not.
boost: bool,
2018-04-12 17:23:40 +02:00
}
impl FirstPersonControls {
/// Creates a new default first person controls.
pub fn new() -> FirstPersonControls {
FirstPersonControls {
theta: 0.0,
phi: 0.0,
position: Vector3::new(0.0, 0.0, 0.0),
forward: Vector3::new(0.0, 0.0, 1.0),
2018-04-12 17:40:49 +02:00
left: Vector3::new(1.0, 0.0, 0.0),
2018-04-12 17:23:40 +02:00
speed: 0.001,
forward_pressed: false,
backward_pressed: false,
2018-04-12 17:40:49 +02:00
left_pressed: false,
right_pressed: false,
boost: false,
2018-04-12 17:23:40 +02:00
sensitivity: 500.0,
}
}
/// Updates the camera according to the state of the controls.
2018-06-12 17:22:16 +02:00
pub fn update_camera(&self, camera: &mut Camera) {
2018-04-12 17:23:40 +02:00
camera.position = self.position;
camera.target = self.position + self.forward;
}
}
impl Controls for FirstPersonControls {
2022-08-14 14:25:17 +02:00
fn manage_event(&mut self, event: &Event<()>, camera: &mut Camera, renderer: &Renderer) {
2018-04-12 17:23:40 +02:00
match *event {
// On resize window
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event: WindowEvent::Resized(PhysicalSize { width, height }),
..
2018-04-12 17:23:40 +02:00
} => {
2018-07-23 10:12:37 +02:00
camera.aspect_ratio = width as f64 / height as f64;
2022-08-14 14:25:17 +02:00
}
2018-04-12 17:23:40 +02:00
// On Z pressed
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Z),
state,
..
},
..
},
..
2018-04-12 17:23:40 +02:00
} => {
self.forward_pressed = state == ElementState::Pressed;
2022-08-14 14:25:17 +02:00
}
2018-04-12 17:23:40 +02:00
// On S pressed
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::S),
state,
..
},
..
},
..
2018-04-12 17:23:40 +02:00
} => {
self.backward_pressed = state == ElementState::Pressed;
2022-08-14 14:25:17 +02:00
}
2018-04-12 17:23:40 +02:00
2018-04-12 17:40:49 +02:00
// On Q pressed
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Q),
state,
..
},
..
},
..
2018-04-12 17:40:49 +02:00
} => {
self.left_pressed = state == ElementState::Pressed;
2022-08-14 14:25:17 +02:00
}
2018-04-12 17:40:49 +02:00
// On D pressed
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::D),
state,
..
},
..
},
..
2018-04-12 17:40:49 +02:00
} => {
self.right_pressed = state == ElementState::Pressed;
2022-08-14 14:25:17 +02:00
}
2018-04-12 17:40:49 +02:00
// On Space pressed
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Space),
state,
..
},
..
},
..
2018-04-12 17:40:49 +02:00
} => {
self.boost = state == ElementState::Pressed;
2022-08-14 14:25:17 +02:00
}
2018-04-12 17:40:49 +02:00
2018-04-12 17:23:40 +02:00
// On mouse move
Event::WindowEvent {
2022-08-14 14:25:17 +02:00
event:
WindowEvent::CursorMoved {
position: PhysicalPosition { x, y },
..
},
..
2018-04-12 17:23:40 +02:00
} => {
2022-08-14 14:25:17 +02:00
let size = renderer.gl_window().window().inner_size();
2018-09-18 15:23:51 +02:00
let center = Vector2::new(size.width as f64 / 2.0, size.height as f64 / 2.0);
2018-07-23 10:12:37 +02:00
let current_position = Vector2::new(x as f64, y as f64);
2018-04-12 17:23:40 +02:00
let difference = (current_position - center) / self.sensitivity;
self.theta += difference.x();
2022-08-14 14:25:17 +02:00
self.phi -= difference.y();
2018-04-12 17:23:40 +02:00
2018-07-23 10:12:37 +02:00
use std::f64::consts::PI;
2022-08-14 14:25:17 +02:00
self.phi = self.phi.max(-PI / 2.0 + EPSILON);
self.phi = self.phi.min(PI / 2.0 - EPSILON);
2018-04-12 17:23:40 +02:00
self.forward = Vector3::new(
self.phi.cos() * self.theta.cos(),
self.phi.sin(),
self.phi.cos() * self.theta.sin(),
);
2022-08-14 14:25:17 +02:00
self.left = Vector3::new(0.0, 1.0, 0.0)
.cross_product(self.forward)
.normalized();
2018-04-12 17:40:49 +02:00
2018-04-12 17:23:40 +02:00
// Move the cursor back to the center
renderer
.gl_window()
.window()
2022-08-14 14:25:17 +02:00
.set_cursor_position(PhysicalPosition::new(
size.width as f64 / 2.0,
size.height as f64 / 2.0,
))
2018-04-12 17:23:40 +02:00
.unwrap();
2022-08-14 14:25:17 +02:00
}
2018-04-12 17:23:40 +02:00
_ => (),
}
self.update_camera(camera);
}
2018-04-17 10:45:44 +02:00
fn update(&mut self, camera: &mut Camera, renderer: &Renderer) {
2022-08-14 14:25:17 +02:00
renderer.gl_window().window().set_cursor_visible(false);
2018-04-12 17:40:49 +02:00
let mut speed = Vector3::new(0.0, 0.0, 0.0);
2018-04-12 17:23:40 +02:00
if self.forward_pressed {
2018-04-12 17:40:49 +02:00
speed += self.forward * self.speed;
2018-04-12 17:23:40 +02:00
}
if self.backward_pressed {
2018-04-12 17:40:49 +02:00
speed -= self.forward * self.speed;
2018-04-12 17:23:40 +02:00
}
2018-04-12 17:40:49 +02:00
if self.left_pressed {
speed += self.left * self.speed;
}
if self.right_pressed {
speed -= self.left * self.speed;
}
if self.boost {
speed *= 10.0;
}
self.position += speed;
2018-04-12 17:23:40 +02:00
self.update_camera(camera);
}
2018-04-10 15:13:35 +02:00
}