mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
change to system where drawing must provide the map
This commit is contained in:
parent
86d5c7ca35
commit
c106efa8b9
|
@ -42,29 +42,18 @@ pub enum BackgroundSize {
|
||||||
/// The map background is the method of drawing game maps to the screen. It
|
/// The map background is the method of drawing game maps to the screen. It
|
||||||
/// automatically handles copying the correct portion of a provided map to the
|
/// automatically handles copying the correct portion of a provided map to the
|
||||||
/// assigned block depending on given coordinates.
|
/// assigned block depending on given coordinates.
|
||||||
pub struct Background<'a> {
|
pub struct Background {
|
||||||
background: u8,
|
background: u8,
|
||||||
block: u8,
|
block: u8,
|
||||||
map: Option<MapStorage<'a>>,
|
|
||||||
map_dim_x: u32,
|
|
||||||
map_dim_y: u32,
|
|
||||||
pos_x: i32,
|
pos_x: i32,
|
||||||
pos_y: i32,
|
pos_y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MapStorage<'a> {
|
impl Background {
|
||||||
R(&'a RefCell<[u16]>),
|
unsafe fn new(layer: u8, block: u8) -> Background {
|
||||||
S(&'a [u16]),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Background<'a> {
|
|
||||||
unsafe fn new(layer: u8, block: u8) -> Background<'a> {
|
|
||||||
let mut background = Background {
|
let mut background = Background {
|
||||||
background: layer,
|
background: layer,
|
||||||
block,
|
block,
|
||||||
map: None,
|
|
||||||
map_dim_x: 0,
|
|
||||||
map_dim_y: 0,
|
|
||||||
pos_x: 0,
|
pos_x: 0,
|
||||||
pos_y: 0,
|
pos_y: 0,
|
||||||
};
|
};
|
||||||
|
@ -73,34 +62,12 @@ impl<'a> Background<'a> {
|
||||||
background.set_block(block);
|
background.set_block(block);
|
||||||
background
|
background
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the internal map to the provided map. Dimensions should be the
|
|
||||||
/// dimensions of the map. The mapping between coordinate and index is given
|
|
||||||
/// by `y * dim_x + x`. The length of the map slice should be `dim_x *
|
|
||||||
/// dim_y`, or panics may occur.
|
|
||||||
///
|
|
||||||
/// The portion of this map that is in view is copied to the map block
|
|
||||||
/// assigned to this background.
|
|
||||||
pub fn set_map(&mut self, map: &'a [u16], dim_x: u32, dim_y: u32) {
|
|
||||||
self.map = Some(MapStorage::S(map));
|
|
||||||
self.map_dim_x = dim_x;
|
|
||||||
self.map_dim_y = dim_y;
|
|
||||||
self.draw_full_map();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_map_refcell(&mut self, map: &'a RefCell<[u16]>, dim_x: u32, dim_y: u32) {
|
|
||||||
self.map = Some(MapStorage::R(map));
|
|
||||||
self.map_dim_x = dim_x;
|
|
||||||
self.map_dim_y = dim_y;
|
|
||||||
self.draw_full_map();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Background<'_> {
|
impl Background {
|
||||||
/// 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(), "map should be set before showing");
|
|
||||||
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);
|
||||||
|
@ -143,14 +110,14 @@ impl Background<'_> {
|
||||||
unsafe { self.set_bits(0x0E, 2, size as u16) }
|
unsafe { self.set_bits(0x0E, 2, size as u16) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_get<T>(&self, map: &T, x: i32, y: i32, default: u16) -> u16
|
fn map_get<T>(&self, map: &T, dim_x: u32, dim_y: u32, x: i32, y: i32, default: u16) -> u16
|
||||||
where
|
where
|
||||||
T: Deref<Target = [u16]>,
|
T: Deref<Target = [u16]>,
|
||||||
{
|
{
|
||||||
if x >= self.map_dim_x as i32 || x < 0 || y >= self.map_dim_y as i32 || y < 0 {
|
if x >= dim_x as i32 || x < 0 || y >= dim_y as i32 || y < 0 {
|
||||||
default
|
default
|
||||||
} else {
|
} else {
|
||||||
map[(self.map_dim_x as i32 * y + x) as usize]
|
map[(dim_x as i32 * y + x) as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,33 +132,34 @@ impl Background<'_> {
|
||||||
/// block assigned to this background. This is currently unnecesary to call.
|
/// block assigned to this background. This is currently unnecesary to call.
|
||||||
/// Setting position already updates the drawn map, and changing map forces
|
/// Setting position already updates the drawn map, and changing map forces
|
||||||
/// an update.
|
/// an update.
|
||||||
pub fn draw_full_map(&mut self) {
|
pub fn draw_full_map(&mut self, map: &[u16], dim_x: u32, dim_y: u32) {
|
||||||
match self.map.as_ref().unwrap() {
|
self.draw_area(map, dim_x, dim_y, -1, -1, 32, 22);
|
||||||
MapStorage::R(m) => {
|
|
||||||
let map = (*m).borrow();
|
|
||||||
self.draw_area_mapped(&map, -1, 32, -1, 22);
|
|
||||||
}
|
|
||||||
MapStorage::S(map) => {
|
|
||||||
self.draw_area_mapped(map, -1, 32, -1, 22);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forces a specific area of the screen to be drawn, taking into account any positonal offsets.
|
/// Forces a specific area of the screen to be drawn, taking into account any positonal offsets.
|
||||||
pub fn draw_area(&mut self, left: i32, top: i32, width: i32, height: i32) {
|
pub fn draw_area(
|
||||||
match self.map.as_ref().unwrap() {
|
&self,
|
||||||
MapStorage::R(m) => {
|
map: &[u16],
|
||||||
let map = (*m).borrow();
|
dim_x: u32,
|
||||||
self.draw_area_mapped(&map, left, top, width, height);
|
dim_y: u32,
|
||||||
}
|
left: i32,
|
||||||
MapStorage::S(map) => {
|
top: i32,
|
||||||
self.draw_area_mapped(map, left, top, width, height);
|
width: i32,
|
||||||
}
|
height: i32,
|
||||||
}
|
) {
|
||||||
|
self.draw_area_mapped(&map, dim_x, dim_y, left, top, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_area_mapped<T>(&self, map: &T, left: i32, top: i32, width: i32, height: i32)
|
fn draw_area_mapped<T>(
|
||||||
where
|
&self,
|
||||||
|
map: &T,
|
||||||
|
dim_x: u32,
|
||||||
|
dim_y: u32,
|
||||||
|
left: i32,
|
||||||
|
top: i32,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
) where
|
||||||
T: Deref<Target = [u16]>,
|
T: Deref<Target = [u16]>,
|
||||||
{
|
{
|
||||||
let x_map_space = self.pos_x / 8;
|
let x_map_space = self.pos_x / 8;
|
||||||
|
@ -206,7 +174,14 @@ impl Background<'_> {
|
||||||
(&mut (*MAP)[self.block as usize][(y_block_space + y).rem_euclid(32) as usize]
|
(&mut (*MAP)[self.block as usize][(y_block_space + y).rem_euclid(32) as usize]
|
||||||
[(x_block_space + x).rem_euclid(32) as usize]
|
[(x_block_space + x).rem_euclid(32) as usize]
|
||||||
as *mut u16)
|
as *mut u16)
|
||||||
.write_volatile(self.map_get(map, x_map_space + x, y_map_space + y, 0))
|
.write_volatile(self.map_get(
|
||||||
|
map,
|
||||||
|
dim_x,
|
||||||
|
dim_y,
|
||||||
|
x_map_space + x,
|
||||||
|
y_map_space + y,
|
||||||
|
0,
|
||||||
|
))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,21 +190,13 @@ impl Background<'_> {
|
||||||
/// Sets the position of the map to be shown on screen. This automatically
|
/// Sets the position of the map to be shown on screen. This automatically
|
||||||
/// manages copying the correct portion to the map block and moving the map
|
/// manages copying the correct portion to the map block and moving the map
|
||||||
/// registers.
|
/// registers.
|
||||||
pub fn set_position(&mut self, x: i32, y: i32) {
|
pub fn set_position(&mut self, map: &[u16], dim_x: u32, dim_y: u32, x: i32, y: i32) {
|
||||||
match self.map.as_ref().unwrap() {
|
self.set_position_mapped(&map, dim_x, dim_y, x, y);
|
||||||
MapStorage::R(m) => {
|
|
||||||
let map = (*m).borrow();
|
|
||||||
self.set_position_mapped(&map, x, y);
|
|
||||||
}
|
|
||||||
MapStorage::S(map) => {
|
|
||||||
self.set_position_mapped(map, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.pos_x = x;
|
self.pos_x = x;
|
||||||
self.pos_y = y;
|
self.pos_y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_position_mapped<T>(&self, map: &T, x: i32, y: i32)
|
pub fn set_position_mapped<T>(&self, map: &T, dim_x: u32, dim_y: u32, x: i32, y: i32)
|
||||||
where
|
where
|
||||||
T: Deref<Target = [u16]>,
|
T: Deref<Target = [u16]>,
|
||||||
{
|
{
|
||||||
|
@ -247,7 +214,7 @@ impl Background<'_> {
|
||||||
|
|
||||||
// don't fancily handle if we've moved more than one tile, just copy the whole new map
|
// don't fancily handle if we've moved more than one tile, just copy the whole new map
|
||||||
if x_difference.abs() > 1 || y_difference.abs() > 1 {
|
if x_difference.abs() > 1 || y_difference.abs() > 1 {
|
||||||
self.draw_area_mapped(map, -1, 32, -1, 22);
|
self.draw_area_mapped(map, dim_x, dim_y, -1, 32, -1, 22);
|
||||||
} else {
|
} else {
|
||||||
if x_difference != 0 {
|
if x_difference != 0 {
|
||||||
let x_offset = match x_difference {
|
let x_offset = match x_difference {
|
||||||
|
@ -263,6 +230,8 @@ impl Background<'_> {
|
||||||
as *mut u16)
|
as *mut u16)
|
||||||
.write_volatile(self.map_get(
|
.write_volatile(self.map_get(
|
||||||
map,
|
map,
|
||||||
|
dim_x,
|
||||||
|
dim_y,
|
||||||
x_map_space + x_offset,
|
x_map_space + x_offset,
|
||||||
y_map_space + y,
|
y_map_space + y,
|
||||||
0,
|
0,
|
||||||
|
@ -284,6 +253,8 @@ impl Background<'_> {
|
||||||
as *mut u16)
|
as *mut u16)
|
||||||
.write_volatile(self.map_get(
|
.write_volatile(self.map_get(
|
||||||
map,
|
map,
|
||||||
|
dim_x,
|
||||||
|
dim_y,
|
||||||
x_map_space + x,
|
x_map_space + x,
|
||||||
y_map_space + y_offset,
|
y_map_space + y_offset,
|
||||||
0,
|
0,
|
||||||
|
|
Loading…
Reference in a new issue