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.
|
/// assigned block depending on given coordinates.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct BackgroundRegular<'a> {
|
pub struct BackgroundRegular<'a> {
|
||||||
background: u8,
|
register: BackgroundRegister,
|
||||||
block: u8,
|
|
||||||
commited_position: Vector2D<i32>,
|
commited_position: Vector2D<i32>,
|
||||||
shadowed_position: Vector2D<i32>,
|
shadowed_position: Vector2D<i32>,
|
||||||
poisoned: bool,
|
poisoned: bool,
|
||||||
shadowed_register: u16,
|
|
||||||
copy_size: Vector2D<u16>,
|
copy_size: Vector2D<u16>,
|
||||||
background_size: BackgroundSize,
|
|
||||||
map: Option<Map<'a>>,
|
map: Option<Map<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,29 +126,31 @@ impl<'a> Map<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> BackgroundRegular<'a> {
|
pub struct BackgroundRegister {
|
||||||
unsafe fn new(background: u8, block: u8, size: BackgroundSize) -> BackgroundRegular<'a> {
|
background: u8,
|
||||||
let mut b = BackgroundRegular {
|
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,
|
background,
|
||||||
block,
|
block,
|
||||||
commited_position: (0, 0).into(),
|
background_size,
|
||||||
shadowed_position: (0, 0).into(),
|
|
||||||
shadowed_register: 0,
|
shadowed_register: 0,
|
||||||
copy_size: (30_u16, 20_u16).into(),
|
|
||||||
background_size: size,
|
|
||||||
poisoned: true,
|
|
||||||
map: None,
|
|
||||||
};
|
};
|
||||||
b.set_block(block);
|
b.set_block(block);
|
||||||
b.set_colour_mode(ColourMode::FourBitPerPixel);
|
b.set_colour_mode(ColourMode::FourBitPerPixel);
|
||||||
b.set_background_size(size);
|
b.set_background_size(background_size);
|
||||||
|
b.write_register();
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the background to be shown on screen. Requires the background to
|
/// Sets the background to be shown on screen. Requires the background to
|
||||||
/// have a map enabled otherwise a panic is caused.
|
/// have a map enabled otherwise a panic is caused.
|
||||||
pub fn show(&mut self) {
|
pub fn show(&mut self) {
|
||||||
assert!(self.map.is_some());
|
|
||||||
let mode = DISPLAY_CONTROL.get();
|
let mode = DISPLAY_CONTROL.get();
|
||||||
let new_mode = mode | (1 << (self.background + 0x08));
|
let new_mode = mode | (1 << (self.background + 0x08));
|
||||||
DISPLAY_CONTROL.set(new_mode);
|
DISPLAY_CONTROL.set(new_mode);
|
||||||
|
@ -164,12 +163,20 @@ impl<'a, 'b> BackgroundRegular<'a> {
|
||||||
DISPLAY_CONTROL.set(new_mode);
|
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) {
|
unsafe fn set_shadowed_register_bits(&mut self, value: u16, length: u16, shift: u16) {
|
||||||
let mask = !(((1 << length) - 1) << shift);
|
let mask = !(((1 << length) - 1) << shift);
|
||||||
let new = (self.shadowed_register & mask) | (value << shift);
|
let new = (self.shadowed_register & mask) | (value << shift);
|
||||||
self.shadowed_register = new;
|
self.shadowed_register = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_register(&self) {
|
||||||
|
unsafe { self.get_register().set(self.shadowed_register) };
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn get_register(&self) -> MemoryMapped<u16> {
|
unsafe fn get_register(&self) -> MemoryMapped<u16> {
|
||||||
MemoryMapped::new(0x0400_0008 + 2 * self.background as usize)
|
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);
|
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) {
|
unsafe fn set_background_size(&mut self, size: BackgroundSize) {
|
||||||
self.set_shadowed_register_bits(size as u16, 0x2, 0xE);
|
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
|
*((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>) {
|
pub fn set_position(&mut self, position: Vector2D<i32>) {
|
||||||
self.shadowed_position = position;
|
self.shadowed_position = position;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +271,7 @@ impl<'a, 'b> BackgroundRegular<'a> {
|
||||||
|
|
||||||
pub fn commit_partial(&'b mut self) -> impl Iterator<Item = ()> + 'b {
|
pub fn commit_partial(&'b mut self) -> impl Iterator<Item = ()> + 'b {
|
||||||
// commit shadowed register
|
// commit shadowed register
|
||||||
unsafe { self.get_register().set(self.shadowed_register) };
|
self.register.write_register();
|
||||||
|
|
||||||
let map = self.map.as_ref().unwrap();
|
let map = self.map.as_ref().unwrap();
|
||||||
|
|
||||||
|
@ -237,11 +295,11 @@ impl<'a, 'b> BackgroundRegular<'a> {
|
||||||
let new_y = if top_bottom_height < 0 {
|
let new_y = if top_bottom_height < 0 {
|
||||||
commited_block.y + self.copy_size.y as i32
|
commited_block.y + self.copy_size.y as i32
|
||||||
} else {
|
} else {
|
||||||
shadowed_block.y
|
shadowed_block.y - 1
|
||||||
};
|
};
|
||||||
Rect::new(
|
Rect::new(
|
||||||
(shadowed_block.x, new_y).into(),
|
(shadowed_block.x - 1, new_y).into(),
|
||||||
(30, top_bottom_height.abs()).into(),
|
(32, top_bottom_height.abs()).into(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,11 +308,11 @@ impl<'a, 'b> BackgroundRegular<'a> {
|
||||||
let new_x = if left_right_width < 0 {
|
let new_x = if left_right_width < 0 {
|
||||||
commited_block.x + self.copy_size.x as i32
|
commited_block.x + self.copy_size.x as i32
|
||||||
} else {
|
} else {
|
||||||
shadowed_block.x
|
shadowed_block.x - 1
|
||||||
};
|
};
|
||||||
Rect::new(
|
Rect::new(
|
||||||
(new_x, shadowed_block.y).into(),
|
(new_x, shadowed_block.y - 1).into(),
|
||||||
(left_right_width.abs(), 20).into(),
|
(left_right_width.abs(), 22).into(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,17 +327,10 @@ impl<'a, 'b> BackgroundRegular<'a> {
|
||||||
|
|
||||||
// update position in registers
|
// update position in registers
|
||||||
|
|
||||||
unsafe {
|
self.register.set_position(self.commited_position);
|
||||||
self.set_position_x_register((self.commited_position.x % (32 * 8)) as u16);
|
let block = self.register.get_block();
|
||||||
self.set_position_y_register((self.commited_position.y % (32 * 8)) as u16);
|
iter.map(move |(x, y)| {
|
||||||
}
|
block[y.rem_euclid(32) as usize][x.rem_euclid(32) as usize] = map.get_position(x, y)
|
||||||
|
|
||||||
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));
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,6 +424,41 @@ impl<'b> BackgroundDistributor {
|
||||||
Ok(unsafe { BackgroundRegular::new(background, availiable_block, BackgroundSize::S32x32) })
|
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
|
/// Copies tiles to tilemap starting at the starting tile. Cannot overwrite
|
||||||
/// blocks that are already written to, panic is caused if this is attempted.
|
/// 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]) {
|
pub fn set_background_tilemap(&mut self, start_tile: u32, tiles: &[u32]) {
|
||||||
|
|
Loading…
Reference in a new issue