diff --git a/Cargo.lock b/Cargo.lock index 11b3a1d..09899ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,11 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "float-ord" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -201,6 +206,7 @@ name = "opengl_rust" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "glam 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", "iota 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -418,6 +424,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" +"checksum float-ord 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94edab108827d67608095e269cf862e60d920f144a5026d3dbcfd8b877fb404" "checksum gl_generator 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" diff --git a/Cargo.toml b/Cargo.toml index cfbb842..5893d82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] byteorder = "1.3.2" - +float-ord = "0.2.0" gl = "0.14.0" glam = "0.8.5" diff --git a/grass.png b/grass.png new file mode 100644 index 0000000..b399963 Binary files /dev/null and b/grass.png differ diff --git a/src/bin/pumpkin.rs b/src/bin/pumpkin.rs index f6877af..e4727e2 100644 --- a/src/bin/pumpkin.rs +++ b/src/bin/pumpkin.rs @@ -1,6 +1,7 @@ #[macro_use] extern crate maplit; +use float_ord::FloatOrd; use glam::{Mat4, Quat, Vec3, Vec4}; use sdl2::event::Event; @@ -124,7 +125,7 @@ impl ControllerState { ) -> 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 = 2.0 * (spin_speed + 1) as f32 / SPIN_RAMP_TIME as f32; let spin_f = spin_f.to_radians (); let mut delta = Quat::default (); @@ -178,6 +179,7 @@ struct WindTunnelState { } struct Airplane { + vel: Vec3, pos: Vec3, ori: Quat, } @@ -195,7 +197,45 @@ impl FlightState { pub fn step (&mut self, controller: &ControllerState) { self.spin_speed = controller.control_quat (&mut self.airplane.ori, self.spin_speed); - self.airplane.pos += self.airplane.ori.mul_vec3 ((0.0, 1.0 / 30.0, 0.0).into ()); + let airplane = &mut self.airplane; + // Info + let nose = airplane.ori.mul_vec3 ((0.0, 1.0, 0.0).into ()); + let speed = airplane.vel.length (); + // Different from nose since planes are always drifting + let direction = match speed { + 0.0 => Vec3::from ((0.0, 0.0, 0.0)), + _ => airplane.vel * (1.0 / speed), + }; + let object_space_dir = airplane.ori.conjugate ().mul_vec3 (direction); + + // Forces + let gravity = Vec3::from ((0.0, 0.0, -0.25)); + let thrust = nose; + let laminar_drag = 0.5 * speed * -object_space_dir.y () * nose; + + let turbulent_dir = Vec3::from ((0.5 * object_space_dir.x (), 0.0, object_space_dir.z ())); + let turbulent_drag = -speed * speed * airplane.ori.mul_vec3 (turbulent_dir); + + let air_drag = laminar_drag + turbulent_drag; + + // Accumulate forces and run an Euler integration step + let dt = 1.0 / 60.0; + airplane.vel += dt * (thrust + gravity + air_drag); + airplane.pos += dt * airplane.vel; + + if airplane.pos.z () < 0.0 { + airplane.vel.set_z (0.0); + airplane.pos.set_z (0.0); + } + + // Gauges + let alti = airplane.pos.z () * 100.0; + let airspeed = speed * 100.0; + + println! ("Alti: {}, Airspeed: {}", + alti as i32, + airspeed as i32 + ); } } @@ -242,7 +282,7 @@ impl WindTunnelState { impl WorldState { pub fn new () -> Self { Self { - play_mode: PlayMode::WindTunnel, + play_mode: PlayMode::FreeFlight, wind_tunnel: WindTunnelState { user_control: UserControl::Camera, camera: Default::default (), @@ -257,6 +297,7 @@ impl WorldState { flight: FlightState { airplane: Airplane { pos: (0.0, -0.5, 0.125).into (), + vel: (0.0, 0.0, 0.0).into (), ori: Default::default (), }, spin_speed: 0, @@ -691,7 +732,8 @@ struct GameGraphics { mesh_pitch: RenderableModel, mesh_arrow: RenderableModel, - texture: Texture, + texture_sky: Texture, + texture_grass: Texture, pitch_colors: Vec , grass_index: usize, @@ -754,8 +796,8 @@ impl GameGraphics { let mesh_pitch = renderable_from_iqm_file ("pitch.iqm"); let mesh_arrow = renderable_from_iqm_file ("arrow.iqm"); - let texture = Texture::from_file ("sky.png"); - texture.bind (); + let texture_sky = Texture::from_file ("sky.png"); + let texture_grass = Texture::from_file ("grass.png"); let (pitch_colors, grass_index) = { let silver = (255.0, 255.0, 255.0); @@ -846,6 +888,7 @@ impl GameGraphics { flags: hashmap! { gl::CULL_FACE => true, gl::DEPTH_TEST => true, + gl::TEXTURE_2D => false, gl::STENCIL_TEST => true, }, front_face: Some (FrontFace::Ccw), @@ -979,7 +1022,8 @@ impl GameGraphics { mesh_pitch, mesh_arrow, - texture, + texture_sky, + texture_grass, pitch_colors, grass_index, @@ -1037,7 +1081,9 @@ impl GameGraphics { }; let inverse_airplane = airplane_model_mat.inverse (); - let proj_mat = Mat4::perspective_rh_gl (30.0f32.to_radians (), 1280.0 / 720.0, 0.5, 500.0); + let proj_mat = Mat4::perspective_rh_gl (30.0f32.to_radians (), 1280.0 / 720.0, 0.125, 200.0); + + let airplane_scale = 1.0 / 128.0; let view_mat = match state.play_mode { PlayMode::WindTunnel => { @@ -1054,14 +1100,14 @@ impl GameGraphics { }, PlayMode::FreeFlight => { proj_mat * - Mat4::from_translation ((0.0, -0.6, -4.0).into ()) * + Mat4::from_translation (Vec3::from ((0.0, -4.8, -32.0)) * airplane_scale) * Mat4::from_rotation_x (-90.0f32.to_radians ()) * inverse_airplane }, }; let airplane_model_mat = airplane_model_mat * - Mat4::from_scale ((0.125, 0.125, 0.125).into ()); + Mat4::from_scale ((airplane_scale, airplane_scale, airplane_scale).into ()); let world_model_mat = Mat4::identity (); @@ -1103,9 +1149,9 @@ impl GameGraphics { let draw_sky = true; if draw_sky { - let sky_mvp_mat = view_mat * Mat4::from_scale ((16.0, 16.0, 16.0).into ()); + let sky_mvp_mat = view_mat * Mat4::from_scale ((64.0, 64.0, 64.0).into ()); - self.texture.bind (); + self.texture_sky.bind (); glezz::uniform_matrix_4fv (unis [&MVP], &sky_mvp_mat); glezz::uniform_3fv (unis [&ALBEDO], &white); glezz::uniform_3fv (unis [&MIN_BRIGHT], &white); @@ -1149,7 +1195,7 @@ impl GameGraphics { let attrs = shader_vars.attrs; glezz::uniform_3fv (unis [&MIN_BRIGHT], &black); - glezz::uniform_3fv (unis [&MIN_ALBEDO], &white); + glezz::uniform_3fv (unis [&MIN_ALBEDO], &black); glezz::uniform_3fv (unis [&OBJECT_SPACE_LIGHT], &light); glezz::uniform_3fv (unis [&OBJECT_SPACE_SKY], &Vec3::from ((0.0, 0.0, 1.0))); @@ -1162,6 +1208,8 @@ impl GameGraphics { self.mesh_pitch.draw (attrs, self.grass_index); }); + self.texture_grass.bind (); + // Draw lit ground passes.next ().unwrap ().with_shader (gl_state, self, |shader_vars| { @@ -1184,7 +1232,7 @@ impl GameGraphics { let unis = &shader_vars.unis; glezz::uniform_3fv (unis [&MIN_BRIGHT], &black); - glezz::uniform_3fv (unis [&MIN_ALBEDO], &white); + glezz::uniform_3fv (unis [&MIN_ALBEDO], &black); for arrow in arrows.iter () { let mvp = view_mat * arrow.model_mat;