diff options
| author | LLLL Colonq <llll@colonq> | 2026-05-06 14:54:58 -0400 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2026-05-06 14:54:58 -0400 |
| commit | cdf8fbe731c41071025dd17080474c935cee75ef (patch) | |
| tree | 068270936c354a0451ab84d7a05c5b3f6a3333be /crates | |
| parent | 27844e551d8b91c0b953e9f534440ab937310f37 (diff) | |
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/teleia/src/assets/fonts/small.png | bin | 0 -> 904 bytes | |||
| -rw-r--r-- | crates/teleia/src/assets/shaders/uber/frag.glsl | 4 | ||||
| -rw-r--r-- | crates/teleia/src/assets/shaders/uber/vert.glsl | 3 | ||||
| -rw-r--r-- | crates/teleia/src/context.rs | 14 | ||||
| -rw-r--r-- | crates/teleia/src/font.rs | 61 | ||||
| -rw-r--r-- | crates/teleia/src/lib.rs | 12 | ||||
| -rw-r--r-- | crates/teleia/src/renderer.rs | 53 | ||||
| -rw-r--r-- | crates/teleia/src/state.rs | 60 | ||||
| -rw-r--r-- | crates/teleia/src/ui.rs | 12 |
9 files changed, 121 insertions, 98 deletions
diff --git a/crates/teleia/src/assets/fonts/small.png b/crates/teleia/src/assets/fonts/small.png Binary files differnew file mode 100644 index 0000000..1d020f7 --- /dev/null +++ b/crates/teleia/src/assets/fonts/small.png diff --git a/crates/teleia/src/assets/shaders/uber/frag.glsl b/crates/teleia/src/assets/shaders/uber/frag.glsl index ebe6438..6778156 100644 --- a/crates/teleia/src/assets/shaders/uber/frag.glsl +++ b/crates/teleia/src/assets/shaders/uber/frag.glsl @@ -23,6 +23,7 @@ uniform float effect_hueshift; uniform float effect_huescale; in vec2 vertex_texcoord; +in vec3 vertex_color; in vec3 vertex_normal; in vec3 vertex_fragpos; in vec4 vertex_fragpos_shadow_dir; @@ -186,4 +187,7 @@ void main() { if (frag_color.a == 0.0) { discard; } + if (flag(VERTEX_COLOR)) { + frag_color.rgb = vertex_color; + } } diff --git a/crates/teleia/src/assets/shaders/uber/vert.glsl b/crates/teleia/src/assets/shaders/uber/vert.glsl index 6de3e7e..8b4ef21 100644 --- a/crates/teleia/src/assets/shaders/uber/vert.glsl +++ b/crates/teleia/src/assets/shaders/uber/vert.glsl @@ -3,6 +3,7 @@ uniform highp int flags; in vec3 vertex; in vec3 normal; in vec2 texcoord; +in vec3 color; uniform mat4 view; uniform mat4 position; @@ -14,6 +15,7 @@ uniform vec3 offset; uniform float yskew; out vec2 vertex_texcoord; +out vec3 vertex_color; out vec3 vertex_normal; out vec3 vertex_fragpos; out vec4 vertex_fragpos_shadow_dir; @@ -25,6 +27,7 @@ bool flag(int mask) { void main() { vertex_texcoord = texcoord; + vertex_color = color; vertex_normal = (normal_matrix * vec4(normal, 1.0)).xyz; vec3 pos = (position * vec4(vertex, 1.0)).xyz; vertex_fragpos = pos; diff --git a/crates/teleia/src/context.rs b/crates/teleia/src/context.rs index 211e23b..d8c6aea 100644 --- a/crates/teleia/src/context.rs +++ b/crates/teleia/src/context.rs @@ -201,6 +201,13 @@ impl Context { } } + pub fn write_and_use_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::EQUAL, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::REPLACE); + } + } + pub fn use_inverse_stencil(&self) { unsafe { self.gl.stencil_func(glow::NOTEQUAL, 1, 0xff); @@ -208,6 +215,13 @@ impl Context { } } + pub fn write_and_use_inverse_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::NOTEQUAL, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::REPLACE); + } + } + pub fn end_stencil(&self) { unsafe { self.gl.stencil_func(glow::ALWAYS, 1, 0xff); diff --git a/crates/teleia/src/font.rs b/crates/teleia/src/font.rs index 0587556..2fe7423 100644 --- a/crates/teleia/src/font.rs +++ b/crates/teleia/src/font.rs @@ -1,16 +1,16 @@ -use crate::{context, mesh, shader, state, texture}; +use crate::{context, mesh, state, texture}; use glow::HasContext; pub struct BitmapParams<'color> { pub color: &'color [glam::Vec3], pub scale: glam::Vec2, + pub offset: glam::Vec2, } pub struct Bitmap { pub char_width: i32, pub char_height: i32, pub font_width: i32, pub font_height: i32, - pub shader: shader::Shader, pub font: texture::Texture, pub vao: glow::VertexArray, pub vertex_buf: glow::Buffer, @@ -26,11 +26,6 @@ impl Bitmap { font_width: i32, font_height: i32, data: &[u8], ) -> Self { - let shader = shader::Shader::new_nolib( - &ctx, - include_str!("assets/shaders/bitmap/vert.glsl"), - include_str!("assets/shaders/bitmap/frag.glsl"), - ); let font = texture::Texture::new(ctx, data); unsafe { let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao"); @@ -52,7 +47,6 @@ impl Bitmap { Self { char_width, char_height, font_width, font_height, - shader, font, vao, vertex_buf, @@ -67,20 +61,23 @@ impl Bitmap { Self::from_image(ctx, 7, 9, 112, 54, include_bytes!("assets/fonts/default.png")) } + pub fn small(ctx: &context::Context) -> Self { + Self::from_image(ctx, 6, 7, 96, 42, include_bytes!("assets/fonts/small.png")) + } + pub fn render_text_parameterized(&self, ctx: &context::Context, st: &state::State, - pos: &glam::Vec2, text: &str, + text: &str, params: BitmapParams, ) { - let fpos = pos.floor(); - let mut cur = glam::Vec2::new(0.0, 0.0); + let mut cur = params.offset; let mut vertices = Vec::new(); let mut texcoords = Vec::new(); let mut colors = Vec::new(); let mut indices = Vec::new(); let cwidth = self.char_width as f32 / self.font_width as f32; let cheight = self.char_height as f32 / self.font_height as f32; - let sdims = glam::Vec2::new(self.char_width as f32, self.char_height as f32) * params.scale; + let sdims = glam::Vec2::new(2.0, 2.0) * params.scale; let row_len = self.font_width as u32 / self.char_width as u32; for (i, c) in text.chars().enumerate() { if c == '\n' { @@ -112,22 +109,7 @@ impl Bitmap { } } let index_bytes: Vec<u8> = indices.iter().flat_map(|x| x.to_ne_bytes()).collect(); - self.shader.bind(ctx); self.font.bind(ctx); - let scale = glam::Vec2::new(2.0 / st.render_dims.x, 2.0 / st.render_dims.y); - let offset = glam::Vec2::new( - -st.render_dims.x / 2.0, - st.render_dims.y / 2.0 - sdims.y, - ); - let npos = (glam::Vec2::new(fpos.x, -fpos.y) + offset) * scale; - self.shader.set_mat4( - ctx, "transform", - &glam::Mat4::from_scale_rotation_translation( - glam::Vec3::new(scale.x, scale.y, 1.0), - glam::Quat::IDENTITY, - glam::Vec3::new(npos.x, npos.y, 0.0), - ), - ); unsafe { ctx.gl.bind_vertex_array(Some(self.vao)); ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buf)); @@ -167,14 +149,25 @@ impl Bitmap { } } - pub fn render_text_helper(&self, ctx: &context::Context, st: &state::State, pos: &glam::Vec2, text: &str, color: &[glam::Vec3]) { - self.render_text_parameterized(ctx, st, pos, text, BitmapParams { - color, - scale: glam::Vec2::ONE, - }) + pub fn render_text_helper(&self, + ctx: &context::Context, st: &state::State, + text: &str, color: &[glam::Vec3] + ) { + self.render_text_parameterized( + ctx, st, + text, + BitmapParams { + color, + scale: glam::Vec2::ONE, + offset: glam::Vec2::ZERO, + } + ) } - pub fn render_text(&self, ctx: &context::Context, st: &state::State, pos: &glam::Vec2, text: &str) { - self.render_text_helper(ctx, st, pos, text, &[]); + pub fn render_text(&self, + ctx: &context::Context, st: &state::State, + text: &str + ) { + self.render_text_helper(ctx, st, text, &[]); } } diff --git a/crates/teleia/src/lib.rs b/crates/teleia/src/lib.rs index 21f3b24..9a55d10 100644 --- a/crates/teleia/src/lib.rs +++ b/crates/teleia/src/lib.rs @@ -168,13 +168,13 @@ where st.mouse_pressed(&ctx, game)?; }, glfw::WindowEvent::MouseButton(_, glfw::Action::Release, _) => { - st.mouse_released(&ctx) + st.mouse_released(&ctx, game)?; }, glfw::WindowEvent::Key(key, _, glfw::Action::Press, _) => { - st.key_pressed(&ctx, state::Keycode::new(key)) + st.key_pressed(&ctx, game, state::Keycode::new(key))?; }, glfw::WindowEvent::Key(key, _, glfw::Action::Release, _) => { - st.key_released(&ctx, state::Keycode::new(key)) + st.key_released(&ctx, game, state::Keycode::new(key))?; }, _ => {}, } @@ -283,7 +283,7 @@ where st.mouse_pressed(&ctx, game)?; }, winit::event::ElementState::Released => { - st.mouse_released(&ctx) + st.mouse_released(&ctx)?; }, } winit::event::WindowEvent::KeyboardInput { @@ -296,10 +296,10 @@ where .. } => match state { winit::event::ElementState::Pressed => { - st.key_pressed(&ctx, state::Keycode { kc: *key }) + st.key_pressed(&ctx, state::Keycode { kc: *key })?; }, winit::event::ElementState::Released => { - st.key_released(&ctx, state::Keycode { kc: *key }) + st.key_released(&ctx, state::Keycode { kc: *key })?; }, } _ => {}, diff --git a/crates/teleia/src/renderer.rs b/crates/teleia/src/renderer.rs index 94c78d8..19dd8a0 100644 --- a/crates/teleia/src/renderer.rs +++ b/crates/teleia/src/renderer.rs @@ -5,15 +5,16 @@ use bitflags::bitflags; bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct UberFlags: u32 { - const TEXTURE_COLOR = 0b000000001; - const TEXTURE_NORMAL = 0b000000010; - const FLIP_TEXTURE = 0b000000100; - const LIGHT_AMBIENT = 0b000001000; - const LIGHT_DIR = 0b000010000; - const LIGHT_POINT = 0b000100000; - const SPRITE = 0b001000000; - const EFFECTS = 0b010000000; - const YSKEW = 0b100000000; + const TEXTURE_COLOR = 0b0000000001; + const TEXTURE_NORMAL = 0b0000000010; + const FLIP_TEXTURE = 0b0000000100; + const LIGHT_AMBIENT = 0b0000001000; + const LIGHT_DIR = 0b0000010000; + const LIGHT_POINT = 0b0000100000; + const SPRITE = 0b0001000000; + const EFFECTS = 0b0010000000; + const YSKEW = 0b0100000000; + const VERTEX_COLOR = 0b1000000000; } } impl UberFlags { @@ -91,6 +92,9 @@ impl<A: Assets> Renderer<A> { } pub fn font_char_width(&self, st: &state::State) -> f32 { st.font_default.char_width as f32 } pub fn font_char_height(&self, st: &state::State) -> f32 { st.font_default.char_height as f32 } + pub fn unbind_texture(&mut self, _ctx: &context::Context, _st: &mut state::State) { + self.texture = BoundTexture::None; + } pub fn bind_texture(&mut self, ctx: &context::Context, _st: &mut state::State, texture: A::Texture) { if self.texture != BoundTexture::Texture(texture) { self.assets.texture(texture).bind(ctx); @@ -272,9 +276,13 @@ impl<A: Assets> Renderer<A> { pos: glam::Vec2, s: &str, ) { - // drawing text might bind the shader and texture - self.shader = BoundShader::None; self.texture = BoundTexture::None; - st.font_default.render_text(ctx, st, &pos, s); + // drawing text might bind the texture + self.texture = BoundTexture::None; + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE); + let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32); + let fpos = (pos + glam::Vec2::new(-dims.x / 2.0, st.font_default.char_height as f32 / 2.0)); + self.set_position_2d(ctx, st, fpos, dims); + st.font_default.render_text(ctx, st, s); } /// Common case: text in the default font, with a color (units are pixels, pos is top left) @@ -284,9 +292,12 @@ impl<A: Assets> Renderer<A> { col: glam::Vec3, s: &str, ) { - // drawing text might bind the shader and texture - self.shader = BoundShader::None; self.texture = BoundTexture::None; - st.font_default.render_text_helper(ctx, st, &pos, s, &[col]); + self.texture = BoundTexture::None; + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE); + let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32); + let fpos = (pos + glam::Vec2::new(-dims.x / 2.0, st.font_default.char_height as f32 / 2.0)); + self.set_position_2d(ctx, st, fpos, dims); + st.font_default.render_text_helper(ctx, st, s, &[col]); } /// Common case: text in the default font (units are pixels, pos is center) @@ -295,13 +306,13 @@ impl<A: Assets> Renderer<A> { pos: glam::Vec2, s: &str, ) { - // drawing text might bind the shader and texture - self.shader = BoundShader::None; self.texture = BoundTexture::None; + self.texture = BoundTexture::None; + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE); let width = s.len() as f32 * st.font_default.char_width as f32; let height = st.font_default.char_height as f32; - st.font_default.render_text(ctx, st, - &(pos - glam::Vec2::new((width / 2.0).round(), (height / 2.0).round())), - s - ); + let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32); + let fpos = (pos + glam::Vec2::new(-dims.x / 2.0 - (width / 2.0).round(), st.font_default.char_height as f32 / 2.0)); + self.set_position_2d(ctx, st, fpos, dims); + st.font_default.render_text(ctx, st, s); } } diff --git a/crates/teleia/src/state.rs b/crates/teleia/src/state.rs index b7b8899..f5b6313 100644 --- a/crates/teleia/src/state.rs +++ b/crates/teleia/src/state.rs @@ -23,6 +23,7 @@ pub trait Game { HashMap::new() } fn finish_title(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { Ok(()) } + fn keybindings_were_reset(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { Ok(()) } fn mouse_move(&mut self, ctx: &context::Context, st: &mut State, x: i32, y: i32) -> utils::Erm<()> { Ok(()) } fn mouse_press(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { Ok(()) } fn update(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { Ok(()) } @@ -72,19 +73,19 @@ impl Keys { pub fn start(&self) -> bool { self.pressed[Key::Start] } pub fn select(&self) -> bool { self.pressed[Key::Select] } pub fn debug(&self) -> bool { self.pressed[Key::Debug] } - pub fn new_up(&self) -> bool { self.new[Key::Up] } - pub fn new_down(&self) -> bool { self.new[Key::Down] } - pub fn new_left(&self) -> bool { self.new[Key::Left] } - pub fn new_right(&self) -> bool { self.new[Key::Right] } - pub fn new_a(&self) -> bool { self.new[Key::A] } - pub fn new_b(&self) -> bool { self.new[Key::B] } - pub fn new_x(&self) -> bool { self.new[Key::X] } - pub fn new_y(&self) -> bool { self.new[Key::Y] } - pub fn new_l(&self) -> bool { self.new[Key::L] } - pub fn new_r(&self) -> bool { self.new[Key::R] } - pub fn new_start(&self) -> bool { self.new[Key::Start] } - pub fn new_select(&self) -> bool { self.new[Key::Select] } - pub fn new_debug(&self) -> bool { self.new[Key::Debug] } + pub fn new_up(&mut self) -> bool { let ret = self.new[Key::Up]; self.new[Key::Up] = false; ret } + pub fn new_down(&mut self) -> bool { let ret = self.new[Key::Down]; self.new[Key::Down] = false; ret } + pub fn new_left(&mut self) -> bool { let ret = self.new[Key::Left]; self.new[Key::Left] = false; ret } + pub fn new_right(&mut self) -> bool { let ret = self.new[Key::Right]; self.new[Key::Right] = false; ret } + pub fn new_a(&mut self) -> bool { let ret = self.new[Key::A]; self.new[Key::A] = false; ret } + pub fn new_b(&mut self) -> bool { let ret = self.new[Key::B]; self.new[Key::B] = false; ret } + pub fn new_x(&mut self) -> bool { let ret = self.new[Key::X]; self.new[Key::X] = false; ret } + pub fn new_y(&mut self) -> bool { let ret = self.new[Key::Y]; self.new[Key::Y] = false; ret } + pub fn new_l(&mut self) -> bool { let ret = self.new[Key::L]; self.new[Key::L] = false; ret } + pub fn new_r(&mut self) -> bool { let ret = self.new[Key::R]; self.new[Key::R] = false; ret } + pub fn new_start(&mut self) -> bool { let ret = self.new[Key::Start]; self.new[Key::Start] = false; ret } + pub fn new_select(&mut self) -> bool { let ret = self.new[Key::Select]; self.new[Key::Select] = false; ret } + pub fn new_debug(&mut self) -> bool { let ret = self.new[Key::Debug]; self.new[Key::Debug] = false; ret } } pub struct PointLight { @@ -176,6 +177,7 @@ pub struct State { pub shader_upscale: shader::Shader, pub mesh_square: mesh::Mesh, pub font_default: font::Bitmap, + pub font_small: font::Bitmap, pub audio: Option<audio::Assets>, pub projection: glam::Mat4, @@ -183,8 +185,6 @@ pub struct State { pub camera: (glam::Vec3, glam::Vec3, glam::Vec3), pub lighting: (glam::Vec3, glam::Vec3, glam::Vec3), pub point_lights: Vec<PointLight>, - - pub log: Vec<(u64, String)>, } #[cfg(target_arch = "wasm32")] @@ -274,6 +274,7 @@ impl State { shader_upscale, mesh_square, font_default: font::Bitmap::default(ctx), + font_small: font::Bitmap::small(ctx), audio: None, projection: glam::Mat4::perspective_lh( @@ -300,16 +301,9 @@ impl State { // waker_ctx, // http_client: reqwest::Client::new(), // request: None, - - log: Vec::new(), } } - pub fn write_log(&mut self, e: &str) { - log::info!("log: {}", e.to_owned()); - self.log.push((self.tick, e.to_owned())); - } - pub fn handle_resize(&mut self, ctx: &context::Context) { self.screen = framebuffer::Framebuffer::screen(ctx); } @@ -484,17 +478,20 @@ impl State { Ok(()) } - pub fn mouse_released( + pub fn mouse_released<G>( &mut self, _ctx: &context::Context, - ) { + _game: &mut G + ) -> utils::Erm<()> where G: Game { + Ok(()) } - pub fn key_pressed( + pub fn key_pressed<G>( &mut self, - _ctx: &context::Context, + ctx: &context::Context, + game: &mut G, key: Keycode, - ) { + ) -> utils::Erm<()> where G: Game { #[cfg(target_arch = "wasm32")] let rebind = key.kc == winit::keyboard::KeyCode::F12; #[cfg(not(target_arch = "wasm32"))] @@ -502,7 +499,7 @@ impl State { if rebind { self.keybindings = default_keybindings(); self.rebinding = None; - self.write_log("Reset keybindings!"); + game.keybindings_were_reset(ctx, self)?; } else if let Some(k) = self.rebinding { self.keybindings.insert(key, k); self.rebinding = None; @@ -510,16 +507,19 @@ impl State { self.keys.pressed[*k] = true; self.keys.new[*k] = true; } + Ok(()) } - pub fn key_released( + pub fn key_released<G>( &mut self, _ctx: &context::Context, + _game: &mut G, key: Keycode, - ) { + ) -> utils::Erm<()> where G: Game { if let Some(k) = self.keybindings.get_by_left(&key) { self.keys.pressed[*k] = false; } + Ok(()) } /// Return the first keybinding for the given virtual key diff --git a/crates/teleia/src/ui.rs b/crates/teleia/src/ui.rs index 056f78a..0f0e52a 100644 --- a/crates/teleia/src/ui.rs +++ b/crates/teleia/src/ui.rs @@ -130,13 +130,11 @@ impl Cursor { /// Read keypresses to update this cursor (assuming that the left/right keys decrement/increment) /// Returns true if an update was performed (e.g. to determine whether to play a sound). - pub fn update_horizontal(&mut self, st: &state::State) -> bool { + pub fn update_horizontal(&mut self, st: &mut state::State) -> bool { if st.keys.new_left() { - self.decrement_unlocked(st.tick); - true + self.decrement_unlocked(st.tick) } else if st.keys.new_right() { - self.increment_unlocked(st.tick); - true + self.increment_unlocked(st.tick) } else if st.keys.left() { self.decrement(st.tick) } else if st.keys.right() { @@ -144,7 +142,7 @@ impl Cursor { } else { false } } - pub fn update_vertical(&mut self, st: &state::State) -> bool { + pub fn update_vertical(&mut self, st: &mut state::State) -> bool { if st.keys.new_up() { self.decrement_unlocked(st.tick) } else if st.keys.new_down() { @@ -156,7 +154,7 @@ impl Cursor { } else { false } } - pub fn update_lr(&mut self, st: &state::State) -> bool { + pub fn update_lr(&mut self, st: &mut state::State) -> bool { if st.keys.new_l() { self.decrement_unlocked(st.tick) } else if st.keys.new_r() { |
