use crate::color::Color; /// Standard sizes for square tiles. #[derive(Clone, Copy, Debug, PartialEq)] pub enum TileSize { /// 8x8 pixels. Size8 = 8, /// 16x16 pixels. Size16 = 16, /// 32x32 pixels. Size32 = 32, } /// A container for graphical assets. /// /// A TileBank stores both the raw pixel data (as palette indices) and the /// color palettes themselves. This encapsulates all the information needed /// to render a set of tiles. pub struct TileBank { /// Dimension of each individual tile in the bank. pub tile_size: TileSize, /// Width of the full bank sheet in pixels. pub width: usize, /// Height of the full bank sheet in pixels. pub height: usize, /// Pixel data stored as 4-bit indices (packed into 8-bit values). /// Index 0 is always reserved for transparency. pub pixel_indices: Vec, /// Table of 64 palettes, each containing 16 RGB565 colors, total of 1024 colors for a bank. pub palettes: [[Color; 16]; 64], } impl TileBank { /// Creates an empty tile bank with the specified dimensions. pub fn new(tile_size: TileSize, width: usize, height: usize) -> Self { Self { tile_size, width, height, pixel_indices: vec![0; width * height], // Index 0 = Transparent palettes: [[Color::BLACK; 16]; 64], } } /// Resolves a global tile ID and local pixel coordinates to a palette index. /// tile_id: the tile index in the bank /// local_x, local_y: the pixel position inside the tile (0 to tile_size-1) pub fn get_pixel_index(&self, tile_id: u16, local_x: usize, local_y: usize) -> u8 { let size = self.tile_size as usize; let tiles_per_row = self.width / size; let tile_x = (tile_id as usize % tiles_per_row) * size; let tile_y = (tile_id as usize / tiles_per_row) * size; let pixel_x = tile_x + local_x; let pixel_y = tile_y + local_y; if pixel_x < self.width && pixel_y < self.height { self.pixel_indices[pixel_y * self.width + pixel_x] } else { 0 // Default to transparent if out of bounds } } /// Maps a 4-bit index to a real RGB565 Color using the specified palette. pub fn resolve_color(&self, palette_id: u8, pixel_index: u8) -> Color { // Hardware Rule: Index 0 is always transparent. // We use Magenta as the 'transparent' signal color during composition. if pixel_index == 0 { return Color::COLOR_KEY; } self.palettes[palette_id as usize][pixel_index as usize] } }