summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/teleia/Cargo.toml6
-rw-r--r--crates/teleia/src/audio.rs13
-rw-r--r--crates/teleia/src/font.rs200
-rw-r--r--crates/teleia/src/lib.rs27
-rw-r--r--crates/teleia/src/state.rs94
-rw-r--r--crates/teleia/src/utils.rs11
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,