diff --git a/.gitignore b/.gitignore index 1eeeee3..08272ef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/quic_server.crt /target **/*.rs.bk diff --git a/cube.iqm b/cube.iqm new file mode 100644 index 0000000..e923f4f Binary files /dev/null and b/cube.iqm differ diff --git a/sphere.iqm b/sphere.iqm new file mode 100644 index 0000000..2a9c7a1 Binary files /dev/null and b/sphere.iqm differ diff --git a/src/bin/platformer.rs b/src/bin/platformer.rs index 71da5ad..8cf36d9 100644 --- a/src/bin/platformer.rs +++ b/src/bin/platformer.rs @@ -8,6 +8,7 @@ use maplit::hashmap; use opengl_rust::{ prelude::*, gl_state::*, + physics::PhysicsBody, renderable_model::{ attributes, RenderableModel, @@ -30,6 +31,11 @@ pub const } } +#[derive (Default)] +struct GameState { + player: PhysicsBody, +} + struct GameGraphics { passes: Vec , @@ -38,6 +44,7 @@ struct GameGraphics { mesh_cube: RenderableModel, mesh_sky: RenderableModel, + mesh_sphere: RenderableModel, text_stream: TriangleStream, @@ -53,6 +60,7 @@ impl ShaderLookup for GameGraphics { impl GameGraphics { fn draw ( &self, + state: &GameState, gl_state: &mut GlState, ) { use uniforms as u; @@ -71,7 +79,7 @@ impl GameGraphics { let world_model_mat = Mat4::IDENTITY; self.passes [0].with (gl_state, || { - glezz::clear_color (1.0f32, 0.0f32, 1.0f32, 1.0f32); + glezz::clear_color (0.5f32, 0.5f32, 0.5f32, 1.0f32); glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); }); @@ -80,14 +88,21 @@ impl GameGraphics { let unis = shader_vars.unis; { - let mvp = view_mat * Mat4::IDENTITY; + let mvp = view_mat * + Mat4::from_translation (state.player.pos) * + Mat4::from_scale ((0.5, 0.5, 0.5).into ()); glezz::uniform_matrix_4fv (unis [&u::MVP], &mvp); - //let object_space_light = make_object_space_vec (&inverse_truck, &light); - //let object_space_sky = make_object_space_vec (&inverse_truck, &Vec3::from ((0.0, 0.0, 1.0))); - - //glezz::uniform_3fv (unis [&OBJECT_SPACE_LIGHT], &object_space_light); - //glezz::uniform_3fv (unis [&OBJECT_SPACE_SKY], &object_space_sky); + self.mesh_sphere.draw_all (attrs, |_| { + true + }); + } + + { + let mvp = view_mat * + Mat4::from_scale ((4.0, 4.0, 1.0).into ()) * + Mat4::from_translation ((0.0, 0.0, -2.0).into ()); + glezz::uniform_matrix_4fv (unis [&u::MVP], &mvp); self.mesh_cube.draw_all (attrs, |_| { true @@ -104,7 +119,7 @@ impl GameGraphics { glezz::uniform_3fv (unis [&u::MIN_ALBEDO], &black); glezz::uniform_1i (unis [&u::TEXTURE], 0); - self.mesh_sky.draw_all (attrs, |_| true); + // self.mesh_sky.draw_all (attrs, |_| true); } }); } @@ -169,6 +184,7 @@ async fn main () -> Result <()> { let mesh_cube = renderable_from_iqm_file ("cube.iqm"); let mesh_sky = renderable_from_iqm_file ("sky-sphere.iqm"); + let mesh_sphere = renderable_from_iqm_file ("sphere.iqm"); let passes = vec![ // Clear everything @@ -185,7 +201,7 @@ async fn main () -> Result <()> { (gl::TEXTURE_2D, true), (gl::STENCIL_TEST, false), ].into_iter ()) - .front_face (FrontFace::Cw) + .front_face (FrontFace::Ccw) .color_mask ([1, 1, 1, 1]) .depth_mask (1) .clone (), @@ -221,6 +237,7 @@ async fn main () -> Result <()> { let graphics = GameGraphics { mesh_cube, mesh_sky, + mesh_sphere, passes, shader_lookup, shaders, @@ -229,6 +246,35 @@ async fn main () -> Result <()> { }; let mut gl_state = Default::default (); + let mut game_state = GameState::default (); + let phys_params = opengl_rust::physics::Params { + dt: 1.0 / 60.0, + gravity: (0.0, 0.0, -0.25).into (), + margin: 0.00125, + }; + let phys_world: Vec <_> = vec! [ + ( + (-4.0, -4.0, -1.0), + (-4.0, 4.0, -1.0), + (4.0, -4.0, -1.0), + ), + ( + (4.0, 4.0, -1.0), + (4.0, -4.0, -1.0), + (-4.0, 4.0, -1.0), + ), + ].into_iter () + .map (|(v0, v1, v2)| { + opengl_rust::physics::Triangle { + verts: [ + v0.into (), + v1.into (), + v2.into (), + ], + } + }) + .collect (); + let player_speed = 2.0; 'running: loop { let _frames_to_do = time_step.step (); @@ -239,13 +285,35 @@ async fn main () -> Result <()> { Event::KeyDown { keycode: Some (Keycode::Escape), .. } => { break 'running }, + Event::KeyDown { keycode: Some (Keycode::R), .. } => { + game_state = Default::default (); + }, + _ => (), } } + let kb_state = event_pump.keyboard_state (); + game_state.player.vel.x = 0.0; + game_state.player.vel.y = 0.0; + if kb_state.is_scancode_pressed (Scancode::Left) { + game_state.player.vel.x -= player_speed; + } + if kb_state.is_scancode_pressed (Scancode::Right) { + game_state.player.vel.x += player_speed; + } + if kb_state.is_scancode_pressed (Scancode::Up) { + game_state.player.vel.y += player_speed; + } + if kb_state.is_scancode_pressed (Scancode::Down) { + game_state.player.vel.y -= player_speed; + } + + game_state.player = opengl_rust::physics::step (&phys_params, &phys_world, 0.5, &game_state.player).body; + window.gl_make_current (&gl_ctx).unwrap (); - graphics.draw (&mut gl_state); + graphics.draw (&game_state, &mut gl_state); window.gl_swap_window (); graphics_frames += 1; diff --git a/src/physics.rs b/src/physics.rs index 886abc9..706c91b 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,10 +1,10 @@ use glam::{Vec2, Vec3}; use partial_min_max::{min, max}; -#[derive (Debug, PartialEq)] +#[derive (Debug, Default, PartialEq)] pub struct PhysicsBody { - pos: Vec3, - vel: Vec3, + pub pos: Vec3, + pub vel: Vec3, } #[derive (Debug, PartialEq)] @@ -16,7 +16,7 @@ pub struct PhysicsResult { #[derive (Copy, Clone)] pub struct Triangle { - verts: [Vec3; 3], + pub verts: [Vec3; 3], } fn vec_min (a: &Vec3, b: &Vec3) -> Vec3 { @@ -193,6 +193,7 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) let denom = (p1 - p0).length (); let t_times_denom = a_ray.x - discriminant.sqrt (); + let t = t_times_denom / denom; if t_times_denom < 0.0 || t_times_denom > denom { // The cylinder is along the line, @@ -204,11 +205,10 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) let p_impact_times_denom = p0 * (denom - t_times_denom) + p1 * (t_times_denom); let p_impact = p_impact_times_denom / denom; - let impact_along_cylinder_times_denom = Vec3::dot (cylinder_axis, p_impact_times_denom); - let impact_along_cylinder = impact_along_cylinder_times_denom / denom; + let impact_along_cylinder = Vec3::dot (cylinder_axis, p_impact); let a_along_cylinder = Vec3::dot (cylinder_axis, a); - if impact_along_cylinder_times_denom < a_along_cylinder * denom || impact_along_cylinder_times_denom > Vec3::dot (cylinder_axis, b) * denom + if impact_along_cylinder < a_along_cylinder || impact_along_cylinder > Vec3::dot (cylinder_axis, b) { // The infinite cylinder is on the line segment, // but the finite cylinder is not. @@ -279,12 +279,12 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) } pub struct Params { - dt: f32, - gravity: Vec3, - margin: f32, + pub dt: f32, + pub gravity: Vec3, + pub margin: f32, } -pub fn physics_step ( +pub fn step ( params: &Params, world: &[Triangle], radius: f32, input: &PhysicsBody, ) -> PhysicsResult @@ -447,7 +447,7 @@ mod test { }, ), ] { - let a = physics_step (¶ms, &world, radius, &body_before); + let a = step (¶ms, &world, radius, &body_before); assert! (a.body.pos.distance_squared (e.body.pos) <= 0.00125); assert! (a.body.vel.distance_squared (e.body.vel) <= 0.00125); @@ -480,7 +480,7 @@ mod test { }, ); - let a = physics_step (¶ms, &world, radius, &body_before); + let a = step (¶ms, &world, radius, &body_before); let e = PhysicsResult { body: PhysicsBody { @@ -503,7 +503,7 @@ mod test { vel: (0.0, 0.0, 0.0).into (), }; - let a = physics_step (¶ms, &world, radius, &body_before); + let a = step (¶ms, &world, radius, &body_before); let e = PhysicsResult { body: PhysicsBody {