allow direct access to screen

This commit is contained in:
Corwin Kuiper 2021-10-24 20:41:21 +01:00
parent 1541d514c9
commit ec0d4431ad

View file

@ -82,14 +82,11 @@ impl<'a> MapStorage<'a> {
/// assigned block depending on given coordinates.
#[allow(dead_code)]
pub struct BackgroundRegular<'a> {
background: u8,
block: u8,
register: BackgroundRegister,
commited_position: Vector2D<i32>,
shadowed_position: Vector2D<i32>,
poisoned: bool,
shadowed_register: u16,
copy_size: Vector2D<u16>,
background_size: BackgroundSize,
map: Option<Map<'a>>,
}
@ -129,29 +126,31 @@ impl<'a> Map<'a> {
}
}
impl<'a, 'b> BackgroundRegular<'a> {
unsafe fn new(background: u8, block: u8, size: BackgroundSize) -> BackgroundRegular<'a> {
let mut b = BackgroundRegular {
pub struct BackgroundRegister {
background: u8,
block: u8,
background_size: BackgroundSize,
shadowed_register: u16,
}
impl<'a> BackgroundRegister {
unsafe fn new(background: u8, block: u8, background_size: BackgroundSize) -> Self {
let mut b = Self {
background,
block,
commited_position: (0, 0).into(),
shadowed_position: (0, 0).into(),
background_size,
shadowed_register: 0,
copy_size: (30_u16, 20_u16).into(),
background_size: size,
poisoned: true,
map: None,
};
b.set_block(block);
b.set_colour_mode(ColourMode::FourBitPerPixel);
b.set_background_size(size);
b.set_background_size(background_size);
b.write_register();
b
}
/// Sets the background to be shown on screen. Requires the background to
/// have a map enabled otherwise a panic is caused.
pub fn show(&mut self) {
assert!(self.map.is_some());
let mode = DISPLAY_CONTROL.get();
let new_mode = mode | (1 << (self.background + 0x08));
DISPLAY_CONTROL.set(new_mode);
@ -164,12 +163,20 @@ impl<'a, 'b> BackgroundRegular<'a> {
DISPLAY_CONTROL.set(new_mode);
}
pub fn set_priority(&mut self, p: Priority) {
unsafe { self.set_shadowed_register_bits(p as u16, 0x2, 0x0) };
}
unsafe fn set_shadowed_register_bits(&mut self, value: u16, length: u16, shift: u16) {
let mask = !(((1 << length) - 1) << shift);
let new = (self.shadowed_register & mask) | (value << shift);
self.shadowed_register = new;
}
pub fn write_register(&self) {
unsafe { self.get_register().set(self.shadowed_register) };
}
unsafe fn get_register(&self) -> MemoryMapped<u16> {
MemoryMapped::new(0x0400_0008 + 2 * self.background as usize)
}
@ -182,10 +189,6 @@ impl<'a, 'b> BackgroundRegular<'a> {
self.set_shadowed_register_bits(mode as u16, 0x1, 0x7);
}
pub fn set_priority(&mut self, p: Priority) {
unsafe { self.set_shadowed_register_bits(p as u16, 0x2, 0x0) };
}
unsafe fn set_background_size(&mut self, size: BackgroundSize) {
self.set_shadowed_register_bits(size as u16, 0x2, 0xE);
}
@ -197,6 +200,61 @@ impl<'a, 'b> BackgroundRegular<'a> {
*((0x0400_0012 + 4 * self.background as usize) as *mut u16) = y
}
pub fn set_position(&self, position: Vector2D<i32>) {
unsafe {
self.set_position_x_register((position.x % (32 * 8)) as u16);
self.set_position_y_register((position.y % (32 * 8)) as u16);
}
}
pub fn get_block(&mut self) -> &mut [[u16; 32]; 32] {
unsafe { &mut (*MAP)[self.block as usize] }
}
pub fn clear_partial(&'a mut self, tile: u16) -> impl Iterator<Item = ()> + 'a {
self.get_block()
.iter_mut()
.flatten()
.map(move |t| unsafe { (t as *mut u16).write_volatile(tile) })
}
pub fn clear(&mut self, tile: u16) {
self.clear_partial(tile).count();
}
}
impl<'a, 'b> BackgroundRegular<'a> {
unsafe fn new(
background: u8,
block: u8,
background_size: BackgroundSize,
) -> BackgroundRegular<'a> {
BackgroundRegular {
register: BackgroundRegister::new(background, block, background_size),
commited_position: (0, 0).into(),
shadowed_position: (0, 0).into(),
copy_size: (30_u16, 20_u16).into(),
poisoned: true,
map: None,
}
}
/// Sets the background to be shown on screen. Requires the background to
/// have a map enabled otherwise a panic is caused.
pub fn show(&mut self) {
assert!(self.map.is_some());
self.register.show();
}
/// Hides the background, nothing from this background is rendered to screen.
pub fn hide(&mut self) {
self.register.hide();
}
pub fn set_priority(&mut self, p: Priority) {
self.register.set_priority(p);
}
pub fn set_position(&mut self, position: Vector2D<i32>) {
self.shadowed_position = position;
}
@ -213,7 +271,7 @@ impl<'a, 'b> BackgroundRegular<'a> {
pub fn commit_partial(&'b mut self) -> impl Iterator<Item = ()> + 'b {
// commit shadowed register
unsafe { self.get_register().set(self.shadowed_register) };
self.register.write_register();
let map = self.map.as_ref().unwrap();
@ -237,11 +295,11 @@ impl<'a, 'b> BackgroundRegular<'a> {
let new_y = if top_bottom_height < 0 {
commited_block.y + self.copy_size.y as i32
} else {
shadowed_block.y
shadowed_block.y - 1
};
Rect::new(
(shadowed_block.x, new_y).into(),
(30, top_bottom_height.abs()).into(),
(shadowed_block.x - 1, new_y).into(),
(32, top_bottom_height.abs()).into(),
)
};
@ -250,11 +308,11 @@ impl<'a, 'b> BackgroundRegular<'a> {
let new_x = if left_right_width < 0 {
commited_block.x + self.copy_size.x as i32
} else {
shadowed_block.x
shadowed_block.x - 1
};
Rect::new(
(new_x, shadowed_block.y).into(),
(left_right_width.abs(), 20).into(),
(new_x, shadowed_block.y - 1).into(),
(left_right_width.abs(), 22).into(),
)
};
@ -269,17 +327,10 @@ impl<'a, 'b> BackgroundRegular<'a> {
// update position in registers
unsafe {
self.set_position_x_register((self.commited_position.x % (32 * 8)) as u16);
self.set_position_y_register((self.commited_position.y % (32 * 8)) as u16);
}
let block = self.block;
iter.map(move |(x, y)| unsafe {
(&mut (*MAP)[block as usize][y.rem_euclid(32) as usize][x.rem_euclid(32) as usize]
as *mut u16)
.write_volatile(map.get_position(x, y));
self.register.set_position(self.commited_position);
let block = self.register.get_block();
iter.map(move |(x, y)| {
block[y.rem_euclid(32) as usize][x.rem_euclid(32) as usize] = map.get_position(x, y)
})
}
@ -373,6 +424,41 @@ impl<'b> BackgroundDistributor {
Ok(unsafe { BackgroundRegular::new(background, availiable_block, BackgroundSize::S32x32) })
}
pub fn get_raw_regular(&mut self) -> Result<BackgroundRegister, &'static str> {
let new_mode = decide_background_mode(self.num_regular + 1, self.num_affine)
.ok_or("there is no mode compatible with the requested backgrounds")?;
unsafe { set_graphics_mode(new_mode) };
if !self.used_blocks == 0 {
return Err("all blocks are used");
}
let mut availiable_block = u8::MAX;
for i in 0..32 {
if (1 << i) & self.used_blocks == 0 {
availiable_block = i;
break;
}
}
assert!(
availiable_block != u8::MAX,
"should be able to find a block"
);
self.used_blocks |= 1 << availiable_block;
let background = self.num_regular;
self.num_regular += 1;
Ok(
unsafe {
BackgroundRegister::new(background, availiable_block, BackgroundSize::S32x32)
},
)
}
/// Copies tiles to tilemap starting at the starting tile. Cannot overwrite
/// blocks that are already written to, panic is caused if this is attempted.
pub fn set_background_tilemap(&mut self, start_tile: u32, tiles: &[u32]) {