Compare commits
	
		
			No commits in common. "main" and "14665512e17da7fd43b2c9eb9dbb61624158613b" have entirely different histories. 
		
	
	
		
			main
			...
			14665512e1
		
	
		| 
						 | 
				
			
			@ -1,13 +1,7 @@
 | 
			
		|||
/checkerboard.png
 | 
			
		||||
/config.json
 | 
			
		||||
/gltf
 | 
			
		||||
/quic_server.crt
 | 
			
		||||
/target
 | 
			
		||||
**/*.rs.bk
 | 
			
		||||
/videos
 | 
			
		||||
 | 
			
		||||
*.blend*
 | 
			
		||||
*.data
 | 
			
		||||
*.obj
 | 
			
		||||
*.trace
 | 
			
		||||
*.xcf
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1327,10 +1327,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
 | 
			
		|||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tokio"
 | 
			
		||||
version = "1.15.0"
 | 
			
		||||
version = "1.5.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
 | 
			
		||||
checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg 1.0.1",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "memchr",
 | 
			
		||||
| 
						 | 
				
			
			@ -1346,9 +1347,9 @@ dependencies = [
 | 
			
		|||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tokio-macros"
 | 
			
		||||
version = "1.7.0"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
 | 
			
		||||
checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ rmp-serde = "0.15.4"
 | 
			
		|||
serde = { version = "1.0.125", features = ["derive"] }
 | 
			
		||||
serde_json = "1.0.73"
 | 
			
		||||
sdl2 = "0.32.2"
 | 
			
		||||
tokio = { version = "1.15.0", features = ["full"] }
 | 
			
		||||
tokio = { version = "1.5.0", features = ["full"] }
 | 
			
		||||
tracing = "0.1.22"
 | 
			
		||||
tracing-subscriber = "0.2.15"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										
											BIN
										
									
								
								crate.png
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								crate.png
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.9 KiB  | 
| 
						 | 
				
			
			@ -4,7 +4,7 @@ use std::{
 | 
			
		|||
 | 
			
		||||
use glam::{
 | 
			
		||||
	Quat,
 | 
			
		||||
	// Vec4,
 | 
			
		||||
	Vec4,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use opengl_rust::{
 | 
			
		||||
| 
						 | 
				
			
			@ -15,13 +15,18 @@ use opengl_rust::{
 | 
			
		|||
		Pass,
 | 
			
		||||
	},
 | 
			
		||||
	renderable_model::{
 | 
			
		||||
		RenderableModel,
 | 
			
		||||
		attributes,
 | 
			
		||||
		RenderableModel,
 | 
			
		||||
	},
 | 
			
		||||
	shader_closure::ShaderLookup,
 | 
			
		||||
	texture::Texture,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
	GameState,
 | 
			
		||||
	TriangleStream,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
mod uniforms {
 | 
			
		||||
use iota::iota;
 | 
			
		||||
iota! {
 | 
			
		||||
| 
						 | 
				
			
			@ -42,12 +47,12 @@ pub struct Graphics {
 | 
			
		|||
	shaders: Vec <ShaderClosure>,
 | 
			
		||||
	shader_lookup: HashMap <u32, usize>,
 | 
			
		||||
	
 | 
			
		||||
	// mesh_cube: RenderableModel,
 | 
			
		||||
	mesh_cube: RenderableModel,
 | 
			
		||||
	mesh_protag_kun: RenderableModel,
 | 
			
		||||
	mesh_sky: RenderableModel,
 | 
			
		||||
	mesh_sphere: RenderableModel,
 | 
			
		||||
	
 | 
			
		||||
	// text_stream: TriangleStream,
 | 
			
		||||
	text_stream: TriangleStream,
 | 
			
		||||
	
 | 
			
		||||
	texture_crate: Texture,
 | 
			
		||||
	texture_earth: Texture,
 | 
			
		||||
| 
						 | 
				
			
			@ -95,7 +100,7 @@ impl Graphics {
 | 
			
		|||
		})
 | 
			
		||||
		.collect ();
 | 
			
		||||
		
 | 
			
		||||
		// let mesh_cube = renderable_from_iqm_file ("cube.iqm");
 | 
			
		||||
		let mesh_cube = renderable_from_iqm_file ("cube.iqm");
 | 
			
		||||
		let mesh_protag_kun = renderable_from_iqm_file ("protag-kun.iqm");
 | 
			
		||||
		let mesh_sky = renderable_from_iqm_file ("sky-sphere.iqm");
 | 
			
		||||
		let mesh_sphere = renderable_from_iqm_file ("sphere.iqm");
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +125,7 @@ impl Graphics {
 | 
			
		|||
				.depth_mask (1)
 | 
			
		||||
			.clone (),
 | 
			
		||||
		];
 | 
			
		||||
		/*
 | 
			
		||||
		
 | 
			
		||||
		let text_stream = TriangleStream {
 | 
			
		||||
			verts: gpu_buffers::VertexBuffer::streaming (4 * 5 * 6 * 1024),
 | 
			
		||||
			indices: {
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +140,7 @@ impl Graphics {
 | 
			
		|||
				gpu_buffers::IndexBuffer::from_slice_u32 (&v)
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
		*/
 | 
			
		||||
		
 | 
			
		||||
		let shader_lookup = HashMap::from_iter (shaders.iter ().enumerate ()
 | 
			
		||||
		.map (|(i, s)| {
 | 
			
		||||
			(s.get_id (), i)
 | 
			
		||||
| 
						 | 
				
			
			@ -149,14 +154,14 @@ impl Graphics {
 | 
			
		|||
		});
 | 
			
		||||
		
 | 
			
		||||
		Graphics {
 | 
			
		||||
			// mesh_cube,
 | 
			
		||||
			mesh_cube,
 | 
			
		||||
			mesh_protag_kun,
 | 
			
		||||
			mesh_sky,
 | 
			
		||||
			mesh_sphere,
 | 
			
		||||
			passes,
 | 
			
		||||
			shader_lookup,
 | 
			
		||||
			shaders,
 | 
			
		||||
			// text_stream,
 | 
			
		||||
			text_stream,
 | 
			
		||||
			texture_crate: Texture::from_file ("crate.png"),
 | 
			
		||||
			texture_earth: Texture::from_file ("earth.png"),
 | 
			
		||||
			texture_sky: Texture::from_file ("sky.png"),
 | 
			
		||||
| 
						 | 
				
			
			@ -167,15 +172,14 @@ impl Graphics {
 | 
			
		|||
	
 | 
			
		||||
	pub fn draw (
 | 
			
		||||
		&self,
 | 
			
		||||
		phys_tris: &[opengl_rust::physics::Triangle],
 | 
			
		||||
		logic: &crate::LogicState,
 | 
			
		||||
		state: &GameState,
 | 
			
		||||
		gl_state: &mut GlState,
 | 
			
		||||
		level: &crate::LoadedLevel,
 | 
			
		||||
		camera: &crate::level_loader::Camera,
 | 
			
		||||
		camera: &crate::Camera,
 | 
			
		||||
	) {
 | 
			
		||||
		// use serde::Deserialize;
 | 
			
		||||
		use serde::Deserialize;
 | 
			
		||||
		use uniforms as u;
 | 
			
		||||
		/*
 | 
			
		||||
		
 | 
			
		||||
		#[derive (Default, Deserialize)]
 | 
			
		||||
		struct Config {
 | 
			
		||||
			camera: CameraCfg,
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +192,7 @@ impl Graphics {
 | 
			
		|||
			#[serde(default)]
 | 
			
		||||
			translate_mix: f32,
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		/*
 | 
			
		||||
		let cfg: Option <Config> = std::fs::read_to_string ("config.json").ok ()
 | 
			
		||||
		.map (|s| serde_json::from_str (s.as_str ()).ok ())
 | 
			
		||||
		.flatten ();
 | 
			
		||||
| 
						 | 
				
			
			@ -212,7 +216,7 @@ impl Graphics {
 | 
			
		|||
		) = camera.transform.clone ().decomposed ();
 | 
			
		||||
		
 | 
			
		||||
		let cam_trans = Vec3::from (cam_trans);
 | 
			
		||||
		let cam_trans = Vec3::new (cam_trans.x.max (logic.player.pos.x + 4.0), cam_trans.y, cam_trans.z);
 | 
			
		||||
		let cam_trans = Vec3::new (cam_trans.x.max (state.player.pos.x + 4.0), cam_trans.y, cam_trans.z);
 | 
			
		||||
		
 | 
			
		||||
		let view_mat = 
 | 
			
		||||
		Mat4::from_quat (Quat::from_array (cam_rot).inverse ()) *
 | 
			
		||||
| 
						 | 
				
			
			@ -222,6 +226,8 @@ impl Graphics {
 | 
			
		|||
		
 | 
			
		||||
		let view_mat = proj_mat * view_mat;
 | 
			
		||||
		
 | 
			
		||||
		let world_model_mat = Mat4::IDENTITY;
 | 
			
		||||
		
 | 
			
		||||
		self.passes [0].with (gl_state, || {
 | 
			
		||||
			glezz::clear_color (109f32 / 255.0, 194f32 / 255.0, 202f32 / 255.0, 1.0f32);
 | 
			
		||||
			glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
 | 
			
		||||
| 
						 | 
				
			
			@ -238,7 +244,7 @@ impl Graphics {
 | 
			
		|||
				self.texture_earth.bind ();
 | 
			
		||||
				
 | 
			
		||||
				let mvp = view_mat * 
 | 
			
		||||
				Mat4::from_translation (logic.player.pos) * 
 | 
			
		||||
				Mat4::from_translation (state.player.pos) * 
 | 
			
		||||
				Mat4::from_scale ((0.5, 0.5, 0.5).into ());
 | 
			
		||||
				glezz::uniform_matrix_4fv (unis [&u::MVP], &mvp);
 | 
			
		||||
				glezz::uniform_3fv (unis [&u::ALBEDO], &white);
 | 
			
		||||
| 
						 | 
				
			
			@ -334,9 +340,9 @@ impl Graphics {
 | 
			
		|||
			if true {
 | 
			
		||||
				// Raycast for player shadow
 | 
			
		||||
				let coll = opengl_rust::physics::get_candidate (
 | 
			
		||||
					&phys_tris, &[],
 | 
			
		||||
					logic.player.pos,
 | 
			
		||||
					logic.player.pos + Vec3::new (0.0, 0.0, -100.0),
 | 
			
		||||
					&state.phys_tris, &state.aabbs,
 | 
			
		||||
					state.player.pos,
 | 
			
		||||
					state.player.pos + Vec3::new (0.0, 0.0, -100.0),
 | 
			
		||||
					0.0
 | 
			
		||||
				);
 | 
			
		||||
				
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,152 +0,0 @@
 | 
			
		|||
use anyhow::Result;
 | 
			
		||||
 | 
			
		||||
use opengl_rust::{
 | 
			
		||||
	prelude::*,
 | 
			
		||||
	physics::Triangle,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub struct LoadedLevel {
 | 
			
		||||
	pub player_spawn: Vec3,
 | 
			
		||||
	pub camera: Camera,
 | 
			
		||||
	pub phys_tris: Vec <Triangle>,
 | 
			
		||||
	pub buffer: Vec <u8>,
 | 
			
		||||
	pub level: gltf::Document,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl LoadedLevel {
 | 
			
		||||
	pub fn from_path (path: &str) -> Result <Self> {
 | 
			
		||||
		use gltf::{
 | 
			
		||||
			Semantic,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let (level, buffers, _) = gltf::import (path)?;
 | 
			
		||||
		let buffer = match buffers.get (0) {
 | 
			
		||||
			None => bail! ("gltf didn't load any buffers"),
 | 
			
		||||
			Some (x) => x.0.to_vec (),
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let scene = match level.scenes ().next () {
 | 
			
		||||
			None => bail! ("No scenes in glTF file"),
 | 
			
		||||
			Some (x) => x,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let mut player_spawn = None;
 | 
			
		||||
		let mut camera = None;
 | 
			
		||||
		let mut phys_tris: Vec <opengl_rust::physics::Triangle> = Vec::new ();
 | 
			
		||||
		
 | 
			
		||||
		for node in scene.nodes () {
 | 
			
		||||
			if node.camera ().is_some () {
 | 
			
		||||
				camera = Some (Camera {
 | 
			
		||||
					transform: node.transform ().clone (),
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			if node.name () == Some ("Player Spawn") {
 | 
			
		||||
				let (translation, _, _) = node.transform ().decomposed ();
 | 
			
		||||
				player_spawn = Some (Vec3::from (translation));
 | 
			
		||||
			}
 | 
			
		||||
			else if let Some (_camera) = node.camera () {
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			else if let Some (mesh) = node.mesh () {
 | 
			
		||||
				let m = gltf_node_get_mat4 (&node);
 | 
			
		||||
				
 | 
			
		||||
				for (_, prim) in mesh.primitives ().enumerate () {
 | 
			
		||||
					let positions = match prim.get (&Semantic::Positions) {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let normals = match prim.get (&Semantic::Normals) {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let indices = match prim.indices () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let pos_view = match positions.view () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let _norm_view = match normals.view () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let indices_view = match indices.view () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					
 | 
			
		||||
					let idx_start = indices.offset () + indices_view.offset ();
 | 
			
		||||
					let idx_slice = &buffer [idx_start..idx_start + indices.count () * 2];
 | 
			
		||||
					let vert_start = positions.offset () + pos_view.offset ();
 | 
			
		||||
					let vert_slice = &buffer [vert_start..vert_start + positions.count () * 4 * 3];
 | 
			
		||||
					
 | 
			
		||||
					for chunk in idx_slice.chunks_exact (2 * 3) {
 | 
			
		||||
						let read_idx = |i: usize| u16::from_le_bytes ([chunk [i * 2 + 0], chunk [i * 2 + 1]]);
 | 
			
		||||
						
 | 
			
		||||
						let idxs = [
 | 
			
		||||
							read_idx (0),
 | 
			
		||||
							read_idx (1),
 | 
			
		||||
							read_idx (2),
 | 
			
		||||
						];
 | 
			
		||||
						
 | 
			
		||||
						let read_pos_coord = |i| f32::from_le_bytes ([
 | 
			
		||||
							vert_slice [i * 4 + 0],
 | 
			
		||||
							vert_slice [i * 4 + 1],
 | 
			
		||||
							vert_slice [i * 4 + 2],
 | 
			
		||||
							vert_slice [i * 4 + 3],
 | 
			
		||||
						]);
 | 
			
		||||
						
 | 
			
		||||
						let read_pos = move |i| {
 | 
			
		||||
							let i = usize::try_from (i).unwrap ();
 | 
			
		||||
							m.transform_point3 (Vec3::new (
 | 
			
		||||
								read_pos_coord (i * 3 + 0),
 | 
			
		||||
								read_pos_coord (i * 3 + 1),
 | 
			
		||||
								read_pos_coord (i * 3 + 2),
 | 
			
		||||
							))
 | 
			
		||||
						};
 | 
			
		||||
						
 | 
			
		||||
						// glTF triangle winding is backwards from what I expected
 | 
			
		||||
						// no biggie
 | 
			
		||||
						let verts = [
 | 
			
		||||
							read_pos (idxs [0]),
 | 
			
		||||
							read_pos (idxs [2]),
 | 
			
		||||
							read_pos (idxs [1]),
 | 
			
		||||
						];
 | 
			
		||||
						
 | 
			
		||||
						phys_tris.push (opengl_rust::physics::Triangle {
 | 
			
		||||
							verts,
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let player_spawn = match player_spawn {
 | 
			
		||||
			None => bail! ("glTF file must have `Player Spawn` node"),
 | 
			
		||||
			Some (x) => x,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let camera = match camera {
 | 
			
		||||
			None => bail! ("Couldn't find camera node in glTF file"),
 | 
			
		||||
			Some (x) => x,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		Ok (Self {
 | 
			
		||||
			buffer,
 | 
			
		||||
			camera,
 | 
			
		||||
			level,
 | 
			
		||||
			phys_tris,
 | 
			
		||||
			player_spawn,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Camera {
 | 
			
		||||
	pub transform: gltf::scene::Transform,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn gltf_node_get_mat4 (node: &gltf::Node) -> Mat4 {
 | 
			
		||||
	Mat4::from_cols_array_2d (&node.transform ().matrix ())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,138 +0,0 @@
 | 
			
		|||
use opengl_rust::{
 | 
			
		||||
	prelude::*,
 | 
			
		||||
	physics::{
 | 
			
		||||
		PhysicsBody,
 | 
			
		||||
		Triangle,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
	LoadedLevel,
 | 
			
		||||
	VirtualGamepad,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive (Clone, Default)]
 | 
			
		||||
pub struct LogicState {
 | 
			
		||||
	pub player: PhysicsBody,
 | 
			
		||||
	player_jump_vec: Option <Vec3>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive (Clone, Copy, Default)]
 | 
			
		||||
pub struct LogicStepOutput {
 | 
			
		||||
	pub reset_level: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl LogicState {
 | 
			
		||||
	pub fn reset_level (&mut self, level: &LoadedLevel) {
 | 
			
		||||
		self.player = Default::default ();
 | 
			
		||||
		self.player.pos = level.player_spawn;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	pub fn step (&mut self, phys_tris: &[Triangle], phys_params: &opengl_rust::physics::Params, p_gp: VirtualGamepad) -> LogicStepOutput 
 | 
			
		||||
	{
 | 
			
		||||
		let player_acc = 1.0;
 | 
			
		||||
		let player_acc_air = 0.125;
 | 
			
		||||
		let player_max_speed = 4.0;
 | 
			
		||||
		let player_max_speed_air = 8.0;
 | 
			
		||||
		let player_jump_speed = 12.0;
 | 
			
		||||
		let kill_z = -3.0;
 | 
			
		||||
		
 | 
			
		||||
		let mut output = LogicStepOutput::default ();
 | 
			
		||||
		let mut wanted_dir = Vec3::default ();
 | 
			
		||||
		
 | 
			
		||||
		if p_gp.d_left.any_press () {
 | 
			
		||||
			wanted_dir.x -= 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		if p_gp.d_right.any_press () {
 | 
			
		||||
			wanted_dir.x += 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		if p_gp.d_up.any_press () {
 | 
			
		||||
			wanted_dir.y += 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		if p_gp.d_down.any_press () {
 | 
			
		||||
			wanted_dir.y -= 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let wanted_dir = if wanted_dir.length_squared () >= 1.0 {
 | 
			
		||||
			wanted_dir.normalize ()
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			wanted_dir
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let wanted_dir = wanted_dir;
 | 
			
		||||
		
 | 
			
		||||
		let old_vel = self.player.vel;
 | 
			
		||||
		let old_vel_2 = old_vel * Vec3::new (1.0, 1.0, 0.0);
 | 
			
		||||
		
 | 
			
		||||
		let new_vel_2 = match self.player_jump_vec.as_ref () {
 | 
			
		||||
			Some (v) => {
 | 
			
		||||
				// Ground
 | 
			
		||||
				let acc = player_acc * v.z * v.z;
 | 
			
		||||
				let wanted_vel = wanted_dir * player_max_speed;
 | 
			
		||||
				let diff = wanted_vel - old_vel_2;
 | 
			
		||||
				
 | 
			
		||||
				if diff.length_squared () < acc * acc {
 | 
			
		||||
					// We're near the wanted velocity, so snap to it
 | 
			
		||||
					wanted_vel
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					// We're not near the wanted velocity, so accelerate
 | 
			
		||||
					old_vel_2 + diff.normalize_or_zero () * acc
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			// Air
 | 
			
		||||
			None => {
 | 
			
		||||
				let proposed_vel = old_vel_2 + wanted_dir * player_acc_air;
 | 
			
		||||
				
 | 
			
		||||
				if old_vel_2.length_squared () < player_max_speed_air * player_max_speed_air {
 | 
			
		||||
					// Air control is normal below player_max_speed
 | 
			
		||||
					proposed_vel
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					// If the player's input would push them beyond player_max_speed,
 | 
			
		||||
					// apply drag to preserve overall energy
 | 
			
		||||
					proposed_vel * old_vel_2.length () / proposed_vel.length ()
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		self.player.vel = new_vel_2;
 | 
			
		||||
		self.player.vel.z = old_vel.z;
 | 
			
		||||
		
 | 
			
		||||
		// dbg! (self.player.vel);
 | 
			
		||||
		
 | 
			
		||||
		if p_gp.jump.pressed {
 | 
			
		||||
			if let Some (normal) = self.player_jump_vec.clone () {
 | 
			
		||||
				self.player.vel.z = 0.0;
 | 
			
		||||
				self.player.vel += normal * player_jump_speed;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let phys_result = opengl_rust::physics::step (&phys_params, phys_tris, &[], 0.5, &self.player);
 | 
			
		||||
		
 | 
			
		||||
		self.player = phys_result.body;
 | 
			
		||||
		if self.player.pos.z < kill_z {
 | 
			
		||||
			output.reset_level = true;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// tracing::debug! ("player pos: {}", self.player.pos);
 | 
			
		||||
		
 | 
			
		||||
		self.player_jump_vec = None;
 | 
			
		||||
		for normal in &phys_result.normals_hit {
 | 
			
		||||
			self.player_jump_vec = Some (match self.player_jump_vec {
 | 
			
		||||
				None => *normal,
 | 
			
		||||
				Some (old) => {
 | 
			
		||||
					if normal.z > old.z {
 | 
			
		||||
						*normal
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						old
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		output
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,32 +1,39 @@
 | 
			
		|||
use std::{
 | 
			
		||||
	sync::Arc,
 | 
			
		||||
	collections::HashMap,
 | 
			
		||||
	time::Instant,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use tokio::{
 | 
			
		||||
	io::AsyncWriteExt,
 | 
			
		||||
	net::TcpListener,
 | 
			
		||||
	sync::watch,
 | 
			
		||||
	task::JoinHandle,
 | 
			
		||||
};
 | 
			
		||||
use maplit::hashmap;
 | 
			
		||||
 | 
			
		||||
use opengl_rust::{
 | 
			
		||||
	prelude::*,
 | 
			
		||||
	gl_state::*,
 | 
			
		||||
	physics::PhysicsBody,
 | 
			
		||||
	renderable_model::{
 | 
			
		||||
		attributes,
 | 
			
		||||
		RenderableModel,
 | 
			
		||||
	},
 | 
			
		||||
	shader_closure::ShaderLookup,
 | 
			
		||||
	texture::Texture,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
mod graphics;
 | 
			
		||||
mod level_loader;
 | 
			
		||||
mod logic;
 | 
			
		||||
mod virtual_gamepad;
 | 
			
		||||
 | 
			
		||||
use graphics::Graphics;
 | 
			
		||||
use level_loader::LoadedLevel;
 | 
			
		||||
use logic::LogicState;
 | 
			
		||||
use virtual_gamepad::VirtualGamepad;
 | 
			
		||||
 | 
			
		||||
#[derive (Default)]
 | 
			
		||||
pub struct GameState {
 | 
			
		||||
	logic: LogicState,
 | 
			
		||||
	player: PhysicsBody,
 | 
			
		||||
	aabbs: Vec <opengl_rust::physics::Aabb>,
 | 
			
		||||
	phys_tris: Vec <opengl_rust::physics::Triangle>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl GameState {
 | 
			
		||||
	fn reset_level (&mut self, level: &LoadedLevel) {
 | 
			
		||||
		self.player = Default::default ();
 | 
			
		||||
		self.player.pos = level.player_spawn;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::main]
 | 
			
		||||
| 
						 | 
				
			
			@ -61,57 +68,122 @@ async fn main () -> Result <()> {
 | 
			
		|||
	let mut time_step = TimeStep::new (60, 1000);
 | 
			
		||||
	
 | 
			
		||||
	let level = LoadedLevel::from_path ("gltf/level-00.glb")?;
 | 
			
		||||
	let scene = level.level.scenes ().next ().unwrap ();
 | 
			
		||||
	
 | 
			
		||||
	let mut camera = None;
 | 
			
		||||
	let mut phys_tris: Vec <opengl_rust::physics::Triangle> = Vec::new ();
 | 
			
		||||
	
 | 
			
		||||
	for node in scene.nodes () {
 | 
			
		||||
		if let Some (c) = node.camera () {
 | 
			
		||||
			camera = Some (Camera {
 | 
			
		||||
				transform: node.transform ().clone (),
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let mesh = match node.mesh () {
 | 
			
		||||
			None => continue,
 | 
			
		||||
			Some (x) => x,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let m = gltf_node_get_mat4 (&node);
 | 
			
		||||
		
 | 
			
		||||
		for prim in mesh.primitives () {
 | 
			
		||||
			use gltf::Semantic;
 | 
			
		||||
			
 | 
			
		||||
			let positions = match prim.get (&Semantic::Positions) {
 | 
			
		||||
				None => continue,
 | 
			
		||||
				Some (x) => x,
 | 
			
		||||
			};
 | 
			
		||||
			let pos_view = match positions.view () {
 | 
			
		||||
				None => continue,
 | 
			
		||||
				Some (x) => x,
 | 
			
		||||
			};
 | 
			
		||||
			let indices = match prim.indices () {
 | 
			
		||||
				None => continue,
 | 
			
		||||
				Some (x) => x,
 | 
			
		||||
			};
 | 
			
		||||
			let indices_view = match indices.view () {
 | 
			
		||||
				None => continue,
 | 
			
		||||
				Some (x) => x,
 | 
			
		||||
			};
 | 
			
		||||
			
 | 
			
		||||
			let idx_start = indices.offset () + indices_view.offset ();
 | 
			
		||||
			let idx_slice = &level.buffer [idx_start..idx_start + indices.count () * 2];
 | 
			
		||||
			let vert_start = positions.offset () + pos_view.offset ();
 | 
			
		||||
			let vert_slice = &level.buffer [vert_start..vert_start + positions.count () * 4 * 3];
 | 
			
		||||
			
 | 
			
		||||
			for chunk in idx_slice.chunks_exact (2 * 3) {
 | 
			
		||||
				let read_idx = |i: usize| u16::from_le_bytes ([chunk [i * 2 + 0], chunk [i * 2 + 1]]);
 | 
			
		||||
				
 | 
			
		||||
				let idxs = [
 | 
			
		||||
					read_idx (0),
 | 
			
		||||
					read_idx (1),
 | 
			
		||||
					read_idx (2),
 | 
			
		||||
				];
 | 
			
		||||
				
 | 
			
		||||
				let read_pos_coord = |i| f32::from_le_bytes ([
 | 
			
		||||
					vert_slice [i * 4 + 0],
 | 
			
		||||
					vert_slice [i * 4 + 1],
 | 
			
		||||
					vert_slice [i * 4 + 2],
 | 
			
		||||
					vert_slice [i * 4 + 3],
 | 
			
		||||
				]);
 | 
			
		||||
				
 | 
			
		||||
				let read_pos = move |i| {
 | 
			
		||||
					let i = usize::try_from (i).unwrap ();
 | 
			
		||||
					m.transform_point3 (Vec3::new (
 | 
			
		||||
						read_pos_coord (i * 3 + 0),
 | 
			
		||||
						read_pos_coord (i * 3 + 1),
 | 
			
		||||
						read_pos_coord (i * 3 + 2),
 | 
			
		||||
					))
 | 
			
		||||
				};
 | 
			
		||||
				
 | 
			
		||||
				// glTF triangle winding is backwards from what I expected
 | 
			
		||||
				// no biggie
 | 
			
		||||
				let verts = [
 | 
			
		||||
					read_pos (idxs [0]),
 | 
			
		||||
					read_pos (idxs [2]),
 | 
			
		||||
					read_pos (idxs [1]),
 | 
			
		||||
				];
 | 
			
		||||
				
 | 
			
		||||
				phys_tris.push (opengl_rust::physics::Triangle {
 | 
			
		||||
					verts,
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	let camera = match camera {
 | 
			
		||||
		None => bail! ("Couldn't find camera node in glTF file"),
 | 
			
		||||
		Some (x) => x,
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	let mut graphics = Graphics::new ();
 | 
			
		||||
	
 | 
			
		||||
	let mut gl_state = Default::default ();
 | 
			
		||||
	let mut game_state = GameState {
 | 
			
		||||
		logic: 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.5).into (),
 | 
			
		||||
		margin: 0.00125,
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	game_state.logic.reset_level (&level);
 | 
			
		||||
	let player_acc = 1.0;
 | 
			
		||||
	let player_acc_air = 0.125;
 | 
			
		||||
	let player_max_speed = 4.0;
 | 
			
		||||
	let player_max_speed_air = 8.0;
 | 
			
		||||
	let player_jump_speed = 12.0;
 | 
			
		||||
	let kill_z = -3.0;
 | 
			
		||||
	let mut player_jump_vec: Option <Vec3> = None;
 | 
			
		||||
	
 | 
			
		||||
	let mut next_upf_print = 60;
 | 
			
		||||
	let mut last_upf_instant = Instant::now ();
 | 
			
		||||
	game_state.reset_level (&level);
 | 
			
		||||
	game_state.phys_tris = phys_tris;
 | 
			
		||||
	
 | 
			
		||||
	let depth_buffer = vec! [0u8; 320 * 2 * 240 * 2 * 4];
 | 
			
		||||
	let depth_buffer = Arc::new (depth_buffer);
 | 
			
		||||
	let (depth_tx, depth_rx) = watch::channel (depth_buffer);
 | 
			
		||||
	let depth_rx_2 = depth_rx.clone ();
 | 
			
		||||
	
 | 
			
		||||
	let _: JoinHandle <anyhow::Result <()>> = tokio::spawn (async move {
 | 
			
		||||
		let tcp_listener = TcpListener::bind ("127.0.0.1:0").await?;
 | 
			
		||||
		tracing::info! ("Listening for TCP on {:?}", tcp_listener.local_addr ());
 | 
			
		||||
		
 | 
			
		||||
		loop {
 | 
			
		||||
			let (socket, _) = tcp_listener.accept ().await?;
 | 
			
		||||
			
 | 
			
		||||
			let mut depth_rx_3 = depth_rx_2.clone ();
 | 
			
		||||
			
 | 
			
		||||
			let _: JoinHandle <anyhow::Result <()>> = tokio::spawn (async move {
 | 
			
		||||
				let (_rx, mut tx) = socket.into_split ();
 | 
			
		||||
				
 | 
			
		||||
				loop {
 | 
			
		||||
					depth_rx_3.changed ().await?;
 | 
			
		||||
					let depth_buffer = Arc::clone (&depth_rx_3.borrow_and_update ());
 | 
			
		||||
					
 | 
			
		||||
					tx.write_all (&depth_buffer [..]).await?;
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	let mut next_mpf_print = 60;
 | 
			
		||||
	let mut last_mpf_instant = Instant::now ();
 | 
			
		||||
	
 | 
			
		||||
	'running: loop {
 | 
			
		||||
		let frames_to_do = time_step.step ();
 | 
			
		||||
		if frames_to_do != 1 {
 | 
			
		||||
			// debug! ("frames_to_do = {}", frames_to_do);
 | 
			
		||||
		}
 | 
			
		||||
		let mut player_gamepad = virtual_gamepad::VirtualGamepad::default ();
 | 
			
		||||
		let _frames_to_do = time_step.step ();
 | 
			
		||||
		let mut player_wants_to_jump = false;
 | 
			
		||||
		
 | 
			
		||||
		for event in event_pump.poll_iter () {
 | 
			
		||||
			match event {
 | 
			
		||||
| 
						 | 
				
			
			@ -120,115 +192,243 @@ async fn main () -> Result <()> {
 | 
			
		|||
					break 'running
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { keycode: Some (Keycode::R), .. } => {
 | 
			
		||||
					game_state.logic.reset_level (&level);
 | 
			
		||||
					game_state.reset_level (&level);
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { keycode: Some (Keycode::F12), .. } => {
 | 
			
		||||
					let depth_bytes: Vec <u8> = depth_rx.borrow ()
 | 
			
		||||
					.chunks_exact (4)
 | 
			
		||||
					.map (|x| u32::from_le_bytes ([x [0], x [1], x [2], x [3]]))
 | 
			
		||||
					.map (|x| (x >> 16) as u16)
 | 
			
		||||
					.map (|x| x.to_le_bytes ())
 | 
			
		||||
					.flatten ()
 | 
			
		||||
					.collect ();
 | 
			
		||||
					
 | 
			
		||||
					let mut f = std::fs::File::create ("screenshot.data")?;
 | 
			
		||||
					f.write_all (&depth_bytes)?;
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { scancode: Some (Scancode::Space), repeat: false, .. } => {
 | 
			
		||||
					player_gamepad.jump.pressed = true;
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { scancode: Some (Scancode::Left), repeat: false, .. } => {
 | 
			
		||||
					player_gamepad.d_left.pressed = true;
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { scancode: Some (Scancode::Right), repeat: false, .. } => {
 | 
			
		||||
					player_gamepad.d_right.pressed = true;
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { scancode: Some (Scancode::Up), repeat: false, .. } => {
 | 
			
		||||
					player_gamepad.d_up.pressed = true;
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { scancode: Some (Scancode::Down), repeat: false, .. } => {
 | 
			
		||||
					player_gamepad.d_down.pressed = true;
 | 
			
		||||
				Event::KeyDown { keycode: Some (Keycode::Space), .. } => {
 | 
			
		||||
					player_wants_to_jump = true;
 | 
			
		||||
				},
 | 
			
		||||
				
 | 
			
		||||
				_ => (),
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		{
 | 
			
		||||
			let kb_state = event_pump.keyboard_state ();
 | 
			
		||||
			
 | 
			
		||||
			if kb_state.is_scancode_pressed (Scancode::Space) {
 | 
			
		||||
				player_gamepad.jump.held = true;
 | 
			
		||||
			}
 | 
			
		||||
			if kb_state.is_scancode_pressed (Scancode::Left) {
 | 
			
		||||
				player_gamepad.d_left.held = true;
 | 
			
		||||
			}
 | 
			
		||||
			if kb_state.is_scancode_pressed (Scancode::Right) {
 | 
			
		||||
				player_gamepad.d_right.held = true;
 | 
			
		||||
			}
 | 
			
		||||
			if kb_state.is_scancode_pressed (Scancode::Up) {
 | 
			
		||||
				player_gamepad.d_up.held = true;
 | 
			
		||||
			}
 | 
			
		||||
			if kb_state.is_scancode_pressed (Scancode::Down) {
 | 
			
		||||
				player_gamepad.d_down.held = true;
 | 
			
		||||
		let kb_state = event_pump.keyboard_state ();
 | 
			
		||||
		
 | 
			
		||||
		let mut wanted_dir = Vec3::default ();
 | 
			
		||||
		
 | 
			
		||||
		if kb_state.is_scancode_pressed (Scancode::Left) {
 | 
			
		||||
			wanted_dir.x -= 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		if kb_state.is_scancode_pressed (Scancode::Right) {
 | 
			
		||||
			wanted_dir.x += 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		if kb_state.is_scancode_pressed (Scancode::Up) {
 | 
			
		||||
			wanted_dir.y += 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		if kb_state.is_scancode_pressed (Scancode::Down) {
 | 
			
		||||
			wanted_dir.y -= 1.0;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let wanted_dir = if wanted_dir.length_squared () >= 1.0 {
 | 
			
		||||
			wanted_dir.normalize ()
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			wanted_dir
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let old_vel = game_state.player.vel;
 | 
			
		||||
		let old_vel_2 = old_vel * Vec3::new (1.0, 1.0, 0.0);
 | 
			
		||||
		
 | 
			
		||||
		let new_vel_2 = match player_jump_vec.as_ref () {
 | 
			
		||||
			Some (v) => {
 | 
			
		||||
				// Ground
 | 
			
		||||
				let acc = player_acc * v.z * v.z;
 | 
			
		||||
				let wanted_vel = wanted_dir * player_max_speed;
 | 
			
		||||
				let diff = wanted_vel - old_vel_2;
 | 
			
		||||
				
 | 
			
		||||
				if diff.length_squared () < acc * acc {
 | 
			
		||||
					// We're near the wanted velocity, so snap to it
 | 
			
		||||
					wanted_vel
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					// We're not near the wanted velocity, so accelerate
 | 
			
		||||
					old_vel_2 + diff.normalize_or_zero () * acc
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			// Air
 | 
			
		||||
			None => {
 | 
			
		||||
				let proposed_vel = old_vel_2 + wanted_dir * player_acc_air;
 | 
			
		||||
				
 | 
			
		||||
				if old_vel_2.length_squared () < player_max_speed_air * player_max_speed_air {
 | 
			
		||||
					// Air control is normal below player_max_speed
 | 
			
		||||
					proposed_vel
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					// If the player's input would push them beyond player_max_speed,
 | 
			
		||||
					// apply drag to preserve overall energy
 | 
			
		||||
					proposed_vel * old_vel_2.length () / proposed_vel.length ()
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		game_state.player.vel = new_vel_2;
 | 
			
		||||
		game_state.player.vel.z = old_vel.z;
 | 
			
		||||
		
 | 
			
		||||
		// dbg! (game_state.player.vel);
 | 
			
		||||
		
 | 
			
		||||
		if player_wants_to_jump {
 | 
			
		||||
			if let Some (normal) = player_jump_vec.clone () {
 | 
			
		||||
				game_state.player.vel.z = 0.0;
 | 
			
		||||
				game_state.player.vel += normal * player_jump_speed;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let p_gp = player_gamepad;
 | 
			
		||||
		let phys_result = opengl_rust::physics::step (&phys_params, &game_state.phys_tris, &[], 0.5, &game_state.player);
 | 
			
		||||
		
 | 
			
		||||
		for _ in 0..frames_to_do {
 | 
			
		||||
			let logic_step_output = game_state.logic.step (&level.phys_tris, &phys_params, p_gp);
 | 
			
		||||
			if logic_step_output.reset_level {
 | 
			
		||||
				game_state.logic.reset_level (&level);
 | 
			
		||||
			}
 | 
			
		||||
		game_state.player = phys_result.body;
 | 
			
		||||
		if game_state.player.pos.z < kill_z {
 | 
			
		||||
			game_state.reset_level (&level);
 | 
			
		||||
		}
 | 
			
		||||
		// tracing::debug! ("player pos: {}", game_state.player.pos);
 | 
			
		||||
		
 | 
			
		||||
		player_jump_vec = None;
 | 
			
		||||
		for normal in &phys_result.normals_hit {
 | 
			
		||||
			player_jump_vec = Some (match player_jump_vec {
 | 
			
		||||
				None => *normal,
 | 
			
		||||
				Some (old) => {
 | 
			
		||||
					if normal.z > old.z {
 | 
			
		||||
						*normal
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						old
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// dbg! (game_state.logic.player.pos);
 | 
			
		||||
		// dbg! (game_state.player.pos);
 | 
			
		||||
		
 | 
			
		||||
		window.gl_make_current (&gl_ctx).unwrap ();
 | 
			
		||||
		
 | 
			
		||||
		let prediction_frames = 4;
 | 
			
		||||
		let mut predicted_logic = game_state.logic.clone ();
 | 
			
		||||
		for _ in 0..prediction_frames {
 | 
			
		||||
			predicted_logic.step (&level.phys_tris, &phys_params, p_gp);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		graphics.draw (&level.phys_tris, &predicted_logic, &mut gl_state, &level, &level.camera);
 | 
			
		||||
		graphics.draw (&game_state, &mut gl_state, &level, &camera);
 | 
			
		||||
		graphics.frames += 1;
 | 
			
		||||
		
 | 
			
		||||
		if graphics.frames == next_upf_print {
 | 
			
		||||
		if graphics.frames == next_mpf_print {
 | 
			
		||||
			let now = Instant::now ();
 | 
			
		||||
			let upf = (now - last_upf_instant).as_micros () / 60;
 | 
			
		||||
			let mpf = (now - last_mpf_instant).as_millis () / 60;
 | 
			
		||||
			
 | 
			
		||||
			dbg! (upf);
 | 
			
		||||
			dbg! (mpf);
 | 
			
		||||
			
 | 
			
		||||
			next_upf_print += 60;
 | 
			
		||||
			last_upf_instant = now;
 | 
			
		||||
			next_mpf_print += 60;
 | 
			
		||||
			last_mpf_instant = now;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		window.gl_swap_window ();
 | 
			
		||||
		
 | 
			
		||||
		{
 | 
			
		||||
			let mut depth_buffer = vec! [0u8; 320 * 2 * 240 * 2 * 4];
 | 
			
		||||
			
 | 
			
		||||
			unsafe {
 | 
			
		||||
				gl::ReadPixels (0, 0, 320 * 2, 240 * 2, gl::DEPTH_COMPONENT, gl::UNSIGNED_INT, &mut depth_buffer [0] as *mut u8 as *mut std::ffi::c_void);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			let depth_buffer = Arc::new (depth_buffer);
 | 
			
		||||
			// Shouldn't fail, because we always keep one receiver open ourselves
 | 
			
		||||
			depth_tx.send (depth_buffer)?;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		tokio::time::sleep (Duration::from_millis (10)).await;
 | 
			
		||||
		tokio::time::sleep (Duration::from_millis (15)).await;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Ok (())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
struct LoadedLevel {
 | 
			
		||||
	player_spawn: Vec3,
 | 
			
		||||
	buffer: Vec <u8>,
 | 
			
		||||
	level: gltf::Document,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl LoadedLevel {
 | 
			
		||||
	fn from_path (path: &str) -> Result <Self> {
 | 
			
		||||
		use gltf::{
 | 
			
		||||
			Semantic,
 | 
			
		||||
			scene::Transform,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let (level, buffers, _) = gltf::import (path)?;
 | 
			
		||||
		let buffer = match buffers.get (0) {
 | 
			
		||||
			None => bail! ("gltf didn't load any buffers"),
 | 
			
		||||
			Some (x) => x.0.to_vec (),
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let scene = match level.scenes ().next () {
 | 
			
		||||
			None => bail! ("No scenes in glTF file"),
 | 
			
		||||
			Some (x) => x,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let mut player_spawn = None;
 | 
			
		||||
		
 | 
			
		||||
		for node in scene.nodes () {
 | 
			
		||||
			if node.name () == Some ("Player Spawn") {
 | 
			
		||||
				let (translation, _, _) = node.transform ().decomposed ();
 | 
			
		||||
				player_spawn = Some (Vec3::from (translation));
 | 
			
		||||
			}
 | 
			
		||||
			else if let Some (camera) = node.camera () {
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			else if let Some (mesh) = node.mesh () {
 | 
			
		||||
				for (i, prim) in mesh.primitives ().enumerate () {
 | 
			
		||||
					let positions = match prim.get (&Semantic::Positions) {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let normals = match prim.get (&Semantic::Normals) {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let indices = match prim.indices () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let pos_view = match positions.view () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let norm_view = match normals.view () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
					let indices_view = match indices.view () {
 | 
			
		||||
						None => continue,
 | 
			
		||||
						Some (x) => x,
 | 
			
		||||
					};
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let player_spawn = match player_spawn {
 | 
			
		||||
			None => bail! ("glTF file must have `Player Spawn` node"),
 | 
			
		||||
			Some (x) => x,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		Ok (Self {
 | 
			
		||||
			buffer,
 | 
			
		||||
			level,
 | 
			
		||||
			player_spawn,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ShaderLocations {
 | 
			
		||||
	attr_pos: u32,
 | 
			
		||||
	attr_normal: u32,
 | 
			
		||||
	attr_color: u32,
 | 
			
		||||
	uni_mvp: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ShaderLocations {
 | 
			
		||||
	pub fn new (shader_program: &opengl_rust::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")?,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct TriangleStream {
 | 
			
		||||
	pub verts: gpu_buffers::VertexBuffer,
 | 
			
		||||
	pub indices: gpu_buffers::IndexBuffer,
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
struct Camera {
 | 
			
		||||
	transform: gltf::scene::Transform,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn gltf_node_get_mat4 (node: &gltf::Node) -> Mat4 {
 | 
			
		||||
	Mat4::from_cols_array_2d (&node.transform ().matrix ())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
#[derive (Clone, Copy, Default)]
 | 
			
		||||
pub struct VirtualGamepad {
 | 
			
		||||
	pub jump: VirtualButton,
 | 
			
		||||
	pub d_left: VirtualButton,
 | 
			
		||||
	pub d_right: VirtualButton,
 | 
			
		||||
	pub d_up: VirtualButton,
 | 
			
		||||
	pub d_down: VirtualButton,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive (Clone, Copy, Default)]
 | 
			
		||||
pub struct VirtualButton {
 | 
			
		||||
	/// True iff the button is down now
 | 
			
		||||
	pub held: bool,
 | 
			
		||||
	
 | 
			
		||||
	/// True if the button was pressed at any point since the last frame,
 | 
			
		||||
	/// even if it's up now.
 | 
			
		||||
	/// This is needed to make really fast clicks air-tight.
 | 
			
		||||
	pub pressed: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VirtualButton {
 | 
			
		||||
	pub fn any_press (self) -> bool {
 | 
			
		||||
		self.held || self.pressed
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
use glam::{Vec2, Vec3};
 | 
			
		||||
use partial_min_max::{min, max};
 | 
			
		||||
 | 
			
		||||
#[derive (Clone, Copy, Debug, Default, PartialEq)]
 | 
			
		||||
#[derive (Debug, Default, PartialEq)]
 | 
			
		||||
pub struct PhysicsBody {
 | 
			
		||||
	pub pos: Vec3,
 | 
			
		||||
	pub vel: Vec3,
 | 
			
		||||
| 
						 | 
				
			
			@ -155,8 +155,6 @@ pub fn step (
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	let _ = t_remaining;
 | 
			
		||||
	
 | 
			
		||||
	PhysicsResult {
 | 
			
		||||
		body: PhysicsBody {
 | 
			
		||||
			pos: old_pos,
 | 
			
		||||
| 
						 | 
				
			
			@ -180,7 +178,7 @@ pub fn get_candidate (
 | 
			
		|||
		radius,
 | 
			
		||||
		radius
 | 
			
		||||
	));
 | 
			
		||||
	let _v = p1 - p0;
 | 
			
		||||
	let v = p1 - p0;
 | 
			
		||||
	
 | 
			
		||||
	let mut candidate = Collision {
 | 
			
		||||
		t: 2.0,
 | 
			
		||||
| 
						 | 
				
			
			@ -360,12 +358,12 @@ pub fn get_candidate (
 | 
			
		|||
fn get_candidate_face (verts: &[Vec3], normal: Vec3, p0: Vec3, p1: Vec3, radius: f32) 
 | 
			
		||||
-> Option <PrimCollision> 
 | 
			
		||||
{
 | 
			
		||||
	let _radius3 = Vec3::from ((
 | 
			
		||||
	let radius3 = Vec3::from ((
 | 
			
		||||
		radius,
 | 
			
		||||
		radius,
 | 
			
		||||
		radius
 | 
			
		||||
	));
 | 
			
		||||
	let _v = p1 - p0;
 | 
			
		||||
	let v = p1 - p0;
 | 
			
		||||
	
 | 
			
		||||
	let distance_to_face0 = Vec3::dot (normal, p0 - verts [0]) - radius;
 | 
			
		||||
	let distance_to_face1 = Vec3::dot (normal, p1 - verts [0]) - radius;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ pub use std::{
 | 
			
		|||
		CString,
 | 
			
		||||
		c_void,
 | 
			
		||||
	},
 | 
			
		||||
	io::Write,
 | 
			
		||||
	time::Duration,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue