diff --git a/src/bin/pumpkin.rs b/src/bin/pumpkin.rs index e4727e2..5c38613 100644 --- a/src/bin/pumpkin.rs +++ b/src/bin/pumpkin.rs @@ -1,7 +1,6 @@ #[macro_use] extern crate maplit; -use float_ord::FloatOrd; use glam::{Mat4, Quat, Vec3, Vec4}; use sdl2::event::Event; @@ -13,10 +12,9 @@ use std::time::{Duration}; use opengl_rust::*; -use file::load_small_file; -use iqm::Model; -use renderable_model::RenderableModel; -use shader::{ShaderProgram, ShaderObject}; +use gl_state::*; +use renderable_model::*; +use shader::*; use shader_closure::*; use texture::Texture; use timestep::TimeStep; @@ -190,7 +188,7 @@ struct FlightState { } impl FlightState { - pub fn handle_event (&mut self, event: &sdl2::event::Event) { + pub fn handle_event (&mut self, _event: &sdl2::event::Event) { } @@ -202,10 +200,13 @@ impl FlightState { let nose = airplane.ori.mul_vec3 ((0.0, 1.0, 0.0).into ()); let speed = airplane.vel.length (); // Different from nose since planes are always drifting - let direction = match speed { - 0.0 => Vec3::from ((0.0, 0.0, 0.0)), - _ => airplane.vel * (1.0 / speed), + let direction = if speed == 0.0 { + Vec3::from ((0.0, 0.0, 0.0)) + } + else { + airplane.vel * (1.0 / speed) }; + let object_space_dir = airplane.ori.conjugate ().mul_vec3 (direction); // Forces @@ -353,24 +354,6 @@ fn make_object_space_vec (inverse_model_mat: &Mat4, world_space_vec: &Vec3) Vec3::from ((v4.x (), v4.y (), v4.z ())) } -fn renderable_from_iqm_file

(filename: P) -> RenderableModel -where P: AsRef -{ - let data = load_small_file (filename, 1024 * 1024).unwrap (); - let model = Model::from_slice (&data).unwrap (); - - RenderableModel::from_iqm (&model) -} - -fn shader_from_files

