Skip to content

Commit

Permalink
added rectangle fill code with less bounds checks required.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lokathor committed May 31, 2024
1 parent 692a8b2 commit be23117
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 19 deletions.
17 changes: 3 additions & 14 deletions examples/paddle_ball.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,36 +144,25 @@ fn main() -> ! {
extern "C" fn draw_sprites(_bits: IrqBits) {
Mode3.clear_to(Color::BLACK);

draw_rect(
Mode3.fill_rect_clipped(
SPRITE_POSITIONS[0].read(),
SPRITE_POSITIONS[1].read(),
PADDLE_WIDTH,
PADDLE_HEIGHT,
Color::RED,
);
draw_rect(
Mode3.fill_rect_clipped(
SPRITE_POSITIONS[2].read(),
SPRITE_POSITIONS[3].read(),
PADDLE_WIDTH,
PADDLE_HEIGHT,
Color::GREEN,
);
draw_rect(
Mode3.fill_rect_clipped(
SPRITE_POSITIONS[4].read(),
SPRITE_POSITIONS[5].read(),
BALL_SIZE,
BALL_SIZE,
Color::CYAN,
);
}

// we out-line this because otherwise `draw_sprites` overloads the stack when it
// holds 3 copies of this function.
#[inline(never)]
fn draw_rect(x: u16, y: u16, width: u16, height: u16, color: Color) {
for i in 0..width {
for j in 0..height {
MODE3_VRAM.index((x + i) as usize, (y + j) as usize).write(color);
}
}
}
48 changes: 43 additions & 5 deletions src/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use bitfrob::{u16_get_bit, u16_with_bit, u16_with_value};

use crate::mmio::MODE3_VRAM;

/// A color value.
///
/// This is a bit-packed linear RGB color value with 5 bits per channel:
Expand Down Expand Up @@ -332,14 +334,17 @@ pub struct Tile8bpp(pub [u32; 16]);
pub struct Mode3;
impl Mode3 {
/// Width, in pixels, of the Mode 3 bitmap.
pub const WIDTH: usize = 240;
pub const WIDTH_USIZE: usize = 240;

/// Height, in pixels, of the Mode 3 bitmap.
pub const HEIGHT: usize = 160;
pub const HEIGHT_USIZE: usize = 160;

/// The size, in bytes, of one scanline of the Mode 3 bitmap.
pub const BYTES_PER_ROW: usize =
core::mem::size_of::<[Color; Mode3::WIDTH_USIZE]>();

/// The size, in bytes, of the Mode 3 bitmap.
pub const BYTES: usize =
Self::WIDTH * Self::HEIGHT * core::mem::size_of::<Color>();
/// The size, in bytes, of the whole Mode 3 bitmap.
pub const BYTES_TOTAL: usize = Self::BYTES_PER_ROW * Self::HEIGHT_USIZE;

/// Clears the entire bitmap to a color of your choosing.
#[cfg_attr(feature = "on_gba", instruction_set(arm::a32))]
Expand Down Expand Up @@ -381,4 +386,37 @@ impl Mode3 {
)
});
}

/// Fills the given rectangle, clipped to the bounds of the bitmap.
#[cfg_attr(feature = "on_gba", instruction_set(arm::a32))]
pub fn fill_rect_clipped(
self, x: u16, y: u16, width: u16, height: u16, color: Color,
) {
on_gba_or_unimplemented!(
let x_start = x.min(Self::WIDTH_USIZE as u16);
let x_end = x.saturating_add(width).min(Self::WIDTH_USIZE as u16);
let x_count = x_end - x_start;
let y_start = y.min(Self::HEIGHT_USIZE as u16);
let y_end = y.saturating_add(height).min(Self::HEIGHT_USIZE as u16);
let y_count = y_end - y_start;
// base
let mut p = MODE3_VRAM.as_usize() as *mut Color;
// go to start y
p = unsafe { p.byte_add(Self::BYTES_PER_ROW * (y_start as u16 as usize)) };
// go to start x
p = unsafe { p.add(x_start as u16 as usize) };
let mut y_remaining = y_count;
while y_remaining > 0 {
let mut within_row = p;
let mut x_remaining = x_count;
while x_remaining > 0 {
unsafe { within_row.write_volatile(color) };
within_row = unsafe { within_row.add(1) };
x_remaining -= 1;
}
p = unsafe { p.byte_add(Self::BYTES_PER_ROW) };
y_remaining -= 1;
}
);
}
}

0 comments on commit be23117

Please sign in to comment.