82 lines
2.9 KiB
Rust
82 lines
2.9 KiB
Rust
use crate::color::Color;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
pub const GLYPH_BANK_PALETTE_COUNT_V1: usize = 64;
|
|
pub const GLYPH_BANK_COLORS_PER_PALETTE: usize = 16;
|
|
|
|
/// Standard sizes for square tiles.
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
|
pub enum TileSize {
|
|
/// 8x8 pixels.
|
|
Size8 = 8,
|
|
/// 16x16 pixels.
|
|
Size16 = 16,
|
|
/// 32x32 pixels.
|
|
Size32 = 32,
|
|
}
|
|
|
|
/// A container for graphical assets.
|
|
///
|
|
/// A GlyphBank stores the decoded runtime representation of a glyph-bank asset.
|
|
///
|
|
/// Serialized `assets.pa` payloads keep pixel indices packed as `4bpp` nibbles.
|
|
/// After decode, the runtime expands them to one `u8` palette index per pixel
|
|
/// while preserving the same `0..15` logical range.
|
|
pub struct GlyphBank {
|
|
/// 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,
|
|
|
|
/// Decoded pixel data stored as one palette index per pixel.
|
|
/// Serialized payloads are packed; runtime memory is expanded.
|
|
/// Palette indices are ordinary indices; transparency is resolved through
|
|
/// the RGBA alpha channel of the palette entry.
|
|
pub pixel_indices: Vec<u8>,
|
|
/// Runtime-facing v1 palette table: 64 palettes of 16 RGBA8888 colors each.
|
|
pub palettes: [[Color; GLYPH_BANK_COLORS_PER_PALETTE]; GLYPH_BANK_PALETTE_COUNT_V1],
|
|
}
|
|
|
|
impl GlyphBank {
|
|
/// Creates an empty glyph 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],
|
|
palettes: [[Color::BLACK; GLYPH_BANK_COLORS_PER_PALETTE]; GLYPH_BANK_PALETTE_COUNT_V1],
|
|
}
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
}
|
|
|
|
/// Maps a 4-bit index to a real RGBA8888 Color using the specified palette.
|
|
pub fn resolve_color(&self, palette_id: u8, pixel_index: u8) -> Color {
|
|
self.palettes
|
|
.get(palette_id as usize)
|
|
.and_then(|palette| palette.get(pixel_index as usize))
|
|
.copied()
|
|
.unwrap_or(Color::TRANSPARENT)
|
|
}
|
|
}
|