use std::collections::HashMap; use log::info; use skia_safe::{ canvas::SrcRectConstraint, Canvas, Color4f, ColorSpace, ISize, Image, Matrix, Paint, Rect, }; use twclient::world::{ helper::Color, map::{format, TILE_NUM}, World, }; pub struct MapRenderer { tileset: HashMap<(Option, Color), Image>, } const TILE_SIZE: f32 = 32.0; impl MapRenderer { pub fn new() -> Self { Self { tileset: HashMap::new(), } } pub fn tick(&mut self) {} pub fn map_changed(&mut self, world: &World) { self.tileset.clear(); for (key, t) in &world.map.tilesets { for layer in world.map.layers.iter().filter(|l| l.image == *key) { let tint = layer.color; let mut bytes: Vec = Vec::with_capacity(t.dim().0 * t.dim().1 * 4); info!( "loading tileset: (texture: {:?}, tint: {}) => {:?}", key, tint, t.dim() ); for ((_x, _y), c) in t.indexed_iter() { bytes.push((c.r as u32 * tint.r as u32) as u8); bytes.push((c.g as u32 * tint.g as u32) as u8); bytes.push((c.b as u32 * tint.b as u32) as u8); bytes.push((c.a as u32 * tint.a as u32) as u8); } let d = skia_safe::Data::new_copy(&bytes); let v = skia_safe::Image::from_raster_data( &skia_safe::ImageInfo::new( ISize::new(t.dim().0 as i32, t.dim().1 as i32), skia_safe::ColorType::RGBA8888, skia_safe::AlphaType::Premul, ColorSpace::new_srgb_linear(), ), d, t.dim().0 * 4, ) .unwrap(); self.tileset.insert((*key, tint), v); } } } pub fn draw(&mut self, world: &World, canvas: &mut Canvas) { let rot90 = Matrix::rotate_deg(90.0); let mut grid_paint = Paint::new( Color4f { a: 1.0, r: 1.0, g: 1.0, b: 1.0, }, &ColorSpace::new_srgb(), ); grid_paint.set_style(skia_safe::PaintStyle::Stroke); grid_paint.set_anti_alias(true); let center = world .tees .local() .map(|t| (t.x / 32, t.y / 32)) .unwrap_or((0, 0)); for l in &world.map.layers { let tileset = self.tileset.get(&(l.image, l.color)).unwrap(); let mut layer_tint = Paint::new( Color4f { a: 1.0, b: 1.0, g: 1.0, r: 1.0, }, &ColorSpace::new_srgb(), ); layer_tint.set_style(skia_safe::PaintStyle::Fill); for layer_y in (center.1 - 15)..(center.1 + 15) { for layer_x in (center.0 - 15)..(center.0 + 15) { let layer_x = layer_x.try_into().unwrap_or(0); let layer_y = layer_y.try_into().unwrap_or(0); let tile = match l.tiles.get((layer_y, layer_x)) { Some(t) => t, None => continue, }; let rotate = tile.flags & format::TILEFLAG_ROTATE != 0; let vflip = tile.flags & format::TILEFLAG_VFLIP != 0; let hflip = tile.flags & format::TILEFLAG_HFLIP != 0; let tile_x = tile.index as u32 % TILE_NUM; let tile_y = tile.index as u32 / TILE_NUM; if tile_x == 0 && tile_y == 0 { continue; } canvas.save(); canvas.translate(( (layer_x as f32 + 0.5) * TILE_SIZE, (layer_y as f32 + 0.5) * TILE_SIZE, )); if rotate { canvas.concat(&rot90); } if vflip { canvas.scale((-1.0, 1.0)); } if hflip { canvas.scale((1.0, -1.0)); } const TL: u32 = 64; canvas.draw_image_rect( tileset, Some(( &Rect { top: (tile_y * TL) as f32, left: (tile_x * TL) as f32, bottom: ((tile_y + 1) * TL) as f32, right: ((tile_x + 1) * TL) as f32, }, SrcRectConstraint::Strict, )), Rect { top: -TILE_SIZE / 2.0, bottom: TILE_SIZE / 2.0, left: -TILE_SIZE / 2.0, right: TILE_SIZE / 2.0, }, &layer_tint, ); canvas.restore(); } } } } }