(vert: P, frag: P) -> ShaderProgram -where P: AsRef -{ - let vert_shader = ShaderObject::from_file (gl::VERTEX_SHADER, vert).unwrap (); - let frag_shader = ShaderObject::from_file (gl::FRAGMENT_SHADER, frag).unwrap (); - - ShaderProgram::new (&vert_shader, &frag_shader).unwrap () -} - struct Arrow { origin: Vec3, direction: Vec3, @@ -383,344 +366,6 @@ struct RenderableArrow { color: Vec3, } -#[derive (Copy, Clone, PartialEq, Eq)] -pub enum FrontFace { - Cw, - Ccw, -} - -impl From for u32 { - fn from (v: FrontFace) -> Self { - use FrontFace::*; - { - use gl::*; - match v { - Cw => CW, - Ccw => CCW, - } - } - } -} - -#[derive (Copy, Clone, PartialEq, Eq)] -pub enum StencilOp { - Keep, - Zero, - Replace, - Incr, - Decr, - Invert, - IncrWrap, - DecrWrap, -} - -impl From for u32 { - fn from (v: StencilOp) -> Self { - use StencilOp::*; - { - use gl::*; - match v { - Keep => KEEP, - Zero => ZERO, - Replace => REPLACE, - Incr => INCR, - Decr => DECR, - Invert => INVERT, - IncrWrap => INCR_WRAP, - DecrWrap => DECR_WRAP, - } - } - } -} - -#[derive (Copy, Clone, PartialEq, Eq)] -pub enum StencilFunc { - Never, - Always, - Less, - LessEqual, - Equal, - Greater, - GreaterEqual, - NotEqual, -} - -impl From for u32 { - fn from (v: StencilFunc) -> Self { - use StencilFunc::*; - { - 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 enum DepthFunc { - Never, - Always, - Less, - LessEqual, - Equal, - Greater, - GreaterEqual, - NotEqual, -} - -impl From 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, - dpfail: StencilOp, - dppass: StencilOp, -} - -#[derive (Copy, Clone, PartialEq, Eq)] -pub struct StencilFuncState { - func: StencilFunc, - reference: i32, - mask: u32, -} - -#[derive (Copy, Clone, PartialEq, Eq)] -pub struct StencilState { - op: StencilOpState, - func: StencilFuncState, -} - -// These are POD where no extra data is needed -// to safely use the flags / numbers - -pub struct IsoGlState { - shader_id: Option , - - flags: HashMap , - front_face: Option , - stencil: Option , - depth_func: Option , - - color_mask: Option <(u8, u8, u8, u8)>, - depth_mask: Option , - stencil_mask: Option , -} - -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, - } - } -} - -// These are POD IDs or hashes of non-POD data - -pub struct NonIsoGlState { -} - -impl std::default::Default for NonIsoGlState { - fn default () -> Self { - Self { - } - } -} - -pub struct GlState { - iso: IsoGlState, - non_iso: NonIsoGlState, -} - -impl std::default::Default for GlState { - fn default () -> Self { - Self { - iso: Default::default (), - non_iso: Default::default (), - } - } -} - -pub struct Pass { - // In the context of a Pass, "None" means "Don't care" - - iso: IsoGlState, -} - -impl Pass { - pub fn apply_diff (&self, old_state: &mut IsoGlState) { - let state = &self.iso; - - let mut flag_elision_count = 0; - - for (flag, value) in state.flags.iter () { - let old_entry = old_state.flags.entry (*flag); - if match &old_entry { - hash_map::Entry::Vacant (_) => true, - hash_map::Entry::Occupied (o) => o.get () != value, - } { - if *value { - glezz::enable (*flag); - } - else { - glezz::disable (*flag); - } - - old_entry.or_insert (*value); - } - else { - flag_elision_count += 1; - } - } - if flag_elision_count > 0 { - //println! ("Elided {} flags", flag_elision_count); - } - - if let Some (v) = &state.front_face { - if old_state.front_face != state.front_face { - glezz::front_face ((*v).into ()); - old_state.front_face = state.front_face; - } - else { - //println! ("Elided front_face ()"); - } - } - - if let Some (v) = &state.stencil { - if old_state.stencil != state.stencil { - let func = &v.func; - unsafe { - gl::StencilFunc ( - func.func.into (), - func.reference.into (), - func.mask.into () - ); - } - - let op = &v.op; - unsafe { - gl::StencilOp ( - op.sfail.into (), - op.dpfail.into (), - op.dppass.into () - ); - } - } - else { - //println! ("Elided stencil state"); - } - } - - 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); - old_state.color_mask = state.color_mask; - } - else { - //println! ("Elided color_mask ()"); - } - } - - if let Some (v) = &state.depth_mask { - if old_state.depth_mask != state.depth_mask { - glezz::depth_mask (*v); - old_state.depth_mask = state.depth_mask; - } - else { - //println! ("Elided depth_mask ()"); - } - } - - if let Some (v) = &state.stencil_mask { - if old_state.stencil_mask != state.stencil_mask { - glezz::stencil_mask (*v); - old_state.stencil_mask = state.stencil_mask; - } - else { - //println! ("Elided stencil_mask ()"); - } - } - } - - pub fn apply_slow (&self) { - let mut iso = IsoGlState::default (); - - self.apply_diff (&mut iso); - } - - pub fn with (&self, gl_state: &mut GlState, callback: F) - where F: Fn () - { - self.apply_diff (&mut gl_state.iso); - callback (); - } - - pub fn with_shader ( - &self, - gl_state: &mut GlState, - shader_component: &S, - callback: F - ) - where F: Fn (BorrowedShaderVars), S: ShaderLookup - { - if let Some (s) = self.iso.shader_id { - self.apply_diff (&mut gl_state.iso); - shader_component.lookup (s).with (gl_state.iso.shader_id, |shader_vars| { - callback (shader_vars); - }); - gl_state.iso.shader_id = Some (s); - } - else { - panic! ("Called with_shader on a pass with no shader"); - } - } -} - -pub trait ShaderLookup { - fn lookup <'a> (&'a self, id: u32) -> &'a ShaderClosure; -} - struct GameGraphics { passes: Vec , @@ -1133,7 +778,7 @@ impl GameGraphics { let gunmetal_grey = color_from_255 ((133.0, 149.0, 161.0)); glezz::uniform_3fv (unis [&ALBEDO], &gunmetal_grey); - self.mesh_airplane.draw_all (attrs, |i| { + self.mesh_airplane.draw_all (attrs, |_i| { true }); diff --git a/src/gl_state.rs b/src/gl_state.rs new file mode 100644 index 0000000..846dad7 --- /dev/null +++ b/src/gl_state.rs @@ -0,0 +1,338 @@ +use std::collections::*; + +use crate::glezz; +use crate::shader_closure::*; + +#[derive (Copy, Clone, PartialEq, Eq)] +pub enum FrontFace { + Cw, + Ccw, +} + +impl From for u32 { + fn from (v: FrontFace) -> Self { + use FrontFace::*; + { + use gl::*; + match v { + Cw => CW, + Ccw => CCW, + } + } + } +} + +#[derive (Copy, Clone, PartialEq, Eq)] +pub enum StencilOp { + Keep, + Zero, + Replace, + Incr, + Decr, + Invert, + IncrWrap, + DecrWrap, +} + +impl From for u32 { + fn from (v: StencilOp) -> Self { + use StencilOp::*; + { + use gl::*; + match v { + Keep => KEEP, + Zero => ZERO, + Replace => REPLACE, + Incr => INCR, + Decr => DECR, + Invert => INVERT, + IncrWrap => INCR_WRAP, + DecrWrap => DECR_WRAP, + } + } + } +} + +#[derive (Copy, Clone, PartialEq, Eq)] +pub enum StencilFunc { + Never, + Always, + Less, + LessEqual, + Equal, + Greater, + GreaterEqual, + NotEqual, +} + +impl From for u32 { + fn from (v: StencilFunc) -> Self { + use StencilFunc::*; + { + 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 enum DepthFunc { + Never, + Always, + Less, + LessEqual, + Equal, + Greater, + GreaterEqual, + NotEqual, +} + +impl From 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 { + pub sfail: StencilOp, + pub dpfail: StencilOp, + pub dppass: StencilOp, +} + +#[derive (Copy, Clone, PartialEq, Eq)] +pub struct StencilFuncState { + pub func: StencilFunc, + pub reference: i32, + pub mask: u32, +} + +#[derive (Copy, Clone, PartialEq, Eq)] +pub struct StencilState { + pub op: StencilOpState, + pub func: StencilFuncState, +} + +// These are POD where no extra data is needed +// to safely use the flags / numbers + +pub struct IsoGlState { + pub shader_id: Option , + + pub flags: HashMap , + pub front_face: Option , + pub stencil: Option , + pub depth_func: Option , + + pub color_mask: Option <(u8, u8, u8, u8)>, + pub depth_mask: Option , + pub stencil_mask: Option , +} + +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, + } + } +} + +// These are POD IDs or hashes of non-POD data + +pub struct NonIsoGlState { +} + +impl std::default::Default for NonIsoGlState { + fn default () -> Self { + Self { + } + } +} + +pub struct GlState { + pub iso: IsoGlState, + pub non_iso: NonIsoGlState, +} + +impl std::default::Default for GlState { + fn default () -> Self { + Self { + iso: Default::default (), + non_iso: Default::default (), + } + } +} + +pub struct Pass { + // In the context of a Pass, "None" means "Don't care" + + pub iso: IsoGlState, +} + +impl Pass { + pub fn apply_diff (&self, old_state: &mut IsoGlState) { + let state = &self.iso; + + let mut flag_elision_count = 0; + + for (flag, value) in state.flags.iter () { + let old_entry = old_state.flags.entry (*flag); + if match &old_entry { + hash_map::Entry::Vacant (_) => true, + hash_map::Entry::Occupied (o) => o.get () != value, + } { + if *value { + glezz::enable (*flag); + } + else { + glezz::disable (*flag); + } + + old_entry.or_insert (*value); + } + else { + flag_elision_count += 1; + } + } + if flag_elision_count > 0 { + //println! ("Elided {} flags", flag_elision_count); + } + + if let Some (v) = &state.front_face { + if old_state.front_face != state.front_face { + glezz::front_face ((*v).into ()); + old_state.front_face = state.front_face; + } + else { + //println! ("Elided front_face ()"); + } + } + + if let Some (v) = &state.stencil { + if old_state.stencil != state.stencil { + let func = &v.func; + unsafe { + gl::StencilFunc ( + func.func.into (), + func.reference.into (), + func.mask.into () + ); + } + + let op = &v.op; + unsafe { + gl::StencilOp ( + op.sfail.into (), + op.dpfail.into (), + op.dppass.into () + ); + } + } + else { + //println! ("Elided stencil state"); + } + } + + 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); + old_state.color_mask = state.color_mask; + } + else { + //println! ("Elided color_mask ()"); + } + } + + if let Some (v) = &state.depth_mask { + if old_state.depth_mask != state.depth_mask { + glezz::depth_mask (*v); + old_state.depth_mask = state.depth_mask; + } + else { + //println! ("Elided depth_mask ()"); + } + } + + if let Some (v) = &state.stencil_mask { + if old_state.stencil_mask != state.stencil_mask { + glezz::stencil_mask (*v); + old_state.stencil_mask = state.stencil_mask; + } + else { + //println! ("Elided stencil_mask ()"); + } + } + } + + pub fn apply_slow (&self) { + let mut iso = IsoGlState::default (); + + self.apply_diff (&mut iso); + } + + pub fn with (&self, gl_state: &mut GlState, callback: F) + where F: Fn () + { + self.apply_diff (&mut gl_state.iso); + callback (); + } + + pub fn with_shader ( + &self, + gl_state: &mut GlState, + shader_component: &S, + callback: F + ) + where F: Fn (BorrowedShaderVars), S: ShaderLookup + { + if let Some (s) = self.iso.shader_id { + self.apply_diff (&mut gl_state.iso); + shader_component.lookup (s).with (gl_state.iso.shader_id, |shader_vars| { + callback (shader_vars); + }); + gl_state.iso.shader_id = Some (s); + } + else { + panic! ("Called with_shader on a pass with no shader"); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index f9b9cdd..f4608be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,12 @@ #[macro_use] extern crate iota; +#[macro_use] +extern crate maplit; + pub mod file; pub mod glezz; +pub mod gl_state; pub mod gpu_buffers; pub mod iqm; pub mod renderable_model; diff --git a/src/renderable_model.rs b/src/renderable_model.rs index 316add7..52a0990 100644 --- a/src/renderable_model.rs +++ b/src/renderable_model.rs @@ -142,3 +142,12 @@ impl RenderableModel { self.meshes.len () } } + +pub fn renderable_from_iqm_file

(filename: P) -> RenderableModel +where P: AsRef +{ + let data = crate::file::load_small_file (filename, 1024 * 1024).unwrap (); + let model = crate::iqm::Model::from_slice (&data).unwrap (); + + RenderableModel::from_iqm (&model) +} diff --git a/src/shader.rs b/src/shader.rs index 207309c..6e8aae3 100644 --- a/src/shader.rs +++ b/src/shader.rs @@ -197,3 +197,12 @@ impl Drop for ShaderProgram { } } } + +pub fn shader_from_files

(vert: P, frag: P) -> ShaderProgram +where P: AsRef +{ + let vert_shader = ShaderObject::from_file (gl::VERTEX_SHADER, vert).unwrap (); + let frag_shader = ShaderObject::from_file (gl::FRAGMENT_SHADER, frag).unwrap (); + + ShaderProgram::new (&vert_shader, &frag_shader).unwrap () +} diff --git a/src/shader_closure.rs b/src/shader_closure.rs index 6141979..b3e68dc 100644 --- a/src/shader_closure.rs +++ b/src/shader_closure.rs @@ -87,3 +87,7 @@ impl ShaderClosure { }); } } + +pub trait ShaderLookup { + fn lookup <'a> (&'a self, id: u32) -> &'a ShaderClosure; +}