Start to rig stuff for the aerodynamics test I wanted to make in the first place
							parent
							
								
									afb0238c1b
								
							
						
					
					
						commit
						8a6d5518f1
					
				| 
						 | 
				
			
			@ -32,6 +32,7 @@ where V: Into <Vec3>
 | 
			
		|||
	))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO: Use iota macro
 | 
			
		||||
const KEY_LEFT: usize = 0;
 | 
			
		||||
const KEY_RIGHT: usize = KEY_LEFT + 1;
 | 
			
		||||
const KEY_UP: usize = KEY_RIGHT + 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -60,41 +61,79 @@ impl ControllerState {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 * std::f32::consts::PI / 180.0;
 | 
			
		||||
		let azi = self.azimuth * std::f32::consts::PI / 180.0;
 | 
			
		||||
		
 | 
			
		||||
		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 ()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct WorldState {
 | 
			
		||||
	azimuth: f32,
 | 
			
		||||
	altitude: f32,
 | 
			
		||||
	camera: EulerAngles,
 | 
			
		||||
	wind: EulerAngles,
 | 
			
		||||
	spin_speed: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl WorldState {
 | 
			
		||||
	pub fn new () -> Self {
 | 
			
		||||
		Self {
 | 
			
		||||
			azimuth: 0.0,
 | 
			
		||||
			altitude: 0.0,
 | 
			
		||||
			camera: Default::default (),
 | 
			
		||||
			wind: Default::default (),
 | 
			
		||||
			spin_speed: 0,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	pub fn step (&mut self, controller: &ControllerState) {
 | 
			
		||||
	pub fn step (
 | 
			
		||||
		&mut self, 
 | 
			
		||||
		controller: &ControllerState,
 | 
			
		||||
		user_control: &UserControl
 | 
			
		||||
	) {
 | 
			
		||||
		const SPIN_RAMP_TIME: i32 = 30;
 | 
			
		||||
		
 | 
			
		||||
		let spin_f = 4.0 * self.spin_speed as f32 / SPIN_RAMP_TIME as f32;
 | 
			
		||||
		
 | 
			
		||||
		let controlled_angle = match user_control {
 | 
			
		||||
			UserControl::Camera => &mut self.camera,
 | 
			
		||||
			UserControl::Wind => &mut self.wind,
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		if controller.is_pressed (KEY_LEFT) {
 | 
			
		||||
			self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
 | 
			
		||||
			self.azimuth += spin_f;
 | 
			
		||||
			controlled_angle.azimuth += spin_f;
 | 
			
		||||
		}
 | 
			
		||||
		else if controller.is_pressed (KEY_RIGHT) {
 | 
			
		||||
			self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
 | 
			
		||||
			self.azimuth -= spin_f;
 | 
			
		||||
			controlled_angle.azimuth -= spin_f;
 | 
			
		||||
		}
 | 
			
		||||
		else if controller.is_pressed (KEY_UP) {
 | 
			
		||||
			self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
 | 
			
		||||
			self.altitude = f32::min (90.0, self.altitude + spin_f);
 | 
			
		||||
			controlled_angle.altitude = f32::min (90.0, controlled_angle.altitude + spin_f);
 | 
			
		||||
		}
 | 
			
		||||
		else if controller.is_pressed (KEY_DOWN) {
 | 
			
		||||
			self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
 | 
			
		||||
			self.altitude = f32::max (-90.0, self.altitude - spin_f);
 | 
			
		||||
			controlled_angle.altitude = f32::max (-90.0, controlled_angle.altitude - spin_f);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			self.spin_speed = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -145,11 +184,13 @@ where P: AsRef <std::path::Path>
 | 
			
		|||
struct Arrow {
 | 
			
		||||
	origin: Vec3,
 | 
			
		||||
	direction: Vec3,
 | 
			
		||||
	color: Vec3,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct RenderableArrow {
 | 
			
		||||
	model_mat: Mat4,
 | 
			
		||||
	inv_model_mat: Mat4,
 | 
			
		||||
	color: Vec3,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive (Copy, Clone, PartialEq, Eq)]
 | 
			
		||||
| 
						 | 
				
			
			@ -233,6 +274,37 @@ impl From <StencilFunc> for u32 {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive (Copy, Clone, PartialEq, Eq)]
 | 
			
		||||
pub enum DepthFunc {
 | 
			
		||||
	Never, 
 | 
			
		||||
	Always, 
 | 
			
		||||
	Less, 
 | 
			
		||||
	LessEqual, 
 | 
			
		||||
	Equal, 
 | 
			
		||||
	Greater, 
 | 
			
		||||
	GreaterEqual,
 | 
			
		||||
	NotEqual,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From <DepthFunc> for u32 {
 | 
			
		||||
	fn from (v: DepthFunc) -> Self {
 | 
			
		||||
		use DepthFunc::*;
 | 
			
		||||
		{
 | 
			
		||||
		use gl::*;
 | 
			
		||||
		match v {
 | 
			
		||||
			Never => NEVER,
 | 
			
		||||
			Always => ALWAYS,
 | 
			
		||||
			Less => LESS,
 | 
			
		||||
			LessEqual => LEQUAL,
 | 
			
		||||
			Equal => EQUAL,
 | 
			
		||||
			Greater => GREATER,
 | 
			
		||||
			GreaterEqual => GEQUAL,
 | 
			
		||||
			NotEqual => NOTEQUAL,
 | 
			
		||||
		}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive (Copy, Clone, PartialEq, Eq)]
 | 
			
		||||
pub struct StencilOpState {
 | 
			
		||||
	sfail: StencilOp,
 | 
			
		||||
| 
						 | 
				
			
			@ -257,9 +329,12 @@ pub struct StencilState {
 | 
			
		|||
// to safely use the flags / numbers
 | 
			
		||||
 | 
			
		||||
pub struct IsoGlState {
 | 
			
		||||
	shader_id: Option <u32>,
 | 
			
		||||
	
 | 
			
		||||
	flags: HashMap <u32, bool>,
 | 
			
		||||
	front_face: Option <FrontFace>,
 | 
			
		||||
	stencil: Option <StencilState>,
 | 
			
		||||
	depth_func: Option <DepthFunc>,
 | 
			
		||||
	
 | 
			
		||||
	color_mask: Option <(u8, u8, u8, u8)>,
 | 
			
		||||
	depth_mask: Option <u8>,
 | 
			
		||||
| 
						 | 
				
			
			@ -269,9 +344,11 @@ pub struct IsoGlState {
 | 
			
		|||
impl std::default::Default for IsoGlState {
 | 
			
		||||
	fn default () -> Self {
 | 
			
		||||
		Self {
 | 
			
		||||
			shader_id: None,
 | 
			
		||||
			flags: hashmap! {},
 | 
			
		||||
			front_face: None,
 | 
			
		||||
			stencil: None,
 | 
			
		||||
			depth_func: None,
 | 
			
		||||
			color_mask: None,
 | 
			
		||||
			depth_mask: None,
 | 
			
		||||
			stencil_mask: None,
 | 
			
		||||
| 
						 | 
				
			
			@ -282,13 +359,11 @@ impl std::default::Default for IsoGlState {
 | 
			
		|||
// These are POD IDs or hashes of non-POD data
 | 
			
		||||
 | 
			
		||||
pub struct NonIsoGlState {
 | 
			
		||||
	shader_id: Option <u32>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl std::default::Default for NonIsoGlState {
 | 
			
		||||
	fn default () -> Self {
 | 
			
		||||
		Self {
 | 
			
		||||
			shader_id: None,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -307,17 +382,13 @@ impl std::default::Default for GlState {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Pass <'a> {
 | 
			
		||||
pub struct Pass {
 | 
			
		||||
	// In the context of a Pass, "None" means "Don't care"
 | 
			
		||||
	
 | 
			
		||||
	iso: IsoGlState,
 | 
			
		||||
	
 | 
			
		||||
	// Non-iso state must have its sources here
 | 
			
		||||
	
 | 
			
		||||
	shader: Option <&'a ShaderClosure>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Pass <'_> {
 | 
			
		||||
impl Pass {
 | 
			
		||||
	pub fn apply_diff (&self, old_state: &mut IsoGlState) {
 | 
			
		||||
		let state = &self.iso;
 | 
			
		||||
		
 | 
			
		||||
| 
						 | 
				
			
			@ -381,6 +452,16 @@ impl Pass <'_> {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if let Some (v) = &state.depth_func {
 | 
			
		||||
			if old_state.depth_func != state.depth_func {
 | 
			
		||||
				glezz::depth_func ((*v).into ());
 | 
			
		||||
				old_state.depth_func = state.depth_func;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				//println! ("Elided depth_func ()");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if let Some ((r, g, b, a)) = &state.color_mask {
 | 
			
		||||
			if old_state.color_mask != state.color_mask {
 | 
			
		||||
				glezz::color_mask (*r, *g, *b, *a);
 | 
			
		||||
| 
						 | 
				
			
			@ -425,15 +506,20 @@ impl Pass <'_> {
 | 
			
		|||
		callback ();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	pub fn with_shader <F> (&self, gl_state: &mut GlState, callback: F) 
 | 
			
		||||
	where F: Fn (BorrowedShaderVars)
 | 
			
		||||
	pub fn with_shader <F, S> (
 | 
			
		||||
		&self, 
 | 
			
		||||
		gl_state: &mut GlState, 
 | 
			
		||||
		shader_component: &S, 
 | 
			
		||||
		callback: F
 | 
			
		||||
	) 
 | 
			
		||||
	where F: Fn (BorrowedShaderVars), S: ShaderLookup
 | 
			
		||||
	{
 | 
			
		||||
		if let Some (s) = self.shader {
 | 
			
		||||
		if let Some (s) = self.iso.shader_id {
 | 
			
		||||
			self.apply_diff (&mut gl_state.iso);
 | 
			
		||||
			s.with (gl_state.non_iso.shader_id, |shader_vars| {
 | 
			
		||||
			shader_component.lookup (s).with (gl_state.iso.shader_id, |shader_vars| {
 | 
			
		||||
				callback (shader_vars);
 | 
			
		||||
			});
 | 
			
		||||
			gl_state.non_iso.shader_id = Some (s.get_id ());
 | 
			
		||||
			gl_state.iso.shader_id = Some (s);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			panic! ("Called with_shader on a pass with no shader");
 | 
			
		||||
| 
						 | 
				
			
			@ -441,9 +527,15 @@ impl Pass <'_> {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait ShaderLookup {
 | 
			
		||||
	fn lookup <'a> (&'a self, id: u32) -> &'a ShaderClosure;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct GameGraphics {
 | 
			
		||||
	shader_diffuse: ShaderClosure,
 | 
			
		||||
	shader_shadow: ShaderClosure,
 | 
			
		||||
	passes: Vec <Pass>,
 | 
			
		||||
	
 | 
			
		||||
	shaders: Vec <ShaderClosure>,
 | 
			
		||||
	shader_lookup: HashMap <u32, usize>,
 | 
			
		||||
	
 | 
			
		||||
	mesh_pumpkin: RenderableModel,
 | 
			
		||||
	mesh_sky: RenderableModel,
 | 
			
		||||
| 
						 | 
				
			
			@ -456,6 +548,12 @@ struct GameGraphics {
 | 
			
		|||
	grass_index: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ShaderLookup for GameGraphics {
 | 
			
		||||
	fn lookup <'a> (&'a self, id: u32) -> &'a ShaderClosure {
 | 
			
		||||
		&self.shaders [self.shader_lookup [&id]]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl GameGraphics {
 | 
			
		||||
	pub fn new () -> Self {
 | 
			
		||||
		let uniform_names = {
 | 
			
		||||
| 
						 | 
				
			
			@ -480,10 +578,21 @@ impl GameGraphics {
 | 
			
		|||
			]
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let shader_diffuse = ShaderClosure::new (shader_from_files ("shaders/pumpkin-vert.glsl", "shaders/pumpkin-frag.glsl"), &uniform_names, &attr_names);
 | 
			
		||||
		let shader_shadow = ShaderClosure::new (shader_from_files ("shaders/shadow-vert.glsl", "shaders/shadow-frag.glsl"), &uniform_names, &attr_names);
 | 
			
		||||
		let shaders: Vec <_> = [
 | 
			
		||||
			("shaders/pumpkin-vert.glsl", "shaders/pumpkin-frag.glsl"),
 | 
			
		||||
			("shaders/shadow-vert.glsl", "shaders/shadow-frag.glsl"),
 | 
			
		||||
		].iter ()
 | 
			
		||||
		.map (|(v, f)| {
 | 
			
		||||
			ShaderClosure::new (shader_from_files (v, f), &uniform_names, &attr_names)
 | 
			
		||||
		})
 | 
			
		||||
		.collect ();
 | 
			
		||||
		
 | 
			
		||||
		shader_diffuse.with (None, |shader_vars| {
 | 
			
		||||
		let shader_lookup = HashMap::from_iter (shaders.iter ().enumerate ()
 | 
			
		||||
		.map (|(i, s)| {
 | 
			
		||||
			(s.get_id (), i)
 | 
			
		||||
		}));
 | 
			
		||||
		
 | 
			
		||||
		shaders [0].with (None, |shader_vars| {
 | 
			
		||||
			let attrs = shader_vars.attrs;
 | 
			
		||||
			use renderable_model::attributes::*;
 | 
			
		||||
			glezz::enable_vertex_attrib_array (attrs [POS]);
 | 
			
		||||
| 
						 | 
				
			
			@ -538,9 +647,183 @@ impl GameGraphics {
 | 
			
		|||
			(colors, grass_index.unwrap ())
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let passes = vec! [
 | 
			
		||||
			// Clear everything
 | 
			
		||||
			Pass {
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					shader_id: None,
 | 
			
		||||
					flags: hashmap! {},
 | 
			
		||||
					front_face: None,
 | 
			
		||||
					stencil: None,
 | 
			
		||||
					depth_func: None,
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (255),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Draw world
 | 
			
		||||
			Pass {
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					shader_id: Some (shaders [0].get_id ()),
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::TEXTURE_2D => true,
 | 
			
		||||
						gl::STENCIL_TEST => false,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Cw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::Always,
 | 
			
		||||
							reference: 0,
 | 
			
		||||
							mask: 0,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Keep,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					depth_func: Some (DepthFunc::Less),
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (0),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Write shadows into stencil buffer
 | 
			
		||||
			Pass {
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					shader_id: Some (shaders [1].get_id ()),
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::STENCIL_TEST => true,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Ccw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::Always,
 | 
			
		||||
							reference: 1,
 | 
			
		||||
							mask: 1,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Replace,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					depth_func: Some (DepthFunc::Less),
 | 
			
		||||
					color_mask: Some ((0, 0, 0, 0)),
 | 
			
		||||
					depth_mask: Some (0),
 | 
			
		||||
					stencil_mask: Some (255),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Draw lit ground
 | 
			
		||||
			Pass {
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					shader_id: Some (shaders [0].get_id ()),
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::TEXTURE_2D => true,
 | 
			
		||||
						gl::STENCIL_TEST => true,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Cw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::NotEqual,
 | 
			
		||||
							reference: 0,
 | 
			
		||||
							mask: 1,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Keep,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					depth_func: Some (DepthFunc::Less),
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (0),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Draw unlit ground
 | 
			
		||||
			Pass {
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					shader_id: Some (shaders [0].get_id ()),
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::TEXTURE_2D => true,
 | 
			
		||||
						gl::STENCIL_TEST => true,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Cw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::Equal,
 | 
			
		||||
							reference: 0,
 | 
			
		||||
							mask: 1,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Keep,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					depth_func: Some (DepthFunc::Less),
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (0),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Clear depth
 | 
			
		||||
			Pass {
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					shader_id: None,
 | 
			
		||||
					flags: hashmap! {},
 | 
			
		||||
					front_face: None,
 | 
			
		||||
					stencil: None,
 | 
			
		||||
					depth_func: None,
 | 
			
		||||
					color_mask: None,
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: None,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Draw arrows
 | 
			
		||||
			Pass {
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					shader_id: Some (shaders [0].get_id ()),
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::TEXTURE_2D => true,
 | 
			
		||||
						gl::STENCIL_TEST => false,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Cw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::Always,
 | 
			
		||||
							reference: 0,
 | 
			
		||||
							mask: 0,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Keep,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					depth_func: Some (DepthFunc::Less),
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (0),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		];
 | 
			
		||||
		
 | 
			
		||||
		Self {
 | 
			
		||||
			shader_diffuse,
 | 
			
		||||
			shader_shadow,
 | 
			
		||||
			passes,
 | 
			
		||||
			shaders,
 | 
			
		||||
			shader_lookup,
 | 
			
		||||
			
 | 
			
		||||
			mesh_pumpkin,
 | 
			
		||||
			mesh_sky,
 | 
			
		||||
| 
						 | 
				
			
			@ -574,8 +857,8 @@ impl GameGraphics {
 | 
			
		|||
			green,
 | 
			
		||||
		];
 | 
			
		||||
		
 | 
			
		||||
		let longitude = state.azimuth.to_radians ();
 | 
			
		||||
		let latitude = (state.altitude - 90.0).to_radians ();
 | 
			
		||||
		let longitude = state.camera.azimuth.to_radians ();
 | 
			
		||||
		let latitude = (state.camera.altitude - 90.0).to_radians ();
 | 
			
		||||
		
 | 
			
		||||
		let proj_mat = Mat4::perspective_rh_gl (30.0f32.to_radians (), 1280.0 / 720.0, 0.5, 500.0);
 | 
			
		||||
		
 | 
			
		||||
| 
						 | 
				
			
			@ -598,122 +881,9 @@ impl GameGraphics {
 | 
			
		|||
		
 | 
			
		||||
		//println! ("Started frame");
 | 
			
		||||
		
 | 
			
		||||
		let passes = vec! [
 | 
			
		||||
			// Clear everything
 | 
			
		||||
			Pass {
 | 
			
		||||
				shader: None,
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					flags: hashmap! {},
 | 
			
		||||
					front_face: None,
 | 
			
		||||
					stencil: None,
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (255),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Draw world
 | 
			
		||||
			Pass {
 | 
			
		||||
				shader: Some (&self.shader_diffuse),
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::TEXTURE_2D => true,
 | 
			
		||||
						gl::STENCIL_TEST => false,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Cw),
 | 
			
		||||
					stencil: None,
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (0),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Write shadows into stencil buffer
 | 
			
		||||
			Pass {
 | 
			
		||||
				shader: Some (&self.shader_shadow),
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::STENCIL_TEST => true,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Ccw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::Always,
 | 
			
		||||
							reference: 1,
 | 
			
		||||
							mask: 1,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Replace,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					color_mask: Some ((0, 0, 0, 0)),
 | 
			
		||||
					depth_mask: Some (0),
 | 
			
		||||
					stencil_mask: Some (255),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Draw lit ground
 | 
			
		||||
			Pass {
 | 
			
		||||
				shader: Some (&self.shader_diffuse),
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::TEXTURE_2D => true,
 | 
			
		||||
						gl::STENCIL_TEST => true,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Cw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::NotEqual,
 | 
			
		||||
							reference: 0,
 | 
			
		||||
							mask: 1,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Keep,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (0),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			// Draw unlit ground
 | 
			
		||||
			Pass {
 | 
			
		||||
				shader: Some (&self.shader_diffuse),
 | 
			
		||||
				iso: IsoGlState {
 | 
			
		||||
					flags: hashmap! {
 | 
			
		||||
						gl::CULL_FACE => true,
 | 
			
		||||
						gl::DEPTH_TEST => true,
 | 
			
		||||
						gl::TEXTURE_2D => true,
 | 
			
		||||
						gl::STENCIL_TEST => true,
 | 
			
		||||
					},
 | 
			
		||||
					front_face: Some (FrontFace::Cw),
 | 
			
		||||
					stencil: Some (StencilState {
 | 
			
		||||
						func: StencilFuncState {
 | 
			
		||||
							func: StencilFunc::Equal,
 | 
			
		||||
							reference: 0,
 | 
			
		||||
							mask: 1,
 | 
			
		||||
						},
 | 
			
		||||
						op: StencilOpState {
 | 
			
		||||
							sfail: StencilOp::Keep,
 | 
			
		||||
							dpfail: StencilOp::Keep,
 | 
			
		||||
							dppass: StencilOp::Keep,
 | 
			
		||||
						},
 | 
			
		||||
					}),
 | 
			
		||||
					color_mask: Some ((1, 1, 1, 1)),
 | 
			
		||||
					depth_mask: Some (1),
 | 
			
		||||
					stencil_mask: Some (0),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		];
 | 
			
		||||
		let mut passes = self.passes.iter ();
 | 
			
		||||
		
 | 
			
		||||
		passes [0].with (gl_state, || {
 | 
			
		||||
		passes.next ().unwrap ().with (gl_state, || {
 | 
			
		||||
			glezz::clear_color (1.0f32, 0.0f32, 1.0f32, 1.0f32);
 | 
			
		||||
			glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
 | 
			
		||||
		});
 | 
			
		||||
| 
						 | 
				
			
			@ -730,7 +900,8 @@ impl GameGraphics {
 | 
			
		|||
		use uniforms::*;
 | 
			
		||||
		
 | 
			
		||||
		// Draw the world except the ground plane
 | 
			
		||||
		passes [1].with_shader (gl_state, |shader_vars| {
 | 
			
		||||
		passes.next ().unwrap ().with_shader (gl_state, self, 
 | 
			
		||||
		|shader_vars| {
 | 
			
		||||
			let unis = shader_vars.unis;
 | 
			
		||||
			let attrs = shader_vars.attrs;
 | 
			
		||||
			
 | 
			
		||||
| 
						 | 
				
			
			@ -759,19 +930,6 @@ impl GameGraphics {
 | 
			
		|||
				i != self.grass_index
 | 
			
		||||
			});
 | 
			
		||||
			
 | 
			
		||||
			glezz::uniform_3fv (unis [&ALBEDO], &magenta);
 | 
			
		||||
			for arrow in arrows.iter () {
 | 
			
		||||
				let mvp = view_mat * arrow.model_mat;
 | 
			
		||||
				
 | 
			
		||||
				glezz::uniform_matrix_4fv (unis [&MVP], &mvp);
 | 
			
		||||
				let object_space_light = make_object_space_vec (&arrow.inv_model_mat, &light);
 | 
			
		||||
				let object_space_sky = make_object_space_vec (&arrow.inv_model_mat, &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_arrow.draw_all (attrs, |_| true);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			let draw_sky = true;
 | 
			
		||||
			if draw_sky {
 | 
			
		||||
				self.texture.bind ();
 | 
			
		||||
| 
						 | 
				
			
			@ -786,7 +944,8 @@ impl GameGraphics {
 | 
			
		|||
		});
 | 
			
		||||
		
 | 
			
		||||
		// Draw shadows into stencil buffer
 | 
			
		||||
		passes [2].with_shader (gl_state, |shader_vars| {
 | 
			
		||||
		passes.next ().unwrap ().with_shader (gl_state, self, 
 | 
			
		||||
		|shader_vars| {
 | 
			
		||||
			let unis = shader_vars.unis;
 | 
			
		||||
			let attrs = shader_vars.attrs;
 | 
			
		||||
			
 | 
			
		||||
| 
						 | 
				
			
			@ -813,7 +972,8 @@ impl GameGraphics {
 | 
			
		|||
		let object_space_light = make_object_space_vec (&inverse_pumpkin, &light);
 | 
			
		||||
		
 | 
			
		||||
		// Draw unlit ground
 | 
			
		||||
		passes [3].with_shader (gl_state, |shader_vars| {
 | 
			
		||||
		passes.next ().unwrap ().with_shader (gl_state, self, 
 | 
			
		||||
		|shader_vars| {
 | 
			
		||||
			let unis = shader_vars.unis;
 | 
			
		||||
			let attrs = shader_vars.attrs;
 | 
			
		||||
			
 | 
			
		||||
| 
						 | 
				
			
			@ -835,14 +995,49 @@ impl GameGraphics {
 | 
			
		|||
		});
 | 
			
		||||
		
 | 
			
		||||
		// Draw lit ground
 | 
			
		||||
		passes [4].with_shader (gl_state, |shader_vars| {
 | 
			
		||||
		passes.next ().unwrap ().with_shader (gl_state, self, 
 | 
			
		||||
		|shader_vars| {
 | 
			
		||||
			let unis = shader_vars.unis;
 | 
			
		||||
			let attrs = shader_vars.attrs;
 | 
			
		||||
			
 | 
			
		||||
			glezz::uniform_3fv (unis [&OBJECT_SPACE_LIGHT], &object_space_light);
 | 
			
		||||
			self.mesh_pitch.draw (attrs, self.grass_index);
 | 
			
		||||
		});
 | 
			
		||||
		
 | 
			
		||||
		// Clear depth
 | 
			
		||||
		passes.next ().unwrap ().with (gl_state, || {
 | 
			
		||||
			glezz::clear (gl::DEPTH_BUFFER_BIT);
 | 
			
		||||
		});
 | 
			
		||||
		
 | 
			
		||||
		// Draw arrows
 | 
			
		||||
		passes.next ().unwrap ().with_shader (gl_state, self,
 | 
			
		||||
		|shader_vars| {
 | 
			
		||||
			let unis = &shader_vars.unis;
 | 
			
		||||
			
 | 
			
		||||
			glezz::uniform_3fv (unis [&MIN_BRIGHT], &black);
 | 
			
		||||
			glezz::uniform_3fv (unis [&MIN_ALBEDO], &white);
 | 
			
		||||
			
 | 
			
		||||
			for arrow in arrows.iter () {
 | 
			
		||||
				let mvp = view_mat * arrow.model_mat;
 | 
			
		||||
				
 | 
			
		||||
				glezz::uniform_matrix_4fv (unis [&MVP], &mvp);
 | 
			
		||||
				let object_space_light = make_object_space_vec (&arrow.inv_model_mat, &light);
 | 
			
		||||
				let object_space_sky = make_object_space_vec (&arrow.inv_model_mat, &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);
 | 
			
		||||
				
 | 
			
		||||
				glezz::uniform_3fv (unis [&ALBEDO], &arrow.color);
 | 
			
		||||
				
 | 
			
		||||
				self.mesh_arrow.draw_all (shader_vars.attrs, |_| true);
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive (Copy, Clone, PartialEq, Eq)]
 | 
			
		||||
enum UserControl {
 | 
			
		||||
	Camera,
 | 
			
		||||
	Wind,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main () {
 | 
			
		||||
| 
						 | 
				
			
			@ -871,16 +1066,13 @@ fn main () {
 | 
			
		|||
	let graphics = GameGraphics::new ();
 | 
			
		||||
	let mut gl_state = Default::default ();
 | 
			
		||||
	
 | 
			
		||||
	let mut user_control = UserControl::Camera;
 | 
			
		||||
	let mut graphics_frames = 0;
 | 
			
		||||
	
 | 
			
		||||
	let mut event_pump = sdl_context.event_pump ().unwrap ();
 | 
			
		||||
	'running: loop {
 | 
			
		||||
		let frames_to_do = time_step.step ();
 | 
			
		||||
		
 | 
			
		||||
		let controller = ControllerState::from_sdl_keyboard (&event_pump.keyboard_state ());
 | 
			
		||||
		
 | 
			
		||||
		for _ in 0..frames_to_do {
 | 
			
		||||
			state.step (&controller);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let _mouse = event_pump.mouse_state ();
 | 
			
		||||
		
 | 
			
		||||
		for event in event_pump.poll_iter() {
 | 
			
		||||
| 
						 | 
				
			
			@ -889,27 +1081,55 @@ fn main () {
 | 
			
		|||
				Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
 | 
			
		||||
					break 'running
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { keycode: Some (Keycode::C), .. } => {
 | 
			
		||||
					user_control = UserControl::Camera;
 | 
			
		||||
				},
 | 
			
		||||
				Event::KeyDown { keycode: Some (Keycode::W), .. } => {
 | 
			
		||||
					user_control = UserControl::Wind;
 | 
			
		||||
				},
 | 
			
		||||
				_ => (),
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let controller = ControllerState::from_sdl_keyboard (&event_pump.keyboard_state ());
 | 
			
		||||
		
 | 
			
		||||
		for _ in 0..frames_to_do {
 | 
			
		||||
			state.step (&controller, &user_control);
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		let gravity = (0.0, 0.0, -1.0).into ();
 | 
			
		||||
		let wind = state.wind.to_vec3 () * -1.0;
 | 
			
		||||
		let origin: Vec3 = (0.0, 0.0, 1.35).into ();
 | 
			
		||||
		
 | 
			
		||||
		let control_flash = if graphics_frames % 16 >= 8 {
 | 
			
		||||
			(1.0, 1.0, 1.0).into ()
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			(1.0, 0.0, 0.0).into ()
 | 
			
		||||
		};
 | 
			
		||||
		
 | 
			
		||||
		let arrows = vec![
 | 
			
		||||
			Arrow {
 | 
			
		||||
				origin: (0.0, 0.0, 1.0).into (),
 | 
			
		||||
				direction: (0.0, 0.0, 1.0).into (),
 | 
			
		||||
				origin: (0.0, 0.0, 1.35).into (),
 | 
			
		||||
				direction: gravity,
 | 
			
		||||
				color: (1.0, 0.5, 0.5).into (),
 | 
			
		||||
			},
 | 
			
		||||
			Arrow {
 | 
			
		||||
				origin: (1.0, 0.0, 1.0).into (),
 | 
			
		||||
				direction: (1.0, 0.0, 0.0).into (),
 | 
			
		||||
				origin: origin + wind * -2.0,
 | 
			
		||||
				direction: wind,
 | 
			
		||||
				color: if user_control == UserControl::Wind {
 | 
			
		||||
					control_flash
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					(1.0, 0.5, 1.0).into ()
 | 
			
		||||
				},
 | 
			
		||||
			Arrow {
 | 
			
		||||
				origin: (0.0, 1.0, 1.0).into (),
 | 
			
		||||
				direction: (0.0, 1.0, 0.0).into (),
 | 
			
		||||
			},
 | 
			
		||||
		];
 | 
			
		||||
		
 | 
			
		||||
		let renderable_arrows: Vec <_> = arrows.iter ().map (|arrow| {
 | 
			
		||||
			let d = arrow.direction;
 | 
			
		||||
			let dir_len = arrow.direction.length ();
 | 
			
		||||
			
 | 
			
		||||
			let d = arrow.direction / dir_len;
 | 
			
		||||
			
 | 
			
		||||
			let up: Vec3 = if d.z () > 0.5 {
 | 
			
		||||
				(-1.0, 0.0, 0.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -932,9 +1152,11 @@ fn main () {
 | 
			
		|||
			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 s = dir_len * 0.0625;
 | 
			
		||||
			
 | 
			
		||||
			let model_mat =
 | 
			
		||||
			Mat4::from_translation (arrow.origin) *
 | 
			
		||||
			Mat4::from_scale ((0.125, 0.125, 0.125).into ()) *
 | 
			
		||||
			Mat4::from_scale ((s, s, s).into ()) *
 | 
			
		||||
			dir_mat;
 | 
			
		||||
			
 | 
			
		||||
			let inv_model_mat = model_mat.inverse ();
 | 
			
		||||
| 
						 | 
				
			
			@ -942,6 +1164,7 @@ fn main () {
 | 
			
		|||
			RenderableArrow {
 | 
			
		||||
				model_mat,
 | 
			
		||||
				inv_model_mat,
 | 
			
		||||
				color: arrow.color,
 | 
			
		||||
			}
 | 
			
		||||
		}).collect ();
 | 
			
		||||
		
 | 
			
		||||
| 
						 | 
				
			
			@ -950,6 +1173,7 @@ fn main () {
 | 
			
		|||
		graphics.draw (&state, &mut gl_state, &renderable_arrows);
 | 
			
		||||
		
 | 
			
		||||
		window.gl_swap_window ();
 | 
			
		||||
		graphics_frames += 1;
 | 
			
		||||
		
 | 
			
		||||
		std::thread::sleep (Duration::from_millis (15));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,12 @@ pub fn stencil_mask (v: u32) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn depth_func (v: u32) {
 | 
			
		||||
	unsafe {
 | 
			
		||||
		gl::DepthFunc (v);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// More abstract things below here
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue