use bitflags::bitflags;
bitflags! {
#[derive(Default, PartialEq, Eq, Copy, Clone, Debug)]
pub struct Attributes: u8 {
const PALETTE_LOW = 0b00000001;
const PALETTE_HIGH = 0b00000010;
const PRIORITY = 0b00100000;
const FLIP_H = 0b01000000;
const FLIP_V = 0b10000000;
const ALL = Self::PALETTE_LOW.bits() | Self::PALETTE_HIGH.bits() | Self::PRIORITY.bits() | Self::FLIP_H.bits() | Self::FLIP_V.bits();
}
}
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
pub struct TileIndexNumber(u8);
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum SelectedField {
YCoord = 0,
TileNum = 1,
Attributes = 2,
XCoord = 3,
}
#[repr(align(4))]
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
pub struct Entry {
y_coord: u8,
tile_num: TileIndexNumber,
attributes: Attributes,
x_coord: u8,
}
impl From<u8> for SelectedField {
fn from(value: u8) -> Self {
match value & 0x03 {
0 => SelectedField::YCoord,
1 => SelectedField::TileNum,
2 => SelectedField::Attributes,
3 => SelectedField::XCoord,
_ => unreachable!(),
}
}
}
impl From<TileIndexNumber> for u8 {
fn from(value: TileIndexNumber) -> Self {
value.0
}
}
impl From<u8> for TileIndexNumber {
fn from(value: u8) -> Self {
TileIndexNumber(value)
}
}
impl TileIndexNumber {
pub fn pattern_index(&self) -> u8 {
self.0 >> 1
}
pub fn pattern_bank(&self) -> u8 {
self.0 & 0x01
}
}
impl std::fmt::UpperHex for TileIndexNumber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::UpperHex::fmt(&self.0, f)
}
}
impl std::fmt::LowerHex for TileIndexNumber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::LowerHex::fmt(&self.0, f)
}
}
impl std::fmt::Display for TileIndexNumber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[allow(dead_code)]
impl Entry {
fn new() -> Self {
Self::default()
}
pub fn y(&self) -> u8 {
self.y_coord
}
pub fn tile_num(&self) -> TileIndexNumber {
self.tile_num
}
pub fn x(&self) -> u8 {
self.x_coord
}
pub fn attributes(&self) -> Attributes {
self.attributes
}
pub fn set_y(&mut self, y: u8) {
self.y_coord = y;
}
pub fn set_tile_num(&mut self, tile: TileIndexNumber) {
self.tile_num = tile;
}
pub fn set_x(&mut self, x: u8) {
self.x_coord = x;
}
pub fn set_attributes(&mut self, attr: Attributes) {
self.attributes = attr;
}
pub fn with_data(y: u8, tile: u8, attr: Attributes, x: u8) -> Self {
Self {
y_coord: y,
tile_num: tile.into(),
attributes: attr,
x_coord: x,
}
}
pub fn read_field(&self, field: SelectedField) -> u8 {
match field {
SelectedField::YCoord => self.y_coord,
SelectedField::TileNum => self.tile_num.into(),
SelectedField::Attributes => self.attributes.bits(),
SelectedField::XCoord => self.x_coord,
}
}
pub fn write_field(&mut self, field: SelectedField, data: u8) {
match field {
SelectedField::YCoord => self.y_coord = data,
SelectedField::TileNum => self.tile_num = data.into(),
SelectedField::Attributes => self.attributes = Attributes::from_bits_truncate(data),
SelectedField::XCoord => self.x_coord = data,
}
}
pub fn palette_index(&self) -> u8 {
self.attributes.bits() & 0b_0011
}
pub fn vertical_flip_flag(&self) -> bool {
self.attributes.contains(Attributes::FLIP_V)
}
pub fn horizontal_flip_flag(&self) -> bool {
self.attributes.contains(Attributes::FLIP_H)
}
pub fn draw_in_front_flag(&self) -> bool {
!self.attributes.contains(Attributes::PRIORITY)
}
#[cfg(test)]
pub fn set_draw_front(&mut self) {
self.attributes.remove(Attributes::PRIORITY);
}
#[cfg(test)]
pub fn set_palette(&mut self, palette: u8) {
if (palette & 0b_1) != 0 {
self.attributes.insert(Attributes::PALETTE_LOW);
}
if (palette & 0b_10) != 0 {
self.attributes.insert(Attributes::PALETTE_HIGH);
}
}
}