Port to glium 0.17 and glutin 0.9.
[mandelwow.git] / support / camera.rs
1 extern crate glutin;
2
3 use cgmath::{Matrix4, Vector4};
4 use cgmath::conv::array4x4;
5 use glutin::WindowEvent::{KeyboardInput, MouseMoved};
6 use glutin::VirtualKeyCode;
7 use std::f32;
8 use std::f32::consts::PI;
9 use support::vec3::Vec3;
10 use support::vec3::norm;
11
12 #[derive(Default)]
13 pub struct CameraState {
14     aspect: f32,
15     pos: Vec3,
16     dir: Vec3,
17
18     moving_up: bool,
19     moving_left: bool,
20     moving_down: bool,
21     moving_right: bool,
22     moving_forward: bool,
23     moving_backward: bool,
24     turning_up: bool,
25     turning_left: bool,
26     turning_down: bool,
27     turning_right: bool,
28
29     mouse_x: i32,
30     mouse_y: i32,
31     rel_x: i32,
32     rel_y: i32,
33 }
34
35 impl CameraState {
36     pub fn new() -> CameraState {
37         CameraState {
38             aspect: 1280.0 / 720.0,
39             pos: Vec3(0.0, 0.0, 0.0),
40             dir: Vec3(0.0, 0.0, -1.0),
41             mouse_x: -1,
42             mouse_y: -1,
43             .. Default::default()
44         }
45     }
46
47     pub fn set_pos(&mut self, pos: Vec3) {
48         self.pos = pos;
49     }
50
51     pub fn get_pos(&self) -> Vec3 {
52         self.pos
53     }
54
55     pub fn set_dir(&mut self, dir: Vec3) {
56         self.dir = dir;
57     }
58
59     pub fn get_persp_mat(&self) -> Matrix4<f32> {
60         let fov: f32 = PI / 2.0;
61         let zfar = 1024.0;
62         let znear = 0.1;
63
64         let f = 1.0 / (fov / 2.0).tan();
65
66         // note: remember that this is column-major, so the lines of code are actually columns
67         Matrix4 {
68             x: Vector4{ x: f / self.aspect, y: 0.0, z:  0.0,                           w: 0.0 },
69             y: Vector4{ x: 0.0,             y: f,   z:  0.0,                           w: 0.0 },
70             z: Vector4{ x: 0.0,             y: 0.0, z:  (zfar+znear)/(zfar-znear),     w: 1.0 },
71             w: Vector4{ x: 0.0,             y: 0.0, z: -(2.0*zfar*znear)/(zfar-znear), w: 0.0 },
72         }
73     }
74
75     pub fn get_view_mat(&self) -> Matrix4<f32> {
76         let f = norm(&self.dir);
77
78         let up = Vec3(0.0, 1.0, 0.0);
79
80         let s = Vec3(f.1 * up.2 - f.2 * up.1,
81                      f.2 * up.0 - f.0 * up.2,
82                      f.0 * up.1 - f.1 * up.0);
83         let sn = norm(&s);
84
85         let u = (sn.1 * f.2 - sn.2 * f.1,
86                  sn.2 * f.0 - sn.0 * f.2,
87                  sn.0 * f.1 - sn.1 * f.0);
88
89         let p = (-self.pos.0 * s.0 - self.pos.1 * s.1 - self.pos.2 * s.2,
90                  -self.pos.0 * u.0 - self.pos.1 * u.1 - self.pos.2 * u.2,
91                  -self.pos.0 * f.0 - self.pos.1 * f.1 - self.pos.2 * f.2);
92
93         // note: remember that this is column-major, so the lines of code are actually columns
94         Matrix4{
95             x: Vector4{ x: sn.0, y: u.0, z: f.0, w: 0.0 },
96             y: Vector4{ x: sn.1, y: u.1, z: f.1, w: 0.0 },
97             z: Vector4{ x: sn.2, y: u.2, z: f.2, w: 0.0 },
98             w: Vector4{ x:  p.0, y: p.1, z: p.2, w: 1.0 },
99         }
100     }
101
102     pub fn get_perspview(&self) -> [[f32; 4]; 4] {
103         array4x4(self.get_persp_mat() * self.get_view_mat())
104     }
105
106     pub fn get_perspective(&self) -> [[f32; 4]; 4] {
107         array4x4(self.get_persp_mat())
108     }
109
110     pub fn get_view(&self) -> [[f32; 4]; 4] {
111         array4x4(self.get_view_mat())
112     }
113
114     pub fn update(&mut self) {
115         let f = norm(&self.dir);
116
117         let up = Vec3(0.0, 1.0, 0.0);
118
119         let s = Vec3(f.1 * up.2 - f.2 * up.1,
120                      f.2 * up.0 - f.0 * up.2,
121                      f.0 * up.1 - f.1 * up.0);
122
123         let s = norm(&s);
124
125         let u = Vec3(s.1 * f.2 - s.2 * f.1,
126                      s.2 * f.0 - s.0 * f.2,
127                      s.0 * f.1 - s.1 * f.0);
128
129         let walk_speed = 0.01;
130         let strife_speed = 0.02;
131         let pan_speed = 0.001;
132
133         if self.moving_up {
134             self.pos += u * strife_speed;
135         }
136         if self.moving_down {
137             self.pos -= u * strife_speed;
138         }
139         if self.moving_left {
140             self.pos -= s * strife_speed;
141         }
142         if self.moving_right {
143             self.pos += s * strife_speed;
144         }
145         if self.moving_forward {
146             self.pos += f * walk_speed;
147         }
148         if self.moving_backward {
149             self.pos -= f * walk_speed;
150         }
151
152         if self.turning_left { self.rel_x -= 8; }
153         if self.turning_right { self.rel_x += 8; }
154         if self.turning_up { self.rel_y -= 2; }
155         if self.turning_down { self.rel_y += 2; }
156         let vx = -pan_speed * self.rel_x as f32;
157         let vy = -pan_speed * self.rel_y as f32;
158         self.dir = Vec3(f.0 * vx.cos() + f.2 * vx.sin(),
159                         f.1 * vy.cos() - f.2 * vy.sin(),
160                         f.1 * vy.sin() - f.0 * vx.sin() + f.2 * vx.cos() * vy.cos());
161         self.rel_x = 0;
162         self.rel_y = 0;
163
164         //println!("camera_pos = {:?}", self.pos);
165         //println!("camera_dir = {:?}", self.dir);
166     }
167
168     pub fn process_input(&mut self, event: &glutin::WindowEvent) {
169         match event {
170             &MouseMoved { position: (x, y), .. }  => {
171                 let (x, y) = (x as i32, y as i32);
172                 if self.mouse_x == -1 {
173                     // Set initial absolute position.
174                     self.mouse_x = x;
175                     self.mouse_y = y;
176                 }
177                 self.rel_x += x - self.mouse_x;
178                 self.rel_y += y - self.mouse_y;
179                 self.mouse_x = x;
180                 self.mouse_y = y;
181             }
182             &KeyboardInput { input, .. } => {
183                 let pressed = input.state == glutin::ElementState::Pressed;
184                 let key = match input.virtual_keycode {
185                     Some(key) => key,
186                     None => return,
187                 };
188                 match key {
189                     VirtualKeyCode::Left => self.moving_left = pressed,
190                     VirtualKeyCode::Right => self.moving_right = pressed,
191                     VirtualKeyCode::Up => self.moving_up = pressed,
192                     VirtualKeyCode::Down => self.moving_down = pressed,
193                     VirtualKeyCode::W => self.moving_forward = pressed,
194                     VirtualKeyCode::S => self.moving_backward = pressed,
195                     VirtualKeyCode::A => self.turning_left = pressed,
196                     VirtualKeyCode::D => self.turning_right = pressed,
197                     VirtualKeyCode::R => self.turning_up = pressed,
198                     VirtualKeyCode::F => self.turning_down = pressed,
199                     _ => (),
200                 }
201             },
202             _ => (),
203         }
204     }
205 }