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