use crate::{display::tiled::TileSet, dma, interrupt::VBlank, memory_mapped::MemoryMapped};
use alloc::{borrow::Cow, boxed::Box};
use bilge::prelude::*;
use tiled::{BackgroundFrame, DisplayControlRegister, VRAM_MANAGER};
use object::{Oam, OamFrame, initilise_oam};
pub use colours::{Rgb, Rgb15, include_colours};
pub use palette16::Palette16;
pub(crate) mod bitmap3;
mod colours;
pub mod object;
mod palette16;
pub mod tile_data;
pub mod tiled;
pub mod utils;
mod affine;
pub use affine::AffineMatrix;
mod blend;
mod window;
pub mod font;
const DISPLAY_CONTROL: MemoryMapped<DisplayControlRegister> =
unsafe { MemoryMapped::new(0x0400_0000) };
pub(crate) const DISPLAY_STATUS: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0004) };
const VCOUNT: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0006) };
pub use blend::{Blend, BlendAlphaEffect, BlendFadeEffect, BlendObjectTransparency, Layer};
pub use window::{MovableWindow, WinIn, Window, Windows};
pub const WIDTH: i32 = 240;
pub const HEIGHT: i32 = 160;
#[non_exhaustive]
pub struct GraphicsDist;
impl GraphicsDist {
pub fn get(&mut self) -> Graphics<'_> {
unsafe { initilise_oam() };
Graphics::new(Oam::new(), VBlank::get())
}
}
pub struct Graphics<'gba> {
oam: Oam<'gba>,
others: Others,
}
pub(crate) trait DmaFrame {
fn commit(&mut self);
fn cleanup(&mut self);
}
struct Others {
vblank: VBlank,
dma: Option<Box<dyn DmaFrame>>,
}
impl<'gba> Graphics<'gba> {
fn new(oam: Oam<'gba>, vblank: VBlank) -> Self {
Self {
oam,
others: Others { vblank, dma: None },
}
}
pub fn frame(&mut self) -> GraphicsFrame<'_> {
GraphicsFrame {
oam_frame: self.oam.frame(),
bg_frame: BackgroundFrame::default(),
blend: Blend::new(),
windows: Windows::new(),
next_dma: None,
others: &mut self.others,
background_palette: Cow::Borrowed(VRAM_MANAGER.vram_background_palette()),
}
}
pub fn set_background_palettes(&mut self, palettes: &[Palette16]) {
VRAM_MANAGER.set_background_palettes(palettes);
}
pub fn set_background_palette_colour(
&mut self,
pal_index: usize,
colour_index: usize,
colour: Rgb15,
) {
VRAM_MANAGER.set_background_palette_colour(pal_index, colour_index, colour);
}
pub fn set_background_palette_colour_256(&mut self, colour_index: usize, colour: Rgb15) {
assert!(colour_index < 256);
self.set_background_palette_colour(colour_index / 16, colour_index % 16, colour);
}
#[must_use]
pub fn find_colour_index_16(&self, palette_index: usize, colour: Rgb15) -> Option<usize> {
VRAM_MANAGER.find_colour_index_16(palette_index, colour)
}
pub fn set_background_palette(&self, pal_index: u8, palette: &Palette16) {
VRAM_MANAGER.set_background_palette(pal_index, palette);
}
#[must_use]
pub fn find_colour_index_256(&self, colour: Rgb15) -> Option<usize> {
for i in 0..16 {
if let Some(index) = self.find_colour_index_16(i, colour) {
return Some(i * 16 + index);
}
}
None
}
pub fn replace_tile(
&self,
source_tile_set: &TileSet,
source_tile: u16,
target_tile_set: &TileSet,
target_tile: u16,
) {
VRAM_MANAGER.replace_tile(source_tile_set, source_tile, target_tile_set, target_tile);
}
pub fn replace_tile_affine(
&self,
source_tile_set: &TileSet,
source_tile: u16,
target_tile_set: &TileSet,
target_tile: u16,
) {
VRAM_MANAGER.replace_tile_affine(
source_tile_set,
source_tile,
target_tile_set,
target_tile,
);
}
}
pub struct GraphicsFrame<'frame> {
pub(crate) oam_frame: OamFrame<'frame>,
pub(crate) bg_frame: BackgroundFrame,
blend: Blend,
windows: Windows,
next_dma: Option<Box<dyn DmaFrame>>,
others: &'frame mut Others,
background_palette: Cow<'static, [Palette16]>,
}
impl GraphicsFrame<'_> {
pub fn commit(mut self) {
#[cfg(not(feature = "embassy"))]
self.others.vblank.wait_for_vblank();
core::mem::swap(&mut self.others.dma, &mut self.next_dma);
if let Some(mut old) = self.next_dma.take() {
old.cleanup();
}
self.oam_frame.commit();
self.bg_frame.commit();
self.blend.commit();
self.windows.commit();
if let Some(dma) = self.others.dma.as_mut() {
dma.commit();
}
if let Cow::Owned(background) = self.background_palette {
VRAM_MANAGER.set_background_palettes(&background);
}
VRAM_MANAGER.gc();
}
pub fn set_background_palette(&mut self, pal_index: u8, palette: &Palette16) {
self.background_palette.to_mut()[pal_index as usize] = palette.clone();
}
pub fn set_background_palettes(&mut self, palettes: &[Palette16]) {
self.background_palette.to_mut()[..palettes.len()].clone_from_slice(palettes);
}
#[must_use]
pub fn background_palette_colour_dma(
&self,
pal_index: usize,
colour_index: usize,
) -> dma::DmaControllable<Rgb15> {
VRAM_MANAGER.background_palette_colour_dma(pal_index, colour_index)
}
#[must_use]
pub fn background_palette_colour_256_dma(
&self,
colour_index: usize,
) -> dma::DmaControllable<Rgb15> {
assert!(colour_index < 256);
self.background_palette_colour_dma(colour_index / 16, colour_index % 16)
}
pub fn set_background_palette_colour(
&mut self,
pal_index: usize,
colour_index: usize,
colour: Rgb15,
) {
self.background_palette.to_mut()[pal_index].update_colour(colour_index, colour);
}
pub fn set_background_palette_colour_256(&mut self, colour_index: usize, colour: Rgb15) {
assert!(colour_index < 256);
self.set_background_palette_colour(colour_index / 16, colour_index % 16, colour);
}
#[must_use]
pub fn find_colour_index_16(&self, palette_index: usize, colour: Rgb15) -> Option<usize> {
self.background_palette[palette_index]
.colours
.iter()
.position(|&c| c == colour)
}
#[must_use]
pub fn find_colour_index_256(&self, colour: Rgb15) -> Option<usize> {
for i in 0..16 {
if let Some(index) = self.find_colour_index_16(i, colour) {
return Some(i * 16 + index);
}
}
None
}
pub fn blend(&mut self) -> &mut Blend {
&mut self.blend
}
pub fn windows(&mut self) -> &mut Windows {
&mut self.windows
}
pub(crate) fn add_dma<C: DmaFrame + 'static>(&mut self, c: C) {
self.next_dma = Some(Box::new(c));
}
}
pub fn busy_wait_for_vblank() {
while VCOUNT.get() >= 160 {}
while VCOUNT.get() < 160 {}
}
#[bitsize(2)]
#[allow(missing_docs)]
#[derive(FromBits, PartialEq, Eq, Clone, Copy, Debug, Default)]
pub enum Priority {
#[default]
P0 = 0,
P1 = 1,
P2 = 2,
P3 = 3,
}