From a09aa839cb548d9ea1ce2cdd30874054ed9a3a80 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Mon, 15 Jul 2024 17:01:29 +0200 Subject: first visible tiles in light client --- light-client/src/atlas.rs | 154 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 light-client/src/atlas.rs (limited to 'light-client/src/atlas.rs') 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, + items: Vec, + + view_scale: u32, + view_offset: Vec2, + + sprites: Vec, +} + +pub struct DrawItem { + z_order: i32, + src: Rect, + dst: Rect, +} + +impl<'a> SpriteRenderer<'a> { + pub fn init(texture_creator: &'a TextureCreator) -> 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::().unwrap(), + toks.next().unwrap().parse::().unwrap(), + toks.next().unwrap().parse::().unwrap(), + toks.next().unwrap().parse::().unwrap(), + ], + ) + }) + .collect::>(); + + 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::>(); + + 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) { + 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 { + 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 + } +} -- cgit v1.2.3-70-g09d2