summaryrefslogtreecommitdiff
path: root/crates/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'crates/renderer')
-rw-r--r--crates/renderer/src/assets/shaders/tcg_screen/frag.glsl7
-rw-r--r--crates/renderer/src/assets/textures/tcg/cardback.pngbin0 -> 34257 bytes
-rw-r--r--crates/renderer/src/overlay/tcg.rs162
3 files changed, 132 insertions, 37 deletions
diff --git a/crates/renderer/src/assets/shaders/tcg_screen/frag.glsl b/crates/renderer/src/assets/shaders/tcg_screen/frag.glsl
index cb4a58f..43acea3 100644
--- a/crates/renderer/src/assets/shaders/tcg_screen/frag.glsl
+++ b/crates/renderer/src/assets/shaders/tcg_screen/frag.glsl
@@ -1,9 +1,10 @@
-uniform sampler2D texture_data;
+uniform sampler2D texture_front;
+uniform sampler2D texture_back;
void main()
{
- vec2 tcfull = vec2(vertex_texcoord.x, vertex_texcoord.y);
- vec4 texel = texture(texture_data, tcfull);
+ vec2 tcfull = vec2(vertex_texcoord.x, 1.0 - vertex_texcoord.y);
+ vec4 texel = gl_FrontFacing ? texture(texture_back, tcfull) : texture(texture_front, tcfull);
if (texel.a == 0.0) {
discard;
}
diff --git a/crates/renderer/src/assets/textures/tcg/cardback.png b/crates/renderer/src/assets/textures/tcg/cardback.png
new file mode 100644
index 0000000..15cb7c7
--- /dev/null
+++ b/crates/renderer/src/assets/textures/tcg/cardback.png
Binary files differ
diff --git a/crates/renderer/src/overlay/tcg.rs b/crates/renderer/src/overlay/tcg.rs
index 4191e6c..cd19556 100644
--- a/crates/renderer/src/overlay/tcg.rs
+++ b/crates/renderer/src/overlay/tcg.rs
@@ -4,6 +4,8 @@ use glow::HasContext;
use crate::overlay;
+pub const CARD_SLOTS: usize = 11;
+pub const CARD_SPACING: u64 = 300;
pub const IWIDTH: usize = 160;
pub const IHEIGHT: usize = 225;
pub const WIDTH: f32 = IWIDTH as f32;
@@ -81,25 +83,103 @@ impl RenderedCardSlot {
ost.assets.shader_tcg_screen.set_position_2d(ctx, st, &pos, &dim);
st.mesh_square.render(ctx);
}
+ pub fn render_3d(&self,
+ ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State,
+ back: &texture::Texture,
+ pos: glam::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);
+ self.texture.bind(ctx);
+ back.bind_index(ctx, 1);
+ ost.assets.shader_tcg_screen.set_position_3d(ctx, st, &pos);
+ st.mesh_square.render(ctx);
+ }
}
-fn load_texture(tex: &texture::Texture, ctx: &context::Context, st: &mut state::State, path: &str) -> Erm<()> {
- unsafe {
- let img = image::ImageReader::open(path)?.decode()?.into_rgba8();
- tex.bind(ctx);
- ctx.gl.tex_image_2d(
- glow::TEXTURE_2D,
- 0,
- glow::RGBA as i32,
- img.width() as i32,
- img.height() as i32,
- 0,
- glow::RGBA,
- glow::UNSIGNED_BYTE,
- Some(&img.as_bytes()),
- );
- ctx.gl.generate_mipmap(glow::TEXTURE_2D);
- Ok(())
+struct MarqueeSlot {
+ card: RenderedCardSlot,
+ active: Option<u64>, // ticks active
+}
+struct Marquee {
+ texture_back: texture::Texture,
+ slots: [MarqueeSlot; CARD_SLOTS],
+ next_slot: usize,
+ queue: std::collections::VecDeque<(Card, image::RgbaImage)>,
+ most_recent: u64,
+}
+impl Marquee {
+ pub fn new(ctx: &context::Context) -> Self {
+ Self {
+ texture_back: texture::Texture::new(ctx, include_bytes!("../assets/textures/tcg/cardback.png")),
+ slots: std::array::from_fn(|_| MarqueeSlot {
+ card: RenderedCardSlot::new(ctx),
+ active: None,
+ }),
+ next_slot: 0,
+ queue: std::collections::VecDeque::new(),
+ most_recent: 0,
+ }
+ }
+ fn fill_slot(&mut self,
+ ctx: &context::Context, st: &state::State,
+ card: &Card, img: &image::RgbaImage
+ ) -> bool {
+ if st.tick - self.most_recent > CARD_SPACING {
+ for s in self.slots.iter_mut() {
+ if s.active.is_none() {
+ s.card.set(ctx, card.clone(), img);
+ s.active = Some(st.tick);
+ self.most_recent = st.tick;
+ return true;
+ }
+ }
+ }
+ false
+ }
+ pub fn add(&mut self,
+ ctx: &context::Context, st: &state::State,
+ card: Card, img: &image::RgbaImage
+ ) {
+ if !self.fill_slot(ctx, st, &card, img) {
+ self.queue.push_back((card, img.clone()))
+ }
+ }
+ pub fn render(&mut self,
+ ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State,
+ ) {
+ for s in self.slots.iter_mut() {
+ if s.active.is_none() && st.tick - self.most_recent > CARD_SPACING{
+ if let Some((c, img)) = self.queue.pop_front() {
+ s.card.set(ctx, c.clone(), &img);
+ s.active = Some(st.tick);
+ self.most_recent = st.tick;
+ } else {
+ break;
+ }
+ }
+ }
+ for s in self.slots.iter_mut() {
+ if let Some(spawn) = s.active {
+ let p = st.tick - spawn;
+ let pos = (p as f32) / 200.0 - 7.0;
+ if pos > 8.0 {
+ s.active = None;
+ } else {
+ s.card.render_3d(ctx, st, ost,
+ &self.texture_back,
+ glam::Mat4::from_scale_rotation_translation(
+ glam::Vec3::new(0.7111, 1.0, 1.0),
+ glam::Quat::from_rotation_y(p as f32 / 75.0),
+ glam::Vec3::new(pos, -2.0,
+ (p as f32 / 100.0).sin() / 2.0 - 8.0
+ ),
+ )
+ );
+ }
+ }
+ }
}
}
@@ -110,12 +190,30 @@ pub struct Overlay {
texture_faction_nate: texture::Texture,
texture_faction_lever: texture::Texture,
texture_faction_tony: texture::Texture,
- // font: font::TrueType,
font: font::Bitmap,
- card: RenderedCardSlot,
+ marquee: Marquee,
}
-
impl Overlay {
+ fn load_texture(tex: &texture::Texture, ctx: &context::Context, st: &mut state::State, path: &str) -> Erm<()> {
+ unsafe {
+ let img = image::ImageReader::open(path)?.decode()?.into_rgba8();
+ tex.bind(ctx);
+ ctx.gl.tex_image_2d(
+ glow::TEXTURE_2D,
+ 0,
+ glow::RGBA as i32,
+ img.width() as i32,
+ img.height() as i32,
+ 0,
+ glow::RGBA,
+ glow::UNSIGNED_BYTE,
+ Some(&img.as_bytes()),
+ );
+ ctx.gl.generate_mipmap(glow::TEXTURE_2D);
+ Ok(())
+ }
+ }
+
pub fn new(ctx: &context::Context) -> Self {
Self {
fb: framebuffer::Framebuffer::new(ctx, &glam::Vec2::new(WIDTH, HEIGHT), &glam::Vec2::new(0.0, 0.0)),
@@ -124,9 +222,8 @@ impl Overlay {
texture_faction_nate: texture::Texture::new(ctx, include_bytes!("../assets/textures/tcg/factions/nate.png")),
texture_faction_lever: texture::Texture::new(ctx, include_bytes!("../assets/textures/tcg/factions/lever.png")),
texture_faction_tony: texture::Texture::new(ctx, include_bytes!("../assets/textures/tcg/factions/tony.png")),
- // font: font::TrueType::new(ctx, 32.0, include_bytes!("../assets/fonts/iosevka-comfy-regular.ttf")),
font: font::Bitmap::from_image(ctx, 6, 12, 96, 72, include_bytes!("../assets/fonts/terminus.png")),
- card: RenderedCardSlot::new(ctx),
+ marquee: Marquee::new(ctx),
}
}
fn draw_rectangle(&self,
@@ -261,7 +358,8 @@ impl Overlay {
st.bind_render_framebuffer(ctx);
let mut pixels = vec![0; IWIDTH * IHEIGHT * 4];
self.fb.get_pixels_raw(ctx, &mut pixels);
- image::RgbaImage::from_vec(IWIDTH as u32, IHEIGHT as u32, pixels)
+ let pixels_rev = pixels.chunks_exact(IWIDTH * 4).rev().flatten().copied().collect();
+ image::RgbaImage::from_vec(IWIDTH as u32, IHEIGHT as u32, pixels_rev)
}
}
@@ -276,7 +374,6 @@ impl overlay::Overlay for Overlay {
let s = std::str::from_utf8(&msg.data)?.to_owned();
log::info!("msg: {}", s);
let mut sp = s.split("\t");
- let 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();
@@ -299,9 +396,9 @@ impl overlay::Overlay for Overlay {
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();
- load_texture(&self.texture_base, ctx, st, &format!("crates/renderer/src/assets/textures/tcg/bases/{}.png", base_image_name))?;
- if load_texture(&self.texture_art, ctx, st, &format!("/home/llll/src/wasp/assets/avatars/{}.png", depicted_subject.to_ascii_lowercase())).is_err() {
- load_texture(&self.texture_art, ctx, st, "/home/llll/src/wasp/assets/avatars/jontest.png")?;
+ Self::load_texture(&self.texture_base, ctx, st, &format!("crates/renderer/src/assets/textures/tcg/bases/{}.png", base_image_name))?;
+ if Self::load_texture(&self.texture_art, ctx, st, &format!("/home/llll/src/wasp/assets/avatars/{}.png", depicted_subject.to_ascii_lowercase())).is_err() {
+ Self::load_texture(&self.texture_art, ctx, st, "/home/llll/src/wasp/assets/avatars/jontest.png")?;
}
let card = Card {
name,
@@ -321,7 +418,7 @@ impl overlay::Overlay for Overlay {
flags,
};
if let Some(img) = self.generate_card(ctx, st, ost, card.clone()) {
- self.card.set(ctx, card, &img);
+ self.marquee.add(ctx, st, card, &img);
let err: Erm<()> = (||{
let mut buf = Vec::new();
let mut cursor = std::io::Cursor::new(&mut buf);
@@ -346,12 +443,9 @@ impl overlay::Overlay for Overlay {
Ok(())
}
fn render(&mut self, ctx: &context::Context, st: &mut state::State, ost: &mut overlay::State) -> Erm<()> {
- if self.card.card.is_some() {
- self.card.render(ctx, st, ost,
- glam::Vec2::new(1000.0, 400.0),
- glam::Vec2::new(WIDTH * 2.0, HEIGHT * 2.0)
- );
- }
+ st.render_framebuffer.bind(ctx);
+ ctx.clear_depth();
+ self.marquee.render(ctx, st, ost);
Ok(())
}
}