From fb90281fe55fff51bfa952d7d7fc946ba5046002 Mon Sep 17 00:00:00 2001 From: Thomas Date: Mon, 18 Dec 2023 23:18:02 +0100 Subject: [PATCH] Fix sprites disappearing too early when sliding left off screen --- src/lib.rs | 1 + src/snes/ppu/bus.rs | 10 +--------- src/snes/ppu/render.rs | 28 ++++++++++++++++++++-------- src/snes/ppu/sprites.rs | 5 +++-- src/util.rs | 9 +++++++++ 5 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 src/util.rs diff --git a/src/lib.rs b/src/lib.rs index 50bc286..5c37863 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod frontend; pub mod snes; pub mod tickable; +pub mod util; #[cfg(test)] pub mod test; diff --git a/src/snes/ppu/bus.rs b/src/snes/ppu/bus.rs index 33dac88..f8580f9 100644 --- a/src/snes/ppu/bus.rs +++ b/src/snes/ppu/bus.rs @@ -2,10 +2,7 @@ use super::*; use crate::frontend::Renderer; use crate::snes::bus::{Address, BusMember}; - -use num::traits::{WrappingShl, WrappingShr}; -use num::Integer; -use std::mem::size_of_val; +use crate::util::sign_extend; macro_rules! write_m7x { ($self:ident, $reg:ident, $val:expr) => {{ @@ -24,11 +21,6 @@ macro_rules! write_m7x_13b { }}; } -fn sign_extend(val: T, nbits: u32) -> T { - let notherbits = size_of_val(&val) as u32 * 8 - nbits; - val.wrapping_shl(notherbits).wrapping_shr(notherbits) -} - impl BusMember
for PPU where TRenderer: Renderer, diff --git a/src/snes/ppu/render.rs b/src/snes/ppu/render.rs index 8cf4dc9..cf35149 100644 --- a/src/snes/ppu/render.rs +++ b/src/snes/ppu/render.rs @@ -198,23 +198,35 @@ where } if (e.y..(e.y + e.height)).contains(&scanline) { - for x in e.x..(e.x + e.width) { - if x >= state.idx.len() { + for x in e.x..(e.x + e.width as i32) { + if x >= state.idx.len() as i32 || x < 0 { // Outside of visible area. - break; + continue; } - if state.window.sprites[x] && state.windowlayermask & (1 << LAYER_SPRITES) != 0 + + if state.window.sprites[x as usize] + && state.windowlayermask & (1 << LAYER_SPRITES) != 0 { // Masked by window. continue; } - let t_x = (x - e.x) / TILE_WIDTH; - let t_y = (scanline - e.y) / TILE_HEIGHT; + // Coordinates within the tile + let (in_x, in_y) = ( + ((x - e.x) % TILE_WIDTH as i32) as usize, + ((scanline - e.y) % TILE_HEIGHT) as usize, + ); + // Sub-tile coordinates + let (t_x, t_y) = ( + ((x - e.x) / TILE_WIDTH as i32) as usize, + ((scanline - e.y) / TILE_HEIGHT) as usize, + ); + // Should be positive from here on + let x = x as usize; + let sprite = self.get_sprite_tile(&e, t_x, t_y); - let coloridx = - sprite.get_coloridx((x - e.x) % TILE_WIDTH, (scanline - e.y) % TILE_HEIGHT); + let coloridx = sprite.get_coloridx(in_x, in_y); if coloridx == 0 || state.idx[x] != 0 { continue; } diff --git a/src/snes/ppu/sprites.rs b/src/snes/ppu/sprites.rs index 2ecafca..ac19aa5 100644 --- a/src/snes/ppu/sprites.rs +++ b/src/snes/ppu/sprites.rs @@ -1,10 +1,11 @@ use super::*; +use crate::util::sign_extend; pub const OAM_ENTRIES: usize = 128; #[derive(Debug)] pub struct OAMEntry { - pub x: usize, + pub x: i32, pub y: usize, pub priority: u8, pub attr: u8, @@ -107,7 +108,7 @@ where }; OAMEntry { - x: usize::from(e[0]) | (usize::from(ext) & 0x01) << 8, + x: sign_extend(i32::from(e[0]) | (i32::from(ext) & 0x01) << 8, 9), y: e[1].into(), tileidx: e[2] as u16 | (e[3] as u16 & 0x01) << 8, attr: e[3], diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..b5c51d6 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,9 @@ +use num::traits::{WrappingShl, WrappingShr}; +use num::Integer; +use std::mem::size_of_val; + +/// Sign-extend a value +pub fn sign_extend(val: T, nbits: u32) -> T { + let notherbits = size_of_val(&val) as u32 * 8 - nbits; + val.wrapping_shl(notherbits).wrapping_shr(notherbits) +}