Skip to content

Commit 48a1978

Browse files
committed
feat: hacky scrolling (horiz only)
1 parent c258fa9 commit 48a1978

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fn main() -> Result<(), Box<dyn Error>> {
8383
move |ppu: &Ppu, gamepad1: &mut GamepadRegister, _gamepad2: &mut GamepadRegister| {
8484
// compute the screen's content from the PPU
8585
let mut frame = Frame::new();
86-
ppu.draw_background(&mut frame);
86+
ppu.draw_scrollable_background(&mut frame);
8787
ppu.draw_sprites(&mut frame);
8888

8989
// redraw the screen

src/ppu.rs

+55-3
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,60 @@ impl Ppu {
182182
let tile_n = self.vram[self.mirror_vram_addr((nt_start + offset) as u16) as usize];
183183
let bgp_idx = self.palette_for_bg_tile((x, y), nt_start);
184184
let palette = self.lookup_palette(bgp_idx);
185-
frame.draw_bg_tile(pattern_table, tile_n as usize, (x, y), palette);
185+
frame.draw_bg_tile(pattern_table, tile_n as usize, (x, y), 0, palette);
186+
}
187+
}
188+
}
189+
190+
/// Draws the entire possible background of 2 frames, but it gets filtered within, which you can then filter by applying a windowed viewport
191+
pub fn draw_scrollable_background(&self, frame: &mut Frame) {
192+
let bank = self.get_background_pattern_bank();
193+
let pattern_table =
194+
&self.chr_rom[bank * PATTERN_TABLE_SIZE..(bank + 1) * PATTERN_TABLE_SIZE];
195+
196+
// In horizontal scrolling, this is the nametable at the LEFT of the screen
197+
let which_nametable = self
198+
.registers
199+
.control
200+
.intersection(ControlRegister::NAMETABLE)
201+
.bits() as usize;
202+
assert!(which_nametable <= 3);
203+
let nt_start = which_nametable * 0x400;
204+
205+
// self.registers.control.
206+
207+
// Determine which nametable is on the left
208+
let nts = if nt_start == 0 {
209+
[0, 0x400]
210+
} else {
211+
[0x400, 0x800]
212+
};
213+
214+
let x_scroll: usize = self.registers.scroll.x_scroll as usize;
215+
let y_scroll: usize = self.registers.scroll.y_scroll as usize;
216+
// TODO
217+
// if self.registers.control.contains(ControlRegister::X_SCROLL) {
218+
// x_scroll += 256;
219+
// }
220+
221+
let rows = 30;
222+
let cols = 32;
223+
for tile_y in 0..rows {
224+
for (nt_idx, &nt_start) in nts.iter().enumerate() {
225+
for tile_x in 0..cols {
226+
let offset = tile_y * cols + tile_x;
227+
let tile_n =
228+
self.vram[self.mirror_vram_addr((nt_start + offset) as u16) as usize];
229+
let bgp_idx = self.palette_for_bg_tile((tile_x, tile_y), nt_start);
230+
let palette = self.lookup_palette(bgp_idx);
231+
frame.draw_bg_tile(
232+
pattern_table,
233+
tile_n as usize,
234+
(tile_x + cols * (nt_idx), tile_y),
235+
x_scroll,
236+
palette,
237+
);
238+
}
186239
}
187240
}
188241
}
@@ -477,8 +530,7 @@ impl Ppu {
477530
let sprite0 = self.parse_sprite_from_oam_data(&self.oam_data[0..4]);
478531
let (scanline_y, scanline_x) = self.get_tick_status();
479532

480-
scanline_y >= sprite0.y as usize
481-
&& (scanline_x % CYCLES_PER_SCANLINE) >= sprite0.x as usize
533+
scanline_y >= sprite0.y as usize && (scanline_x % CYCLES_PER_SCANLINE) >= sprite0.x as usize
482534
}
483535
}
484536

src/render.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl Frame {
4848

4949
pub fn new() -> Self {
5050
Self {
51+
// TODO: Consider a 'double-sized' frame with a viewport() function
5152
data: vec![0; Frame::WIDTH * Frame::HEIGHT * 3],
5253
}
5354
}
@@ -68,18 +69,24 @@ impl Frame {
6869
pattern_table: &[u8],
6970
tile_n: usize,
7071
pos: (usize, usize),
72+
x_scroll: usize,
73+
// y_scroll: usize,
7174
palette: [u8; 4],
7275
) {
7376
let tile = get_tile(pattern_table, tile_n);
7477
let (tile_x, tile_y) = pos;
7578
for (row, row_data) in tile.iter().enumerate() {
7679
for (col, &palette_idx) in row_data.iter().enumerate() {
7780
let color = SYSTEM_PALETTE[palette[palette_idx as usize] as usize];
78-
self.set_pixel(
79-
(tile_x * TILE_SIZE_PIXELS) + col,
80-
(tile_y * TILE_SIZE_PIXELS) + row,
81-
color,
82-
);
81+
let left_x = (tile_x * TILE_SIZE_PIXELS) + col;
82+
// only draw pixels within the screen width
83+
if x_scroll <= left_x && left_x - x_scroll <= 256 {
84+
self.set_pixel(
85+
(tile_x * TILE_SIZE_PIXELS) + col - x_scroll,
86+
(tile_y * TILE_SIZE_PIXELS) + row,
87+
color,
88+
);
89+
}
8390
}
8491
}
8592
}
@@ -156,7 +163,7 @@ mod test {
156163

157164
let mut f = Frame::new();
158165
assert_eq!(f.data[0], 0);
159-
f.draw_bg_tile(&pattern_table, tile_n, pos, palette);
166+
f.draw_bg_tile(&pattern_table, tile_n, pos, 0, palette);
160167
assert_eq!(f.data[0], 128);
161168
assert_eq!(f.data[1], 128);
162169
assert_eq!(f.data[2], 128);
@@ -175,7 +182,7 @@ mod test {
175182
let palette = [65, 65, 65, 3]; // 65 should crash if read, since it's OOB the palette with 64 colors
176183

177184
let mut f = Frame::new();
178-
f.draw_bg_tile(&pattern_table, tile_n, pos, palette);
185+
f.draw_bg_tile(&pattern_table, tile_n, pos, 0, palette);
179186

180187
// verify we drew the entire tile in the one selected color
181188
for row in 0..8 {

0 commit comments

Comments
 (0)