model-converter/src/renderer/controls.rs

151 lines
4.6 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-04-10 15:13:35 +02:00
const EPSILON: f32 = 0.001;
use glium::glutin::{
Event,
WindowEvent,
ElementState,
MouseButton,
MouseScrollDelta,
};
2018-04-11 14:13:49 +02:00
use math::vector::{Vector2, Vector3};
2018-04-10 15:13:35 +02:00
use renderer::camera::Camera;
2018-04-11 14:13:49 +02:00
use model::Model;
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.
fn manage_event(&mut self, event: &Event, camera: &mut Camera);
}
/// An orbit controls allowing to orbit around an object.
///
/// Only object centered are supported.
pub struct OrbitControls {
/// The last position of the mouse.
mouse_position: Vector2<f32>,
/// 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.
theta: f32,
/// The phi angle of the position of the camera in spheric coordinates.
phi: f32,
/// The distance between the camera and the origin.
distance: f32,
/// The sensitiviy of the rotation of the mouse.
sensitivity: f32,
2018-04-11 14:13:49 +02:00
/// The center of the object.
center: Vector3<f32>,
2018-04-10 15:13:35 +02:00
}
impl OrbitControls {
/// Creates a new orbit controls, and initializes the camera.
2018-04-11 14:13:49 +02:00
pub fn new(center: Vector3<f32>, distance: f32, 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(
Vector3::new(center.x() as f32, center.y() as f32, center.z() as f32),
distance as f32,
camera
)
}
2018-04-10 15:13:35 +02:00
}
impl Controls for OrbitControls {
fn manage_event(&mut self, event: &Event, camera: &mut Camera) {
match *event {
Event::WindowEvent {
event: WindowEvent::MouseInput {
button: MouseButton::Left,
state, ..
}, ..
} => {
self.pressed = state == ElementState::Pressed;
},
Event::WindowEvent {
event: WindowEvent::MouseWheel {
delta: MouseScrollDelta::LineDelta(_, y), ..
}, ..
} => {
self.distance -= y;
*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
},
Event::WindowEvent{
event: WindowEvent::CursorMoved {
position: (x, y), ..
}, ..
} => {
let current_position = Vector2::new(x as f32, y as f32);
if self.pressed {
let difference = (current_position - self.mouse_position) / self.sensitivity;
self.theta += difference.x();
self.phi += difference.y();
use std::f32::consts::PI;
self.phi = self.phi.max(- PI/2.0 + EPSILON);
self.phi = self.phi.min( PI/2.0 - EPSILON);
*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;
},
_ => (),
}
}
}