mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 08:41:34 +11:00
allow direct access to screen
This commit is contained in:
parent
1541d514c9
commit
ec0d4431ad
|
@ -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]) {
|
||||
|
|
Loading…
Reference in a new issue