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_LEFT: usize = 0;
|
||||||
const KEY_RIGHT: usize = KEY_LEFT + 1;
|
const KEY_RIGHT: usize = KEY_LEFT + 1;
|
||||||
const KEY_UP: usize = KEY_RIGHT + 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 {
|
struct WorldState {
|
||||||
azimuth: f32,
|
camera: EulerAngles,
|
||||||
altitude: f32,
|
wind: EulerAngles,
|
||||||
spin_speed: i32,
|
spin_speed: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorldState {
|
impl WorldState {
|
||||||
pub fn new () -> Self {
|
pub fn new () -> Self {
|
||||||
Self {
|
Self {
|
||||||
azimuth: 0.0,
|
camera: Default::default (),
|
||||||
altitude: 0.0,
|
wind: Default::default (),
|
||||||
spin_speed: 0,
|
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;
|
const SPIN_RAMP_TIME: i32 = 30;
|
||||||
|
|
||||||
let spin_f = 4.0 * self.spin_speed as f32 / SPIN_RAMP_TIME as f32;
|
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) {
|
if controller.is_pressed (KEY_LEFT) {
|
||||||
self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
|
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) {
|
else if controller.is_pressed (KEY_RIGHT) {
|
||||||
self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
|
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) {
|
else if controller.is_pressed (KEY_UP) {
|
||||||
self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
|
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) {
|
else if controller.is_pressed (KEY_DOWN) {
|
||||||
self.spin_speed = std::cmp::min (self.spin_speed + 1, SPIN_RAMP_TIME);
|
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 {
|
else {
|
||||||
self.spin_speed = 0;
|
self.spin_speed = 0;
|
||||||
|
@ -145,11 +184,13 @@ where P: AsRef <std::path::Path>
|
||||||
struct Arrow {
|
struct Arrow {
|
||||||
origin: Vec3,
|
origin: Vec3,
|
||||||
direction: Vec3,
|
direction: Vec3,
|
||||||
|
color: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RenderableArrow {
|
struct RenderableArrow {
|
||||||
model_mat: Mat4,
|
model_mat: Mat4,
|
||||||
inv_model_mat: Mat4,
|
inv_model_mat: Mat4,
|
||||||
|
color: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Copy, Clone, PartialEq, Eq)]
|
#[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)]
|
#[derive (Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct StencilOpState {
|
pub struct StencilOpState {
|
||||||
sfail: StencilOp,
|
sfail: StencilOp,
|
||||||
|
@ -257,9 +329,12 @@ pub struct StencilState {
|
||||||
// to safely use the flags / numbers
|
// to safely use the flags / numbers
|
||||||
|
|
||||||
pub struct IsoGlState {
|
pub struct IsoGlState {
|
||||||
|
shader_id: Option <u32>,
|
||||||
|
|
||||||
flags: HashMap <u32, bool>,
|
flags: HashMap <u32, bool>,
|
||||||
front_face: Option <FrontFace>,
|
front_face: Option <FrontFace>,
|
||||||
stencil: Option <StencilState>,
|
stencil: Option <StencilState>,
|
||||||
|
depth_func: Option <DepthFunc>,
|
||||||
|
|
||||||
color_mask: Option <(u8, u8, u8, u8)>,
|
color_mask: Option <(u8, u8, u8, u8)>,
|
||||||
depth_mask: Option <u8>,
|
depth_mask: Option <u8>,
|
||||||
|
@ -269,9 +344,11 @@ pub struct IsoGlState {
|
||||||
impl std::default::Default for IsoGlState {
|
impl std::default::Default for IsoGlState {
|
||||||
fn default () -> Self {
|
fn default () -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
shader_id: None,
|
||||||
flags: hashmap! {},
|
flags: hashmap! {},
|
||||||
front_face: None,
|
front_face: None,
|
||||||
stencil: None,
|
stencil: None,
|
||||||
|
depth_func: None,
|
||||||
color_mask: None,
|
color_mask: None,
|
||||||
depth_mask: None,
|
depth_mask: None,
|
||||||
stencil_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
|
// These are POD IDs or hashes of non-POD data
|
||||||
|
|
||||||
pub struct NonIsoGlState {
|
pub struct NonIsoGlState {
|
||||||
shader_id: Option <u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::default::Default for NonIsoGlState {
|
impl std::default::Default for NonIsoGlState {
|
||||||
fn default () -> Self {
|
fn default () -> Self {
|
||||||
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"
|
// In the context of a Pass, "None" means "Don't care"
|
||||||
|
|
||||||
iso: IsoGlState,
|
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) {
|
pub fn apply_diff (&self, old_state: &mut IsoGlState) {
|
||||||
let state = &self.iso;
|
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 let Some ((r, g, b, a)) = &state.color_mask {
|
||||||
if old_state.color_mask != state.color_mask {
|
if old_state.color_mask != state.color_mask {
|
||||||
glezz::color_mask (*r, *g, *b, *a);
|
glezz::color_mask (*r, *g, *b, *a);
|
||||||
|
@ -425,15 +506,20 @@ impl Pass <'_> {
|
||||||
callback ();
|
callback ();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_shader <F> (&self, gl_state: &mut GlState, callback: F)
|
pub fn with_shader <F, S> (
|
||||||
where F: Fn (BorrowedShaderVars)
|
&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);
|
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);
|
callback (shader_vars);
|
||||||
});
|
});
|
||||||
gl_state.non_iso.shader_id = Some (s.get_id ());
|
gl_state.iso.shader_id = Some (s);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
panic! ("Called with_shader on a pass with no shader");
|
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 {
|
struct GameGraphics {
|
||||||
shader_diffuse: ShaderClosure,
|
passes: Vec <Pass>,
|
||||||
shader_shadow: ShaderClosure,
|
|
||||||
|
shaders: Vec <ShaderClosure>,
|
||||||
|
shader_lookup: HashMap <u32, usize>,
|
||||||
|
|
||||||
mesh_pumpkin: RenderableModel,
|
mesh_pumpkin: RenderableModel,
|
||||||
mesh_sky: RenderableModel,
|
mesh_sky: RenderableModel,
|
||||||
|
@ -456,6 +548,12 @@ struct GameGraphics {
|
||||||
grass_index: usize,
|
grass_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ShaderLookup for GameGraphics {
|
||||||
|
fn lookup <'a> (&'a self, id: u32) -> &'a ShaderClosure {
|
||||||
|
&self.shaders [self.shader_lookup [&id]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GameGraphics {
|
impl GameGraphics {
|
||||||
pub fn new () -> Self {
|
pub fn new () -> Self {
|
||||||
let uniform_names = {
|
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 shaders: Vec <_> = [
|
||||||
let shader_shadow = ShaderClosure::new (shader_from_files ("shaders/shadow-vert.glsl", "shaders/shadow-frag.glsl"), &uniform_names, &attr_names);
|
("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;
|
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]);
|
||||||
|
@ -538,9 +647,183 @@ impl GameGraphics {
|
||||||
(colors, grass_index.unwrap ())
|
(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 {
|
Self {
|
||||||
shader_diffuse,
|
passes,
|
||||||
shader_shadow,
|
shaders,
|
||||||
|
shader_lookup,
|
||||||
|
|
||||||
mesh_pumpkin,
|
mesh_pumpkin,
|
||||||
mesh_sky,
|
mesh_sky,
|
||||||
|
@ -574,8 +857,8 @@ impl GameGraphics {
|
||||||
green,
|
green,
|
||||||
];
|
];
|
||||||
|
|
||||||
let longitude = state.azimuth.to_radians ();
|
let longitude = state.camera.azimuth.to_radians ();
|
||||||
let latitude = (state.altitude - 90.0).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);
|
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");
|
//println! ("Started frame");
|
||||||
|
|
||||||
let passes = vec! [
|
let mut passes = self.passes.iter ();
|
||||||
// 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),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
passes [0].with (gl_state, || {
|
passes.next ().unwrap ().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);
|
||||||
});
|
});
|
||||||
|
@ -730,7 +900,8 @@ impl GameGraphics {
|
||||||
use uniforms::*;
|
use uniforms::*;
|
||||||
|
|
||||||
// Draw the world except the ground plane
|
// 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 unis = shader_vars.unis;
|
||||||
let attrs = shader_vars.attrs;
|
let attrs = shader_vars.attrs;
|
||||||
|
|
||||||
|
@ -759,19 +930,6 @@ impl GameGraphics {
|
||||||
i != self.grass_index
|
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;
|
let draw_sky = true;
|
||||||
if draw_sky {
|
if draw_sky {
|
||||||
self.texture.bind ();
|
self.texture.bind ();
|
||||||
|
@ -786,7 +944,8 @@ impl GameGraphics {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw shadows into stencil buffer
|
// 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 unis = shader_vars.unis;
|
||||||
let attrs = shader_vars.attrs;
|
let attrs = shader_vars.attrs;
|
||||||
|
|
||||||
|
@ -813,7 +972,8 @@ 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 (gl_state, |shader_vars| {
|
passes.next ().unwrap ().with_shader (gl_state, self,
|
||||||
|
|shader_vars| {
|
||||||
let unis = shader_vars.unis;
|
let unis = shader_vars.unis;
|
||||||
let attrs = shader_vars.attrs;
|
let attrs = shader_vars.attrs;
|
||||||
|
|
||||||
|
@ -835,16 +995,51 @@ impl GameGraphics {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Draw lit ground
|
// 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 unis = shader_vars.unis;
|
||||||
let attrs = shader_vars.attrs;
|
let attrs = shader_vars.attrs;
|
||||||
|
|
||||||
glezz::uniform_3fv (unis [&OBJECT_SPACE_LIGHT], &object_space_light);
|
glezz::uniform_3fv (unis [&OBJECT_SPACE_LIGHT], &object_space_light);
|
||||||
self.mesh_pitch.draw (attrs, self.grass_index);
|
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 () {
|
fn main () {
|
||||||
let sdl_context = sdl2::init ().unwrap ();
|
let sdl_context = sdl2::init ().unwrap ();
|
||||||
let video_subsystem = sdl_context.video ().unwrap ();
|
let video_subsystem = sdl_context.video ().unwrap ();
|
||||||
|
@ -871,16 +1066,13 @@ fn main () {
|
||||||
let graphics = GameGraphics::new ();
|
let graphics = GameGraphics::new ();
|
||||||
let mut gl_state = Default::default ();
|
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 ();
|
let mut event_pump = sdl_context.event_pump ().unwrap ();
|
||||||
'running: loop {
|
'running: loop {
|
||||||
let frames_to_do = time_step.step ();
|
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 ();
|
let _mouse = event_pump.mouse_state ();
|
||||||
|
|
||||||
for event in event_pump.poll_iter() {
|
for event in event_pump.poll_iter() {
|
||||||
|
@ -889,27 +1081,55 @@ fn main () {
|
||||||
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
|
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
|
||||||
break 'running
|
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![
|
let arrows = vec![
|
||||||
Arrow {
|
Arrow {
|
||||||
origin: (0.0, 0.0, 1.0).into (),
|
origin: (0.0, 0.0, 1.35).into (),
|
||||||
direction: (0.0, 0.0, 1.0).into (),
|
direction: gravity,
|
||||||
|
color: (1.0, 0.5, 0.5).into (),
|
||||||
},
|
},
|
||||||
Arrow {
|
Arrow {
|
||||||
origin: (1.0, 0.0, 1.0).into (),
|
origin: origin + wind * -2.0,
|
||||||
direction: (1.0, 0.0, 0.0).into (),
|
direction: wind,
|
||||||
},
|
color: if user_control == UserControl::Wind {
|
||||||
Arrow {
|
control_flash
|
||||||
origin: (0.0, 1.0, 1.0).into (),
|
}
|
||||||
direction: (0.0, 1.0, 0.0).into (),
|
else {
|
||||||
|
(1.0, 0.5, 1.0).into ()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
let renderable_arrows: Vec <_> = arrows.iter ().map (|arrow| {
|
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 {
|
let up: Vec3 = if d.z () > 0.5 {
|
||||||
(-1.0, 0.0, 0.0)
|
(-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_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 ());
|
dir_mat.set_z_axis ((d.x (), d.y (), d.z (), 0.0).into ());
|
||||||
|
|
||||||
|
let s = dir_len * 0.0625;
|
||||||
|
|
||||||
let model_mat =
|
let model_mat =
|
||||||
Mat4::from_translation (arrow.origin) *
|
Mat4::from_translation (arrow.origin) *
|
||||||
Mat4::from_scale ((0.125, 0.125, 0.125).into ()) *
|
Mat4::from_scale ((s, s, s).into ()) *
|
||||||
dir_mat;
|
dir_mat;
|
||||||
|
|
||||||
let inv_model_mat = model_mat.inverse ();
|
let inv_model_mat = model_mat.inverse ();
|
||||||
|
@ -942,6 +1164,7 @@ fn main () {
|
||||||
RenderableArrow {
|
RenderableArrow {
|
||||||
model_mat,
|
model_mat,
|
||||||
inv_model_mat,
|
inv_model_mat,
|
||||||
|
color: arrow.color,
|
||||||
}
|
}
|
||||||
}).collect ();
|
}).collect ();
|
||||||
|
|
||||||
|
@ -950,6 +1173,7 @@ fn main () {
|
||||||
graphics.draw (&state, &mut gl_state, &renderable_arrows);
|
graphics.draw (&state, &mut gl_state, &renderable_arrows);
|
||||||
|
|
||||||
window.gl_swap_window ();
|
window.gl_swap_window ();
|
||||||
|
graphics_frames += 1;
|
||||||
|
|
||||||
std::thread::sleep (Duration::from_millis (15));
|
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
|
// More abstract things below here
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue