update `glam`, add tests to the physics
							parent
							
								
									f5da7b5188
								
							
						
					
					
						commit
						96436d6c36
					
				|  | @ -1,5 +1,7 @@ | |||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| version = 3 | ||||
| 
 | ||||
| [[package]] | ||||
| name = "adler32" | ||||
| version = "1.0.4" | ||||
|  | @ -297,9 +299,9 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "glam" | ||||
| version = "0.8.5" | ||||
| version = "0.20.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bb24d4e1b92ceed0450bbf803ac894b597c5b8d0e16f175f7ef28c42024d8cbd" | ||||
| checksum = "68270e16582ea40f9c5b2fcd588fbc9cb696577222e04a64d9085cc314806a8a" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hermit-abi" | ||||
|  |  | |||
|  | @ -15,7 +15,8 @@ float-ord = "0.2.0" | |||
| futures = "0.3.8" | ||||
| futures-util = "0.3.9" | ||||
| gl = "0.14.0" | ||||
| glam = "0.8.5" | ||||
| # glam = "0.8.5" | ||||
| glam = "0.20.1" | ||||
| iota = "0.2.1" | ||||
| maplit = "1.0.2" | ||||
| partial-min-max = "0.4.0" | ||||
|  |  | |||
|  | @ -24,5 +24,62 @@ async fn main () -> Result <()> { | |||
| 	
 | ||||
| 	window.gl_make_current (&gl_ctx).map_err (|e| anyhow! ("Can't make OpenGL context current: {}", e))?; | ||||
| 	
 | ||||
| 	let mut event_pump = sdl_context.event_pump ().unwrap (); | ||||
| 	
 | ||||
| 	let mut time_step = TimeStep::new (60, 1000); | ||||
| 	let mut graphics_frames = 0; | ||||
| 	
 | ||||
| 	let shader_program = shader::shader_from_files ("shaders/terrain-vert.glsl", "shaders/terrain-frag.glsl"); | ||||
| 	let shader_locations = ShaderLocations::new (&shader_program)?; | ||||
| 	
 | ||||
| 	let mesh_cube = renderable_from_iqm_file ("cube.iqm"); | ||||
| 	
 | ||||
| 	'running: loop { | ||||
| 		let _frames_to_do = time_step.step (); | ||||
| 		
 | ||||
| 		for event in event_pump.poll_iter () { | ||||
| 			match event { | ||||
| 				Event::Quit {..} | | ||||
| 				Event::KeyDown { keycode: Some (Keycode::Escape), .. } => { | ||||
| 					break 'running | ||||
| 				}, | ||||
| 				_ => (), | ||||
| 			} | ||||
| 		} | ||||
| 		
 | ||||
| 		window.gl_make_current (&gl_ctx).unwrap (); | ||||
| 		
 | ||||
| 		glezz::enable (gl::DEPTH_TEST); | ||||
| 		
 | ||||
| 		glezz::clear_color (0.392f32, 0.710f32, 0.965f32, 1.0f32); | ||||
| 		glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); | ||||
| 		
 | ||||
| 		window.gl_swap_window (); | ||||
| 		
 | ||||
| 		tokio::time::sleep (Duration::from_millis (15)).await; | ||||
| 	} | ||||
| 	
 | ||||
| 	Ok (()) | ||||
| } | ||||
| 
 | ||||
| struct ShaderLocations { | ||||
| 	attr_pos: u32, | ||||
| 	attr_normal: u32, | ||||
| 	attr_color: u32, | ||||
| 	uni_mvp: i32, | ||||
| } | ||||
| 
 | ||||
