76 lines
2.6 KiB
Rust
76 lines
2.6 KiB
Rust
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<u8>,
|
|
/// 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]
|
|
}
|
|
}
|