summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2025-01-18 20:46:08 -0500
committerLLLL Colonq <llll@colonq>2025-01-18 20:46:08 -0500
commit6c00c069ccf08ef5e577c16acc78a5b1f53a0f8f (patch)
treeca0cf7a5e042883cfa7fe95725d8eda35860d56e /src
parent82d1c94d999654bda5d40108393eade80b77342c (diff)
Rework font rendering, configurable resolution
Diffstat (limited to 'src')
-rw-r--r--src/assets/shaders/bitmap/frag.glsl46
-rw-r--r--src/assets/shaders/bitmap/vert.glsl24
-rw-r--r--src/audio.rs5
-rw-r--r--src/context.rs39
-rw-r--r--src/font.rs149
-rw-r--r--src/framebuffer.rs6
-rw-r--r--src/lib.rs19
-rw-r--r--src/net/client.rs69
-rw-r--r--src/net/client/wasm.rs67
-rw-r--r--src/shader.rs4
-rw-r--r--src/state.rs21
-rw-r--r--src/utils.rs4
12 files changed, 230 insertions, 223 deletions
diff --git a/src/assets/shaders/bitmap/frag.glsl b/src/assets/shaders/bitmap/frag.glsl
index 94d27c9..470a7b8 100644
--- a/src/assets/shaders/bitmap/frag.glsl
+++ b/src/assets/shaders/bitmap/frag.glsl
@@ -2,55 +2,13 @@
precision highp float;
uniform sampler2D texture_data;
-uniform int text_length;
-uniform int text[256];
-uniform int char_width;
-uniform int char_height;
-uniform int font_width;
-uniform int font_height;
-uniform int text_width;
-uniform int text_height;
uniform vec3 text_color;
in vec2 vertex_texcoord;
out vec4 frag_color;
-void main()
-{
- vec2 inverted_texcoord = vec2(vertex_texcoord.x, 1.0 - vertex_texcoord.y);
- vec2 texcoord_pixels = inverted_texcoord * vec2(float(text_width), float(text_height));
- int texcoord_char_x = int(floor(texcoord_pixels.x)) / char_width;
- int texcoord_char_y = int(floor(texcoord_pixels.y)) / char_height;
-
- int x = 0;
- int y = 0;
- int i = 0;
- for (; i < text_length; ++i) {
- if (x == texcoord_char_x && y == texcoord_char_y) {
- break;
- }
- if (text[i] == 10) {
- x = 0;
- y += 1;
- } else {
- x += 1;
- }
- }
- if (i == text_length || text[i] == 10) discard;
-
- int entry = text[i] - 32;
- vec2 texcoord_base = vec2(
- float(entry % (font_width / char_width)) * float(char_width),
- float(entry / (font_width / char_width)) * float(char_height)
- );
- // vec2 texcoord_base = vec2(8.0, 0.0);
- vec2 texcoord_off = vec2(
- mod(texcoord_pixels.x, float(char_width)),
- mod(texcoord_pixels.y, float(char_height))
- );
- vec2 texcoord_final = (texcoord_base + texcoord_off) / vec2(float(font_width), float(font_height));
-
- vec4 texel = texture(texture_data, texcoord_final);
+void main() {
+ vec4 texel = texture(texture_data, vertex_texcoord);
if (texel.rgb == vec3(0.0, 0.0, 0.0)) discard;
texel.r = text_color.r;
texel.g = text_color.g;
diff --git a/src/assets/shaders/bitmap/vert.glsl b/src/assets/shaders/bitmap/vert.glsl
index 4005d75..4ff9865 100644
--- a/src/assets/shaders/bitmap/vert.glsl
+++ b/src/assets/shaders/bitmap/vert.glsl
@@ -1,26 +1,14 @@
#version 300 es
precision highp float;
-uniform mat4 view;
-uniform mat4 position;
+in vec2 vertex;
+in vec2 texcoord;
+
+uniform mat4 transform;
out vec2 vertex_texcoord;
void main() {
- const vec2 positions[4] = vec2[](
- vec2(-1, -1),
- vec2(+1, -1),
- vec2(-1, +1),
- vec2(+1, +1)
- );
- const vec2 coords[4] = vec2[](
- vec2(0, 0),
- vec2(1, 0),
- vec2(0, 1),
- vec2(1, 1)
- );
- vec4 vertex = vec4(positions[gl_VertexID], 0.0, 1.0);
-
- vertex_texcoord = coords[gl_VertexID];
- gl_Position = view * position * vertex;
+ vertex_texcoord = texcoord;
+ gl_Position = transform * vec4(vertex, 0.0, 1.0);
}
diff --git a/src/audio.rs b/src/audio.rs
index 0dca32e..2b4226c 100644
--- a/src/audio.rs
+++ b/src/audio.rs
@@ -1,4 +1,7 @@
-use std::{cell::RefCell, collections::HashMap};
+use std::collections::HashMap;
+
+#[cfg(target_arch = "wasm32")]
+use std::cell::RefCell;
#[cfg(target_arch = "wasm32")]
pub struct Context {
diff --git a/src/context.rs b/src/context.rs
index 28d0a79..ca3ebe3 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -10,24 +10,10 @@ extern {
fn js_poll_resized() -> bool;
}
-pub const RENDER_WIDTH: f32 = 240.0;
-pub const RENDER_HEIGHT: f32 = 160.0;
-
-pub fn compute_upscale(windoww: u32, windowh: u32) -> u32 {
- let mut ratio = 1;
- loop {
- if (RENDER_WIDTH as u32) * ratio > windoww
- || (RENDER_HEIGHT as u32) * ratio > windowh
- {
- break;
- }
- ratio += 1;
- }
- (ratio - 1).max(1)
-}
-
#[cfg(not(target_arch = "wasm32"))]
pub struct Context {
+ pub render_width: f32,
+ pub render_height: f32,
pub window: sdl2::video::Window,
pub gl: glow::Context,
pub emptyvao: glow::VertexArray,
@@ -37,6 +23,8 @@ pub struct Context {
#[cfg(target_arch = "wasm32")]
pub struct Context {
+ pub render_width: f32,
+ pub render_height: f32,
pub window: winit::window::Window,
pub gl: glow::Context,
pub emptyvao: glow::VertexArray,
@@ -44,12 +32,26 @@ pub struct Context {
}
impl Context {
+ pub fn compute_upscale(&self, windoww: u32, windowh: u32) -> u32 {
+ let mut ratio = 1;
+ loop {
+ if (self.render_width as u32) * ratio > windoww
+ || (self.render_height as u32) * ratio > windowh
+ {
+ break;
+ }
+ ratio += 1;
+ }
+ (ratio - 1).max(1)
+ }
+
#[cfg(not(target_arch = "wasm32"))]
- pub fn new(sdl: sdl2::Sdl, window: sdl2::video::Window, gl: glow::Context) -> Self {
+ pub fn new(sdl: sdl2::Sdl, window: sdl2::video::Window, gl: glow::Context, render_width: f32, render_height: f32) -> Self {
let emptyvao = unsafe {
gl.create_vertex_array().expect("failed to initialize vao")
};
let ret = Self {
+ render_width, render_height,
window,
gl,
emptyvao,
@@ -60,7 +62,7 @@ impl Context {
}
#[cfg(target_arch = "wasm32")]
- pub fn new(window: winit::window::Window, gl: glow::Context) -> Self {
+ pub fn new(window: winit::window::Window, gl: glow::Context, render_width: f32, render_height: f32) -> Self {
let emptyvao = unsafe {
gl.create_vertex_array().expect("failed to initialize vao")
};
@@ -69,6 +71,7 @@ impl Context {
unsafe { js_track_resized_setup(); }
let ret = Self {
+ render_width, render_height,
window,
gl,
emptyvao,
diff --git a/src/font.rs b/src/font.rs
index fb8f133..047e1f7 100644
--- a/src/font.rs
+++ b/src/font.rs
@@ -1,6 +1,6 @@
use std::collections::HashMap;
-use crate::{context, texture, shader};
+use crate::{context, mesh, shader, texture};
use glow::HasContext;
pub const CHAR_WIDTH: i32 = 7;
@@ -11,6 +11,10 @@ pub const FONT_HEIGHT: i32 = 54;
pub struct Bitmap {
pub shader: shader::Shader,
pub font: texture::Texture,
+ pub vao: glow::VertexArray,
+ pub vertex_buf: glow::Buffer,
+ pub texcoords_buf: glow::Buffer,
+ pub index_buf: glow::Buffer,
}
impl Bitmap {
@@ -21,67 +25,110 @@ impl Bitmap {
include_str!("assets/shaders/bitmap/frag.glsl"),
);
let font = texture::Texture::new(ctx, include_bytes!("assets/fonts/simple.png"));
- Self {
- shader,
- font,
+ unsafe {
+ 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 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,
+ vao,
+ vertex_buf,
+ texcoords_buf,
+ index_buf,
+ }
}
}
pub fn render_text_helper(&self, ctx: &context::Context, pos: &glam::Vec2, text: &str, color: &glam::Vec3) {
- let mut width = 0;
- let mut linewidth = 0;
- let mut height = CHAR_HEIGHT;
+ let mut cur = glam::Vec2::new(0.0, 0.0);
+ let mut vertices = Vec::new();
+ let mut texcoords = Vec::new();
+ let mut indices = Vec::new();
+ let cwidth = CHAR_WIDTH as f32 / FONT_WIDTH as f32;
+ let cheight = CHAR_HEIGHT as f32 / FONT_HEIGHT as f32;
+ let row_len = FONT_WIDTH as u32 / CHAR_WIDTH as u32;
for c in text.chars() {
if c == '\n' {
- width = width.max(linewidth);
- linewidth = 0;
- height += CHAR_HEIGHT;
+ cur.x = 0.0;
+ cur.y += CHAR_HEIGHT as f32;
} else {
- linewidth += CHAR_WIDTH;
+ let idx = vertices.len() as u32;
+ vertices.push(cur);
+ vertices.push(cur + glam::Vec2::new(CHAR_WIDTH as f32, 0.0));
+ vertices.push(cur + glam::Vec2::new(CHAR_WIDTH as f32, CHAR_HEIGHT as f32));
+ vertices.push(cur + glam::Vec2::new(0.0, CHAR_HEIGHT as f32));
+ let cidx = c as u32 - ' ' as u32;
+ let col = cidx % row_len;
+ let row = cidx / row_len;
+ let tcbase = glam::Vec2::new(col as f32 * cwidth, row as f32 * cheight);
+ 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);
+ 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 += CHAR_WIDTH as f32;
}
}
- width = width.max(linewidth);
-
+ let index_bytes: Vec<u8> = indices.iter().flat_map(|x| x.to_ne_bytes()).collect();
self.shader.bind(ctx);
- let len = text.len().min(256);
- self.shader.set_i32(ctx, "text_length", len as _);
- let textvals: Vec<i32> = text.as_bytes().into_iter().take(len).map(|b| {
- *b as i32
- }).collect();
- self.shader.set_i32_array(ctx, "text[0]", &textvals);
- self.shader.set_i32(ctx, "char_width", CHAR_WIDTH as _);
- self.shader.set_i32(ctx, "char_height", CHAR_HEIGHT as _);
- self.shader.set_i32(ctx, "font_width", FONT_WIDTH as _);
- self.shader.set_i32(ctx, "font_height", FONT_HEIGHT as _);
- self.shader.set_i32(ctx, "text_width", width as _);
- self.shader.set_i32(ctx, "text_height", height as _);
- self.shader.set_vec3(ctx, "text_color", color as _);
- self.shader.set_mat4(
- ctx, "view",
- &glam::Mat4::from_scale(
- glam::Vec3::new(
- 2.0 / context::RENDER_WIDTH,
- 2.0 / context::RENDER_HEIGHT,
- 1.0,
- ),
- ),
+ self.font.bind(ctx);
+ let scale = glam::Vec2::new(2.0 / ctx.render_width, 2.0 / ctx.render_height);
+ let offset = glam::Vec2::new(
+ -ctx.render_width / 2.0,
+ ctx.render_height / 2.0 - CHAR_HEIGHT as f32,
);
- let halfwidth = width as f32 / 2.0;
- let halfheight = height as f32 / 2.0;
+ let npos = (glam::Vec2::new(pos.x, -pos.y) + offset) * scale;
+ self.shader.set_vec3(ctx, "text_color", color as _);
self.shader.set_mat4(
- ctx, "position",
+ ctx, "transform",
&glam::Mat4::from_scale_rotation_translation(
- glam::Vec3::new(halfwidth, halfheight, 1.0),
+ glam::Vec3::new(scale.x, scale.y, 1.0),
glam::Quat::IDENTITY,
- glam::Vec3::new(
- -context::RENDER_WIDTH / 2.0 + pos.x + halfwidth,
- context::RENDER_HEIGHT / 2.0 - pos.y - halfheight,
- 0.0,
- ),
- )
+ glam::Vec3::new(npos.x, npos.y, 0.0),
+ ),
);
- self.font.bind(ctx);
- ctx.render_no_geometry();
+ unsafe {
+ 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::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);
+ }
}
pub fn render_text(&self, ctx: &context::Context, pos: &glam::Vec2, text: &str) {
@@ -180,8 +227,8 @@ impl TrueType {
ctx, "view",
&glam::Mat4::from_scale(
glam::Vec3::new(
- 2.0 / context::RENDER_WIDTH,
- 2.0 / context::RENDER_HEIGHT,
+ 2.0 / ctx.render_width,
+ 2.0 / ctx.render_height,
1.0,
),
),
@@ -193,8 +240,8 @@ impl TrueType {
glam::Vec3::new(width as f32 / 2.0, self.cellheight as f32 / 2.0, 1.0),
glam::Quat::IDENTITY,
glam::Vec3::new(
- -context::RENDER_WIDTH / 2.0 + pos.x + width as f32 / 2.0,
- context::RENDER_HEIGHT / 2.0 - pos.y - self.cellheight as f32 / 2.0,
+ -ctx.render_width / 2.0 + pos.x + width as f32 / 2.0,
+ ctx.render_height / 2.0 - pos.y - self.cellheight as f32 / 2.0,
0.0,
),
)
diff --git a/src/framebuffer.rs b/src/framebuffer.rs
index 6d8d1b5..ae96d6a 100644
--- a/src/framebuffer.rs
+++ b/src/framebuffer.rs
@@ -18,9 +18,9 @@ impl Framebuffer {
let (w, h) = ctx.window.size();
(w as f32, h as f32)
};
- let ratio = context::compute_upscale(windoww as _, windowh as _) as f32;
- let upscalew = context::RENDER_WIDTH * ratio;
- let upscaleh = context::RENDER_HEIGHT * ratio;
+ let ratio = ctx.compute_upscale(windoww as _, windowh as _) as f32;
+ let upscalew = ctx.render_width * ratio;
+ let upscaleh = ctx.render_height * ratio;
let offsetx = (windoww - upscalew) / 2.0;
let offsety = (windowh - upscaleh) / 2.0;
Self {
diff --git a/src/lib.rs b/src/lib.rs
index f50bb09..32502d2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,6 +11,8 @@ pub mod font;
pub mod shadow;
pub mod audio;
pub mod net;
+
+#[cfg(target_arch = "wasm32")]
use std::ops::Rem;
#[cfg(target_arch = "wasm32")]
@@ -39,7 +41,7 @@ where
}
#[cfg(not(target_arch = "wasm32"))]
-pub async fn run<'a, F, G, Fut>(title: &str, gnew: F)
+pub async fn run<'a, F, G, Fut>(title: &str, w: u32, h: u32, gnew: F)
where
Fut: std::future::Future<Output = G>,
G: state::Game + 'static,
@@ -72,7 +74,7 @@ where
(sdl, window, gl, event_loop, gl_context)
};
- let ctx = Box::leak(Box::new(context::Context::new(sdl, window, gl)));
+ let ctx = Box::leak(Box::new(context::Context::new(sdl, window, gl, w as f32, h as f32)));
let game = Box::leak(Box::new(gnew(ctx).await));
let st = Box::leak(Box::new(state::State::new(&ctx)));
@@ -140,7 +142,7 @@ where
}
#[cfg(target_arch = "wasm32")]
-pub async fn run<'a, F, G, Fut>(gnew: F)
+pub async fn run<'a, F, G, Fut>(w: u32, h: u32, gnew: F)
where
Fut: std::future::Future<Output = G>,
G: state::Game + 'static,
@@ -176,7 +178,7 @@ where
(window, gl)
};
- let ctx = Box::leak(Box::new(context::Context::new(window, gl)));
+ let ctx = Box::leak(Box::new(context::Context::new(window, gl, w as f32, h as f32)));
ctx.maximize_canvas();
let game = Box::leak(Box::new(gnew(ctx).await));
let st = Box::leak(Box::new(state::State::new(&ctx)));
@@ -271,7 +273,6 @@ where
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
-
#[cfg(target_arch = "wasm32")]
struct TestGame {
font: font::Bitmap,
@@ -281,6 +282,7 @@ struct TestGame {
tex: texture::Texture,
shader: shader::Shader,
}
+#[cfg(target_arch = "wasm32")]
impl TestGame {
pub async fn new(ctx: &context::Context) -> Self {
Self {
@@ -293,6 +295,7 @@ impl TestGame {
}
}
}
+#[cfg(target_arch = "wasm32")]
impl state::Game for TestGame {
fn update(&mut self, ctx: &context::Context, st: &mut state::State) -> Option<()> {
st.move_camera(
@@ -319,8 +322,8 @@ impl state::Game for TestGame {
);
self.tex.bind(ctx);
self.fox.render(ctx, &self.shader);
- self.font.render_text(ctx, &glam::Vec2::new(0.0, 0.0), "he's all FIXED up");
- self.tt.render_text(ctx, &glam::Vec2::new(10.0, 10.0), "tESTge");
+ self.font.render_text(ctx, &glam::Vec2::new(0.0, 10.0), "he's all FIXED up");
+ // self.tt.render_text(ctx, &glam::Vec2::new(10.0, 10.0), "tESTge");
Some(())
}
}
@@ -328,5 +331,5 @@ impl state::Game for TestGame {
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub async fn main_js_test() {
- run(TestGame::new).await;
+ run(240, 160, TestGame::new).await;
}
diff --git a/src/net/client.rs b/src/net/client.rs
index d9936e5..fcd51b8 100644
--- a/src/net/client.rs
+++ b/src/net/client.rs
@@ -1,67 +1,2 @@
-use std::{collections::VecDeque, sync::{Arc, Mutex}};
-
-use wasm_bindgen::prelude::*;
-
-#[derive(Debug)]
-pub enum Message {
- Binary(Vec<u8>),
- Text(String),
-}
-
-impl Message {
- pub fn from_messageevent(e: web_sys::MessageEvent) -> Self {
- if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
- let array = js_sys::Uint8Array::new(&abuf).to_vec();
- Message::Binary(array)
- } else if let Ok(txt) = e.data().dyn_into::<js_sys::JsString>() {
- Message::Text(txt.into())
- } else {
- panic!("received weird websocked message: {:?}", e);
- }
- }
-}
-
-pub struct Client {
- pub ws: Option<web_sys::WebSocket>,
- pub messages: Arc<Mutex<VecDeque<Message>>>,
-}
-
-impl Client {
- pub fn new() -> Self {
- Self {
- ws: None,
- messages: Arc::new(Mutex::new(VecDeque::new())),
- }
- }
- pub fn connect(&mut self, url: &str) {
- let ws = web_sys::WebSocket::new(url).expect("failed to open websocket");
- let messages_ref = self.messages.clone();
- let cb: Closure<dyn Fn(web_sys::MessageEvent)> = Closure::new(move |e: web_sys::MessageEvent| {
- let msg = Message::from_messageevent(e);
- log::info!("incoming: {:?}", msg);
- messages_ref.lock().unwrap().push_back(msg);
- });
- ws.set_onmessage(Some(cb.as_ref().unchecked_ref()));
- cb.forget();
- self.ws = Some(ws);
- }
- pub fn poll(&mut self) -> Option<Message> {
- self.messages.lock().unwrap().pop_front()
- }
- pub fn send(&self, msg: Message) {
- if let Some(ws) = &self.ws {
- match msg {
- Message::Text(txt) => {
- if let Err(e) = ws.send_with_str(&txt) {
- log::warn!("failed to send string: {:?}", e);
- }
- },
- Message::Binary(bytes) => {
- if let Err(e) = ws.send_with_u8_array(&bytes) {
- log::warn!("failed to send bytes: {:?}", e);
- }
- },
- }
- }
- }
-}
+#[cfg(target_arch = "wasm32")]
+pub mod wasm;
diff --git a/src/net/client/wasm.rs b/src/net/client/wasm.rs
new file mode 100644
index 0000000..d9936e5
--- /dev/null
+++ b/src/net/client/wasm.rs
@@ -0,0 +1,67 @@
+use std::{collections::VecDeque, sync::{Arc, Mutex}};
+
+use wasm_bindgen::prelude::*;
+
+#[derive(Debug)]
+pub enum Message {
+ Binary(Vec<u8>),
+ Text(String),
+}
+
+impl Message {
+ pub fn from_messageevent(e: web_sys::MessageEvent) -> Self {
+ if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
+ let array = js_sys::Uint8Array::new(&abuf).to_vec();
+ Message::Binary(array)
+ } else if let Ok(txt) = e.data().dyn_into::<js_sys::JsString>() {
+ Message::Text(txt.into())
+ } else {
+ panic!("received weird websocked message: {:?}", e);
+ }
+ }
+}
+
+pub struct Client {
+ pub ws: Option<web_sys::WebSocket>,
+ pub messages: Arc<Mutex<VecDeque<Message>>>,
+}
+
+impl Client {
+ pub fn new() -> Self {
+ Self {
+ ws: None,
+ messages: Arc::new(Mutex::new(VecDeque::new())),
+ }
+ }
+ pub fn connect(&mut self, url: &str) {
+ let ws = web_sys::WebSocket::new(url).expect("failed to open websocket");
+ let messages_ref = self.messages.clone();
+ let cb: Closure<dyn Fn(web_sys::MessageEvent)> = Closure::new(move |e: web_sys::MessageEvent| {
+ let msg = Message::from_messageevent(e);
+ log::info!("incoming: {:?}", msg);
+ messages_ref.lock().unwrap().push_back(msg);
+ });
+ ws.set_onmessage(Some(cb.as_ref().unchecked_ref()));
+ cb.forget();
+ self.ws = Some(ws);
+ }
+ pub fn poll(&mut self) -> Option<Message> {
+ self.messages.lock().unwrap().pop_front()
+ }
+ pub fn send(&self, msg: Message) {
+ if let Some(ws) = &self.ws {
+ match msg {
+ Message::Text(txt) => {
+ if let Err(e) = ws.send_with_str(&txt) {
+ log::warn!("failed to send string: {:?}", e);
+ }
+ },
+ Message::Binary(bytes) => {
+ if let Err(e) = ws.send_with_u8_array(&bytes) {
+ log::warn!("failed to send bytes: {:?}", e);
+ }
+ },
+ }
+ }
+ }
+}
diff --git a/src/shader.rs b/src/shader.rs
index 46deb82..cbaf3ee 100644
--- a/src/shader.rs
+++ b/src/shader.rs
@@ -210,8 +210,8 @@ impl Shader {
glam::Vec3::new(halfwidth, halfheight, 1.0),
rot.clone(),
glam::Vec3::new(
- -context::RENDER_WIDTH / 2.0 + pos.x + halfwidth,
- context::RENDER_HEIGHT / 2.0 - pos.y - halfheight,
+ -ctx.render_width / 2.0 + pos.x + halfwidth,
+ ctx.render_height / 2.0 - pos.y - halfheight,
0.0,
),
)
diff --git a/src/state.rs b/src/state.rs
index 0be163b..cf910a3 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -2,6 +2,7 @@
use std::collections::HashMap;
use bimap::BiHashMap;
use enum_map::{enum_map, Enum, EnumMap};
+use serde::{Serialize, Deserialize};
use crate::{context, framebuffer, shader, audio};
@@ -35,7 +36,7 @@ pub trait Game {
fn render(&mut self, ctx: &context::Context, st: &mut State) -> Option<()> { Some(()) }
}
-#[derive(Debug, Enum, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Enum, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Key {
Up, Down, Left, Right,
A, B, L, R,
@@ -96,10 +97,10 @@ pub struct PointLight {
type Timestamp = f64;
#[cfg(target_arch = "wasm32")]
-type Keycode = winit::keyboard::KeyCode;
+pub type Keycode = winit::keyboard::KeyCode;
#[cfg(not(target_arch = "wasm32"))]
-type Keycode = sdl2::keyboard::Keycode;
+pub type Keycode = sdl2::keyboard::Keycode;
pub struct State {
pub acc: f64,
@@ -175,7 +176,7 @@ impl State {
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(ctx.render_width, ctx.render_height),
&glam::Vec2::new(0.0, 0.0),
);
let shader_upscale = shader::Shader::new_nolib(
@@ -209,7 +210,7 @@ impl State {
projection: glam::Mat4::perspective_lh(
std::f32::consts::PI / 4.0,
- context::RENDER_WIDTH / context::RENDER_HEIGHT,
+ ctx.render_width / ctx.render_height,
// 0.1,
0.5,
50.0,
@@ -342,8 +343,8 @@ impl State {
ctx, "view",
&glam::Mat4::from_scale(
glam::Vec3::new(
- 2.0 / context::RENDER_WIDTH,
- 2.0 / context::RENDER_HEIGHT,
+ 2.0 / ctx.render_width,
+ 2.0 / ctx.render_height,
1.0,
),
),
@@ -357,9 +358,9 @@ impl State {
game: &mut G
) where G: Game
{
- let rx = ((x - self.screen.offsets.x) * context::RENDER_WIDTH / self.screen.dims.x) as i32;
- let ry = ((y - self.screen.offsets.y) * context::RENDER_HEIGHT / self.screen.dims.y) as i32;
- if !(rx < 0 || rx >= context::RENDER_WIDTH as i32 || ry < 0 || ry >= context::RENDER_HEIGHT as i32) {
+ let rx = ((x - self.screen.offsets.x) * ctx.render_width / self.screen.dims.x) as i32;
+ let ry = ((y - self.screen.offsets.y) * ctx.render_height / self.screen.dims.y) as i32;
+ if !(rx < 0 || rx >= ctx.render_width as i32 || ry < 0 || ry >= ctx.render_height as i32) {
game.mouse_move(ctx, self, rx, ry);
}
}
diff --git a/src/utils.rs b/src/utils.rs
index af0d77d..4d5916c 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,4 +1,6 @@
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+use serde::{Serialize, Deserialize};
+
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Cardinal {
North,
South,