| impl ShaderLocations { | ||||
| 	pub fn new (shader_program: &shader::ShaderProgram) -> anyhow::Result <Self> 
 | ||||
| 	{ | ||||
| 		let attr = |name: &str| shader_program.get_attribute_location (&CString::new (name.as_bytes ())?).try_into ().context ("Attribute location negative"); | ||||
| 		let uni = |name: &str| shader_program.get_uniform_location (&CString::new (name.as_bytes ())?).try_into ().context ("Uniform location bad"); | ||||
| 		
 | ||||
| 		Ok (Self { | ||||
| 			attr_pos:    attr ("attr_pos")?, | ||||
| 			attr_normal: attr ("attr_normal")?, | ||||
| 			attr_color:  attr ("attr_color")?, | ||||
| 			uni_mvp:     uni ("uni_mvp")?, | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -25,9 +25,9 @@ where V: Into <Vec3> | |||
| 	let rgb: Vec3 = rgb.into (); | ||||
| 	
 | ||||
| 	Vec3::from (( | ||||
| 		rgb.x () / 255.0, | ||||
| 		rgb.y () / 255.0, | ||||
| 		rgb.z () / 255.0 | ||||
| 		rgb.x / 255.0, | ||||
| 		rgb.y / 255.0, | ||||
| 		rgb.z / 255.0 | ||||
| 	)) | ||||
| } | ||||
| 
 | ||||
|  | @ -293,9 +293,9 @@ impl FlightState { | |||
| 			// Forces
 | ||||
| 			let gravity = Vec3::from ((0.0, 0.0, -0.25)); | ||||
| 			let thrust = 0.125 * nose * throttle; | ||||
| 			let linear_drag = 0.0 * 0.25 * speed * -object_space_dir.y () * nose; | ||||
| 			let linear_drag = 0.0 * 0.25 * speed * -object_space_dir.y * nose; | ||||
| 			
 | ||||
| 			let turbulent_dir = Vec3::from ((-1.0 * object_space_dir.x (), -0.03125 * object_space_dir.y (), -16.0 * object_space_dir.z ())); | ||||
| 			let turbulent_dir = Vec3::from ((-1.0 * object_space_dir.x, -0.03125 * object_space_dir.y, -16.0 * object_space_dir.z)); | ||||
| 			let quadratic_drag = speed * speed * airplane.ori.mul_vec3 (turbulent_dir); | ||||
| 			
 | ||||
| 			let air_drag = linear_drag + quadratic_drag; | ||||
|  | @ -305,9 +305,9 @@ impl FlightState { | |||
| 			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); | ||||
| 			if airplane.pos.z < 0.0 { | ||||
| 				airplane.vel.z = 0.0; | ||||
| 				airplane.pos.z = 0.0; | ||||
| 			} | ||||
| 			
 | ||||
| 			if microstep == microsteps - 1 { | ||||
|  | @ -325,10 +325,10 @@ impl FlightState { | |||
| 				]; | ||||
| 				
 | ||||
| 				// Gauges
 | ||||
| 				let alti = airplane.pos.z () * 100.0; | ||||
| 				let sink_rate = -airplane.vel.z () * 100.0; | ||||
| 				let alti = airplane.pos.z * 100.0; | ||||
| 				let sink_rate = -airplane.vel.z * 100.0; | ||||
| 				let air_speed = speed * 100.0; | ||||
| 				let ground_vel = Vec3::from ((airplane.vel.x (), airplane.vel.y (), 0.0)); | ||||
| 				let ground_vel = Vec3::from ((airplane.vel.x, airplane.vel.y, 0.0)); | ||||
| 				let ground_speed = ground_vel.length () * 100.0; | ||||
| 				let glide_ratio = if sink_rate > 1.0 && throttle == 0.0 { | ||||
| 					Some (ground_speed / sink_rate) | ||||
|  | @ -457,8 +457,8 @@ fn make_object_space_vec (inverse_model_mat: &Mat4, world_space_vec: &Vec3) | |||
| -> Vec3 | ||||
| { | ||||
| 	let v = world_space_vec; | ||||
| 	let v4 = *inverse_model_mat * Vec4::from ((v.x (), v.y (), v.z (), 0.0)); | ||||
| 	Vec3::from ((v4.x (), v4.y (), v4.z ())) | ||||
| 	let v4 = *inverse_model_mat * Vec4::from ((v.x, v.y, v.z, 0.0)); | ||||
| 	Vec3::from ((v4.x, v4.y, v4.z)) | ||||
| } | ||||
| 
 | ||||
| #[derive (Clone)] | ||||
|  | @ -861,11 +861,12 @@ impl GameGraphics { | |||
| 		
 | ||||
| 		let light = state.wind_tunnel.sunlight.to_vec3 (); | ||||
| 		
 | ||||
| 		let shadow_mat = { | ||||
| 			let mut mat = Mat4::identity (); | ||||
| 			mat.set_z_axis ((-light.x () / light.z (), -light.y () / light.z (), 0.0, 0.0).into ()); | ||||
| 			mat | ||||
| 		}; | ||||
| 		let shadow_mat = Mat4::from_cols ( | ||||
| 			(1.0, 0.0, 0.0, 0.0).into (), | ||||
| 			(0.0, 1.0, 0.0, 0.0).into (), | ||||
| 			(-light.x / light.z, -light.y / light.z, 0.0, 0.0).into (), | ||||
| 			(0.0, 0.0, 0.0, 1.0).into (), | ||||
| 		); | ||||
| 		
 | ||||
| 		let mut passes = self.passes.iter (); | ||||
| 		//println! ("Started frame");
 | ||||
|  | @ -931,7 +932,7 @@ impl GameGraphics { | |||
| 		let inverse_truck = truck_model_mat.inverse (); | ||||
| 		let truck_model_mat = truck_model_mat * Mat4::from_scale ((airplane_scale, airplane_scale, airplane_scale).into ()); | ||||
| 		
 | ||||
| 		let world_model_mat = Mat4::identity (); | ||||
| 		let world_model_mat = Mat4::IDENTITY; | ||||
| 		
 | ||||
| 		use uniforms::*; | ||||
| 		
 | ||||
|  | @ -1272,7 +1273,7 @@ fn main () { | |||
| 				let gravity = (0.0, 0.0, -1.0).into (); | ||||
| 				
 | ||||
| 				let wind = state.wind.to_vec3 () * -1.0; | ||||
| 				let wind_force = (wind.x (), 0.125 * wind.y (), wind.z ()).into (); | ||||
| 				let wind_force = (wind.x, 0.125 * wind.y, wind.z).into (); | ||||
| 				
 | ||||
| 				let get_flash = |control_type, default_color| { | ||||
| 					if state.user_control == control_type { | ||||
|  | @ -1314,10 +1315,10 @@ fn main () { | |||
| 			
 | ||||
| 			let d = arrow.direction / dir_len; | ||||
| 			
 | ||||
| 			let up: Vec3 = if d.z () > 0.5 { | ||||
| 			let up: Vec3 = if d.z > 0.5 { | ||||
| 				(-1.0, 0.0, 0.0) | ||||
| 			} | ||||
| 			else if d.z () < -0.5 { | ||||
| 			else if d.z < -0.5 { | ||||
| 				(-1.0, 0.0, 0.0) | ||||
| 			} | ||||
| 			else { | ||||
|  | @ -1329,11 +1330,12 @@ fn main () { | |||
| 			let left = d.cross (up); | ||||
| 			let up = d.cross (left); | ||||
| 			
 | ||||
| 			let mut dir_mat = Mat4::identity (); | ||||
| 			
 | ||||
| 			dir_mat.set_x_axis ((left.x (), left.y (), left.z (), 0.0).into ()); | ||||
| 			dir_mat.set_y_axis ((up.x (), up.y (), up.z (), 0.0).into ()); | ||||
| 			dir_mat.set_z_axis ((d.x (), d.y (), d.z (), 0.0).into ()); | ||||
| 			let dir_mat = Mat4::from_cols ( | ||||
| 				(left, 0.0).into (), | ||||
| 				(up, 0.0).into (), | ||||
| 				(d, 0.0).into (), | ||||
| 				(0.0, 0.0, 0.0, 1.0).into (), | ||||
| 			); | ||||
| 			
 | ||||
| 			let s = dir_len * 0.0625; | ||||
| 			
 | ||||
|  |  | |||
|  | @ -9,8 +9,6 @@ use std::io::Cursor; | |||
| 
 | ||||
| pub struct VertexBuffer { | ||||
| 	id: u32, | ||||
| 	// Not bytes. 
 | ||||
| 	len: usize, | ||||
| } | ||||
| 
 | ||||
| const FLOAT_SIZE: usize = 4; | ||||
|  | @ -59,7 +57,6 @@ impl VertexBuffer { | |||
| 		
 | ||||
| 		Self { | ||||
| 			id, | ||||
| 			len, | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
|  | @ -74,7 +71,6 @@ impl VertexBuffer { | |||
| 		
 | ||||
| 		Self { | ||||
| 			id, | ||||
| 			len, | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
|  | @ -103,9 +99,6 @@ pub struct IndexBuffer { | |||
| 	/// The OpenGL ID of the buffer
 | ||||
| 	id: u32, | ||||
| 	
 | ||||
| 	/// The count of 32-bit indices the buffer can store
 | ||||
| 	len: usize, | ||||
| 	
 | ||||
| 	/// The largest index stored in the buffer when it was created
 | ||||
| 	max: u32, | ||||
| } | ||||
|  | @ -144,7 +137,6 @@ impl IndexBuffer { | |||
| 		
 | ||||
| 		Self { | ||||
| 			id, | ||||
| 			len: slice.len () / IDX_SIZE, | ||||
| 			max: max.unwrap (), | ||||
| 		} | ||||
| 	} | ||||
|  | @ -166,7 +158,6 @@ impl IndexBuffer { | |||
| 		
 | ||||
| 		Self { | ||||
| 			id, | ||||
| 			len: slice.len (), | ||||
| 			max: *max.unwrap (), | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
							
								
								
									
										196
									
								
								src/physics.rs
								
								
								
								
							
							
						
						
									
										196
									
								
								src/physics.rs
								
								
								
								
							|  | @ -1,39 +1,37 @@ | |||
| use glam::{Vec2, Vec3}; | ||||
| use partial_min_max::{min, max}; | ||||
| 
 | ||||
| #[derive (Debug, PartialEq)] | ||||
| pub struct PhysicsBody { | ||||
| 	pos: Vec3, | ||||
| 	vel: Vec3, | ||||
| } | ||||
| 
 | ||||
| #[derive (Debug, PartialEq)] | ||||
| pub struct PhysicsResult { | ||||
| 	body: PhysicsBody, | ||||
| 	triangles_hit: Vec <usize>, | ||||
| 	kill: bool, | ||||
| 	pub body: PhysicsBody, | ||||
| 	pub triangles_hit: Vec <usize>, | ||||
| 	pub kill: bool, | ||||
| } | ||||
| 
 | ||||
| #[derive (Copy, Clone)] | ||||
| pub struct Triangle { | ||||
| 	verts: [Vec3; 3], | ||||
| } | ||||
| 
 | ||||
| pub trait MeshBuffer { | ||||
| 	fn num_triangles (&self) -> usize; | ||||
| 	fn get_triangle (&self, i: usize) -> Triangle; | ||||
| } | ||||
| 
 | ||||
| fn vec_min (a: &Vec3, b: &Vec3) -> Vec3 { | ||||
| 	Vec3::from (( | ||||
| 		min (a.x (), b.x ()), | ||||
| 		min (a.y (), b.y ()), | ||||
| 		min (a.z (), b.z ()) | ||||
| 		min (a.x, b.x), | ||||
| 		min (a.y, b.y), | ||||
| 		min (a.z, b.z) | ||||
| 	)) | ||||
| } | ||||
| 
 | ||||
| fn vec_max (a: &Vec3, b: &Vec3) -> Vec3 { | ||||
| 	Vec3::from (( | ||||
| 		max (a.x (), b.x ()), | ||||
| 		max (a.y (), b.y ()), | ||||
| 		max (a.z (), b.z ()) | ||||
| 		max (a.x, b.x), | ||||
| 		max (a.y, b.y), | ||||
| 		max (a.z, b.z) | ||||
| 	)) | ||||
| } | ||||
| 
 | ||||
|  | @ -53,7 +51,7 @@ impl Triangle { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive (Clone)] | ||||
| #[derive (Clone, Debug, PartialEq)] | ||||
| pub struct Collision { | ||||
| 	t: f32, | ||||
| 	p_impact: Vec3, | ||||
|  | @ -72,11 +70,9 @@ impl Collision { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn get_candidate <MB> (world: &MB, p0: Vec3, p1: Vec3) | ||||
| pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) | ||||
| -> Collision | ||||
| where MB: MeshBuffer | ||||
| { | ||||
| 	let radius = 0.0625f32; | ||||
| 	let radius3 = Vec3::from (( | ||||
| 		radius, | ||||
| 		radius, | ||||
|  | @ -91,19 +87,17 @@ where MB: MeshBuffer | |||
| 		i: 0, | ||||
| 	}; | ||||
| 	
 | ||||
| 	for i in 0..world.num_triangles () { | ||||
| 		let tri = world.get_triangle (i); | ||||
| 		
 | ||||
| 	for (i, tri) in world.iter ().enumerate () { | ||||
| 		let tri_min = tri.min () - radius3; | ||||
| 		let tri_max = tri.max () + radius3; | ||||
| 		
 | ||||
| 		let ray_min = min (p0, p1); | ||||
| 		let ray_max = max (p0, p1); | ||||
| 		let ray_min = p0.min (p1); | ||||
| 		let ray_max = p0.max (p1); | ||||
| 		
 | ||||
| 		if 
 | ||||
| 			ray_max.x () < tri_min.x () || ray_min.x () > tri_max.x () || | ||||
| 			ray_max.y () < tri_min.y () || ray_min.y () > tri_max.y () || | ||||
| 			ray_max.z () < tri_min.z () || ray_min.z () > tri_max.z () | ||||
| 			ray_max.x < tri_min.x || ray_min.x > tri_max.x || | ||||
| 			ray_max.y < tri_min.y || ray_min.y > tri_max.y || | ||||
| 			ray_max.z < tri_min.z || ray_min.z > tri_max.z | ||||
| 		{ | ||||
| 			// AABB reject
 | ||||
| 			continue; | ||||
|  | @ -189,14 +183,14 @@ where MB: MeshBuffer | |||
| 			// and Y is the cross of those.
 | ||||
| 			
 | ||||
| 			// I forgot the maths word for this
 | ||||
| 			let discriminant = radius * radius - a_ray.y () * a_ray.y (); | ||||
| 			let discriminant = radius * radius - a_ray.y * a_ray.y; | ||||
| 			
 | ||||
| 			if discriminant < 0.0 { | ||||
| 				// No possible collision
 | ||||
| 				continue; | ||||
| 			} | ||||
| 			
 | ||||
| 			let t = (a_ray.x () - discriminant.sqrt ()) / (p1 - p0).length (); | ||||
| 			let t = (a_ray.x - discriminant.sqrt ()) / (p1 - p0).length (); | ||||
| 			
 | ||||
| 			if t < 0.0 || t > 1.0 { | ||||
| 				// The cylinder is along the line,
 | ||||
|  | @ -280,25 +274,31 @@ where MB: MeshBuffer | |||
| 	candidate | ||||
| } | ||||
| 
 | ||||
| pub fn physics_step <MB> (input: &PhysicsBody, world: &MB) | ||||
| -> PhysicsResult | ||||
| where MB: MeshBuffer | ||||
| pub struct Params { | ||||
| 	dt: f32, | ||||
| 	gravity: Vec3, | ||||
| 	margin: f32, | ||||
| } | ||||
| 
 | ||||
| pub fn physics_step ( | ||||
| 	params: &Params, world: &[Triangle], 
 | ||||
| 	radius: f32, input: &PhysicsBody, 
 | ||||
| ) -> PhysicsResult | ||||
| { | ||||
| 	let dt = 1.0 / 60.0; | ||||
| 	let z = Vec3::from ((0.0, 0.0, 1.0)); | ||||
| 	let gravity = z * -16.0 * dt; | ||||
| 	let margin = 0.00125; | ||||
| 	let margin = params.margin; | ||||
| 	let dt = params.dt; | ||||
| 	
 | ||||
| 	let mut t_remaining = 1.0; | ||||
| 	
 | ||||
| 	let mut old_pos = input.pos; | ||||
| 	let mut new_vel = input.vel + gravity; | ||||
| 	let mut new_vel = input.vel + params.gravity; | ||||
| 	let mut new_pos = old_pos + new_vel * dt * t_remaining; | ||||
| 	
 | ||||
| 	let mut triangles_hit = Vec::new (); | ||||
| 	
 | ||||
| 	for i in 0..5 { | ||||
| 		let candidate = get_candidate (world, old_pos, new_pos); | ||||
| 	// Do 5 iterations of the sub-step, trying to converge on a valid state
 | ||||
| 	for _ in 0..5 { | ||||
| 		let candidate = get_candidate (world, old_pos, new_pos, radius); | ||||
| 		
 | ||||
| 		if candidate.t <= 1.0 { | ||||
| 			t_remaining *= 1.0 - candidate.t; | ||||
|  | @ -315,6 +315,8 @@ where MB: MeshBuffer | |||
| 			new_vel += candidate.normal * speed_towards_normal; | ||||
| 			// But also compensate for the slide distance it lost
 | ||||
| 			new_pos = push_out_pos + new_vel * dt * t_remaining; | ||||
| 			
 | ||||
| 			triangles_hit.push (candidate.i); | ||||
| 		} | ||||
| 		else { | ||||
| 			t_remaining = 0.0; | ||||
|  | @ -332,3 +334,121 @@ where MB: MeshBuffer | |||
| 		kill: false, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[cfg (test)] | ||||
| mod test { | ||||
| 	use super::*; | ||||
| 	
 | ||||
| 	#[test] | ||||
| 	fn test_physics () { | ||||
| 		// Remember, Z is up
 | ||||
| 		
 | ||||
| 		let params = Params { | ||||
| 			dt: 1.0, | ||||
| 			gravity: (0.0, 0.0, 0.0).into (), | ||||
| 			margin: 0.00125, | ||||
| 		}; | ||||
| 		
 | ||||
| 		let world: Vec <_> = vec! [ | ||||
| 			( | ||||
| 				(0.0, 0.0, 0.0), | ||||
| 				(0.0, 2.0, 0.0), | ||||
| 				(2.0, 0.0, 0.0), | ||||
| 			), | ||||
| 		].into_iter () | ||||
| 		.map (|(v0, v1, v2)| { | ||||
| 			Triangle { | ||||
| 				verts: [ | ||||
| 					v0.into (), | ||||
| 					v1.into (), | ||||
| 					v2.into (), | ||||
| 				], | ||||
| 			} | ||||
| 		}) | ||||
| 		.collect (); | ||||
| 		
 | ||||
| 		let magic_0 = f32::sqrt (f32::powf (0.5 + params.margin, 2.0) / 2.0); | ||||
| 		
 | ||||
| 		for ((radius, body_before), e) in [ | ||||
| 			// Ray striking triangle from above, stops at triangle
 | ||||
| 			( | ||||
| 				( | ||||
| 					0.0, | ||||
| 					PhysicsBody { | ||||
| 						pos: (0.5, 0.5, 0.5).into (), | ||||
| 						vel: (0.0, 0.0, -1.0).into (), | ||||
| 					}, | ||||
| 				), | ||||
| 				PhysicsResult { | ||||
| 					body: PhysicsBody { | ||||
| 						pos: (0.5, 0.5, params.margin).into (), | ||||
| 						vel: (0.0, 0.0, 0.0).into (), | ||||
| 					}, | ||||
| 					triangles_hit: vec! [0], | ||||
| 					kill: false, | ||||
| 				}, | ||||
| 			), | ||||
| 			// Ball striking triangle from above, stops at ball radius
 | ||||
| 			( | ||||
| 				( | ||||
| 					0.5, | ||||
| 					PhysicsBody { | ||||
| 						pos: (0.5, 0.5, 2.0).into (), | ||||
| 						vel: (0.0, 0.0, -2.0).into (), | ||||
| 					}, | ||||
| 				), | ||||
| 				PhysicsResult { | ||||
| 					body: PhysicsBody { | ||||
| 						pos: (0.5, 0.5, params.margin + 0.5).into (), | ||||
| 						vel: (0.0, 0.0, 0.0).into (), | ||||
| 					}, | ||||
| 					triangles_hit: vec! [0], | ||||
| 					kill: false, | ||||
| 				}, | ||||
| 			), | ||||
| 			// Ball striking triangle on edge
 | ||||
| 			( | ||||
| 				( | ||||
| 					0.5, | ||||
| 					PhysicsBody { | ||||
| 						pos: (-2.0, 1.0, 0.0).into (), | ||||
| 						vel: (2.0, 0.0, 0.0).into (), | ||||
| 					}, | ||||
| 				), | ||||
| 				PhysicsResult { | ||||
| 					body: PhysicsBody { | ||||
| 						pos: (-params.margin - 0.5, 1.0, 0.0).into (), | ||||
| 						vel: (0.0, 0.0, 0.0).into (), | ||||
| 					}, | ||||
| 					triangles_hit: vec! [0], | ||||
| 					kill: false, | ||||
| 				}, | ||||
| 			), | ||||
| 			// Ball striking triangle on diagonal edge
 | ||||
| 			( | ||||
| 				( | ||||
| 					0.5, | ||||
| 					PhysicsBody { | ||||
| 						pos: (2.0, 2.0, 0.0).into (), | ||||
| 						vel: (-2.0, -2.0, 0.0).into (), | ||||
| 					}, | ||||
| 				), | ||||
| 				PhysicsResult { | ||||
| 					body: PhysicsBody { | ||||
| 						pos: (1.0 + magic_0, 1.0 + magic_0, 0.0).into (), | ||||
| 						vel: (0.0, 0.0, 0.0).into (), | ||||
| 					}, | ||||
| 					triangles_hit: vec! [0], | ||||
| 					kill: false, | ||||
| 				}, | ||||
| 			), | ||||
| 		] { | ||||
| 			let a = physics_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); | ||||
| 			assert_eq! (a.triangles_hit, e.triangles_hit); | ||||
| 			assert_eq! (a.kill, e.kill); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ pub use crate::{ | |||
| 	gpu_buffers, | ||||
| 	network_protocol::*, | ||||
| 	quinn_common::make_client_endpoint, | ||||
| 	renderable_model::renderable_from_iqm_file, | ||||
| 	shader, | ||||
| 	timestep::TimeStep, | ||||
| }; | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ pub struct RenderableMesh { | |||
| pub struct RenderableModel { | ||||
| 	num_pos: usize, | ||||
| 	num_uv: usize, | ||||
| 	num_normal: usize, | ||||
| 	
 | ||||
| 	vertexes: VertexBuffer, | ||||
| 	indexes: IndexBuffer, | ||||
|  | @ -89,7 +88,6 @@ impl RenderableModel { | |||
| 		Self { | ||||
| 			num_pos, | ||||
| 			num_uv, | ||||
| 			num_normal, | ||||
| 			
 | ||||
| 			vertexes, | ||||
| 			indexes, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 _
						_