diff --git a/src/io.rs b/src/io.rs index 4248d94..b744a9b 100644 --- a/src/io.rs +++ b/src/io.rs @@ -8,8 +8,6 @@ use super::*; -use gba_proc_macro::register_bit; - pub mod display; pub mod dma; pub mod keypad; diff --git a/src/lib.rs b/src/lib.rs index 193139f..52116e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,8 @@ //! **Do not** use this crate in programs that aren't running on the GBA. If you //! do, it's a giant bag of Undefined Behavior. +pub(crate) use gba_proc_macro::register_bit; + /// Assists in defining a newtype wrapper over some base type. /// /// Note that rustdoc and derives are all the "meta" stuff, so you can write all @@ -64,6 +66,7 @@ pub mod bios; pub mod io; pub mod mgba; pub mod video; +pub mod palram; newtype! { /// A color on the GBA is an RGB 5.5.5 within a `u16` diff --git a/src/palram.rs b/src/palram.rs new file mode 100644 index 0000000..2296cf0 --- /dev/null +++ b/src/palram.rs @@ -0,0 +1,69 @@ +//! Module that allows interacting with `PALRAM`. +//! +//! The `PALRAM` is 256 `Color` values for Background use, and 256 `Color` +//! values for Object use. +//! +//! Each type of `PALRAM` can be viewed as "8 bits per pixel" (8bpp), where +//! there's a single palette of 256 entries. It can also be viewed as "4 bits +//! per pixel" (4bpp), where there's 16 "palbank" entries that each have 16 +//! slots. **Both** interpretations are correct, simultaneously. If you're a +//! real palette wizard you can carefully arrange for some things to use 4bpp +//! mode while other things use 8bpp mode and have it all look good. +//! +//! ## Transparency +//! +//! In 8bpp mode the 0th palette index is "transparent" when used in an image +//! (giving you 255 usable slots). In 4bpp mode the 0th palbank index _of each +//! palbank_ is considered a transparency pixel (giving you 15 usable slots per +//! palbank). +//! +//! ## Clear Color +//! +//! The 0th palette index of the background palette holds the color that the +//! display will show if no background or object draws over top of a given pixel +//! during rendering. + +use super::{ + base::volatile::{VolAddress, VolAddressBlock}, + Color, +}; + +// TODO: PalIndex newtypes? + +/// The `PALRAM` for background colors, 256 slot view. +pub const PALRAM_BG: VolAddressBlock = unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(0x500_0000), 256) }; + +/// The `PALRAM` for object colors, 256 slot view. +pub const PALRAM_OBJ: VolAddressBlock = unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(0x500_0200), 256) }; + +/// Obtains the address of the specified 8bpp background palette slot. +pub fn index_palram_bg_8bpp(slot: u8) -> VolAddress { + // TODO: const this + // Note(Lokathor): because of the `u8` limit we can't go out of bounds here. + unsafe { PALRAM_BG.index_unchecked(slot as usize) } +} + +/// Obtains the address of the specified 8bpp object palette slot. +pub fn index_palram_obj_8bpp(slot: u8) -> VolAddress { + // TODO: const this + // Note(Lokathor): because of the `u8` limit we can't go out of bounds here. + unsafe { PALRAM_OBJ.index_unchecked(slot as usize) } +} + +/// Obtains the address of the specified 4bpp background palbank and slot. +/// +/// If `palbank` or `palslot` are out of bounds they'll wrap around. +pub fn index_palram_bg_4bpp(palbank: u8, palslot: u8) -> VolAddress { + // TODO: const this + // Note(Lokathor): because of the `u8` limit we can't go out of bounds here. + unsafe { PALRAM_BG.index_unchecked(palbank.wrapping_mul(16).wrapping_add(palslot) as usize) } +} + +/// Obtains the address of the specified 4bpp object palbank and slot. +/// +/// If `palbank` or `palslot` are out of bounds they'll wrap around. +pub fn index_palram_obj_4bpp(palbank: u8, palslot: u8) -> VolAddress { + // TODO: const this + // Note(Lokathor): because of the `u8` limit we can't go out of bounds here. + unsafe { PALRAM_OBJ.index_unchecked(palbank.wrapping_mul(16).wrapping_add(palslot) as usize) } +}