use crate::{
boot::wait,
blitter::{Bcr, SpriteQuadrant},
scr::VideoFlags,
video_dma::{framebuffers::Framebuffers, spritemem::SpriteMem, VideoDma},
};
#[repr(C)]
pub(crate) struct Blitter;
impl Blitter {
#[inline(always)]
pub fn framebuffers(self, vf: &mut VideoFlags) -> Framebuffers {
vf.remove(VideoFlags::DMA_ENABLE);
vf.insert(VideoFlags::DMA_CPU_TO_VRAM);
write_video_flags(*vf);
Framebuffers
}
#[inline(always)]
pub fn sprite_mem(self, vf: &mut VideoFlags) -> SpriteMem {
vf.remove(VideoFlags::DMA_ENABLE | VideoFlags::DMA_CPU_TO_VRAM);
write_video_flags(*vf);
SpriteMem
}
}
#[inline(always)]
fn write_video_flags(flags: VideoFlags) {
unsafe {
core::ptr::write_volatile(0x2007 as *mut u8, flags.bits());
}
}
pub struct BlitterGuard<'a> {
pub(crate) dma_slot: &'a mut Option<VideoDma>,
pub(crate) video_flags: &'a mut VideoFlags,
#[allow(dead_code)]
pub(crate) inner: Blitter,
}
impl<'a> Drop for BlitterGuard<'a> {
fn drop(&mut self) {
*self.dma_slot = Some(VideoDma::DmaBlit(Blitter));
}
}
impl<'a> BlitterGuard<'a> {
#[inline(always)]
pub fn draw_square(
&mut self,
x: u8,
y: u8,
width: u8,
height: u8,
color: u8,
) {
self.video_flags.insert(VideoFlags::DMA_COLORFILL);
write_video_flags(*self.video_flags);
unsafe {
let bcr = Bcr::new();
bcr.fb_x.write(x);
bcr.fb_y.write(y);
bcr.width.write(width);
bcr.height.write(height);
bcr.color.write(color);
bcr.start.write(1);
}
}
#[inline(always)]
pub fn draw_sprite(
&mut self,
sx: u8,
sy: u8,
fb_x: u8,
fb_y: u8,
width: u8,
height: u8,
) {
self.video_flags.remove(VideoFlags::DMA_COLORFILL);
write_video_flags(*self.video_flags);
unsafe {
let bcr = Bcr::new();
bcr.vram_x.write(sx);
bcr.vram_y.write(sy);
bcr.fb_x.write(fb_x);
bcr.fb_y.write(fb_y);
bcr.width.write(width);
bcr.height.write(height);
bcr.start.write(1);
}
}
#[inline(always)]
pub fn set_vram_quad(&mut self, quad: SpriteQuadrant) {
unsafe {
let bcr = &mut *(0x4000 as *mut Bcr);
bcr.vram_x.write(quad.value_gx());
bcr.vram_y.write(quad.value_gy());
bcr.width.write(1);
bcr.height.write(1);
bcr.start.write(1);
bcr.start.write(0);
}
}
#[inline(always)]
pub fn wait_blit(&self) {
unsafe {
wait();
let bcr = Bcr::new();
bcr.start.write(0);
}
}
pub fn bcr(&mut self) -> &mut Bcr {
unsafe { Bcr::new() }
}
#[inline(always)]
pub fn draw_letterbox(&mut self) {
const BLACK: u8 = !0u8; const LETTERBOX_HEIGHT: u8 = 10;
self.draw_square(0, 0, 127, LETTERBOX_HEIGHT, BLACK);
self.wait_blit();
self.draw_square(127, 0, 1, LETTERBOX_HEIGHT, BLACK);
self.wait_blit();
self.draw_square(0, 128 - LETTERBOX_HEIGHT, 127, LETTERBOX_HEIGHT, BLACK);
self.wait_blit();
self.draw_square(127, 128 - LETTERBOX_HEIGHT, 1, LETTERBOX_HEIGHT, BLACK);
self.wait_blit();
self.draw_square(127, LETTERBOX_HEIGHT, 1, 128 - (LETTERBOX_HEIGHT * 2), BLACK);
}
}