🚧 still improving the pass system

main
_ 2020-03-08 19:32:02 +00:00
parent 9e74609eb1
commit afb0238c1b
4 changed files with 184 additions and 54 deletions

View File

@ -152,7 +152,7 @@ struct RenderableArrow {
inv_model_mat: Mat4, inv_model_mat: Mat4,
} }
#[derive (Copy, Clone)] #[derive (Copy, Clone, PartialEq, Eq)]
pub enum FrontFace { pub enum FrontFace {
Cw, Cw,
Ccw, Ccw,
@ -171,7 +171,7 @@ impl From <FrontFace> for u32 {
} }
} }
#[derive (Copy, Clone)] #[derive (Copy, Clone, PartialEq, Eq)]
pub enum StencilOp { pub enum StencilOp {
Keep, Keep,
Zero, Zero,
@ -202,7 +202,7 @@ impl From <StencilOp> for u32 {
} }
} }
#[derive (Copy, Clone)] #[derive (Copy, Clone, PartialEq, Eq)]
pub enum StencilFunc { pub enum StencilFunc {
Never, Never,
Always, Always,
@ -233,26 +233,30 @@ impl From <StencilFunc> for u32 {
} }
} }
#[derive (Copy, Clone, PartialEq, Eq)]
pub struct StencilOpState { pub struct StencilOpState {
sfail: StencilOp, sfail: StencilOp,
dpfail: StencilOp, dpfail: StencilOp,
dppass: StencilOp, dppass: StencilOp,
} }
#[derive (Copy, Clone, PartialEq, Eq)]
pub struct StencilFuncState { pub struct StencilFuncState {
func: StencilFunc, func: StencilFunc,
reference: i32, reference: i32,
mask: u32, mask: u32,
} }
#[derive (Copy, Clone, PartialEq, Eq)]
pub struct StencilState { pub struct StencilState {
op: StencilOpState, op: StencilOpState,
func: StencilFuncState, func: StencilFuncState,
} }
// Anything that's None is "unknown" // These are POD where no extra data is needed
// to safely use the flags / numbers
pub struct GlState { pub struct IsoGlState {
flags: HashMap <u32, bool>, flags: HashMap <u32, bool>,
front_face: Option <FrontFace>, front_face: Option <FrontFace>,
stencil: Option <StencilState>, stencil: Option <StencilState>,
@ -262,83 +266,174 @@ pub struct GlState {
stencil_mask: Option <u32>, stencil_mask: Option <u32>,
} }
impl std::default::Default for IsoGlState {
fn default () -> Self {
Self {
flags: hashmap! {},
front_face: None,
stencil: None,
color_mask: None,
depth_mask: None,
stencil_mask: None,
}
}
}
// 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,
}
}
}
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 <'a> { pub struct Pass <'a> {
// 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>, shader: Option <&'a ShaderClosure>,
// Anything that's None is "don't care"
required_state: GlState,
} }
impl Pass <'_> { impl Pass <'_> {
pub fn apply_slow (&self) { pub fn apply_diff (&self, old_state: &mut IsoGlState) {
let state = &self.required_state; let state = &self.iso;
let mut flag_elision_count = 0;
for (flag, value) in state.flags.iter () { for (flag, value) in state.flags.iter () {
if *value { let old_entry = old_state.flags.entry (*flag);
glezz::enable (*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 { else {
glezz::disable (*flag); flag_elision_count += 1;
} }
} }
if flag_elision_count > 0 {
//println! ("Elided {} flags", flag_elision_count);
}
if let Some (v) = &state.front_face { if let Some (v) = &state.front_face {
glezz::front_face ((*v).into ()); 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 let Some (v) = &state.stencil {
let func = &v.func; if old_state.stencil != state.stencil {
let op = &v.op; let func = &v.func;
unsafe {
unsafe { gl::StencilFunc (
gl::StencilFunc ( func.func.into (),
func.func.into (), func.reference.into (),
func.reference.into (), func.mask.into ()
func.mask.into () );
); }
gl::StencilOp (
op.sfail.into (), let op = &v.op;
op.dpfail.into (), unsafe {
op.dppass.into () gl::StencilOp (
); op.sfail.into (),
op.dpfail.into (),
op.dppass.into ()
);
}
}
else {
//println! ("Elided stencil state");
} }
} }
if let Some ((r, g, b, a)) = &state.color_mask { if let Some ((r, g, b, a)) = &state.color_mask {
unsafe { if old_state.color_mask != state.color_mask {
gl::ColorMask (*r, *g, *b, *a); 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 let Some (v) = &state.depth_mask {
unsafe { if old_state.depth_mask != state.depth_mask {
gl::DepthMask (*v); glezz::depth_mask (*v);
old_state.depth_mask = state.depth_mask;
}
else {
//println! ("Elided depth_mask ()");
} }
} }
if let Some (v) = &state.stencil_mask { if let Some (v) = &state.stencil_mask {
unsafe { if old_state.stencil_mask != state.stencil_mask {
gl::StencilMask (*v); glezz::stencil_mask (*v);
old_state.stencil_mask = state.stencil_mask;
}
else {
//println! ("Elided stencil_mask ()");
} }
} }
} }
pub fn with <F> (&self, callback: F) pub fn apply_slow (&self) {
let mut iso = IsoGlState::default ();
self.apply_diff (&mut iso);
}
pub fn with <F> (&self, gl_state: &mut GlState, callback: F)
where F: Fn () where F: Fn ()
{ {
self.apply_slow (); self.apply_diff (&mut gl_state.iso);
callback (); callback ();
} }
pub fn with_shader <F> (&self, callback: F) pub fn with_shader <F> (&self, gl_state: &mut GlState, callback: F)
where F: Fn (BorrowedShaderVars) where F: Fn (BorrowedShaderVars)
{ {
if let Some (s) = self.shader { if let Some (s) = self.shader {
s.with (|shader_vars| { self.apply_diff (&mut gl_state.iso);
self.apply_slow (); s.with (gl_state.non_iso.shader_id, |shader_vars| {
callback (shader_vars); callback (shader_vars);
}); });
gl_state.non_iso.shader_id = Some (s.get_id ());
} }
else { else {
panic! ("Called with_shader on a pass with no shader"); panic! ("Called with_shader on a pass with no shader");
@ -388,7 +483,7 @@ impl GameGraphics {
let shader_diffuse = ShaderClosure::new (shader_from_files ("shaders/pumpkin-vert.glsl", "shaders/pumpkin-frag.glsl"), &uniform_names, &attr_names); 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 shader_shadow = ShaderClosure::new (shader_from_files ("shaders/shadow-vert.glsl", "shaders/shadow-frag.glsl"), &uniform_names, &attr_names);
shader_diffuse.with (|shader_vars| { shader_diffuse.with (None, |shader_vars| {
let attrs = shader_vars.attrs; let attrs = shader_vars.attrs;
use renderable_model::attributes::*; use renderable_model::attributes::*;
glezz::enable_vertex_attrib_array (attrs [POS]); glezz::enable_vertex_attrib_array (attrs [POS]);
@ -462,6 +557,7 @@ impl GameGraphics {
pub fn draw ( pub fn draw (
&self, &self,
state: &WorldState, state: &WorldState,
gl_state: &mut GlState,
arrows: &[RenderableArrow] arrows: &[RenderableArrow]
) )
{ {
@ -500,11 +596,13 @@ impl GameGraphics {
let light = Vec3::from ((0.25, -0.125, 1.0)).normalize (); let light = Vec3::from ((0.25, -0.125, 1.0)).normalize ();
//println! ("Started frame");
let passes = vec! [ let passes = vec! [
// Clear everything // Clear everything
Pass { Pass {
shader: None, shader: None,
required_state: GlState { iso: IsoGlState {
flags: hashmap! {}, flags: hashmap! {},
front_face: None, front_face: None,
stencil: None, stencil: None,
@ -516,7 +614,7 @@ impl GameGraphics {
// Draw world // Draw world
Pass { Pass {
shader: Some (&self.shader_diffuse), shader: Some (&self.shader_diffuse),
required_state: GlState { iso: IsoGlState {
flags: hashmap! { flags: hashmap! {
gl::CULL_FACE => true, gl::CULL_FACE => true,
gl::DEPTH_TEST => true, gl::DEPTH_TEST => true,
@ -533,7 +631,7 @@ impl GameGraphics {
// Write shadows into stencil buffer // Write shadows into stencil buffer
Pass { Pass {
shader: Some (&self.shader_shadow), shader: Some (&self.shader_shadow),
required_state: GlState { iso: IsoGlState {
flags: hashmap! { flags: hashmap! {
gl::CULL_FACE => true, gl::CULL_FACE => true,
gl::DEPTH_TEST => true, gl::DEPTH_TEST => true,
@ -560,7 +658,7 @@ impl GameGraphics {
// Draw lit ground // Draw lit ground
Pass { Pass {
shader: Some (&self.shader_diffuse), shader: Some (&self.shader_diffuse),
required_state: GlState { iso: IsoGlState {
flags: hashmap! { flags: hashmap! {
gl::CULL_FACE => true, gl::CULL_FACE => true,
gl::DEPTH_TEST => true, gl::DEPTH_TEST => true,
@ -588,7 +686,7 @@ impl GameGraphics {
// Draw unlit ground // Draw unlit ground
Pass { Pass {
shader: Some (&self.shader_diffuse), shader: Some (&self.shader_diffuse),
required_state: GlState { iso: IsoGlState {
flags: hashmap! { flags: hashmap! {
gl::CULL_FACE => true, gl::CULL_FACE => true,
gl::DEPTH_TEST => true, gl::DEPTH_TEST => true,
@ -615,7 +713,7 @@ impl GameGraphics {
}, },
]; ];
passes [0].with (|| { passes [0].with (gl_state, || {
glezz::clear_color (1.0f32, 0.0f32, 1.0f32, 1.0f32); 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); glezz::clear (gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
}); });
@ -632,7 +730,7 @@ impl GameGraphics {
use uniforms::*; use uniforms::*;
// Draw the world except the ground plane // Draw the world except the ground plane
passes [1].with_shader (|shader_vars| { passes [1].with_shader (gl_state, |shader_vars| {
let unis = shader_vars.unis; let unis = shader_vars.unis;
let attrs = shader_vars.attrs; let attrs = shader_vars.attrs;
@ -688,7 +786,7 @@ impl GameGraphics {
}); });
// Draw shadows into stencil buffer // Draw shadows into stencil buffer
passes [2].with_shader (|shader_vars| { passes [2].with_shader (gl_state, |shader_vars| {
let unis = shader_vars.unis; let unis = shader_vars.unis;
let attrs = shader_vars.attrs; let attrs = shader_vars.attrs;
@ -715,7 +813,7 @@ impl GameGraphics {
let object_space_light = make_object_space_vec (&inverse_pumpkin, &light); let object_space_light = make_object_space_vec (&inverse_pumpkin, &light);
// Draw unlit ground // Draw unlit ground
passes [3].with_shader (|shader_vars| { passes [3].with_shader (gl_state, |shader_vars| {
let unis = shader_vars.unis; let unis = shader_vars.unis;
let attrs = shader_vars.attrs; let attrs = shader_vars.attrs;
@ -737,7 +835,7 @@ impl GameGraphics {
}); });
// Draw lit ground // Draw lit ground
passes [4].with_shader (|shader_vars| { passes [4].with_shader (gl_state, |shader_vars| {
let unis = shader_vars.unis; let unis = shader_vars.unis;
let attrs = shader_vars.attrs; let attrs = shader_vars.attrs;
@ -771,6 +869,7 @@ fn main () {
let mut state = WorldState::new (); let mut state = WorldState::new ();
let graphics = GameGraphics::new (); let graphics = GameGraphics::new ();
let mut gl_state = Default::default ();
let mut event_pump = sdl_context.event_pump ().unwrap (); let mut event_pump = sdl_context.event_pump ().unwrap ();
'running: loop { 'running: loop {
@ -848,7 +947,7 @@ fn main () {
window.gl_make_current (&gl_ctx).unwrap (); window.gl_make_current (&gl_ctx).unwrap ();
graphics.draw (&state, &renderable_arrows); graphics.draw (&state, &mut gl_state, &renderable_arrows);
window.gl_swap_window (); window.gl_swap_window ();

View File

@ -79,6 +79,24 @@ pub fn uniform_matrix_4fv (uni: i32, m: &Mat4) {
} }
} }
pub fn color_mask (r: u8, g: u8, b: u8, a: u8) {
unsafe {
gl::ColorMask (r, g, b, a);
}
}
pub fn depth_mask (v: u8) {
unsafe {
gl::DepthMask (v);
}
}
pub fn stencil_mask (v: u32) {
unsafe {
gl::StencilMask (v);
}
}
// More abstract things below here // More abstract things below here

View File

@ -119,6 +119,10 @@ impl ShaderProgram {
} }
} }
pub fn get_id (&self) -> u32 {
self.id
}
// 'use' is a keyword // 'use' is a keyword
pub fn use_program (&self) { pub fn use_program (&self) {

View File

@ -67,10 +67,19 @@ impl ShaderClosure {
} }
} }
pub fn with <F> (&self, callback: F) pub fn get_id (&self) -> u32 {
self.program.get_id ()
}
pub fn with <F> (&self, previous_id: Option <u32>, callback: F)
where F: Fn (BorrowedShaderVars) where F: Fn (BorrowedShaderVars)
{ {
self.program.use_program (); if previous_id != Some (self.get_id ()) {
self.program.use_program ();
}
else {
//println! ("Elided use_program ()");
}
callback (BorrowedShaderVars { callback (BorrowedShaderVars {
unis: &self.uniforms, unis: &self.uniforms,