diff options
Diffstat (limited to 'crates/renderer/src')
| -rw-r--r-- | crates/renderer/src/assets/shaders/automata/frag.glsl | 5 | ||||
| -rw-r--r-- | crates/renderer/src/main.rs | 1 | ||||
| -rw-r--r-- | crates/renderer/src/overlay.rs | 80 | ||||
| -rw-r--r-- | crates/renderer/src/overlay/automata.rs | 109 |
4 files changed, 127 insertions, 68 deletions
diff --git a/crates/renderer/src/assets/shaders/automata/frag.glsl b/crates/renderer/src/assets/shaders/automata/frag.glsl index 7eda644..29f5c71 100644 --- a/crates/renderer/src/assets/shaders/automata/frag.glsl +++ b/crates/renderer/src/assets/shaders/automata/frag.glsl @@ -5,8 +5,5 @@ void main() { vec2 tcfull = vec2(vertex_texcoord.x, 1.0 - vertex_texcoord.y); vec4 texel = texture(texture_data, tcfull); - if (texel.r == 0.0) { - discard; - } - frag_color = vec4(1.0, 1.0, 1.0, 1.0); + frag_color = texel; } diff --git a/crates/renderer/src/main.rs b/crates/renderer/src/main.rs index fa35852..854eae2 100644 --- a/crates/renderer/src/main.rs +++ b/crates/renderer/src/main.rs @@ -30,6 +30,7 @@ pub fn main() -> Erm<()> { Box::new(overlay::automata::Overlay::new(ctx)), Box::new(overlay::shader::Overlay::new(ctx)), Box::new(overlay::drawing::Overlay::new(ctx)), + // Box::new(overlay::model::Overlay::new(ctx)), ]) })?; }, diff --git a/crates/renderer/src/overlay.rs b/crates/renderer/src/overlay.rs index fd59f82..accf3bb 100644 --- a/crates/renderer/src/overlay.rs +++ b/crates/renderer/src/overlay.rs @@ -70,6 +70,7 @@ impl State { sexp!((avatar overlay chat)), sexp!((avatar overlay cursor)), sexp!((avatar overlay emacs)), + sexp!((avatar automata spawn)), ]), fig_binary: fig::BinaryClient::new("shiro:32051", false, &[ b"background frame" @@ -146,44 +147,6 @@ impl State { ); let (x, y) = self.input.get_mouse(); self.mouse_cursor = (x as f32, y as f32); - while let Some(msg) = self.fig.pump() { - let malformed = format!("malformed {} data: {}", msg.event, msg.data); - if msg.event == sexp!((avatar tracking)) { - if self.handle_tracking(msg).is_none() { log::warn!("{}", malformed) } - } else if msg.event == sexp!((avatar reset)) { - self.reset(ctx, st); - } else if msg.event == sexp!((avatar toggle)) { - if self.toggles.handle(ctx, st, msg).is_none() { log::warn!("{}", malformed) } - } else if msg.event == sexp!((avatar toggle set)) { - if self.toggles.handle_set(ctx, st, msg, true).is_none() { log::warn!("{}", malformed) } - } else if msg.event == sexp!((avatar toggle unset)) { - if self.toggles.handle_set(ctx, st, msg, false).is_none() { log::warn!("{}", malformed) } - } else if msg.event == sexp!((avatar overlay muzak)) { - if self.handle_overlay_muzak(msg).is_none() { log::warn!("{}", malformed) } - } else if msg.event == sexp!((avatar overlay muzak clear)) { - if self.handle_overlay_muzak_clear().is_none() { log::warn!("{}", malformed) } - } else if msg.event == sexp!((avatar overlay chat)) { - if self.handle_overlay_chat(msg).is_none() { log::warn!("{}", malformed) } - } else if msg.event == sexp!((avatar overlay cursor)) { - if self.handle_overlay_cursor(msg).is_none() { log::warn!("{}", malformed) } - } else { - log::info!("received unhandled event {} with data: {}", msg.event, msg.data); - } - } - while let Some(msg) = self.fig_binary.pump() { - match &*msg.event { - b"background frame" => { - if let Some(f) = background::Frame::parse(&mut &*msg.data) { - self.backgrounds.update(ctx, f); - } else { - log::warn!("failed to parse frame"); - } - }, - ev => { - log::info!("unhandled event: {:?}", ev); - }, - } - } if let Some(n) = self.model.nodes_by_name.get("J_Bip_C_Neck").and_then(|i| self.model.nodes.get_mut(*i)) { n.transform = self.model_neck_base * glam::Mat4::from_quat(self.tracking_neck); } @@ -233,7 +196,46 @@ impl teleia::state::Game for Overlays { &glam::Vec3::new(0.0, 0.0, -1.0), &glam::Vec3::new(0.0, 1.0, 0.0), ); - self.state.reset(ctx, st); + while let Some(msg) = self.state.fig.pump() { + let malformed = format!("malformed {} data: {}", msg.event, msg.data); + for ov in self.overlays.iter_mut() { + ov.handle(ctx, st, &mut self.state, msg.clone())?; + } + if msg.event == sexp!((avatar tracking)) { + if self.state.handle_tracking(msg).is_none() { log::warn!("{}", malformed) } + } else if msg.event == sexp!((avatar reset)) { + self.reset(ctx, st)?; + } else if msg.event == sexp!((avatar toggle)) { + if self.state.toggles.handle(ctx, st, msg).is_none() { log::warn!("{}", malformed) } + } else if msg.event == sexp!((avatar toggle set)) { + if self.state.toggles.handle_set(ctx, st, msg, true).is_none() { log::warn!("{}", malformed) } + } else if msg.event == sexp!((avatar toggle unset)) { + if self.state.toggles.handle_set(ctx, st, msg, false).is_none() { log::warn!("{}", malformed) } + } else if msg.event == sexp!((avatar overlay muzak)) { + if self.state.handle_overlay_muzak(msg).is_none() { log::warn!("{}", malformed) } + } else if msg.event == sexp!((avatar overlay muzak clear)) { + if self.state.handle_overlay_muzak_clear().is_none() { log::warn!("{}", malformed) } + } else if msg.event == sexp!((avatar overlay chat)) { + if self.state.handle_overlay_chat(msg).is_none() { log::warn!("{}", malformed) } + } else if msg.event == sexp!((avatar overlay cursor)) { + if self.state.handle_overlay_cursor(msg).is_none() { log::warn!("{}", malformed) } + } + } + while let Some(msg) = self.state.fig_binary.pump() { + match &*msg.event { + b"background frame" => { + if let Some(f) = background::Frame::parse(&mut &*msg.data) { + self.state.backgrounds.update(ctx, f); + } else { + log::warn!("failed to parse frame"); + } + }, + ev => { + log::info!("unhandled event: {:?}", ev); + }, + } + } + self.state.update(ctx, st)?; for ov in self.overlays.iter_mut() { ov.update(ctx, st, &mut self.state)?; } diff --git a/crates/renderer/src/overlay/automata.rs b/crates/renderer/src/overlay/automata.rs index b5d749e..22f7884 100644 --- a/crates/renderer/src/overlay/automata.rs +++ b/crates/renderer/src/overlay/automata.rs @@ -1,6 +1,9 @@ use teleia::*; use glow::HasContext; +use lexpr::sexp; +use base64::prelude::*; +use rand::Rng; use crate::overlay; @@ -34,6 +37,7 @@ impl Pattern { data.push_str(&line); } } + if w == 0 || h == 0 || w > WIDTH || h > HEIGHT { return None } let mut ret = Self { w, h, cells: vec![false; w * h], @@ -91,7 +95,7 @@ impl Pattern { type Cell = u8; struct CellRule { - color: glam::Vec4, + color: [u8; 4], } struct CellBuffer { @@ -111,6 +115,17 @@ impl CellBuffer { pub fn get(&self, x: i32, y: i32) -> Cell { self.buf[Self::idx(x, y)] } + pub fn neighbors(&self, x: i32, y: i32) -> [Cell; 8] { + [ self.get(x-1, y-1), + self.get(x, y-1), + self.get(x+1, y-1), + self.get(x-1, y), + self.get(x+1, y), + self.get(x-1, y+1), + self.get(x, y+1), + self.get(x+1, y+1), + ] + } pub fn is_nonzero(&self, x: i32, y: i32) -> bool { self.get(x, y) > 0 } @@ -118,9 +133,22 @@ impl CellBuffer { self.get(x, y).min(1) as i32 } pub fn count_neighbors(&self, x: i32, y: i32) -> i32 { - self.count_cell(x-1, y-1) + self.count_cell(x, y-1) + self.count_cell(x+1, y-1) - + self.count_cell(x-1, y) + self.count_cell(x+1, y) - + self.count_cell(x-1, y+1) + self.count_cell(x, y+1) + self.count_cell(x+1, y+1) + self.neighbors(x, y).into_iter().map(|c| c.min(1) as i32).sum() + } + pub fn most_common_neighbor(&self, x: i32, y: i32) -> u8 { + let mut ns = self.neighbors(x, y); + ns.sort_unstable(); + let mut winner = 0; + let mut score = 0; + let mut cur = 0; + let mut curscore = 0; + for c in ns { + if c == 0 { continue; } + if c != cur { cur = c; curscore = 1; } + else { curscore += 1; } + if curscore >= score { winner = c; score = curscore; } + } + winner } pub fn set(&mut self, x: i32, y: i32, v: Cell) { self.buf[Self::idx(x, y)] = v; @@ -133,15 +161,16 @@ pub struct Overlay { active: bool, buf0: CellBuffer, buf1: CellBuffer, + next_rule: usize, rules: [CellRule; 256], } impl Overlay { pub fn new(ctx: &context::Context) -> Self { let rules = std::array::from_fn(|idx| match idx { - 0 => CellRule { color: glam::Vec4::new(0.0, 0.0, 0.0, 0.0) }, - _ => CellRule { color: glam::Vec4::new(1.0, 1.0, 1.0, 1.0) }, + 0 => CellRule { color: [0, 0, 0, 0] }, + _ => CellRule { color: [0xff, 0xff, 0xff, 0xff] }, }); - let mut ret = Self { + Self { shader: shader::Shader::new( ctx, include_str!("../assets/shaders/automata/vert.glsl"), @@ -151,21 +180,9 @@ impl Overlay { active: false, buf0: CellBuffer::new(), buf1: CellBuffer::new(), + next_rule: 1, rules, - }; - if let Some(pat) = Pattern::from_rle(" -#N Tanner's p46 -#O Tanner Jacobi -#C A period 46 oscillator discovered by Tanner Jacobi in October 2017. -#C https://conwaylife.com/wiki/Tanner%27s_p46 -x = 13, y = 26, rule = B3/S23 -2b2o9b$2bo10b$3bo9b$2b2o9b$13b$9b2o2b$9bo3b$10bo2b$9b2o2b$b2o10b$b2o6b -2o2b$o7bobo2b$b2o6bo3b$b2o7b3o$12bo$13b$13b$13b$13b$13b$13b$b2o10b$b2o -2b2o6b$5bobo5b$7bo5b$7b2o4b! -") { - ret.spawn(30, 10, 1, &pat); } - ret } pub fn spawn(&mut self, x: i32, y: i32, c: Cell, pat: &Pattern) { let cur = if self.active { &mut self.buf0 } else { &mut self.buf1 }; @@ -189,7 +206,7 @@ x = 13, y = 26, rule = B3/S23 if cur.is_nonzero(x, y) && n != 2 && n != 3{ next.set(x, y, 0) } else if n == 3 { - next.set(x, y, 1) + next.set(x, y, cur.most_common_neighbor(x, y)) } else { next.set(x, y, cur.get(x, y)) } @@ -199,25 +216,67 @@ x = 13, y = 26, rule = B3/S23 } pub fn upload(&self, ctx: &context::Context) { let cur = if self.active { &self.buf0 } else { &self.buf1 }; + let mut buf = vec![0; WIDTH * HEIGHT * 4]; + for (idx, c) in cur.buf.iter().enumerate() { + for off in 0..4 { buf[idx * 4 + off] = self.rules[*c as usize].color[off] } + } unsafe { - let err = ctx.gl.get_error(); self.tex.bind(ctx); ctx.gl.tex_image_2d( glow::TEXTURE_2D, 0, - glow::R8 as i32, + glow::RGBA as i32, WIDTH as i32, HEIGHT as i32, 0, - glow::RED, + glow::RGBA, glow::UNSIGNED_BYTE, - Some(&cur.buf), + Some(&buf), ); ctx.gl.generate_mipmap(glow::TEXTURE_2D); } } + pub fn handle_spawn(&mut self, msg: fig::SexpMessage) -> Option<()> { + let bs = BASE64_STANDARD.decode(msg.data.get(0)?.as_str()?).ok()?; + let s = std::str::from_utf8(&bs).ok()?; + let bcol = BASE64_STANDARD.decode(msg.data.get(2)?.as_str()?).ok()?; + let scol = std::str::from_utf8(&bcol).ok()?.trim().strip_prefix("#")?; + let col = u32::from_str_radix(scol, 16).ok()?; + let r = (col >> 16 & 0xff) as u8; + let g = (col >> 8 & 0xff) as u8; + let b = (col & 0xff) as u8; + if let Some(pat) = Pattern::from_rle(s) { + let mut rng = rand::thread_rng(); + let x = rng.gen_range(0..WIDTH); + let y = rng.gen_range(0..HEIGHT); + self.rules[self.next_rule] = CellRule { color: [r, g, b, 0xff] }; + self.spawn(x as i32, y as i32, self.next_rule as u8, &pat); + self.next_rule = (self.next_rule + 1) % 256; + if self.next_rule == 0 { self.next_rule = 1; } + } + Some(()) + } } impl overlay::Overlay for Overlay { + fn reset(&mut self, ctx: &context::Context, st: &mut state::State, _ost: &mut overlay::State) -> Erm<()> { + let cur = if self.active { &mut self.buf0 } else { &mut self.buf1 }; + for ux in 0..WIDTH { + for uy in 0..HEIGHT { + cur.set(ux as i32, uy as i32, 0) + } + } + Ok(()) + } + fn handle( + &mut self, ctx: &context::Context, st: &mut state::State, _ost: &mut overlay::State, + msg: fig::SexpMessage, + ) -> Erm<()> { + let malformed = format!("malformed {} data: {}", msg.event, msg.data); + if msg.event == sexp!((avatar automata spawn)) { + if self.handle_spawn(msg).is_none() { log::warn!("{}", malformed) } + } + Ok(()) + } fn update(&mut self, ctx: &context::Context, st: &mut state::State, _ost: &mut overlay::State) -> Erm<()> { if st.tick % 10 == 0 { self.step(); |
