camera_controllers/
first_person.rs

1#![allow(dead_code)]
2
3//! A first person camera.
4
5use input::{ Button, GenericEvent };
6use vecmath::traits::{ Float, Radians };
7
8use Camera;
9
10bitflags!(pub struct Keys: u8 {
11    const MOVE_FORWARD  = 0b00000001;
12    const MOVE_BACKWARD = 0b00000010;
13    const STRAFE_LEFT   = 0b00000100;
14    const STRAFE_RIGHT  = 0b00001000;
15    const FLY_UP        = 0b00010000;
16    const FLY_DOWN      = 0b00100000;
17});
18
19/// First person camera settings.
20pub struct FirstPersonSettings<T=f32> {
21    /// Which button to press to move forward.
22    pub move_forward_button: Button,
23    /// Which button to press to move backward.
24    pub move_backward_button: Button,
25    /// Which button to press to strafe left.
26    pub strafe_left_button: Button,
27    /// Which button to press to strafe right.
28    pub strafe_right_button: Button,
29    /// Which button to press to fly up.
30    pub fly_up_button: Button,
31    /// Which button to press to fly down.
32    pub fly_down_button: Button,
33    /// Which button to press to move faster.
34    pub move_faster_button: Button,
35    /// The horizontal movement speed.
36    ///
37    /// This is measured in units per second.
38    pub speed_horizontal: T,
39    /// The vertical movement speed.
40    ///
41    /// This is measured in units per second.
42    pub speed_vertical: T,
43    /// The horizontal mouse sensitivity.
44    ///
45    /// This is a multiplier applied to horizontal mouse movements.
46    pub mouse_sensitivity_horizontal: T,
47    /// The vertical mouse sensitivity.
48    ///
49    /// This is a multiplier applied to vertical mouse movements.
50    pub mouse_sensitivity_vertical: T,
51}
52
53impl<T> FirstPersonSettings<T>
54    where T: Float
55{
56    /// Creates new first person camera settings with wasd defaults.
57    pub fn keyboard_wasd() -> FirstPersonSettings<T> {
58        use input::Button::Keyboard;
59        use input::Key;
60
61        FirstPersonSettings {
62            move_forward_button: Keyboard(Key::W),
63            move_backward_button: Keyboard(Key::S),
64            strafe_left_button: Keyboard(Key::A),
65            strafe_right_button: Keyboard(Key::D),
66            fly_up_button: Keyboard(Key::Space),
67            fly_down_button: Keyboard(Key::LShift),
68            move_faster_button: Keyboard(Key::LCtrl),
69            speed_horizontal: T::one(),
70            speed_vertical: T::one(),
71            mouse_sensitivity_horizontal: T::one(),
72            mouse_sensitivity_vertical: T::one(),
73        }
74    }
75
76    /// Creates a new first person camera settings with esdf defaults.
77    pub fn keyboard_esdf() -> FirstPersonSettings<T> {
78        use input::Button::Keyboard;
79        use input::Key;
80
81        FirstPersonSettings {
82            move_forward_button: Keyboard(Key::E),
83            move_backward_button: Keyboard(Key::D),
84            strafe_left_button: Keyboard(Key::S),
85            strafe_right_button: Keyboard(Key::F),
86            fly_up_button: Keyboard(Key::Space),
87            fly_down_button: Keyboard(Key::Z),
88            move_faster_button: Keyboard(Key::LShift),
89            speed_horizontal: T::one(),
90            speed_vertical: T::one(),
91            mouse_sensitivity_horizontal: T::one(),
92            mouse_sensitivity_vertical: T::one(),
93        }
94    }
95
96    /// Creates new first person camera settings with zqsd defaults (azerty keyboard layout).
97    pub fn keyboard_zqsd() -> FirstPersonSettings<T> {
98        use input::Button::Keyboard;
99        use input::Key;
100
101        FirstPersonSettings {
102            move_forward_button: Keyboard(Key::Z),
103            move_backward_button: Keyboard(Key::S),
104            strafe_left_button: Keyboard(Key::Q),
105            strafe_right_button: Keyboard(Key::D),
106            fly_up_button: Keyboard(Key::Space),
107            fly_down_button: Keyboard(Key::LShift),
108            move_faster_button: Keyboard(Key::LCtrl),
109            speed_horizontal: T::one(),
110            speed_vertical: T::one(),
111            mouse_sensitivity_horizontal: T::one(),
112            mouse_sensitivity_vertical: T::one(),
113        }
114    }
115}
116
117/// Models a flying first person camera.
118pub struct FirstPerson<T=f32> {
119    /// The first person camera settings.
120    pub settings: FirstPersonSettings<T>,
121    /// The yaw angle (in radians).
122    pub yaw: T,
123    /// The pitch angle (in radians).
124    pub pitch: T,
125    /// The direction we are heading.
126    ///
127    /// By default the direction is `[0.0, 0.0, 0.0]`.
128    /// This direction is changed by user input.
129    pub direction: [T; 3],
130    /// The position of the camera.
131    pub position: [T; 3],
132    /// The velocity we are moving in the direction (slow = 1, fast = 2).
133    ///
134    /// By default, this is not activated since direction is `[0.0, 0.0, 0.0]`.
135    pub velocity: T,
136    /// The keys that are pressed.
137    keys: Keys,
138}
139
140impl<T> FirstPerson<T>
141    where T: Float
142{
143    /// Creates a new first person camera.
144    pub fn new(
145        position: [T; 3],
146        settings: FirstPersonSettings<T>
147    ) -> FirstPerson<T> {
148        let _0: T = T::zero();
149        FirstPerson {
150            settings: settings,
151            yaw: _0,
152            pitch: _0,
153            keys: Keys::empty(),
154            direction: [_0, _0, _0],
155            position: position,
156            velocity: T::one(),
157        }
158    }
159
160    /// Computes camera.
161    pub fn camera(&self, dt: f64) -> Camera<T> {
162        let dt = T::from_f64(dt);
163        let dh = dt * self.velocity * self.settings.speed_horizontal;
164        let [dx, dy, dz] = self.direction;
165        let (s, c) = (self.yaw.sin(), self.yaw.cos());
166        let mut camera = Camera::new([
167            self.position[0] + (s * dx - c * dz) * dh,
168            self.position[1] + dy * dt * self.settings.speed_vertical,
169            self.position[2] + (s * dz + c * dx) * dh
170        ]);
171        camera.set_yaw_pitch(self.yaw, self.pitch);
172        camera
173    }
174
175    /// Handles game event and updates camera.
176    pub fn event<E>(&mut self, e: &E) where E: GenericEvent {
177        e.update(|args| {
178            let cam = self.camera(args.dt);
179            self.position = cam.position;
180        });
181
182        let &mut FirstPerson {
183            ref mut yaw,
184            ref mut pitch,
185            ref mut keys,
186            ref mut direction,
187            ref mut velocity,
188            ref settings,
189            ..
190        } = self;
191
192        let pi: T = Radians::_180();
193
194
195        let _0 = T::zero();
196        let _1 = T::one();
197        let _2 = _1 + _1;
198        let _3 = _2 + _1;
199        let _4 = _3 + _1;
200        let _360 = T::from_isize(360);
201        let sqrt2 = _2.sqrt();
202
203        e.mouse_relative(|d| {
204
205            let dx = T::from_f64(d[0]) * settings.mouse_sensitivity_horizontal;
206            let dy = T::from_f64(d[1]) * settings.mouse_sensitivity_vertical;
207
208            *yaw = (*yaw - dx / _360 * pi / _4) % (_2 * pi);
209            *pitch = *pitch + dy / _360 * pi / _4;
210            *pitch = (*pitch).min(pi / _2).max(-pi / _2);
211        });
212        e.press(|button| {
213            let [dx, dy, dz] = *direction;
214            let sgn = |x: T| if x == _0 { _0 } else { x.signum() };
215            let mut set = |k, x: T, y: T, z: T| {
216                let (x, z) = (sgn(x), sgn(z));
217                let (x, z) = if x != _0 && z != _0 {
218                    (x / sqrt2, z / sqrt2)
219                } else {
220                    (x, z)
221                };
222                *direction = [x, y, z];
223                keys.insert(k);
224            };
225            match button {
226                x if x == settings.move_forward_button =>
227                    set(Keys::MOVE_FORWARD, -_1, dy, dz),
228                x if x == settings.move_backward_button =>
229                    set(Keys::MOVE_BACKWARD, _1, dy, dz),
230                x if x == settings.strafe_left_button =>
231                    set(Keys::STRAFE_LEFT, dx, dy, _1),
232                x if x == settings.strafe_right_button =>
233                    set(Keys::STRAFE_RIGHT, dx, dy, -_1),
234                x if x == settings.fly_up_button =>
235                    set(Keys::FLY_UP, dx, _1, dz),
236                x if x == settings.fly_down_button =>
237                    set(Keys::FLY_DOWN, dx, -_1, dz),
238                x if x == settings.move_faster_button => *velocity = _2,
239                _ => {}
240            }
241        });
242        e.release(|button| {
243            let [dx, dy, dz] = *direction;
244            let sgn = |x: T| if x == _0 { _0 } else { x.signum() };
245            let mut set = |x: T, y: T, z: T| {
246                let (x, z) = (sgn(x), sgn(z));
247                let (x, z) = if x != _0 && z != _0 {
248                    (x / sqrt2, z / sqrt2)
249                } else {
250                    (x, z)
251                };
252                *direction = [x, y, z];
253            };
254            let mut release = |key, rev_key, rev_val| {
255                keys.remove(key);
256                if keys.contains(rev_key) { rev_val } else { _0 }
257            };
258            match button {
259                x if x == settings.move_forward_button =>
260                    set(release(Keys::MOVE_FORWARD, Keys::MOVE_BACKWARD, _1), dy, dz),
261                x if x == settings.move_backward_button =>
262                    set(release(Keys::MOVE_BACKWARD, Keys::MOVE_FORWARD, -_1), dy, dz),
263                x if x == settings.strafe_left_button =>
264                    set(dx, dy, release(Keys::STRAFE_LEFT, Keys::STRAFE_RIGHT, -_1)),
265                x if x == settings.strafe_right_button =>
266                    set(dx, dy, release(Keys::STRAFE_RIGHT, Keys::STRAFE_LEFT, _1)),
267                x if x == settings.fly_up_button =>
268                    set(dx, release(Keys::FLY_UP, Keys::FLY_DOWN, -_1), dz),
269                x if x == settings.fly_down_button =>
270                    set(dx, release(Keys::FLY_DOWN, Keys::FLY_UP, _1), dz),
271                x if x == settings.move_faster_button => *velocity = _1,
272                _ => {}
273            }
274        });
275    }
276}