🚧 Work on pass manager idea

main
_ 2020-03-08 18:08:22 +00:00
parent 1a42b60f71
commit 838226b2de
3 changed files with 257 additions and 20 deletions

7
Cargo.lock generated
View File

@ -134,6 +134,11 @@ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.2.1"
@ -199,6 +204,7 @@ dependencies = [
"gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glam 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
"iota 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -423,6 +429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum lexical-core 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2304bccb228c4b020f3a4835d247df0a02a7c4686098d4167762cfbbe4c5cb14"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
"checksum nom 5.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c433f4d505fe6ce7ff78523d2fa13a0b9f2690e181fc26168bcbe5ccc5d14e07"

View File

@ -15,6 +15,7 @@ glam = "0.8.5"
iota = "0.2.1"
maplit = "1.0.2"
# TODO: Drop nom depend. It's way overkill for iqm.
nom = "5.1.0"

View File

@ -1,3 +1,6 @@
#[macro_use]
extern crate maplit;
use glam::{Mat4, Vec3, Vec4};
use sdl2::event::Event;
@ -149,6 +152,161 @@ struct RenderableArrow {
inv_model_mat: Mat4,
}
#[derive (Copy, Clone)]
pub enum FrontFace {
Cw,
Ccw,
}
impl From <FrontFace> for u32 {
fn from (v: FrontFace) -> Self {
use FrontFace::*;
{
use gl::*;
match v {
Cw => CW,
Ccw => CCW,
}
}
}
}
#[derive (Copy, Clone)]
pub enum StencilOp {
Keep,
Zero,
Replace,
Incr,
Decr,
Invert,
IncrWrap,
DecrWrap,
}
impl From <StencilOp> 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)]
pub enum StencilFunc {
Never,
Always,
Less,
LessEqual,
Equal,
Greater,
GreaterEqual,
NotEqual,
}
impl From <StencilFunc> 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,
}
}
}
}
pub struct StencilOpState {
sfail: StencilOp,
dpfail: StencilOp,
dppass: StencilOp,
}
pub struct StencilFuncState {
func: StencilFunc,
reference: i32,
mask: u32,
}
pub struct StencilState {
op: StencilOpState,
func: StencilFuncState,
}
// Anything that's None is "unknown"
pub struct GlState {
flags: HashMap <u32, bool>,
front_face: Option <FrontFace>,
stencil: Option <StencilState>,
}
pub struct Pass <'a> {
shader: &'a ShaderClosure,
// Anything that's None is "don't care"
required_state: GlState,
}
impl Pass <'_> {
pub fn apply_slow (&self) {
let state = &self.required_state;
for (flag, value) in state.flags.iter () {
if *value {
glezz::enable (*flag);
}
else {
glezz::disable (*flag);
}
}
match state.front_face {
Some (v) => glezz::front_face (v.into ()),
_ => (),
}
match &state.stencil {
Some (v) => {
let func = &v.func;
let op = &v.op;
unsafe {
gl::StencilFunc (
func.func.into (),
func.reference.into (),
func.mask.into ()
);
gl::StencilOp (
op.sfail.into (),
op.dpfail.into (),
op.dppass.into ()
);
}
},
_ => (),
}
}
}
struct GameGraphics {
shader_diffuse: ShaderClosure,
shader_shadow: ShaderClosure,
@ -305,6 +463,83 @@ impl GameGraphics {
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);
let passes = vec! [
Pass {
shader: &self.shader_diffuse,
required_state: GlState {
flags: hashmap! {
gl::STENCIL_TEST => false,
},
front_face: Some (FrontFace::Cw),
stencil: None,
},
},
Pass {
shader: &self.shader_shadow,
required_state: GlState {
flags: hashmap! {
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,
},
}),
},
},
Pass {
shader: &self.shader_shadow,
required_state: GlState {
flags: hashmap! {
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,
},
}),
},
},
Pass {
shader: &self.shader_shadow,
required_state: GlState {
flags: hashmap! {
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,
},
}),
},
},
];
glezz::enable (gl::CULL_FACE);
let pumpkin_model_mat =
@ -324,9 +559,8 @@ impl GameGraphics {
let unis = shader_vars.unis;
let attrs = shader_vars.attrs;
// Pass 1 - Draw the world except the ground plane
glezz::disable (gl::STENCIL_TEST);
glezz::front_face (gl::CW);
// Pass 0 - Draw the world except the ground plane
passes [0].apply_slow ();
let mvp = view_mat * pumpkin_model_mat;
glezz::uniform_matrix_4fv (unis [&MVP], &mvp);
@ -385,13 +619,9 @@ impl GameGraphics {
let unis = shader_vars.unis;
let attrs = shader_vars.attrs;
// Pass 2: Draw shadows into stencil buffer
glezz::front_face (gl::CCW);
glezz::enable (gl::STENCIL_TEST);
// Pass 1: Draw shadows into stencil buffer
passes [1].apply_slow ();
unsafe {
gl::StencilFunc (gl::ALWAYS, 1, 1);
gl::StencilOp (gl::KEEP, gl::KEEP, gl::REPLACE);
gl::ColorMask (0, 0, 0, 0);
gl::DepthMask (0);
gl::StencilMask (1);
@ -421,16 +651,13 @@ impl GameGraphics {
let unis = shader_vars.unis;
let attrs = shader_vars.attrs;
// Pass 3: Draw lit ground
// Pass 2: Draw lit ground
passes [2].apply_slow ();
unsafe {
gl::ColorMask (255, 255, 255, 255);
gl::DepthMask (1);
gl::StencilFunc (gl::NOTEQUAL, 0, 1);
gl::StencilOp (gl::KEEP, gl::KEEP, gl::KEEP);
}
glezz::front_face (gl::CW);
let inverse_pumpkin = pumpkin_model_mat.inverse ();
let object_space_light = make_object_space_vec (&inverse_pumpkin, &light);
@ -449,11 +676,9 @@ impl GameGraphics {
glezz::uniform_3fv (unis [&OBJECT_SPACE_LIGHT], &Vec3::from ((0.0, 0.0, 0.0)));
self.mesh_pitch.draw (attrs, self.grass_index);
// Pass 4: Draw shadowed ground
unsafe {
gl::StencilFunc (gl::EQUAL, 0, 1);
gl::StencilOp (gl::KEEP, gl::KEEP, gl::KEEP);
}
// Pass 3: Draw shadowed ground
passes [3].apply_slow ();
glezz::uniform_3fv (unis [&OBJECT_SPACE_LIGHT], &object_space_light);
self.mesh_pitch.draw (attrs, self.grass_index);
});
@ -574,7 +799,11 @@ mod tests {
use super::*;
#[test]
pub fn iqm () {
pub fn sizes () {
use std::mem;
assert_eq! (8, mem::size_of::<Option <u32>>());
assert_eq! (1, mem::size_of::<FrontFace>());
assert_eq! (1, mem::size_of::<Option <FrontFace>>());
}
}