Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 36 additions & 16 deletions ppu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub struct Ppu {
line: usize,

stat_irq: bool,
current_window_line: usize,

// Vector of indexes into OAM entries
selected_oam_entries: heapless::Vec<usize, MAX_SELECTED_OBJECTS>,
Expand Down Expand Up @@ -158,6 +159,7 @@ impl Ppu {
line: 0,

stat_irq: false,
current_window_line: 0,
selected_oam_entries: heapless::Vec::new(),
framebuffer: unsafe {
core::mem::transmute::<Box<UninitFrame>, Box<Frame>>(framebuffer)
Expand Down Expand Up @@ -270,6 +272,7 @@ impl Ppu {
self.draw_line();
}
Mode::Vblank => {
self.current_window_line = 0;
self.update_registers();
return (Interrupt::Vblank.into(), PpuResult::FrameComplete);
}
Expand Down Expand Up @@ -335,7 +338,7 @@ impl Ppu {
}

#[cfg_attr(feature = "profile", inline(never))]
fn draw_line_window(&self, line: &mut [PaletteIndex; DISPLAY_WIDTH]) {
fn draw_line_window(&mut self, line: &mut [PaletteIndex; DISPLAY_WIDTH]) {
let bg_win_enable = self.regs.lcdc.read(regs::LCDC::BG_AND_WINDOW_ENABLE) != 0;
if !bg_win_enable {
return;
Expand All @@ -346,7 +349,6 @@ impl Ppu {
// Nothing to draw, return
return;
}
let win_line = self.line - wy;

let win_tile_map: crate::regs::LCDC::WINDOW_TILE_MAP::Value = self
.regs
Expand All @@ -360,20 +362,22 @@ impl Ppu {
.read_as_enum(crate::regs::LCDC::BG_AND_WINDOW_TILE_DATA)
.expect("Invalid LCDC bit 4");

const WX_OFFSET: usize = 7;
const WX_OFFSET: usize = 8;
let wx = self.regs.wx as usize;
let disp_x_offset = if wx >= WX_OFFSET { wx - WX_OFFSET } else { 0 };
let disp_x_offset = wx.saturating_sub(WX_OFFSET);
if disp_x_offset >= DISPLAY_WIDTH {
return;
}

let disp_x_initial_skip = if wx >= WX_OFFSET { 0 } else { WX_OFFSET - wx };
let tile_line_idx = win_line % vram::TILE_HEIGHT;
let current_window_line = self.current_window_line;
self.current_window_line += 1;

let disp_x_initial_skip = WX_OFFSET.saturating_sub(wx);
let tile_line_idx = current_window_line % vram::TILE_HEIGHT;
let window_pixels = self
.vram
.get_win_tile_map(win_tile_map)
.line(win_line)
.line(current_window_line)
.iter()
.flat_map(|tile_idx| {
self.vram
Expand All @@ -395,8 +399,17 @@ impl Ppu {
bg_line: &[PaletteIndex; DISPLAY_WIDTH],
line: &mut [Option<(usize, Color)>; DISPLAY_WIDTH],
) {
for (obj_prio, object) in self
.selected_oam_entries
let double_size_tiles: regs::LCDC::OBJ_SIZE::Value =
self.regs.lcdc.read_as_enum(regs::LCDC::OBJ_SIZE).unwrap();
let obj_height = (double_size_tiles as usize + 1) * 8;

let objects = &self.oam.objects();
let mut oam_entries: heapless::Vec<usize, MAX_SELECTED_OBJECTS> =
self.selected_oam_entries.clone();
// OAM object priorities are based on the X coordinate.
oam_entries.sort_by_key(|i| objects[*i].x);

for (obj_prio, object) in oam_entries
.iter()
.map(|i| &self.oam.objects()[*i])
.enumerate()
Expand All @@ -405,17 +418,24 @@ impl Ppu {
let x_flip = object.attrs.read(oam::OBJ_ATTRS::X_FLIP) != 0;

let tile_line = OBJ_OFFSET_Y + self.line - object.y as usize;
let (tile_idx, tile_line) = if tile_line >= TILE_HEIGHT {
(object.tile_idx.next(), tile_line - TILE_HEIGHT)
debug_assert!(tile_line < obj_height);
let tile_line = if y_flip {
obj_height - 1 - tile_line
} else {
(object.tile_idx, tile_line)
tile_line
};

debug_assert!(tile_line < TILE_HEIGHT);
let tile_line = if y_flip {
TILE_HEIGHT - 1 - tile_line
// In 8x16 mode, the tile index is always aligned to 2, enforced by the hardware.
let tile_idx = if double_size_tiles == regs::LCDC::OBJ_SIZE::Value::Tile8x16 {
object.tile_idx.discard_bit_zero()
} else {
tile_line
object.tile_idx
};

let (tile_idx, tile_line) = if tile_line >= TILE_HEIGHT {
(tile_idx.next(), tile_line - TILE_HEIGHT)
} else {
(tile_idx, tile_line)
};

let palette = match object
Expand Down
3 changes: 3 additions & 0 deletions ppu/src/vram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ impl TileIndex {
pub fn next(self) -> Self {
Self(self.0 + 1)
}
pub fn discard_bit_zero(self) -> Self {
Self(self.0 & 0xfe)
}
}

impl From<u8> for TileIndex {
Expand Down