summaryrefslogtreecommitdiff
path: root/src/state.rs
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2024-03-03 00:10:10 -0500
committerLLLL Colonq <llll@colonq>2024-03-03 00:10:10 -0500
commit070108cf09b1b561613b6eea04723afbbb464507 (patch)
tree01503df63f16ef6ef4ab4a37b24305286bb2477c /src/state.rs
Initial commit (new winit)
Diffstat (limited to 'src/state.rs')
-rw-r--r--src/state.rs262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/state.rs b/src/state.rs
new file mode 100644
index 0000000..bb479c6
--- /dev/null
+++ b/src/state.rs
@@ -0,0 +1,262 @@
+use std::collections::HashMap;
+
+use crate::{context, framebuffer, shader, audio};
+
+const DELTA_TIME: f64 = 1.0 / 60.0;
+
+pub trait Game {
+ fn initialize_audio(&self, ctx: &context::Context, st: &State, actx: &audio::Context) ->
+ HashMap<String, audio::Audio>;
+ fn finish_title(&mut self);
+ fn update(&mut self, ctx: &context::Context, st: &mut State) -> Option<()>;
+ fn render(&mut self, ctx: &context::Context, st: &mut State) -> Option<()>;
+}
+
+pub struct Keys {
+ pub up: bool,
+ pub down: bool,
+ pub left: bool,
+ pub right: bool,
+ pub a: bool,
+ pub b: bool,
+ pub l: bool,
+ pub r: bool,
+ pub start: bool,
+ pub select: bool,
+}
+
+impl Keys {
+ pub fn new() -> Self {
+ Self {
+ up: false,
+ down: false,
+ left: false,
+ right: false,
+ a: false,
+ b: false,
+ l: false,
+ r: false,
+ start: false,
+ select: false,
+ }
+ }
+}
+
+pub struct State {
+ pub acc: f64,
+ pub last: f64,
+ pub tick: u64,
+
+ pub keys: Keys,
+
+ pub screen: framebuffer::Framebuffer,
+ pub render_framebuffer: framebuffer::Framebuffer,
+ pub shader_upscale: shader::Shader,
+ pub audio: Option<audio::Assets>,
+
+ pub projection: glam::Mat4,
+ pub camera: glam::Mat4,
+ pub lighting: (glam::Vec3, glam::Vec3),
+
+ pub log: Vec<(u64, String)>,
+}
+
+pub fn now(ctx: &context::Context) -> f64 {
+ ctx.performance.now() / 1000.0
+}
+
+impl State {
+ pub fn new(ctx: &context::Context) -> Self {
+ let screen = framebuffer::Framebuffer::screen(ctx);
+ let render_framebuffer = framebuffer::Framebuffer::new(
+ ctx,
+ &glam::Vec2::new(context::RENDER_WIDTH, context::RENDER_HEIGHT),
+ &glam::Vec2::new(0.0, 0.0),
+ );
+ let shader_upscale = shader::Shader::new_nolib(
+ ctx,
+ include_str!("assets/shaders/scale/vert.glsl"),
+ include_str!("assets/shaders/scale/frag.glsl"),
+ );
+
+ Self {
+ acc: 0.0,
+ last: now(ctx),
+ tick: 0,
+ keys: Keys::new(),
+ screen,
+ render_framebuffer,
+ shader_upscale,
+ audio: None,
+
+ projection: glam::Mat4::perspective_lh(
+ std::f32::consts::PI / 4.0,
+ context::RENDER_WIDTH / context::RENDER_HEIGHT,
+ 0.1,
+ 400.0,
+ ),
+ camera: glam::Mat4::IDENTITY,
+ lighting: (
+ glam::Vec3::new(1.0, 0.0, 0.0),
+ glam::Vec3::new(1.0, -1.0, 1.0),
+ ),
+
+ log: Vec::new(),
+ }
+ }
+
+ pub fn write_log(&mut self, e: &str) {
+ self.log.push((self.tick, e.to_owned()));
+ }
+
+ pub fn handle_resize(&mut self, ctx: &context::Context) {
+ self.screen = framebuffer::Framebuffer::screen(ctx);
+ }
+
+ pub fn move_camera(
+ &mut self,
+ _ctx: &context::Context,
+ camera: &glam::Mat4,
+ ) {
+ self.camera = camera.clone();
+ }
+
+ pub fn set_lighting(
+ &mut self,
+ _ctx: &context::Context,
+ color: &glam::Vec3,
+ dir: &glam::Vec3,
+ ) {
+ self.lighting = (color.clone(), dir.clone());
+ }
+
+ pub fn view(&self) -> glam::Mat4 {
+ self.camera.clone()
+ }
+
+ pub fn bind_3d(&mut self, ctx: &context::Context, shader: &shader::Shader) {
+ shader.bind(ctx);
+ shader.set_mat4(&ctx, "projection", &self.projection);
+ shader.set_mat4(ctx, "view", &self.view());
+ shader.set_vec3(
+ ctx, "light_ambient_color",
+ &glam::Vec3::new(1.0, 1.0, 1.0));
+ shader.set_vec3(
+ ctx, "light_dir_color",
+ &self.lighting.0,
+ );
+ shader.set_vec3(
+ ctx, "light_dir",
+ &self.lighting.1,
+ );
+ }
+
+ pub fn bind_2d(&mut self, ctx: &context::Context, shader: &shader::Shader) {
+ shader.bind(ctx);
+ shader.set_mat4(&ctx, "projection", &glam::Mat4::IDENTITY);
+ shader.set_mat4(
+ ctx, "view",
+ &glam::Mat4::from_scale(
+ glam::Vec3::new(
+ 2.0 / context::RENDER_WIDTH,
+ 2.0 / context::RENDER_HEIGHT,
+ 1.0,
+ ),
+ ),
+ );
+ }
+
+ pub fn mouse_pressed<G>(
+ &mut self,
+ ctx: &context::Context,
+ _button: winit::event::MouseButton,
+ game: &mut G
+ ) where G: Game {
+ log::info!("click");
+ if self.audio.is_none() {
+ self.audio = Some(audio::Assets::new(|actx| {
+ game.initialize_audio(ctx, &self, actx)
+ }));
+ game.finish_title();
+ }
+ }
+
+ pub fn mouse_released(
+ &mut self,
+ _ctx: &context::Context,
+ _button: winit::event::MouseButton,
+ ) {
+ }
+
+ pub fn key_pressed(
+ &mut self,
+ _ctx: &context::Context,
+ key: winit::keyboard::KeyCode,
+ ) {
+ match key {
+ winit::keyboard::KeyCode::KeyW => self.keys.up = true,
+ winit::keyboard::KeyCode::KeyS => self.keys.down = true,
+ winit::keyboard::KeyCode::KeyA => self.keys.left = true,
+ winit::keyboard::KeyCode::KeyD => self.keys.right = true,
+ winit::keyboard::KeyCode::Digit1 => self.keys.a = true,
+ winit::keyboard::KeyCode::Digit2 => self.keys.b = true,
+ winit::keyboard::KeyCode::KeyQ => self.keys.l = true,
+ winit::keyboard::KeyCode::KeyE => self.keys.r = true,
+ winit::keyboard::KeyCode::Tab => self.keys.start = true,
+ winit::keyboard::KeyCode::Space => self.keys.select = true,
+ _ => {},
+ }
+ }
+
+ pub fn key_released(
+ &mut self,
+ _ctx: &context::Context,
+ key: winit::keyboard::KeyCode,
+ ) {
+ match key {
+ winit::keyboard::KeyCode::KeyW => self.keys.up = false,
+ winit::keyboard::KeyCode::KeyS => self.keys.down = false,
+ winit::keyboard::KeyCode::KeyA => self.keys.left = false,
+ winit::keyboard::KeyCode::KeyD => self.keys.right = false,
+ winit::keyboard::KeyCode::Digit1 => self.keys.a = false,
+ winit::keyboard::KeyCode::Digit2 => self.keys.b = false,
+ winit::keyboard::KeyCode::KeyQ => self.keys.l = false,
+ winit::keyboard::KeyCode::KeyE => self.keys.r = false,
+ winit::keyboard::KeyCode::Tab => self.keys.start = false,
+ winit::keyboard::KeyCode::Space => self.keys.select = false,
+ _ => {},
+ }
+ }
+
+ pub fn run_update<G>(&mut self, ctx: &context::Context, game: &mut G) where G: Game {
+ let now = now(ctx);
+ self.acc += now - self.last;
+ self.last = now;
+
+ // update, if enough time has accumulated since last update
+ if self.acc >= DELTA_TIME {
+ self.acc -= DELTA_TIME;
+ self.tick += 1;
+ game.update(ctx, self);
+
+ // if a lot of time has elapsed (e.g. if window is unfocused and not
+ // running update loop), prevent "death spiral"
+ if self.acc >= DELTA_TIME { self.acc = 0.0 }
+ }
+ }
+
+ pub fn run_render<G>(&mut self, ctx: &context::Context, game: &mut G) where G: Game {
+ self.render_framebuffer.bind(&ctx);
+ ctx.clear_color(glam::Vec4::new(0.1, 0.1, 0.1, 1.0));
+ ctx.clear();
+
+ game.render(ctx, self);
+
+ self.screen.bind(&ctx);
+ ctx.clear_color(glam::Vec4::new(0.0, 0.0, 0.0, 1.0));
+ ctx.clear();
+ self.shader_upscale.bind(&ctx);
+ self.render_framebuffer.bind_texture(&ctx);
+ ctx.render_no_geometry();
+ }
+}