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