Skip to content

Commit d2dc547

Browse files
committed
8x16 sprites
1 parent 0dfaeb9 commit d2dc547

5 files changed

Lines changed: 78 additions & 46 deletions

File tree

src/cpu/bus.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl Bus {
100100
} else if (0x6000..0x8000).contains(&a) {
101101
self.prg_ram.write(a - 0x6000, v);
102102
} else {
103-
panic!("Tried to write to unmapped address: {:#X}", a)
103+
println!("Tried to write to unmapped address: {:#X}", a)
104104
}
105105
}
106106

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ async fn main() -> Result<(), anyhow::Error> {
2121
println!("Starting Emulator!");
2222

2323
// let rom = NesRom::read_from_file("vendor/nes-test-roms/blargg_litewall/litewall5.nes")?;
24-
let rom = NesRom::read_from_file("./Thwaite.nes")?;
24+
let rom = NesRom::read_from_file("./lode_runner.nes")?;
2525
println!("{rom:#?}");
2626

2727
let bus = Bus::new(rom.clone());

src/ppu.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::memory::{Memory, Ram};
1+
use crate::memory::Memory;
22
use crate::nes_rom::NametableMirroring;
33
use crate::ppu::ppu_memory::PpuMemory;
44

@@ -120,7 +120,6 @@ pub struct Ppu<M: Memory> {
120120
scroll: PpuScroll,
121121
addr: PpuAddr,
122122
data_buffer: u8,
123-
oam_dma: u8,
124123

125124
scanline: u32,
126125
pub cycle: u32,
@@ -141,7 +140,6 @@ impl Ppu<PpuMemory> {
141140
scroll: PpuScroll::new(),
142141
addr: PpuAddr::new(),
143142
data_buffer: 0,
144-
oam_dma: 0,
145143
scanline: 1,
146144
cycle: 0,
147145
nmi: false,
@@ -305,6 +303,10 @@ impl<M: Memory> Ppu<M> {
305303
}
306304
}
307305

306+
pub fn tall_sprites(&self) -> bool {
307+
self.get_ctrl_bit(PPU_CTRL_SPRITE_SIZE_BIT)
308+
}
309+
308310
pub fn base_nametable_index(&self) -> u8 {
309311
self.ctrl & PPU_CTRL_NAMETABLE_MASK
310312
}
@@ -313,7 +315,7 @@ impl<M: Memory> Ppu<M> {
313315
#[cfg(test)]
314316
mod test {
315317
use crate::memory::test::DummyMemory;
316-
use crate::memory::{Memory, Ram};
318+
use crate::memory::Memory;
317319
use crate::ppu::{Ppu, PpuAddr, PpuScroll, OAM_SIZE, PPU_CTRL_VRAM_ADD_INCREMENT_BIT};
318320
use std::cell::RefCell;
319321
use std::rc::Rc;
@@ -328,7 +330,6 @@ mod test {
328330
scroll: PpuScroll::new(),
329331
addr: PpuAddr::new(),
330332
data_buffer: 0,
331-
oam_dma: 0,
332333
scanline: 1,
333334
cycle: 0,
334335
nmi: false,

src/render.rs

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -110,42 +110,62 @@ async fn render_background(ppu: &mut Ppu<PpuMemory>) {
110110

111111
async fn render_sprites(ppu: &Ppu<PpuMemory>) {
112112
for oam_idx in (0..OAM_SIZE).step_by(4).rev() {
113-
let sprite = Sprite::from_data(&ppu.oam[oam_idx..oam_idx + 4]);
113+
let sprite = Sprite::from_data(&ppu.oam[oam_idx..oam_idx + 4], ppu.tall_sprites());
114114
if !sprite.visible {
115115
continue;
116116
}
117-
let bank = ppu.sprite_pattern_addr();
118-
let tile = sprite.tile_index as u16;
119-
let chr_data = ppu.memory.chr_rom
120-
[(bank + tile * 16) as usize..(bank + tile * 16 + 16) as usize]
121-
.to_vec();
122-
let pixels = chr_data_to_pixels(chr_data);
123117

124-
let colors = get_sprite_palette(ppu, sprite.palette as u16);
125-
126-
for x in 0..8 {
127-
for y in 0..8 {
128-
let pixel_idx = (y * 8 + x) as usize;
129-
if pixels[pixel_idx] == 0 {
130-
continue;
131-
}
132-
133-
let x = if sprite.flip_horizontally { 7 - x } else { x };
134-
let y = if sprite.flip_vertically { 7 - y } else { y };
135-
136-
if sprite.x as u16 + x > SCREEN_WIDTH || sprite.y as u16 + y > SCREEN_HEIGHT {
137-
continue;
138-
}
139-
let (screen_x, screen_y) = (sprite.x as u16 + x, sprite.y as u16 + y);
140-
141-
draw_rectangle(
142-
screen_x as f32 * RENDER_SCALE,
143-
screen_y as f32 * RENDER_SCALE,
144-
RENDER_SCALE,
145-
RENDER_SCALE,
146-
colors[pixels[pixel_idx] as usize],
147-
)
118+
if ppu.tall_sprites() {
119+
let bank = sprite.bank;
120+
let (mut top_tile, mut bottom_tile) = (sprite.tile_index, sprite.tile_index + 1);
121+
if sprite.flip_vertically {
122+
(top_tile, bottom_tile) = (bottom_tile, top_tile);
123+
}
124+
render_sprite_tile(&sprite, ppu, bank, top_tile, 0).await;
125+
render_sprite_tile(&sprite, ppu, bank, bottom_tile, 8).await;
126+
} else {
127+
let bank = ppu.sprite_pattern_addr();
128+
let tile = sprite.tile_index;
129+
render_sprite_tile(&sprite, ppu, bank, tile, 0).await;
130+
}
131+
}
132+
}
133+
134+
async fn render_sprite_tile(
135+
sprite: &Sprite,
136+
ppu: &Ppu<PpuMemory>,
137+
bank: u16,
138+
tile: u16,
139+
y_offset: u16,
140+
) {
141+
let chr_data =
142+
ppu.memory.chr_rom[(bank + tile * 16) as usize..(bank + tile * 16 + 16) as usize].to_vec();
143+
let pixels = chr_data_to_pixels(chr_data);
144+
145+
let colors = get_sprite_palette(ppu, sprite.palette as u16);
146+
147+
for x in 0..8 {
148+
for y in 0..8 {
149+
let pixel_idx = (y * 8 + x) as usize;
150+
if pixels[pixel_idx] == 0 {
151+
continue;
148152
}
153+
154+
let x = if sprite.flip_horizontally { 7 - x } else { x };
155+
let y = if sprite.flip_vertically { 7 - y } else { y };
156+
if sprite.x + x > SCREEN_WIDTH || sprite.y + y_offset + y > SCREEN_HEIGHT {
157+
continue;
158+
}
159+
160+
let (screen_x, screen_y) = (sprite.x + x, sprite.y + y_offset + y);
161+
162+
draw_rectangle(
163+
screen_x as f32 * RENDER_SCALE,
164+
screen_y as f32 * RENDER_SCALE,
165+
RENDER_SCALE,
166+
RENDER_SCALE,
167+
colors[pixels[pixel_idx] as usize],
168+
)
149169
}
150170
}
151171
}

src/render/sprite.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
pub struct Sprite {
2-
pub x: u8,
3-
pub y: u8,
4-
pub tile_index: u8,
2+
pub x: u16,
3+
pub y: u16,
4+
pub bank: u16,
5+
pub tile_index: u16,
56
pub palette: u8,
67
pub visible: bool,
78
pub flip_horizontally: bool,
@@ -14,17 +15,27 @@ const ATTR_FLIP_HORIZONTALLY_BIT: u8 = 6;
1415
const ATTR_FLIP_VERTICALLY_BIT: u8 = 7;
1516

1617
impl Sprite {
17-
pub fn from_data(data: &[u8]) -> Self {
18-
let x = data[3];
19-
let y = data[0];
20-
let tile_index = data[1]; // TODO support 8x16 sprites
21-
let palette = data[2] & 0b11;
18+
pub fn from_data(data: &[u8], tall_sprite: bool) -> Self {
19+
let x = data[3] as u16;
20+
let y = data[0] as u16;
21+
let bank = if tall_sprite && data[1] & 1 == 1 {
22+
0x1000
23+
} else {
24+
0
25+
};
26+
let tile_index = if tall_sprite {
27+
data[1] & 0b1111_1110
28+
} else {
29+
data[1]
30+
} as u16;
31+
let palette = data[2] & ATTR_PALETTE_MASK;
2232
let visible = (data[2] >> ATTR_PRIORITY_BIT) & 1 == 0;
2333
let flip_horizontally = (data[2] >> ATTR_FLIP_HORIZONTALLY_BIT) & 1 == 1;
2434
let flip_vertically = (data[2] >> ATTR_FLIP_VERTICALLY_BIT) & 1 == 1;
2535
Self {
2636
x,
2737
y,
38+
bank,
2839
tile_index,
2940
palette,
3041
visible,

0 commit comments

Comments
 (0)