diff options
| author | LLLL Colonq <llll@colonq> | 2025-11-17 20:38:45 -0500 |
|---|---|---|
| committer | LLLL Colonq <llll@colonq> | 2025-11-17 20:38:45 -0500 |
| commit | 3c3cb9cf6f571fb9a525da73116bac7bd39b70df (patch) | |
| tree | 992a516f0a9d7cf5c7cf0d278addbd5947ed07d0 /crates | |
| parent | 2986b9f40734fac6aa40b0e6c70d2d4ed59686f5 (diff) | |
Update
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/teleia/Cargo.toml | 6 | ||||
| -rw-r--r-- | crates/teleia/src/audio.rs | 13 | ||||
| -rw-r--r-- | crates/teleia/src/font.rs | 200 | ||||
| -rw-r--r-- | crates/teleia/src/lib.rs | 27 | ||||
| -rw-r--r-- | crates/teleia/src/state.rs | 94 | ||||
| -rw-r--r-- | crates/teleia/src/utils.rs | 11 |
6 files changed, 81 insertions, 270 deletions
diff --git a/crates/teleia/Cargo.toml b/crates/teleia/Cargo.toml index 6de4df0..bc17d9c 100644 --- a/crates/teleia/Cargo.toml +++ b/crates/teleia/Cargo.toml @@ -13,7 +13,7 @@ glow = {version = "=0.13.1", features = []} # rendering tobj = "*" # loader for .obj meshes loader gltf = {git = "https://github.com/lcolonq/gltf", features = ["extras", "import", "names", "utils"]} # loader for .gltf scenes image = { version = "0.25", default-features = false, features = ["jpeg", "png"] } # texture loader -fontdue = "*" # truetype fonts +cosmic-text = "*" # advanced text rendering glam = "0.29" # linear algebra log = "*" # logging rand = {version = "=0.8.5", features = ["small_rng"]} # rng @@ -22,10 +22,10 @@ serde_json = "*" # serialize JSON bincode = {version = "*", features = ["serde"]} # binary serialization enum-map = "*" # fast maps with enums as keys bimap = "*" # bijective maps -reqwest = "*" # http requests +# reqwest = "*" # http requests bytes = "*" # bytes for http responses bitflags = "*" # bitwise flags -color-eyre = { version = "*", default-features = false } # error reporting and formatting +simple-eyre = { version = "*", default-features = false } # error reporting and formatting rapier3d = "*" # rigid-body physics parry3d = "*" # collision detection nalgebra = {version = "0.33.2", features = ["convert-glam029"]} # linear algebra library for rapier3d diff --git a/crates/teleia/src/audio.rs b/crates/teleia/src/audio.rs index 2b4226c..44965bb 100644 --- a/crates/teleia/src/audio.rs +++ b/crates/teleia/src/audio.rs @@ -207,3 +207,16 @@ impl Assets { } } } + +pub trait AudioPlayback { + fn play_sfx(&mut self, name: &str); + fn play_music(&mut self, name: &str, start: Option<f64>, end: Option<f64>); +} +impl AudioPlayback for Option<Assets> { + fn play_sfx(&mut self, name: &str) { + if let Some(a) = self { a.play_sfx(name); } + } + fn play_music(&mut self, name: &str, start: Option<f64>, end: Option<f64>) { + if let Some(a) = self { a.play_music(name, start, end); } + } +} diff --git a/crates/teleia/src/font.rs b/crates/teleia/src/font.rs index bba7de2..04527f2 100644 --- a/crates/teleia/src/font.rs +++ b/crates/teleia/src/font.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use crate::{context, mesh, shader, state, texture}; use glow::HasContext; @@ -163,201 +161,3 @@ impl Bitmap { self.render_text_helper(ctx, st, pos, text, &[]); } } - -pub struct AtlasInfo { - pub pos: usize, -} - -pub struct TrueType { - pub shader: shader::Shader, - pub font: fontdue::Font, - pub atlas: texture::Texture, - pub atlaswidth: usize, - pub cellwidth: usize, - pub cellheight: usize, - pub info: HashMap<char, AtlasInfo>, - pub vao: glow::VertexArray, - pub vertex_buf: glow::Buffer, - pub texcoords_buf: glow::Buffer, - pub colors_buf: glow::Buffer, - pub index_buf: glow::Buffer, -} - -impl TrueType { - pub fn new(ctx: &context::Context, size: f32, data: &[u8]) -> Self { - let shader = shader::Shader::new_nolib( - &ctx, - include_str!("assets/shaders/truetype/vert.glsl"), - include_str!("assets/shaders/truetype/frag.glsl"), - ); - let font = fontdue::Font::from_bytes(data, fontdue::FontSettings::default()) - .expect("failed to load font"); - let mut chardata = HashMap::new(); - for ci in 0..128 { - if let Some(c) = char::from_u32(ci) { - if !c.is_ascii_graphic() { continue; } - let res = font.rasterize(c, size); - chardata.insert(c, res); - } - } - let mut cellwidth = 0; - let mut cellbase = 0; - let mut cellextra = 0; - for (_, (m, _)) in &chardata { - if m.width > cellwidth { cellwidth = m.width } - if m.height > cellbase { cellbase = m.height } - let extra = (-m.ymin.min(0)) as usize; - if extra > cellextra { cellextra = extra } - } - let mut cellheight = cellbase + cellextra; - cellwidth = cellwidth.next_power_of_two(); - cellheight = cellheight.next_power_of_two(); - let atlaswidth = (chardata.len() * cellwidth).next_power_of_two(); - let mut info = HashMap::new(); - let mut atlas_bmp: Vec<u8> = vec![0; atlaswidth * cellheight]; - for (i, (c, (m, bmp))) in chardata.iter().enumerate() { - let by = ((cellbase as i32) - (m.height as i32) - m.ymin) as usize; - let bx = cellwidth * i; - info.insert(*c, AtlasInfo { - pos: cellwidth * i, - }); - for x in 0..m.width { - for y in 0..m.height { - atlas_bmp[bx + x + (by + y) * atlaswidth] = bmp[x + y * m.width]; - } - } - } - let atlas = texture::Texture::new_empty(ctx); - unsafe { - ctx.gl.bind_texture(glow::TEXTURE_2D, Some(atlas.tex)); - ctx.gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); - ctx.gl.tex_image_2d( - glow::TEXTURE_2D, - 0, - glow::R8 as i32, - atlaswidth as i32, - cellheight as i32, - 0, - glow::RED, - glow::UNSIGNED_BYTE, - Some(&atlas_bmp), - ); - ctx.gl.generate_mipmap(glow::TEXTURE_2D); - let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao"); - ctx.gl.bind_vertex_array(Some(vao)); - let vertex_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); - ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buf)); - ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_VERTEX, 2, glow::FLOAT, false, 0, 0); - ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_VERTEX); - let texcoords_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); - ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(texcoords_buf)); - ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_TEXCOORD, 2, glow::FLOAT, false, 0, 0); - ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_TEXCOORD); - let colors_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); - ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(colors_buf)); - ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_COLOR, 3, glow::FLOAT, false, 0, 0); - ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_COLOR); - let index_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); - ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buf)); - Self { - shader, font, atlas, atlaswidth, cellwidth, cellheight, info, - vao, vertex_buf, texcoords_buf, colors_buf, index_buf, - } - } - } - - pub fn render_text_helper(&self, ctx: &context::Context, st: &state::State, pos: &glam::Vec2, spacing: &glam::Vec2, text: &str, color: &[glam::Vec3]) { - let mut cur = glam::Vec2::new(0.0, 0.0); - let mut vertices = Vec::new(); - let mut texcoords = Vec::new(); - let mut colors = Vec::new(); - let mut indices = Vec::new(); - let cellwidth = self.cellwidth as f32; - let cellheight = self.cellheight as f32; - let cwidth = cellwidth / self.atlaswidth as f32; - let cheight = 1.0; - for (i, c) in text.chars().enumerate() { - if c == '\n' { - cur.x = 0.0; - cur.y -= spacing.y; - } else { - let idx = vertices.len() as u32; - if let Some(off) = self.info.get(&c) { - vertices.push(cur); - vertices.push(cur + glam::Vec2::new(cellwidth, 0.0)); - vertices.push(cur + glam::Vec2::new(cellwidth, cellheight)); - vertices.push(cur + glam::Vec2::new(0.0, cellheight)); - let tcbase = glam::Vec2::new(off.pos as f32 / self.atlaswidth as f32, 0.0); - texcoords.push(tcbase + glam::Vec2::new(0.0, cheight)); - texcoords.push(tcbase + glam::Vec2::new(cwidth, cheight)); - texcoords.push(tcbase + glam::Vec2::new(cwidth, 0.0)); - texcoords.push(tcbase); - let c = if let Some(c) = color.get(i) { - *c - } else { - glam::Vec3::new(1.0, 1.0, 1.0) - }; - colors.push(c); colors.push(c); colors.push(c); colors.push(c); - indices.push(idx + 0); indices.push(idx + 1); indices.push(idx + 2); - indices.push(idx + 0); indices.push(idx + 3); indices.push(idx + 2); - } - cur.x += spacing.x; - } - } - let index_bytes: Vec<u8> = indices.iter().flat_map(|x| x.to_ne_bytes()).collect(); - 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 - cellheight as f32, - ); - let npos = (glam::Vec2::new(pos.x, -pos.y) + offset) * scale; - self.shader.bind(ctx); - 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.active_texture(glow::TEXTURE0); - ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.atlas.tex)); - ctx.gl.bind_vertex_array(Some(self.vao)); - ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buf)); - ctx.gl.buffer_data_u8_slice( - glow::ARRAY_BUFFER, - std::slice::from_raw_parts( - vertices.as_ptr() as _, - vertices.len() * std::mem::size_of::<f32>() * 2, - ), - glow::STATIC_DRAW, - ); - ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.texcoords_buf)); - ctx.gl.buffer_data_u8_slice( - glow::ARRAY_BUFFER, - std::slice::from_raw_parts( - texcoords.as_ptr() as _, - texcoords.len() * std::mem::size_of::<f32>() * 2, - ), - glow::STATIC_DRAW, - ); - ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.colors_buf)); - ctx.gl.buffer_data_u8_slice( - glow::ARRAY_BUFFER, - std::slice::from_raw_parts( - colors.as_ptr() as _, - colors.len() * std::mem::size_of::<f32>() * 3, - ), - glow::STATIC_DRAW, - ); - ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buf)); - ctx.gl.buffer_data_u8_slice( - glow::ELEMENT_ARRAY_BUFFER, - &index_bytes, - glow::STATIC_DRAW, - ); - ctx.gl.draw_elements(glow::TRIANGLES, indices.len() as _, glow::UNSIGNED_INT, 0); - } - } -} diff --git a/crates/teleia/src/lib.rs b/crates/teleia/src/lib.rs index c59263f..5e13cbb 100644 --- a/crates/teleia/src/lib.rs +++ b/crates/teleia/src/lib.rs @@ -17,7 +17,8 @@ pub mod level2d; pub mod fig; pub use utils::{erm, install_error_handler, Erm}; -pub use color_eyre::eyre::WrapErr; +pub use audio::AudioPlayback; +pub use simple_eyre::eyre::WrapErr; #[cfg(target_arch = "wasm32")] use winit::platform::web::EventLoopExtWebSys; @@ -165,18 +166,18 @@ where if ctx.resize_necessary() { st.handle_resize(&ctx); } - if let Some(f) = &mut st.request { - match std::future::Future::poll(f.as_mut(), &mut st.waker_ctx) { - std::task::Poll::Pending => {}, - std::task::Poll::Ready(res) => { - st.request = None; - match res { - Ok(r) => st.request_returned(&ctx, game, r), - Err(e) => log::warn!("error during HTTP request: {}", e), - } - }, - } - } + // if let Some(f) = &mut st.request { + // match std::future::Future::poll(f.as_mut(), &mut st.waker_ctx) { + // std::task::Poll::Pending => {}, + // std::task::Poll::Ready(res) => { + // st.request = None; + // match res { + // Ok(r) => st.request_returned(&ctx, game, r), + // Err(e) => log::warn!("error during HTTP request: {}", e), + // } + // }, + // } + // } st.run_update(&ctx, game)?; st.run_render(&ctx, game)?; ctx.window.borrow_mut().swap_buffers(); diff --git a/crates/teleia/src/state.rs b/crates/teleia/src/state.rs index b992703..270ea8c 100644 --- a/crates/teleia/src/state.rs +++ b/crates/teleia/src/state.rs @@ -8,19 +8,19 @@ use crate::{audio, context, framebuffer, mesh, shader, utils}; const DELTA_TIME: f64 = 0.016; // todo -pub struct WinitWaker {} -impl WinitWaker { - fn new() -> Self { Self {} } -} -impl std::task::Wake for WinitWaker { - fn wake(self: std::sync::Arc<Self>) {} -} - -pub struct Response { - pub url: String, - pub status: reqwest::StatusCode, - pub body: bytes::Bytes, -} +// pub struct WinitWaker {} +// impl WinitWaker { +// fn new() -> Self { Self {} } +// } +// impl std::task::Wake for WinitWaker { +// fn wake(self: std::sync::Arc<Self>) {} +// } + +// pub struct Response { +// pub url: String, +// pub status: reqwest::StatusCode, +// pub body: bytes::Bytes, +// } pub trait Game { fn initialize(&self, ctx: &context::Context, st: &State) -> utils::Erm<()> { Ok(()) } @@ -34,7 +34,7 @@ pub trait Game { fn finish_title(&mut self, st: &mut State) {} fn mouse_move(&mut self, ctx: &context::Context, st: &mut State, x: i32, y: i32) {} fn mouse_press(&mut self, ctx: &context::Context, st: &mut State) {} - fn request_return(&mut self, ctx: &context::Context, st: &mut State, res: Response) {} + // fn request_return(&mut self, ctx: &context::Context, st: &mut State, res: Response) {} fn update(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { Ok(()) } fn render(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { Ok(()) } } @@ -186,9 +186,9 @@ pub struct State { pub lighting: (glam::Vec3, glam::Vec3, glam::Vec3), pub point_lights: Vec<PointLight>, - pub waker_ctx: std::task::Context<'static>, - pub http_client: reqwest::Client, - pub request: Option<std::pin::Pin<Box<dyn std::future::Future<Output = reqwest::Result<Response>>>>>, + // pub waker_ctx: std::task::Context<'static>, + // pub http_client: reqwest::Client, + // pub request: Option<std::pin::Pin<Box<dyn std::future::Future<Output = reqwest::Result<Response>>>>>, pub log: Vec<(u64, String)>, } @@ -252,9 +252,9 @@ impl State { ); let mesh_square = mesh::Mesh::from_obj(ctx, include_bytes!("assets/meshes/square.obj")); - let waker = std::sync::Arc::new(WinitWaker::new()); - let cwaker = Box::leak(Box::new(waker.into())); - let waker_ctx = std::task::Context::from_waker(cwaker); + // let waker = std::sync::Arc::new(WinitWaker::new()); + // let cwaker = Box::leak(Box::new(waker.into())); + // let waker_ctx = std::task::Context::from_waker(cwaker); let nextframe = now(ctx); @@ -294,9 +294,9 @@ impl State { ), point_lights: Vec::new(), - waker_ctx, - http_client: reqwest::Client::new(), - request: None, + // waker_ctx, + // http_client: reqwest::Client::new(), + // request: None, log: Vec::new(), } @@ -515,31 +515,29 @@ impl State { self.rebinding = Some(*k); } - pub fn request<F>(&mut self, f: F) - where F: Fn(&reqwest::Client) -> reqwest::RequestBuilder - { - let builder = f(&self.http_client); - let fut = async { - let resp = builder.send().await?; - let url = resp.url().clone().to_string(); - let status = resp.status().clone(); - let body = resp.bytes().await?; - reqwest::Result::Ok(Response { - url, - status, - body, - }) - }; - self.request = Some(Box::pin(fut)); - } - - pub fn requesting(&self) -> bool { self.request.is_some() } - - pub fn request_returned<G>(&mut self, ctx: &context::Context, game: &mut G, res: Response) - where G: Game - { - game.request_return(ctx, self, res); - } + // pub fn request<F>(&mut self, f: F) + // where F: Fn(&reqwest::Client) -> reqwest::RequestBuilder + // { + // let builder = f(&self.http_client); + // let fut = async { + // let resp = builder.send().await?; + // let url = resp.url().clone().to_string(); + // let status = resp.status().clone(); + // let body = resp.bytes().await?; + // reqwest::Result::Ok(Response { + // url, + // status, + // body, + // }) + // }; + // self.request = Some(Box::pin(fut)); + // } + // pub fn requesting(&self) -> bool { self.request.is_some() } + // pub fn request_returned<G>(&mut self, ctx: &context::Context, game: &mut G, res: Response) + // where G: Game + // { + // game.request_return(ctx, self, res); + // } pub fn run_update<G>(&mut self, ctx: &context::Context, game: &mut G) -> utils::Erm<()> where G: Game { let now = now(ctx); diff --git a/crates/teleia/src/utils.rs b/crates/teleia/src/utils.rs index c479560..9a543f3 100644 --- a/crates/teleia/src/utils.rs +++ b/crates/teleia/src/utils.rs @@ -1,9 +1,10 @@ use std::f32::consts::PI; +use enum_map::Enum; use serde::{Serialize, Deserialize}; use strum::EnumIter; -pub type Erm<T> = color_eyre::Result<T>; +pub type Erm<T> = simple_eyre::Result<T>; pub fn erm<E, T>(e: E) -> Erm<T> where E: std::error::Error + std::marker::Send + std::marker::Sync + 'static { Err(e.into()) @@ -27,7 +28,7 @@ pub fn erm_msg<T>(msg: &str) -> Erm<T> { } pub struct ErrorHandler; -impl color_eyre::eyre::EyreHandler for ErrorHandler { +impl simple_eyre::eyre::EyreHandler for ErrorHandler { fn debug( &self, error: &(dyn std::error::Error + 'static), @@ -50,12 +51,10 @@ impl color_eyre::eyre::EyreHandler for ErrorHandler { } pub fn install_error_handler() { - let (panic_hook, _) = color_eyre::config::HookBuilder::default().into_hooks(); - panic_hook.install(); - color_eyre::eyre::set_hook(Box::new(move |_| Box::new(ErrorHandler))).expect("failed to install error handler"); + simple_eyre::eyre::set_hook(Box::new(move |_| Box::new(ErrorHandler))).expect("failed to install error handler"); } -#[derive(Clone, Copy, Debug, EnumIter, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Enum, EnumIter, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub enum Cardinal { North, South, |
