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