use na::*;
use angle::{Deg, Rad, Angle};
use super::{node, Node, NodeRef, NodeMut};
use window;
use util::ValueCache;
#[derive(Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Camera{
node: Node,
view: Mat4,
projection: Mat4,
proj_view: Mat4,
aspect_ratio: f32,
znear: f32,
zfar: f32,
fov: Deg<f32>,
target: ValueCache<Pnt3>,
up: Unit<Vec3>,
}
pub struct Builder{
eye: Pnt3,
look_at: Pnt3,
fov: Deg<f32>,
aspect_ratio: f32,
znear_far: Option<(f32,f32)>,
up: Unit<Vec3>,
}
impl Builder{
pub fn new(aspect_ratio: f32) -> Builder{
Builder{
eye: origin(),
look_at: pnt3(0., 0., -1.),
fov: Deg(60f32),
aspect_ratio: aspect_ratio,
znear_far: None,
up: Unit::new_unchecked(Vec3::y()),
}
}
pub fn from_window(window: &mut window::WindowT) -> Builder{
Builder::new(window.aspect_ratio())
}
pub fn clip_planes(&mut self, znear: f32, zfar: f32) -> &mut Builder{
self.znear_far = Some((znear, zfar));
self
}
pub fn up_axis(&mut self, up: Unit<Vec3>) -> &mut Builder{
self.up = up;
self
}
pub fn position(&mut self, pos: Pnt3) -> &mut Builder{
self.eye = pos;
self
}
pub fn look_at(&mut self, target: Pnt3) -> &mut Builder{
self.look_at = target;
self
}
pub fn fov(&mut self, fov: Deg<f32>) -> &mut Builder{
self.fov = fov;
self
}
pub fn aspect_ratio(&mut self, aspect_ratio: f32) -> &mut Builder{
self.aspect_ratio = aspect_ratio;
self
}
pub fn create(&self) -> Camera{
if let Some((near, far)) = self.znear_far{
Camera::new_with_frustum(self.eye, self.look_at, self.up, self.fov, self.aspect_ratio, near, far)
}else{
Camera::new(self.eye, self.look_at, self.up, self.fov, self.aspect_ratio)
}
}
}
impl Camera{
pub fn new(eye: Pnt3, look_at: Pnt3, up: Unit<Vec3>, fov: Deg<f32>, aspect_ratio: f32) -> Camera {
let half_fov = fov/2.0;
let tan = half_fov.tan();
let dist = norm(&(look_at-eye)) / tan;
let znear = dist / 100.0;
let zfar = dist * 10.0;
Camera::new_with_frustum(eye, look_at, up, fov, aspect_ratio, znear, zfar)
}
pub fn new_with_frustum(eye: Pnt3,
look_at: Pnt3,
up: Unit<Vec3>,
fov: Deg<f32>,
aspect_ratio: f32,
znear: f32,
zfar: f32) -> Camera {
let node = Node::new_look_at(eye, look_at, *up);
let view = node.inv_global_transformation();
let mut camera = Camera {
fov: fov.to_deg(),
znear: znear,
zfar: zfar,
view: view,
aspect_ratio: aspect_ratio,
proj_view: one(),
projection: one(),
target: ValueCache::new(look_at),
up: up,
node: node
};
camera.refresh_projection();
camera
}
pub fn projection(&self) -> Mat4{
self.projection
}
pub fn view(&self) -> Mat4{
self.view
}
pub fn projection_view(&self) -> Mat4{
self.proj_view
}
pub fn fov(&self) -> Deg<f32>{
self.fov
}
pub fn set_fov(&mut self, fov: Deg<f32>){
self.fov = fov;
self.refresh_projection();
}
pub fn near_far_clip(&self) -> (f32,f32){
(self.znear, self.zfar)
}
pub fn near_clip(&self) -> f32{
self.znear
}
pub fn far_clip(&self) -> f32{
self.zfar
}
pub fn set_near(&mut self, near: f32){
self.znear = near;
self.refresh_projection();
}
pub fn set_far(&mut self, far: f32){
self.zfar = far;
self.refresh_projection();
}
pub fn set_near_far(&mut self, near: f32, far: f32){
self.znear = near;
self.zfar = far;
self.refresh_projection();
}
pub fn set_aspect_ratio(&mut self, aspect: f32){
self.aspect_ratio = aspect;
}
pub fn target(&self) -> &Pnt3{
&self.target
}
pub fn set_target(&mut self, target: Pnt3){
*self.target = target;
}
pub fn update(&mut self) -> bool{
self.update_with_parent_flags(None, super::node::Flags::empty())
}
fn refresh_projection(&mut self){
let proj = Perspective3::new(self.aspect_ratio, self.fov.to_rad().value(), self.znear, self.zfar);
self.projection = *proj.as_matrix();
self.proj_view = self.projection * self.view;
}
}
impl NodeRef for Camera {
fn node(&self) -> &Node{
&self.node
}
}
impl NodeMut for Camera{
fn node_mut(&mut self) -> &mut Node{
&mut self.node
}
fn update_with_parent_flags(&mut self, parent: Option<&Node>, flags: node::Flags) -> bool{
if self.target.has_changed(){
self.node.look_at(&self.target, &self.up);
}
self.target.update();
if self.node.update_with_parent_flags(parent, flags) {
self.view = self.node.global_transformation().fast_orthonormal_inverse();
self.proj_view = self.projection * self.view;
true
}else{
false
}
}
fn update_with_parent(&mut self, parent: Option<&Node>) -> bool{
self.update_with_parent_flags(parent, node::Flags::empty())
}
fn look_at(&mut self, at: &Pnt3, up: &Vec3){
*self.target = *at;
self.up = Unit::new_unchecked(*up);
self.node_mut().look_at(at, up);
}
fn rotate(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
let orientation = UnitQuat::from_axis_angle(axis, angle.value());
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().append_orientation(&orientation);
}
fn append_orientation(&mut self, orientation: &UnitQuat){
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().append_orientation(orientation);
}
fn tilt(&mut self, angle: Rad<f32>){
let axis = self.x_axis();
self.node_mut().rotate(angle, &axis);
}
fn pan(&mut self, angle: Rad<f32>){
let axis = self.y_axis();
self.node_mut().rotate(angle, &axis);
}
fn roll(&mut self, angle: Rad<f32>){
let axis = self.z_axis();
self.node_mut().rotate(angle, &axis);
}
fn set_scale(&mut self, _: Vec3){
}
fn translate(&mut self, t: &Vec3){
self.node_mut().translate(t);
*self.target += *t;
}
fn set_position(&mut self, pos: Pnt3){
let diff = pos - self.position().to_vec();
self.node_mut().set_position(pos);
*self.target += diff.to_vec();
}
fn set_angle_axis(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
let orientation = UnitQuat::from_axis_angle(axis, angle.value());
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().set_orientation(orientation);
}
fn set_orientation(&mut self, orientation: UnitQuat){
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().set_orientation(orientation);
}
}
pub trait CameraExt: NodeRef + NodeMut {
fn projection(&self) -> Mat4;
fn view(&self) -> Mat4;
fn projection_view(&self) -> Mat4;
fn fov(&self) -> Option<Deg<f32>>;
fn width(&self) -> Option<f32>;
fn near_far_clip(&self) -> (f32,f32);
fn near_clip(&self) -> f32;
fn far_clip(&self) -> f32;
fn target(&self) -> &Pnt3;
fn up(&self) -> &Unit<Vec3>;
fn aspect_ratio(&self) -> f32;
fn set_near(&mut self, near: f32);
fn set_far(&mut self, far: f32);
fn set_near_far(&mut self, near: f32, far: f32);
fn set_aspect_ratio(&mut self, aspect: f32);
fn set_target(&mut self, target: Pnt3);
fn update(&mut self) -> bool;
}
pub trait CameraPerspective: CameraExt {
fn set_fov(&mut self, fov: Deg<f32>);
}
pub trait CameraOrthographic: CameraExt{
fn set_width(&mut self, width: f32);
}
impl CameraExt for Camera{
fn projection(&self) -> Mat4{
self.projection
}
fn view(&self) -> Mat4{
self.view
}
fn projection_view(&self) -> Mat4{
self.proj_view
}
fn fov(&self) -> Option<Deg<f32>>{
Some(self.fov)
}
fn width(&self) -> Option<f32>{
None
}
fn near_far_clip(&self) -> (f32,f32){
(self.znear, self.zfar)
}
fn near_clip(&self) -> f32{
self.znear
}
fn far_clip(&self) -> f32{
self.zfar
}
fn set_near(&mut self, near: f32){
self.znear = near;
self.refresh_projection();
}
fn set_far(&mut self, far: f32){
self.zfar = far;
self.refresh_projection();
}
fn set_near_far(&mut self, near: f32, far: f32){
self.znear = near;
self.zfar = far;
self.refresh_projection();
}
fn set_aspect_ratio(&mut self, aspect: f32){
self.aspect_ratio = aspect;
}
fn aspect_ratio(&self) -> f32{
self.aspect_ratio
}
fn target(&self) -> &Pnt3{
&*self.target
}
fn up(&self) -> &Unit<Vec3>{
&self.up
}
fn set_target(&mut self, target: Pnt3){
*self.target = target;
}
fn update(&mut self) -> bool{
self.update()
}
}
impl CameraPerspective for Camera{
fn set_fov(&mut self, fov: Deg<f32>){
self.fov = fov;
self.refresh_projection();
}
}
pub mod ortho_camera {
use na::*;
use angle::{Deg, Rad, Angle};
use graphics::{node, Node, NodeRef, NodeMut};
use super::{CameraExt, CameraOrthographic};
use util::ValueCache;
use window;
pub struct OrthoCamera{
node: Node,
target: ValueCache<Pnt3>,
up: Unit<Vec3>,
view: Mat4,
projection: Mat4,
proj_view: Mat4,
left: f32,
right: f32,
bottom: f32,
top: f32,
znear: f32,
zfar: f32,
}
pub struct Builder{
eye: Pnt3,
look_at: Pnt3,
aspect_ratio: f32,
znear_far: Option<(f32,f32)>,
width: Option<f32>,
up: Unit<Vec3>,
}
impl Builder{
pub fn new(aspect_ratio: f32) -> Builder{
Builder{
eye: origin(),
look_at: pnt3(0., 0., -1.),
aspect_ratio: aspect_ratio,
znear_far: None,
width: None,
up: Unit::new_unchecked(Vec3::y()),
}
}
pub fn from_window(window: &mut window::WindowT) -> Builder{
Builder::new(window.aspect_ratio())
}
pub fn clip_planes(&mut self, znear: f32, zfar: f32) -> &mut Builder{
self.znear_far = Some((znear, zfar));
self
}
pub fn up_axis(&mut self, up: Unit<Vec3>) -> &mut Builder{
self.up = up;
self
}
pub fn position(&mut self, pos: Pnt3) -> &mut Builder{
self.eye = pos;
self
}
pub fn look_at(&mut self, target: Pnt3) -> &mut Builder{
self.look_at = target;
self
}
pub fn aspect_ratio(&mut self, aspect_ratio: f32) -> &mut Builder{
self.aspect_ratio = aspect_ratio;
self
}
pub fn width(&mut self, width: f32) -> &mut Builder{
self.width = Some(width);
self
}
pub fn create(&self) -> OrthoCamera{
if let Some((near, far)) = self.znear_far{
let width = self.width.unwrap_or_else(||{
let dist = norm(&(self.look_at - self.eye));
dist
});
let left = -width / 2.;
let right = width / 2.;
let bottom = left / self.aspect_ratio;
let top = right / self.aspect_ratio;
OrthoCamera::new_with_frustum(
self.eye,
self.look_at,
self.up,
left, right,
bottom, top,
near, far)
}else{
OrthoCamera::new(
self.eye,
self.look_at,
self.up,
self.aspect_ratio)
}
}
}
impl OrthoCamera{
pub fn new(eye: Pnt3,
look_at: Pnt3,
up: Unit<Vec3>,
aspect_ratio: f32) -> OrthoCamera
{
let dist = norm(&(look_at - eye));
let left = -dist / 2.;
let right = dist / 2.;
let bottom = left / aspect_ratio;
let top = right / aspect_ratio;
let znear = dist / 100.0;
let zfar = dist * 10.0;
OrthoCamera::new_with_frustum(eye, look_at, up, left, right, bottom, top, znear, zfar)
}
pub fn new_with_frustum(eye: Pnt3,
look_at: Pnt3,
up: Unit<Vec3>,
left: f32,
right: f32,
bottom: f32,
top: f32,
znear: f32,
zfar: f32) -> OrthoCamera {
let node = Node::new_look_at(eye, look_at, *up);
let view = node.inv_global_transformation();
let mut camera = OrthoCamera {
left,
right,
bottom,
top,
znear,
zfar,
target: ValueCache::new(look_at),
up,
view: view,
proj_view: one(),
projection: one(),
node: node
};
camera.refresh_projection();
camera
}
pub fn projection(&self) -> Mat4{
self.projection
}
pub fn view(&self) -> Mat4{
self.view
}
pub fn projection_view(&self) -> Mat4{
self.proj_view
}
pub fn near_far_clip(&self) -> (f32,f32){
(self.znear, self.zfar)
}
pub fn near_clip(&self) -> f32{
self.znear
}
pub fn far_clip(&self) -> f32{
self.zfar
}
pub fn set_near(&mut self, near: f32){
self.znear = near;
self.refresh_projection();
}
pub fn set_far(&mut self, far: f32){
self.zfar = far;
self.refresh_projection();
}
pub fn set_near_far(&mut self, near: f32, far: f32){
self.znear = near;
self.zfar = far;
self.refresh_projection();
}
pub fn set_aspect_ratio(&mut self, aspect: f32){
self.bottom = self.left / aspect;
self.top = self.right / aspect;
self.refresh_projection();
}
pub fn target(&self) -> &Pnt3{
&self.target
}
pub fn set_target(&mut self, target: Pnt3){
*self.target = target;
}
pub fn left(&self) -> f32{
self.left
}
pub fn right(&self) -> f32{
self.right
}
pub fn bottom(&self) -> f32{
self.bottom
}
pub fn top(&self) -> f32{
self.top
}
pub fn set_left(&mut self, left: f32) {
self.left = left;
self.refresh_projection();
}
pub fn set_right(&mut self, right: f32) {
self.right = right;
self.refresh_projection();
}
pub fn set_bottom(&mut self, bottom: f32) {
self.bottom = bottom;
self.refresh_projection();
}
pub fn set_top(&mut self, top: f32) {
self.top = top;
self.refresh_projection();
}
pub fn update(&mut self) -> bool{
self.update_with_parent_flags(None, super::node::Flags::empty())
}
fn refresh_projection(&mut self){
let proj = Orthographic3::new(self.left, self.right, self.bottom, self.top, self.znear, self.zfar);
self.projection = *proj.as_matrix();
self.proj_view = self.projection * self.view;
}
}
impl NodeRef for OrthoCamera {
fn node(&self) -> &Node{
&self.node
}
}
impl CameraOrthographic for OrthoCamera{
fn set_width(&mut self, width: f32){
self.left = -width / 2.;
self.right = width / 2.;
}
}
impl NodeMut for OrthoCamera{
fn node_mut(&mut self) -> &mut Node{
&mut self.node
}
fn update_with_parent_flags(&mut self, parent: Option<&Node>, flags: node::Flags) -> bool{
if self.target.has_changed(){
self.node.look_at(&self.target, &self.up);
}
self.target.update();
if self.node.update_with_parent_flags(parent, flags) {
self.view = self.node.global_transformation().fast_orthonormal_inverse();
self.proj_view = self.projection * self.view;
true
}else{
false
}
}
fn update_with_parent(&mut self, parent: Option<&Node>) -> bool{
self.update_with_parent_flags(parent, node::Flags::empty())
}
fn look_at(&mut self, at: &Pnt3, up: &Vec3){
*self.target = *at;
self.up = Unit::new_unchecked(*up);
self.node_mut().look_at(at, up);
}
fn rotate(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
let orientation = UnitQuat::from_axis_angle(axis, angle.value());
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().append_orientation(&orientation);
}
fn append_orientation(&mut self, orientation: &UnitQuat){
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().append_orientation(orientation);
}
fn tilt(&mut self, angle: Rad<f32>){
let axis = self.x_axis();
self.node_mut().rotate(angle, &axis);
}
fn pan(&mut self, angle: Rad<f32>){
let axis = self.y_axis();
self.node_mut().rotate(angle, &axis);
}
fn roll(&mut self, angle: Rad<f32>){
let axis = self.z_axis();
self.node_mut().rotate(angle, &axis);
}
fn translate(&mut self, t: &Vec3){
self.node_mut().translate(t);
*self.target += *t;
}
fn set_position(&mut self, pos: Pnt3){
let diff = pos - self.position().to_vec();
self.node_mut().set_position(pos);
*self.target += diff.to_vec();
}
fn set_angle_axis(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
let orientation = UnitQuat::from_axis_angle(axis, angle.value());
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().set_orientation(orientation);
}
fn set_orientation(&mut self, orientation: UnitQuat){
let new_target = orientation * *self.target;
self.target.set(new_target);
self.node_mut().set_orientation(orientation);
}
}
impl CameraExt for OrthoCamera{
fn projection(&self) -> Mat4{
self.projection
}
fn view(&self) -> Mat4{
self.view
}
fn projection_view(&self) -> Mat4{
self.proj_view
}
fn fov(&self) -> Option<Deg<f32>>{
None
}
fn width(&self) -> Option<f32>{
Some(self.right - self.left)
}
fn near_far_clip(&self) -> (f32,f32){
(self.znear, self.zfar)
}
fn near_clip(&self) -> f32{
self.znear
}
fn far_clip(&self) -> f32{
self.zfar
}
fn set_near(&mut self, near: f32){
self.znear = near;
self.refresh_projection();
}
fn set_far(&mut self, far: f32){
self.zfar = far;
self.refresh_projection();
}
fn set_near_far(&mut self, near: f32, far: f32){
self.znear = near;
self.zfar = far;
self.refresh_projection();
}
fn set_aspect_ratio(&mut self, aspect: f32){
self.bottom = self.left / aspect;
self.top = self.right / aspect;
self.refresh_projection();
}
fn aspect_ratio(&self) -> f32{
let w = self.right - self.left;
let h = self.top - self.bottom;
w / h
}
fn target(&self) -> &Pnt3{
&*self.target
}
fn up(&self) -> &Unit<Vec3>{
&self.up
}
fn set_target(&mut self, target: Pnt3){
*self.target = target;
}
fn update(&mut self) -> bool{
self.update()
}
}
}
pub mod arcball_camera {
use na::*;
use math;
use angle::{Deg, Rad, Angle};
use graphics::{node, Node, NodeRef, NodeMut};
use window::events::*;
use window;
use events::{self, StreamT};
use std::mem;
use super::{Camera, CameraExt, CameraPerspective, CameraOrthographic};
#[derive(Clone, Debug, Copy, PartialEq)]
pub enum ViewsEvent{
Front,
Back,
Left,
Right,
Top,
Bottom,
OrbitUp(Deg<f32>),
OrbitDown(Deg<f32>),
OrbitLeft(Deg<f32>),
OrbitRight(Deg<f32>),
}
impl ViewsEvent{
pub fn stream_from_numpad_keys<S: StreamT<'static, Event>>(events: S) -> events::Stream<'static, ViewsEvent>{
let keys = events.keys().rc();
let front_back = keys.clone().pressed(Key::Kp1)
.scan(false, |b, _| {
*b = !*b;
if *b { Some(ViewsEvent::Front) } else { Some(ViewsEvent::Back) }
});
let left_right = keys.clone().pressed(Key::Kp3)
.scan(false, |b, _| {
*b = !*b;
if *b { Some(ViewsEvent::Left) } else { Some(ViewsEvent::Right) }
});
let top_bottom = keys.clone().pressed(Key::Kp7)
.scan(false, |b, _| {
*b = !*b;
if *b { Some(ViewsEvent::Top) } else { Some(ViewsEvent::Bottom) }
});
let left = keys.clone().pressed(Key::Kp4).map(|_| ViewsEvent::OrbitLeft(Deg(10.)));
let right = keys.clone().pressed(Key::Kp6).map(|_| ViewsEvent::OrbitRight(Deg(10.)));
let up = keys.clone().pressed(Key::Kp8).map(|_| ViewsEvent::OrbitUp(Deg(10.)));
let down = keys.clone().pressed(Key::Kp2).map(|_| ViewsEvent::OrbitDown(Deg(10.)));
events::Stream::merge_all(vec![
front_back,
left_right,
top_bottom,
left,
right,
up,
down,
])
}
}
pub struct ArcballCamera<C = Camera>{
camera: C,
prev_mouse: Pnt2<f64>,
mouse_pressed: bool,
translating: bool,
window_size: Vec2<i32>,
window_size_iter: events::IterAsync<'static, Vec2<i32>>,
prev_camera: Node,
rolling: bool,
up: Unit<Vec3>,
do_roll: bool,
events: events::IterAsync<'static, window::Event>,
camera_views: events::IterAsync<'static, ViewsEvent>,
}
pub struct Builder{
events_stream: events::StreamRc<'static, window::Event>,
camera_views: events::Stream<'static, ViewsEvent>,
window_size: Vec2<i32>,
eye: Pnt3,
look_at: Pnt3,
fov: Deg<f32>,
aspect_ratio: f32,
znear_far: Option<(f32,f32)>,
up: Unit<Vec3>,
do_roll: bool,
}
impl Builder{
pub fn new<S: events::StreamT<'static, window::Event>>(events_stream: S,
window_size: Vec2<i32>) -> Builder{
Builder{
events_stream: events_stream.rc(),
camera_views: events::Stream::never(),
window_size,
eye: origin(),
look_at: pnt3(0., 0., -1.),
fov: Deg(60f32),
aspect_ratio: window_size.x as f32 / window_size.y as f32,
znear_far: None,
up: Unit::new_unchecked(Vec3::y()),
do_roll: false,
}
}
pub fn from_window(window: &mut window::WindowT) -> Builder{
Builder::new(window.event_stream(), window.size())
}
pub fn from_camera_view_events<S, C, V>(camera: C, event_stream: S, view_events: V, window_size: Vec2<i32>) -> ArcballCamera<C>
where S: events::StreamT<'static, window::Event>,
V: events::StreamT<'static, ViewsEvent>,
C: CameraExt,
{
let event_stream = event_stream.rc();
let view_events = view_events.unique();
ArcballCamera{
prev_mouse: origin(),
mouse_pressed: false,
translating: false,
prev_camera: Node::identity(),
window_size: window_size,
window_size_iter: event_stream.clone().window().resized().iter_async(),
rolling: false,
up: *camera.up(),
do_roll: false,
events: event_stream.iter_async(),
camera_views: view_events.iter_async(),
camera,
}
}
pub fn from_camera<S, C>(camera: C, event_stream: S, window_size: Vec2<i32>) -> ArcballCamera<C>
where S: events::StreamT<'static, window::Event>,
C: CameraExt,
{
Self::from_camera_view_events(camera, event_stream, events::Stream::never(), window_size)
}
pub fn clip_planes(mut self, znear: f32, zfar: f32) -> Builder{
self.znear_far = Some((znear, zfar));
self
}
pub fn up_axis(mut self, up: Unit<Vec3>) -> Builder{
self.up = up;
self
}
pub fn position(mut self, pos: Pnt3) -> Builder{
self.eye = pos;
self
}
pub fn look_at(mut self, target: Pnt3) -> Builder{
self.look_at = target;
self
}
pub fn fov(mut self, fov: Deg<f32>) -> Builder{
self.fov = fov;
self
}
pub fn aspect_ratio(mut self, aspect_ratio: f32) -> Builder{
self.aspect_ratio = aspect_ratio;
self
}
pub fn do_roll(mut self, do_roll: bool) -> Builder{
self.do_roll = do_roll;
self
}
pub fn view_events<S: StreamT<'static, ViewsEvent>>(mut self, view_events: S) -> Builder{
self.camera_views = view_events.unique();
self
}
pub fn create(self) -> ArcballCamera{
let camera = if let Some((near, far)) = self.znear_far{
Camera::new_with_frustum(self.eye, self.look_at, self.up, self.fov, self.aspect_ratio, near, far)
}else{
Camera::new(self.eye, self.look_at, self.up, self.fov, self.aspect_ratio)
};
Self::from_camera_view_events(camera, self.events_stream, self.camera_views, self.window_size)
}
}
impl<C: CameraExt + NodeMut> ArcballCamera<C>{
pub fn target(&self) -> &Pnt3{
self.camera.target()
}
pub fn set_target(&mut self, target: Pnt3){
self.camera.set_target(target);
}
pub fn camera(&self) -> &C{
&self.camera
}
pub fn update(&mut self) -> bool {
self.poll_window_events();
self.camera.update()
}
fn poll_window_events<'a>(&'a mut self){
if let Some(window_size) = self.window_size_iter.by_ref().last(){
self.window_size = window_size;
}
if let Some(view) = self.camera_views.by_ref().last(){
if !self.mouse_pressed {
let target = *self.camera.target();
let position = self.camera.position();
let (dir, up) = match view{
ViewsEvent::Front => (-Vec3::y(), Vec3::z()),
ViewsEvent::Back => ( Vec3::y(), Vec3::z()),
ViewsEvent::Left => (-Vec3::x(), Vec3::z()),
ViewsEvent::Right => ( Vec3::x(), Vec3::z()),
ViewsEvent::Bottom => (-Vec3::z(), Vec3::y()),
ViewsEvent::Top => ( Vec3::z(), Vec3::y()),
ViewsEvent::OrbitUp(deg) => {
let curr_dir = (target - position).normalize();
let rot = UnitQuat::from_axis_angle(&self.camera.x_axis(), -deg.to_rad().value());
let dir = rot * curr_dir;
let up = *self.camera.y_axis();
(dir, up)
}
ViewsEvent::OrbitDown(deg) => {
let curr_dir = (target - position).normalize();
let rot = UnitQuat::from_axis_angle(&self.camera.x_axis(), deg.to_rad().value());
let dir = rot * curr_dir;
let up = *self.camera.y_axis();
(dir, up)
}
ViewsEvent::OrbitLeft(deg) => {
let curr_dir = (target - position).normalize();
let rot = UnitQuat::from_axis_angle(&self.camera.y_axis(), -deg.to_rad().value());
let dir = rot * curr_dir;
let up = *self.camera.y_axis();
(dir, up)
}
ViewsEvent::OrbitRight(deg) => {
let curr_dir = (target - position).normalize();
let rot = UnitQuat::from_axis_angle(&self.camera.y_axis(), deg.to_rad().value());
let dir = rot * curr_dir;
let up = *self.camera.y_axis();
(dir, up)
}
};
let dist = norm(&(target - position));
let offset = dist * dir;
self.camera.set_position((target - offset));
self.camera.look_at(&target, &up);
}
}
let events: &mut events::IterAsync<'a, window::Event> = unsafe{ mem::transmute(self.events.by_ref()) };
for event in events {
match event{
window::Event::MousePressed{pos,button,..} => self.mouse_pressed(&pos,button),
window::Event::MouseReleased{pos,button,..} => self.mouse_released(&pos,button),
window::Event::MouseMoved{pos} => self.mouse_moved(&pos),
window::Event::Scroll{scroll} => self.scroll(&scroll),
_ => {}
}
}
}
fn mouse_moved(&mut self, pos: &Pnt2<f64>){
if self.mouse_pressed{
let diff = *pos - self.prev_mouse;
let yaw = Rad(-diff.x as f32 * 0.005);
let pitch = Rad(-diff.y as f32 * 0.005);
let rot = if self.rolling{
let screen_coords = vec2((pos.x as f32 - self.window_size.x as f32*0.5)/self.window_size.y as f32 * 2.0,
pos.y as f32/self.window_size.y as f32 * 2.0 - 1.0);
let prev_screen_coords = vec2((self.prev_mouse.x as f32 - self.window_size.x as f32*0.5)/self.window_size.y as f32 * 2.0,
self.prev_mouse.y as f32/self.window_size.y as f32 * 2.0 - 1.0);
UnitQuat::from_axis_angle(&self.prev_camera.z_axis(), math::atan2(&prev_screen_coords, &screen_coords).value())
}else{
UnitQuat::from_axis_angle(&self.up, yaw.value()) * UnitQuat::from_axis_angle(&self.prev_camera.x_axis(), pitch.value())
};
let orbit_radius = self.prev_camera.position() - *self.camera.target();
let rotated = rot * orbit_radius;
let new_position = *self.camera.target() + rotated;
self.camera.node_mut().set_position(new_position);
self.camera.node_mut().set_orientation((rot * self.prev_camera.orientation()));
if !self.rolling && pitch.abs() > Deg(90f32).to_rad(){
self.prev_mouse = *pos;
self.prev_camera = self.camera.node().clone();
}
}
if self.translating{
let new_pos = *pos - self.prev_mouse;
let axis_x = self.camera.x_axis().unwrap();
let axis_y = self.camera.y_axis().unwrap();
let ratio_x;
let ratio_y;
if self.camera.fov().is_some(){
let max_distance = norm(&(*self.camera.target() - self.camera.position()));
ratio_x = max_distance/self.window_size.x as f32;
ratio_y = max_distance/self.window_size.y as f32;
}else{
let width = self.camera.width().unwrap();
let height = width / self.camera.aspect_ratio();
ratio_x = width / self.camera().scale().x / self.window_size.x as f32;
ratio_y = height / self.camera().scale().y / self.window_size.y as f32;
}
let translation = axis_x * -new_pos.x as f32 * ratio_x + axis_y * new_pos.y as f32 * ratio_y;
self.camera.translate(&translation);
self.prev_mouse = *pos;
}
}
fn mouse_pressed(&mut self, pos: &Pnt2<f64>, button: window::MouseButton){
match button{
window::MouseButton::Left => {
self.prev_mouse = *pos;
self.mouse_pressed = true;
self.prev_camera = self.camera.node().clone();
let screen_coords = vec2((pos.x as f32 - self.window_size.x as f32*0.5)/self.window_size.y as f32 * 2.0,
pos.y as f32/self.window_size.y as f32 * 2.0 - 1.0);
if self.do_roll && norm_squared(&screen_coords) > 1.0{
self.rolling = true;
}else{
self.rolling = false;
}
}
window::MouseButton::Middle => {
self.prev_mouse = *pos;
self.translating = true;
}
_=>{}
}
}
fn mouse_released(&mut self, _pos: &Pnt2<f64>, button: window::MouseButton){
match button{
window::MouseButton::Left => {
self.mouse_pressed = false;
}
window::MouseButton::Middle => {
self.translating = false;
}
_=>{}
}
}
fn scroll(&mut self, scroll: &Vec2<f64>){
if self.camera.fov().is_some(){
let dir = norm(&(*self.camera.target() - self.camera.position())) * self.camera.z_axis().unwrap();
self.camera.node_mut().translate(&(dir * (scroll.y as f32 * 0.1)));
}else{
let scale = self.camera.scale();
let scale = scale + (scale * scroll.y as f32 * 0.1);
self.camera.set_scale(scale);
}
}
}
impl<C: CameraExt + NodeMut> CameraExt for ArcballCamera<C>{
fn projection(&self) -> Mat4{
self.camera.projection()
}
fn view(&self) -> Mat4{
self.camera.view()
}
fn projection_view(&self) -> Mat4{
self.camera.projection_view()
}
fn fov(&self) -> Option<Deg<f32>>{
self.camera.fov()
}
fn width(&self) -> Option<f32>{
self.camera.width()
}
fn near_far_clip(&self) -> (f32,f32){
self.camera.near_far_clip()
}
fn near_clip(&self) -> f32{
self.camera.near_clip()
}
fn far_clip(&self) -> f32{
self.camera.far_clip()
}
fn set_near(&mut self, near: f32){
self.camera.set_near(near);
}
fn set_far(&mut self, far: f32){
self.camera.set_far(far);
}
fn set_near_far(&mut self, near: f32, far: f32){
self.camera.set_near_far(near,far);
}
fn set_aspect_ratio(&mut self, aspect: f32){
self.camera.set_aspect_ratio(aspect);
}
fn aspect_ratio(&self) -> f32{
self.camera.aspect_ratio()
}
fn target(&self) -> &Pnt3{
self.camera.target()
}
fn set_target(&mut self, target: Pnt3){
self.camera.set_target(target)
}
fn up(&self) -> &Unit<Vec3>{
&self.up
}
fn update(&mut self) -> bool{
self.update()
}
}
impl<C: CameraPerspective + NodeMut> CameraPerspective for ArcballCamera<C>{
fn set_fov(&mut self, fov: Deg<f32>){
self.camera.set_fov(fov);
}
}
impl<C: CameraOrthographic + NodeMut> CameraOrthographic for ArcballCamera<C>{
fn set_width(&mut self, width: f32){
self.camera.set_width(width)
}
}
impl<C: NodeRef> NodeRef for ArcballCamera<C>{
fn node(&self) -> &Node{
self.camera.node()
}
}
impl<C: NodeMut> NodeMut for ArcballCamera<C>{
fn node_mut(&mut self) -> &mut Node{
self.camera.node_mut()
}
fn update_with_parent_flags(&mut self, parent: Option<&Node>, flags: node::Flags) -> bool{
self.camera.update_with_parent_flags(parent, flags)
}
fn update_with_parent(&mut self, parent: Option<&Node>) -> bool{
self.update_with_parent_flags(parent, node::Flags::empty())
}
fn look_at(&mut self, at: &Pnt3, up: &Vec3){
self.camera.look_at(at, up)
}
fn rotate(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
self.camera.rotate(angle, axis)
}
fn append_orientation(&mut self, orientation: &UnitQuat){
self.camera.append_orientation(orientation)
}
fn tilt(&mut self, angle: Rad<f32>){
self.camera.tilt(angle)
}
fn pan(&mut self, angle: Rad<f32>){
self.camera.pan(angle)
}
fn roll(&mut self, angle: Rad<f32>){
self.camera.roll(angle)
}
fn set_scale(&mut self, _: Vec3){
}
fn translate(&mut self, t: &Vec3){
self.camera.translate(t)
}
fn set_position(&mut self, pos: Pnt3){
self.camera.set_position(pos)
}
fn set_angle_axis(&mut self, angle: Rad<f32>, axis: &Unit<Vec3>){
self.camera.set_angle_axis(angle, axis)
}
fn set_orientation(&mut self, orientation: UnitQuat){
self.camera.set_orientation(orientation)
}
}
}