#![allow(dead_code)]
use piston::event::GenericEvent;
use vecmath::{ Vector3, vec3_add, vec3_scale };
use vecmath::traits::Float;
use quaternion;
use quaternion::Quaternion;
use piston::input;
use piston::input::Button::{ Keyboard, Mouse };
use piston::input::keyboard::Key;
use piston::input::mouse::MouseButton;
use Camera;
bitflags!(
flags Keys: u8 {
const ZOOM = 0b00000001,
const PAN = 0b00000010,
const ORBIT = 0b00000100,
}
);
pub struct OrbitZoomCameraSettings<T=f32> {
pub orbit_button: input::Button,
pub zoom_button: input::Button,
pub pan_button: input::Button,
pub orbit_speed: T,
pub pitch_speed: T,
pub pan_speed: T,
pub zoom_speed: T,
}
impl<T: Float> OrbitZoomCameraSettings<T> {
pub fn default() -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
orbit_button : Mouse(MouseButton::Left),
zoom_button : Keyboard(Key::LCtrl),
pan_button : Keyboard(Key::LShift),
orbit_speed: T::from_f32(0.05),
pitch_speed: T::from_f32(0.1),
pan_speed: T::from_f32(0.1),
zoom_speed: T::from_f32(0.1),
}
}
pub fn orbit_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
orbit_button: button,
.. self
}
}
pub fn zoom_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
zoom_button: button,
.. self
}
}
pub fn pan_button(self, button: input::Button) -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
pan_button: button,
.. self
}
}
pub fn orbit_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
orbit_speed: s,
.. self
}
}
pub fn pitch_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
pitch_speed: s,
.. self
}
}
pub fn pan_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
pan_speed: s,
.. self
}
}
pub fn zoom_speed(self, s: T) -> OrbitZoomCameraSettings<T> {
OrbitZoomCameraSettings {
zoom_speed: s,
.. self
}
}
}
pub struct OrbitZoomCamera<T=f32> {
pub target: Vector3<T>,
pub rotation: Quaternion<T>,
pub pitch: T,
pub yaw: T,
pub distance: T,
pub settings: OrbitZoomCameraSettings<T>,
keys: Keys,
}
impl<T: Float>
OrbitZoomCamera<T> {
pub fn new(target: [T; 3], settings: OrbitZoomCameraSettings<T>) -> OrbitZoomCamera<T> {
OrbitZoomCamera {
target: target,
rotation: quaternion::id(),
distance: T::from_f32(10.0),
pitch: T::zero(),
yaw: T::zero(),
keys: Keys::empty(),
settings: settings
}
}
pub fn camera(&self, _dt: f64) -> Camera<T> {
let target_to_camera = quaternion::rotate_vector(
self.rotation,
[T::zero(), T::zero(), self.distance]
);
let mut camera = Camera::new(vec3_add(self.target, target_to_camera));
camera.set_rotation(self.rotation);
camera
}
fn control_camera(&mut self, dx: T, dy: T) {
let _1 = T::one();
let _0 = T::zero();
if self.keys.contains(PAN) {
let dx = dx * self.settings.pan_speed;
let dy = dy * self.settings.pan_speed;
let right = quaternion::rotate_vector(self.rotation, [_1, _0, _0]);
let up = quaternion::rotate_vector(self.rotation, [_0, _1, _0]);
self.target = vec3_add(
vec3_add(self.target, vec3_scale(up, dy)),
vec3_scale(right,dx)
);
} else if self.keys.contains(ZOOM) {
self.distance = self.distance + dy * self.settings.zoom_speed;
} else {
let dx = dx * self.settings.orbit_speed;
let dy = dy * self.settings.orbit_speed;
self.yaw = self.yaw + dx;
self.pitch = self.pitch + dy*self.settings.pitch_speed;
self.rotation = quaternion::mul(
quaternion::axis_angle([_0, _1, _0], self.yaw),
quaternion::axis_angle([_1, _0, _0], self.pitch)
);
}
}
pub fn event<E: GenericEvent>(&mut self, e: &E) {
use piston::event::{ MouseRelativeEvent, MouseScrollEvent, PressEvent, ReleaseEvent };
e.mouse_scroll(|dx, dy| {
let dx = T::from_f64(dx);
let dy = T::from_f64(dy);
self.control_camera(dx, dy);
});
e.mouse_relative(|dx, dy| {
let dx = T::from_f64(dx);
let dy = T::from_f64(dy);
if self.keys.contains(ORBIT){
self.control_camera(-dx, dy);
}
});
e.press(|button| {
match button {
x if x == self.settings.orbit_button => self.keys.insert(ORBIT),
x if x == self.settings.pan_button => self.keys.insert(PAN),
x if x == self.settings.zoom_button => self.keys.insert(ZOOM),
_ => {}
}
});
e.release(|button| {
match button {
x if x == self.settings.orbit_button => self.keys.remove(ORBIT),
x if x == self.settings.pan_button => self.keys.remove(PAN),
x if x == self.settings.zoom_button => self.keys.remove(ZOOM),
_ => {}
}
});
}
}