diff --git a/src/bin/pumpkin.rs b/src/bin/pumpkin.rs index 04c8abd..1fade6d 100644 --- a/src/bin/pumpkin.rs +++ b/src/bin/pumpkin.rs @@ -32,6 +32,35 @@ where V: Into )) } +struct EulerAngles { + pub azimuth: f32, + pub altitude: f32, +} + +impl Default for EulerAngles { + fn default () -> Self { + Self { + azimuth: 0.0, + altitude: 0.0, + } + } +} + +impl EulerAngles { + pub fn to_vec3 (&self) -> Vec3 { + let alt = self.altitude.to_radians (); + let azi = self.azimuth.to_radians (); + + let z = alt.sin (); + let xy_len = alt.cos (); + + let x = xy_len * -azi.sin (); + let y = xy_len * azi.cos (); + + (x, y, z).into () + } +} + // TODO: Use iota macro const KEY_LEFT: usize = 0; const KEY_RIGHT: usize = KEY_LEFT + 1; @@ -71,55 +100,60 @@ impl ControllerState { if self.is_pressed (KEY_LEFT) { controlled_angle.azimuth += spin_f; - std::cmp::min (spin_speed + 1, SPIN_RAMP_TIME) } else if self.is_pressed (KEY_RIGHT) { controlled_angle.azimuth -= spin_f; - std::cmp::min (spin_speed + 1, SPIN_RAMP_TIME) } else if self.is_pressed (KEY_UP) { controlled_angle.altitude = f32::min (90.0, controlled_angle.altitude + spin_f); - std::cmp::min (spin_speed + 1, SPIN_RAMP_TIME) } else if self.is_pressed (KEY_DOWN) { controlled_angle.altitude = f32::max (-90.0, controlled_angle.altitude - spin_f); - std::cmp::min (spin_speed + 1, SPIN_RAMP_TIME) } else { + return 0; + } + + std::cmp::min (spin_speed + 1, SPIN_RAMP_TIME) + } + + pub fn control_quat ( + &self, + controlled_quat: &mut Quat, + spin_speed: i32 + ) -> i32 + { + const SPIN_RAMP_TIME: i32 = 30; + let spin_f = 4.0 * (spin_speed + 1) as f32 / SPIN_RAMP_TIME as f32; + let spin_f = spin_f.to_radians (); + + let mut delta = Quat::default (); + + if self.is_pressed (KEY_LEFT) { + delta = delta.mul_quat (Quat::from_rotation_y (-spin_f)); + } + if self.is_pressed (KEY_RIGHT) { + delta = delta.mul_quat (Quat::from_rotation_y (spin_f)); + } + if self.is_pressed (KEY_UP) { + delta = delta.mul_quat (Quat::from_rotation_x (-spin_f)); + } + if self.is_pressed (KEY_DOWN) { + delta = delta.mul_quat (Quat::from_rotation_x (spin_f)); + } + + //println! ("spin_f {}, Quat {:?}", spin_f, delta); + + if delta == Quat::default () { 0 } - } -} - -struct EulerAngles { - pub azimuth: f32, - pub altitude: f32, -} - -impl Default for EulerAngles { - fn default () -> Self { - Self { - azimuth: 0.0, - altitude: 0.0, + else { + *controlled_quat = (controlled_quat.mul_quat (delta)).normalize (); + std::cmp::min (spin_speed + 1, SPIN_RAMP_TIME) } } } -impl EulerAngles { - pub fn to_vec3 (&self) -> Vec3 { - let alt = self.altitude.to_radians (); - let azi = self.azimuth.to_radians (); - - let z = alt.sin (); - let xy_len = alt.cos (); - - let x = xy_len * -azi.sin (); - let y = xy_len * azi.cos (); - - (x, y, z).into () - } -} - enum PlayMode { WindTunnel, FreeFlight, @@ -143,8 +177,13 @@ struct WindTunnelState { spin_speed: i32, } +struct Airplane { + pos: Vec3, + ori: Quat, +} + struct FlightState { - airplane: EulerAngles, + airplane: Airplane, spin_speed: i32, } @@ -154,7 +193,7 @@ impl FlightState { } pub fn step (&mut self, controller: &ControllerState) { - self.spin_speed = controller.control_eulers (&mut self.airplane, self.spin_speed); + self.spin_speed = controller.control_quat (&mut self.airplane.ori, self.spin_speed); } } @@ -214,7 +253,10 @@ impl WorldState { spin_speed: 0, }, flight: FlightState { - airplane: Default::default (), + airplane: Airplane { + pos: (0.0, 0.0, 1.35).into (), + ori: Default::default (), + }, spin_speed: 0, }, } @@ -986,10 +1028,9 @@ impl GameGraphics { Mat4::from_rotation_x (euler.altitude.to_radians ()) }, PlayMode::FreeFlight => { - let euler = &state.flight.airplane; - Mat4::from_translation ((0.0, 0.0, 2.7 * 0.5).into ()) * - Mat4::from_rotation_z (euler.azimuth.to_radians ()) * - Mat4::from_rotation_x (euler.altitude.to_radians ()) + let airplane = &state.flight.airplane; + Mat4::from_translation (airplane.pos) * + Mat4::from_quat (airplane.ori) }, }; let inverse_airplane = airplane_model_mat.inverse ();