diff options
author | metamuffin <metamuffin@disroot.org> | 2024-07-15 17:01:29 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-07-15 17:01:29 +0200 |
commit | a09aa839cb548d9ea1ce2cdd30874054ed9a3a80 (patch) | |
tree | 061cb86d3878f62090dd080eaef1f9db6f9454f7 /light-client/src/atlas.rs | |
parent | e04589e8b766882375a30c00fb715687a7cc9821 (diff) | |
download | hurrycurry-a09aa839cb548d9ea1ce2cdd30874054ed9a3a80.tar hurrycurry-a09aa839cb548d9ea1ce2cdd30874054ed9a3a80.tar.bz2 hurrycurry-a09aa839cb548d9ea1ce2cdd30874054ed9a3a80.tar.zst |
first visible tiles in light client
Diffstat (limited to 'light-client/src/atlas.rs')
-rw-r--r-- | light-client/src/atlas.rs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/light-client/src/atlas.rs b/light-client/src/atlas.rs new file mode 100644 index 00000000..e75430c5 --- /dev/null +++ b/light-client/src/atlas.rs @@ -0,0 +1,154 @@ +use hurrycurry_protocol::{ + glam::{IVec2, Vec2}, + ClientGamedata, ItemIndex, TileIndex, +}; +use sdl2::{ + pixels::PixelFormatEnum, + rect::Rect, + render::{Canvas, Texture, TextureAccess, TextureCreator}, + video::{Window, WindowContext}, +}; +use std::collections::HashMap; + +pub struct SpriteRenderer<'a> { + texture: Texture<'a>, + + tiles: Vec<Rect>, + items: Vec<Rect>, + + view_scale: u32, + view_offset: Vec2, + + sprites: Vec<DrawItem>, +} + +pub struct DrawItem { + z_order: i32, + src: Rect, + dst: Rect, +} + +impl<'a> SpriteRenderer<'a> { + pub fn init(texture_creator: &'a TextureCreator<WindowContext>) -> Self { + let palette = include_str!("../textures/palette.csv") + .split('\n') + .filter(|l| !l.is_empty()) + .map(|s| { + let mut toks = s.split(","); + ( + toks.next().unwrap().chars().next().unwrap(), + [ + toks.next().unwrap().parse::<u8>().unwrap(), + toks.next().unwrap().parse::<u8>().unwrap(), + toks.next().unwrap().parse::<u8>().unwrap(), + toks.next().unwrap().parse::<u8>().unwrap(), + ], + ) + }) + .collect::<HashMap<_, _>>(); + + let mut texels = vec![255; 1024 * 1024 * 4]; + + for (y, line) in include_str!("../textures/atlas.ta").lines().enumerate() { + if line.is_empty() { + continue; + } + for (x, char) in line.chars().enumerate() { + let color = palette.get(&char).unwrap(); + let base = (y * 1024 + x) * 4; + texels[base..base + 4].copy_from_slice(color); + } + } + + let mut texture = texture_creator + .create_texture( + Some(PixelFormatEnum::RGBA8888), + TextureAccess::Streaming, + 1024, + 1024, + ) + .unwrap(); + + texture.update(None, &texels, 1024 * 4).unwrap(); + + Self { + texture, + items: vec![], + tiles: vec![], + sprites: vec![], + view_offset: Vec2::ZERO, + view_scale: 32, + } + } + + pub fn set_sprite_map(&mut self, data: ClientGamedata) { + let meta = include_str!("../textures/atlas.meta.csv") + .lines() + .filter(|l| !l.is_empty()) + .map(|l| { + let mut toks = l.split(","); + let x: i32 = toks.next().unwrap().parse().unwrap(); + let y: i32 = toks.next().unwrap().parse().unwrap(); + let w: u32 = toks.next().unwrap().parse().unwrap(); + let h: u32 = toks.next().unwrap().parse().unwrap(); + let name = toks.next().unwrap().to_string(); + (name, Rect::new(x, y, w, h)) + }) + .collect::<HashMap<_, _>>(); + + self.items = data + .item_names + .iter() + .map(|i| meta.get(i).copied().unwrap_or(Rect::new(0, 0, 100, 100))) + .collect(); + self.tiles = data + .tile_names + .iter() + .map(|i| meta.get(i).copied().unwrap_or(Rect::new(0, 0, 100, 100))) + .collect(); + } + + pub fn draw_tile(&mut self, TileIndex(i): TileIndex, position: IVec2) { + let p = (self.view_offset.as_ivec2() + position) * self.view_scale as i32; + self.sprites.push(DrawItem { + z_order: position.y, + src: self.tiles[i], + dst: Rect::from_center((p.x as i32, p.y as i32), self.view_scale, self.view_scale), + }); + } + pub fn draw_item(&mut self, ItemIndex(i): ItemIndex, position: Vec2) { + self.sprites.push(DrawItem { + z_order: position.y as i32, + src: self.tiles[i], + dst: Rect::from_center( + (position.x as i32, position.y as i32), + self.view_scale, + self.view_scale, + ), + }) + } + + pub fn submit(&mut self, canvas: &mut Canvas<Window>) { + self.sprites.sort(); + for DrawItem { src, dst, .. } in self.sprites.drain(..) { + canvas.copy(&self.texture, src, dst).unwrap(); + } + } +} + +impl Ord for DrawItem { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.z_order.cmp(&other.z_order) + } +} +impl PartialOrd for DrawItem { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(self.cmp(&other)) + } +} +impl Eq for DrawItem {} +impl PartialEq for DrawItem { + fn eq(&self, other: &Self) -> bool { + self.z_order == other.z_order && self.src == other.src && self.dst == other.dst + } +} |