From 44cbef39e79b48481d7a111954cd4367e3d6b9fe Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Mon, 21 Sep 2026 22:44:32 -0400 Subject: Add dueling --- crates/renderer/src/assets.rs | 2 + crates/renderer/src/main.rs | 1 + crates/renderer/src/overlay.rs | 2 + crates/renderer/src/overlay/clippy.rs | 25 ++--- crates/renderer/src/overlay/combo.rs | 6 +- crates/renderer/src/overlay/duel.rs | 158 +++++++++++++++++++++++++++++ crates/renderer/src/overlay/tcg.rs | 182 +++++++++++++++++----------------- crates/renderer/src/terminal.rs | 5 +- 8 files changed, 272 insertions(+), 109 deletions(-) create mode 100644 crates/renderer/src/overlay/duel.rs (limited to 'crates/renderer/src') diff --git a/crates/renderer/src/assets.rs b/crates/renderer/src/assets.rs index 042fc88..a44294f 100644 --- a/crates/renderer/src/assets.rs +++ b/crates/renderer/src/assets.rs @@ -17,6 +17,7 @@ pub struct Assets { pub texture_operabottom: texture::Texture, pub texture_clippyborder: texture::Texture, pub texture_exclusive: texture::Texture, + pub texture_cardback: texture::Texture, } impl Assets { @@ -74,6 +75,7 @@ impl Assets { texture_operabottom: texture::Texture::new(ctx, include_bytes!("assets/textures/operabottom.png")), texture_clippyborder: texture::Texture::new(ctx, include_bytes!("assets/textures/clippyborder.png")), texture_exclusive: texture::Texture::new(ctx, include_bytes!("assets/textures/exclusive.png")), + texture_cardback: texture::Texture::new(ctx, include_bytes!("assets/textures/tcg/cardback.png")), } } } diff --git a/crates/renderer/src/main.rs b/crates/renderer/src/main.rs index 5f73df8..1b77f49 100644 --- a/crates/renderer/src/main.rs +++ b/crates/renderer/src/main.rs @@ -29,6 +29,7 @@ pub fn main() -> Erm<()> { Box::new(overlay::automata::Overlay::new(ctx)), Box::new(overlay::shader::Overlay::new(ctx)), Box::new(overlay::tcg::Overlay::new(ctx)), + Box::new(overlay::duel::Overlay::new(ctx)), Box::new(overlay::clippy::Overlay::new(ctx)), // Box::new(overlay::handcam::Overlay::new(ctx)), Box::new(overlay::combo::Overlay::new(ctx)), diff --git a/crates/renderer/src/overlay.rs b/crates/renderer/src/overlay.rs index ec8acb8..9f4170c 100644 --- a/crates/renderer/src/overlay.rs +++ b/crates/renderer/src/overlay.rs @@ -5,6 +5,7 @@ pub mod shader; pub mod drawing; pub mod automata; pub mod tcg; +pub mod duel; pub mod loopback; pub mod clippy; pub mod combo; @@ -93,6 +94,7 @@ impl State { b"overlay shader chat", b"overlay automata spawn", b"overlay tcg generate", + b"overlay tcg duel", b"overlay clippy animate", b"overlay clippy border on", b"overlay clippy border off", diff --git a/crates/renderer/src/overlay/clippy.rs b/crates/renderer/src/overlay/clippy.rs index 741f3bb..13c53e2 100644 --- a/crates/renderer/src/overlay/clippy.rs +++ b/crates/renderer/src/overlay/clippy.rs @@ -579,21 +579,18 @@ impl overlay::Overlay for Overlay { Ok(()) } fn render(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State) -> Erm<()> { - if st.tick % 60 == 0 { - log::info!("drawing clippy"); - } - st.bind_2d(ctx, &ost.assets.shader_acs); - let w = 3.0 * self.acs.character_info.width as f32; - let h = 3.0 * self.acs.character_info.height as f32; - ost.assets.shader_acs.set_position_2d_helper(ctx, st, - &(st.render_dims - glam::Vec2::new(w, h)), - &glam::Vec2::new(w, h), - // &glam::Quat::from_rotation_z(st.tick as f32 / 100.0), - &glam::Quat::IDENTITY, - ); - self.tex.bind(ctx); - st.mesh_square.render(ctx); if self.border { + st.bind_2d(ctx, &ost.assets.shader_acs); + let w = 3.0 * self.acs.character_info.width as f32; + let h = 3.0 * self.acs.character_info.height as f32; + ost.assets.shader_acs.set_position_2d_helper(ctx, st, + &(st.render_dims - glam::Vec2::new(w, h)), + &glam::Vec2::new(w, h), + // &glam::Quat::from_rotation_z(st.tick as f32 / 100.0), + &glam::Quat::IDENTITY, + ); + self.tex.bind(ctx); + st.mesh_square.render(ctx); st.bind_2d(ctx, &ost.assets.shader_flat); ost.assets.shader_flat.set_position_2d_helper(ctx, st, &glam::Vec2::new(1590.0, 541.0), diff --git a/crates/renderer/src/overlay/combo.rs b/crates/renderer/src/overlay/combo.rs index bf415a5..03f02ad 100644 --- a/crates/renderer/src/overlay/combo.rs +++ b/crates/renderer/src/overlay/combo.rs @@ -165,7 +165,7 @@ impl overlay::Overlay for Overlay { glam::Vec2::new(4.0, tagy), &format!("+ {t} (x{count})"), font::BitmapParams { - color: &[glam::Vec3::new(1.0, 1.0, 1.0)], + color: &[glam::Vec4::new(1.0, 1.0, 1.0, 1.0)], scale: glam::Vec2::new(2.0, 2.0), offset: glam::Vec2::ZERO, }, @@ -179,7 +179,7 @@ impl overlay::Overlay for Overlay { glam::Vec2::new(4.0, HEIGHT as f32 - 50.0), &format!("MULT:"), font::BitmapParams { - color: &[glam::Vec3::new(1.0, 1.0, 1.0)], + color: &[glam::Vec4::new(1.0, 1.0, 1.0, 1.0)], scale: glam::Vec2::new(4.0, 4.0), offset: glam::Vec2::ZERO, }, @@ -189,7 +189,7 @@ impl overlay::Overlay for Overlay { glam::Vec2::new(128.0, HEIGHT as f32 - 50.0), &format!("{}x", self.tag_multiplier()), font::BitmapParams { - color: &[glam::Vec3::new(1.0, 0.7, 0.0)], + color: &[glam::Vec4::new(1.0, 0.7, 0.0, 1.0)], scale: glam::Vec2::new(4.0, 4.0), offset: glam::Vec2::ZERO, }, diff --git a/crates/renderer/src/overlay/duel.rs b/crates/renderer/src/overlay/duel.rs new file mode 100644 index 0000000..4f90062 --- /dev/null +++ b/crates/renderer/src/overlay/duel.rs @@ -0,0 +1,158 @@ +use teleia::*; + +use crate::overlay; +use crate::overlay::tcg; + +use std::{collections::VecDeque, io::Read}; +use byteorder::{LE, ReadBytesExt}; + +const DUEL_DURATION: u64 = 5 * 60; +const FLIP_START: u64 = 60; +const FLIP_END: u64 = 90; + +fn read_length_prefixed(r: &mut impl Read) -> Erm> { + let len = r.read_u32::()?; + let mut bytes = vec![0; len as usize]; + r.read_exact(&mut bytes)?; + Ok(bytes) +} + +fn extract_meta(png: &[u8]) -> Erm> { + let cursor = std::io::Cursor::new(png); + let decoder = png::Decoder::new(cursor); + let mut reader = decoder.read_info()?; + let mut buf = vec![0; reader.output_buffer_size().unwrap()]; + while let Ok(f) = reader.next_frame(&mut buf) {} + reader.finish()?; + for tc in reader.info().uncompressed_latin1_text.iter() { + if tc.keyword == "lcolonqtcg" { + let (sig, meta) = if let Some(suffix) = tc.text.strip_prefix("+SIGNED+") { + suffix.split_once("+").unwrap_or(("", suffix)) + } else { + ("", &*tc.text) + }; + return Ok(Some(tcg::Card::parse(meta)?)); + } + } + Ok(None) +} + +fn render_card_texture( + ctx: &context::Context, st: &state::State, + ost: &overlay::State, + t: &texture::Texture, + pos: Mat4 +) { + st.bind_3d(ctx, &ost.assets.shader_tcg_screen); + ost.assets.shader_tcg_screen.set_i32(ctx, "texture_front", 0); + ost.assets.shader_tcg_screen.set_i32(ctx, "texture_back", 1); + t.bind(ctx); + ost.assets.texture_cardback.bind_index(ctx, 1); + ost.assets.shader_tcg_screen.set_position_3d(ctx, st, &pos); + st.mesh_square.render(ctx); +} + +pub struct Duel { + duelist1: String, + duelist2: String, + png1: Vec, + png2: Vec, + meta1: Option, + meta2: Option, +} + +pub struct Overlay { + current: Option<(Duel, u64)>, + queue: VecDeque, + card1: texture::Texture, + card2: texture::Texture, +} +impl Overlay { + pub fn new(ctx: &context::Context) -> Self { + Self { + current: None, + queue: VecDeque::new(), + card1: texture::Texture::new_empty(ctx), + card2: texture::Texture::new_empty(ctx), + } + } +} +impl overlay::Overlay for Overlay { + fn handle_binary(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State, msg: &net::fig::BinaryMessage) -> Erm<()> { + #[allow(clippy::single_match)] + match &*msg.event { + b"overlay tcg duel" => { + let mut reader = std::io::Cursor::new(&msg.data); + let duelist1 = String::from_utf8(read_length_prefixed(&mut reader)?)?; + let duelist2 = String::from_utf8(read_length_prefixed(&mut reader)?)?; + let png1 = read_length_prefixed(&mut reader)?; + let png2 = read_length_prefixed(&mut reader)?; + let meta1 = extract_meta(&png1)?; + let meta2 = extract_meta(&png2)?; + self.queue.push_back(Duel { duelist1, duelist2, png1, png2, meta1, meta2 }); + }, + _ => {}, + } + Ok(()) + } + fn update(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State) -> Erm<()> { + if let Some((_, start)) = &self.current { + let elapsed = st.tick - start; + if elapsed > DUEL_DURATION { + self.current = None; + } + } else if let Some(d) = self.queue.pop_front() { + self.card1.upload(ctx, &d.png1); + self.card2.upload(ctx, &d.png2); + self.current = Some((d, st.tick)); + } + Ok(()) + } + fn render(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State) -> Erm<()> { + if let Some((d, start)) = &self.current { + let elapsed = st.tick - start; + let card_scale = glam::Vec3::new(0.7111, 1.0, 1.0); + let card_rotation = glam::Quat::from_rotation_y( + if elapsed < FLIP_START { 0.0 } + else if elapsed < FLIP_END { + utils::lerp(0.0, std::f32::consts::PI, + (elapsed - FLIP_START) as f32 / (FLIP_END - FLIP_START) as f32 + ) + } + else { std::f32::consts::PI } + ); + render_card_texture(ctx, st, ost, &self.card1, + glam::Mat4::from_scale_rotation_translation( + card_scale, + card_rotation, + glam::Vec3::new(3.0, 1.9, -8.0) + ) + ); + render_card_texture(ctx, st, ost, &self.card2, + glam::Mat4::from_scale_rotation_translation( + card_scale, + card_rotation, + glam::Vec3::new(-3.0, 1.9, -8.0) + ) + ); + let mut names_pos = glam::Vec2::new(0.0, 80.0); + let names = format!("{} vs {}", d.duelist1, d.duelist2); + let scale = 8.0; + let width = names.len() as f32 * st.font_default.char_width as f32 * scale; + names_pos += glam::Vec2::new( + st.render_dims.x / 2.0 - width / 2.0, + 0.0, + ); + st.font_default.render_text_at(ctx, st, + names_pos, + &names, + font::BitmapParams { + color: &[glam::Vec4::new(1.0, 1.0, 1.0, 1.0)], + scale: glam::Vec2::new(scale, scale), + offset: glam::Vec2::ZERO, + }, + ); + } + Ok(()) + } +} diff --git a/crates/renderer/src/overlay/tcg.rs b/crates/renderer/src/overlay/tcg.rs index e6cc34a..e550f45 100644 --- a/crates/renderer/src/overlay/tcg.rs +++ b/crates/renderer/src/overlay/tcg.rs @@ -30,25 +30,75 @@ impl std::fmt::Display for Error { impl std::error::Error for Error {} #[derive(Debug, Clone)] -struct Card { - frames: u32, encoded: String, - owner: String, owner_id: String, - name: String, - ty: String, - depicted_subject: String, - element: String, - color: glam::Vec4, - faction: String, - faction_color: glam::Vec4, - equity: i64, - boost_level: String, - rarity: String, - rarity_level: i64, - body_text: String, - base_image_name: String, - set: String, - minted_date: String, - flags: String, +pub struct Card { + pub frames: u32, pub encoded: String, + pub owner: String, pub owner_id: String, + pub name: String, + pub ty: String, + pub depicted_subject: String, + pub element: String, + pub color: glam::Vec4, + pub faction: String, + pub faction_color: glam::Vec4, + pub equity: i64, + pub boost_level: String, + pub rarity: String, + pub rarity_level: i64, + pub body_text: String, + pub base_image_name: String, + pub set: String, + pub minted_date: String, + pub flags: String, +} +impl Card { + pub fn parse(s: &str) -> Erm { + let mut sp = s.split("\t"); + let owner = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let owner_id = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let name = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let ty = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let depicted_subject = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let element = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let color = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let r = i64::from_str_radix(&color[1..=2], 16)?; + let g = i64::from_str_radix(&color[3..=4], 16)?; + let b = i64::from_str_radix(&color[5..=6], 16)?; + let faction = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let faction_color = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let f_r = i64::from_str_radix(&faction_color[1..=2], 16)?; + let f_g = i64::from_str_radix(&faction_color[3..=4], 16)?; + let f_b = i64::from_str_radix(&faction_color[5..=6], 16)?; + let equity = sp.next().ok_or(Error::NotEnoughFields)?.parse()?; + let boost_level = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let rarity = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let rarity_level = sp.next().ok_or(Error::NotEnoughFields)?.parse()?; + let body_text = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let base_image_name = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let set = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let minted_date = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let flags = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); + let card = Card { + frames: 1, encoded: s.to_owned(), + owner, + owner_id, + name, + ty, + depicted_subject, + element, + color: glam::Vec4::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, 1.0), + faction, + faction_color: glam::Vec4::new(f_r as f32 / 255.0, f_g as f32 / 255.0, f_b as f32 / 255.0, 1.0), + equity, + boost_level, + rarity, rarity_level, + body_text, + base_image_name, + set, + minted_date, + flags, + }; + Ok(card) + } } struct RenderedCardSlot { @@ -111,7 +161,6 @@ impl RenderedCardSlot { } pub fn render_3d(&self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State, - back: &texture::Texture, progress: f32, pos: glam::Mat4, ) { @@ -120,7 +169,7 @@ impl RenderedCardSlot { ost.assets.shader_tcg_screen.set_i32(ctx, "texture_front", 0); ost.assets.shader_tcg_screen.set_i32(ctx, "texture_back", 1); self.effect_fb.bind_texture(ctx); - back.bind_index(ctx, 1); + ost.assets.texture_cardback.bind_index(ctx, 1); ost.assets.shader_tcg_screen.set_position_3d(ctx, st, &pos); st.mesh_square.render(ctx); } @@ -170,7 +219,7 @@ impl ImageEncoder { } fn write_frame(&mut self, pixels: &[u8]) { if self.frames_left > 0 { - let _ = self.writer.write_image_data(&pixels); + let _ = self.writer.write_image_data(pixels); self.frames_left -= 1; } } @@ -212,16 +261,14 @@ impl MarqueeSlot { } fn render_3d(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State, - back: &texture::Texture, progress: f32, pos: glam::Mat4, ) { - self.card.render_3d(ctx, st, ost, back, progress, pos); + self.card.render_3d(ctx, st, ost, progress, pos); self.write_frame(ctx); } } struct Marquee { - texture_back: texture::Texture, font: font::Bitmap, slots: [MarqueeSlot; CARD_SLOTS], next_slot: usize, @@ -232,7 +279,6 @@ struct Marquee { impl Marquee { pub fn new(ctx: &context::Context) -> Self { Self { - texture_back: texture::Texture::new(ctx, include_bytes!("../assets/textures/tcg/cardback.png")), font: font::Bitmap::from_image(ctx, 6, 12, 96, 72, include_bytes!("../assets/fonts/terminus.png")), slots: std::array::from_fn(|_| MarqueeSlot { card: RenderedCardSlot::new(ctx), @@ -301,7 +347,7 @@ impl Marquee { for s in self.slots.iter_mut() { if let Some(b) = s.encoder.take_if(|e| e.is_finished()).and_then(|enc| enc.finish()) { if let Some(c) = &s.card.card { - let _ = Self::upload_card(ctx, st, ost, &c, &b).expect("failed to upload"); + Self::upload_card(ctx, st, ost, c, &b).expect("failed to upload"); } } } @@ -335,7 +381,7 @@ impl Marquee { (p as u32 % c.frames) as f32 / c.frames as f32 } } else { 1.0 }; - s.render_3d(ctx, st, ost, &self.texture_back, progress, trans); + s.render_3d(ctx, st, ost, progress, trans); if let Some(c) = &s.card.card { let scale = 4.0; let owner_width = c.owner.len() as f32 * self.font.char_width as f32 * scale; @@ -344,7 +390,7 @@ impl Marquee { -200.0 + if s.height_offset { -50.0 } else { 0.0 }), &c.owner, font::BitmapParams { - color: &[glam::Vec3::new(1.0, 1.0, 1.0)], + color: &[glam::Vec4::new(1.0, 1.0, 1.0, 1.0)], scale: glam::Vec2::new(scale, scale), offset: glam::Vec2::ZERO, }, @@ -378,7 +424,7 @@ impl CardRenderer { 0, glow::RGBA, glow::UNSIGNED_BYTE, - Some(&img.as_bytes()), + Some(img.as_bytes()), ); ctx.gl.generate_mipmap(glow::TEXTURE_2D); Ok(()) @@ -413,7 +459,7 @@ impl CardRenderer { if Self::load_texture(&self.texture_art, ctx, st, &format!("/home/llll/src/wasp/assets/avatars/{}.png", card.depicted_subject.to_ascii_lowercase())).is_err() { let _ = Self::load_texture(&self.texture_art, ctx, st, "/home/llll/src/wasp/assets/avatars/jontest.png"); } - st.bind_framebuffer(ctx, &fb); + st.bind_framebuffer(ctx, fb); ctx.clear(); st.bind_2d(ctx, &ost.assets.shader_tcg_base); @@ -425,7 +471,7 @@ impl CardRenderer { // top bar self.draw_rectangle(ctx, st, ost, - card.color.clone(), + card.color, glam::Vec2::new(0.0, 0.0), glam::Vec2::new(WIDTH, 16.0), ); @@ -433,7 +479,7 @@ impl CardRenderer { glam::Vec2::new(8.0, 1.0), &card.name, font::BitmapParams { - color: &[glam::Vec3::new(0.0, 0.0, 0.0)], + color: &[glam::Vec4::new(0.0, 0.0, 0.0, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, } @@ -442,7 +488,7 @@ impl CardRenderer { glam::Vec2::new(WIDTH - 8.0 * card.rarity.len() as f32, 1.0), &card.rarity, font::BitmapParams { - color: &[glam::Vec3::new(0.0, 0.0, 0.0)], + color: &[glam::Vec4::new(0.0, 0.0, 0.0, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, } @@ -497,7 +543,7 @@ impl CardRenderer { boost_pos, &card.boost_level, font::BitmapParams { - color: &[glam::Vec3::new(0.1, 0.1, 0.1)], + color: &[glam::Vec4::new(0.1, 0.1, 0.1, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, }, @@ -506,7 +552,7 @@ impl CardRenderer { boost_pos - glam::Vec2::new(1.0, 1.0), &card.boost_level, font::BitmapParams { - color: &[glam::Vec3::new(0.9, 0.9, 0.9)], + color: &[glam::Vec4::new(0.9, 0.9, 0.9, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, }, @@ -519,7 +565,7 @@ impl CardRenderer { equity_pos + glam::Vec2::new(0.0, 10.0) * i as f32, "$", font::BitmapParams { - color: &[glam::Vec3::new(0.1, 0.1, 0.1)], + color: &[glam::Vec4::new(0.1, 0.1, 0.1, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, }, @@ -536,9 +582,9 @@ impl CardRenderer { let line: String = cs.iter().collect(); self.font.render_text_at(ctx, st, glam::Vec2::new(5.0, 120.0 + 10.0 * i as f32), - &format!("{}", line), + &line, font::BitmapParams { - color: &[glam::Vec3::new(0.2, 0.2, 0.2)], + color: &[glam::Vec4::new(0.2, 0.2, 0.2, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, }, @@ -553,18 +599,18 @@ impl CardRenderer { ); self.font.render_text_at(ctx, st, glam::Vec2::new(1.0, HEIGHT - 15.0), - &format!("{}", card.set), + &card.set, font::BitmapParams { - color: &[glam::Vec3::new(1.0, 1.0, 1.0)], + color: &[glam::Vec4::new(1.0, 1.0, 1.0, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, } ); self.font.render_text_at(ctx, st, glam::Vec2::new(WIDTH - 7.0 * (card.minted_date.len() - 1) as f32, HEIGHT - 15.0), - &format!("{}", card.minted_date), + &card.minted_date, font::BitmapParams { - color: &[glam::Vec3::new(1.0, 1.0, 1.0)], + color: &[glam::Vec4::new(1.0, 1.0, 1.0, 1.0)], scale: glam::Vec2::ONE, offset: glam::Vec2::ZERO, } @@ -598,56 +644,12 @@ impl overlay::Overlay for Overlay { Ok(()) } fn handle_binary(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State, msg: &net::fig::BinaryMessage) -> Erm<()> { + #[allow(clippy::single_match)] match &*msg.event { b"overlay tcg generate" => { let res: Erm<()> = (|| { - let s = std::str::from_utf8(&msg.data)?.to_owned(); - log::info!("msg: {}", s); - let mut sp = s.split("\t"); - let owner = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let owner_id = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let name = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let ty = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let depicted_subject = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let element = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let color = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let r = i64::from_str_radix(&color[1..=2], 16)?; - let g = i64::from_str_radix(&color[3..=4], 16)?; - let b = i64::from_str_radix(&color[5..=6], 16)?; - let faction = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let faction_color = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let f_r = i64::from_str_radix(&faction_color[1..=2], 16)?; - let f_g = i64::from_str_radix(&faction_color[3..=4], 16)?; - let f_b = i64::from_str_radix(&faction_color[5..=6], 16)?; - let equity = sp.next().ok_or(Error::NotEnoughFields)?.parse()?; - let boost_level = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let rarity = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let rarity_level = sp.next().ok_or(Error::NotEnoughFields)?.parse()?; - let body_text = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let base_image_name = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let set = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let minted_date = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let flags = sp.next().ok_or(Error::NotEnoughFields)?.to_owned(); - let card = Card { - frames: 1, encoded: s.clone(), - owner, - owner_id, - name, - ty, - depicted_subject, - element, - color: glam::Vec4::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, 1.0), - faction, - faction_color: glam::Vec4::new(f_r as f32 / 255.0, f_g as f32 / 255.0, f_b as f32 / 255.0, 1.0), - equity, - boost_level, - rarity, rarity_level, - body_text, - base_image_name, - set, - minted_date, - flags, - }; + let s = std::str::from_utf8(&msg.data)?; + let card = Card::parse(s)?; self.marquee.add(ctx, st, ost, &self.renderer, card); Ok(()) })(); diff --git a/crates/renderer/src/terminal.rs b/crates/renderer/src/terminal.rs index 9f7187b..001e87e 100644 --- a/crates/renderer/src/terminal.rs +++ b/crates/renderer/src/terminal.rs @@ -201,11 +201,12 @@ impl Terminal { for col in 0..self.width { let pos = Pos::new(col as _, row as _); let (p, c) = self.get(pos); - colors.push(c); colors.push(c); + let c4 = glam::Vec4::new(c.x, c.y, c.z, 1.0); + colors.push(c4); colors.push(c4); s += &format!("{}{}", p.first, if let Some(snd) = p.second { snd } else { ' ' }); } s += "\n"; - colors.push(glam::Vec3::new(1.0, 1.0, 1.0)); + colors.push(glam::Vec4::new(1.0, 1.0, 1.0, 1.0)); } self.font.render_text_at(ctx, st, *pos, &s, font::BitmapParams { color: &colors, -- cgit v1.3.1