Skip to content

Commit f15ef0b

Browse files
committed
feat: hacky step sideways, to get tileset rendering
1 parent 9920f25 commit f15ef0b

File tree

3 files changed

+191
-44
lines changed

3 files changed

+191
-44
lines changed

src/main.rs

Lines changed: 74 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod ppu;
1313
mod rom;
1414
mod utility;
1515

16+
use ppu::Frame;
1617
use rand::random;
1718
use rom::Rom;
1819
use sdl2::event::Event;
@@ -27,45 +28,74 @@ fn main() -> Result<(), Box<dyn Error>> {
2728
let sdl_context = sdl2::init()?;
2829
let video_subsystem = sdl_context.video()?;
2930
let window = video_subsystem
30-
.window("", 320, 320)
31+
.window("Tile Viewer", (256.0 * 3.0) as u32, (240.0 * 3.0) as u32)
3132
.position_centered()
3233
.build()?;
3334

3435
let mut canvas = window.into_canvas().present_vsync().build()?;
3536
let mut event_pump = sdl_context.event_pump()?;
36-
canvas.set_scale(10., 10.)?;
37+
canvas.set_scale(3., 3.)?;
3738

3839
let creator = canvas.texture_creator();
39-
let mut texture = creator.create_texture_target(PixelFormatEnum::RGB24, 32, 32)?;
40+
let mut texture = creator.create_texture_target(PixelFormatEnum::RGB24, 256, 240)?;
4041

41-
let mut screen_state = [0_u8; 32 * 3 * 32];
42+
// let mut screen_state = [0_u8; 32 * 3 * 32];
4243

43-
// snake game, for basic testing
44-
// let program = fs::read("roms/snake.nes").unwrap();
45-
let program = fs::read("roms/nestest.nes").unwrap();
44+
// TODO: get program name from args at CLI
45+
let program = fs::read("roms/Alter_Ego.nes").unwrap();
46+
// let program = fs::read("roms/pacman.nes").unwrap();
47+
// let program = fs::read("roms/Ms_pacman.nes").unwrap();
4648

4749
let mut cpu = Cpu::new();
48-
cpu.load_rom(Rom::new(&program));
49-
cpu.reset();
50-
cpu.run_with_callback(move |cpu| {
51-
println!("{}", cpu.trace());
52-
53-
// read user input and write it to mem[0xFF]
54-
handle_user_input(cpu, &mut event_pump);
55-
56-
// update mem[0xFE] with a new random number
57-
cpu.mem_write(0xFE, random::<u8>());
58-
59-
// read mem mapped screen state
60-
if read_screen_state(cpu, &mut screen_state) {
61-
// redraw the screen
62-
texture.update(None, &screen_state, 32 * 3).unwrap();
63-
canvas.copy(&texture, None, None).unwrap();
64-
canvas.present();
50+
let rom = Rom::new(&program);
51+
52+
let mut frame = Frame::new();
53+
54+
let tiles_per_row = 24;
55+
let tile_size = 8 + 1;
56+
for bank in 0..=1 {
57+
for tile_n in 0..256 {
58+
let x = tile_n % tiles_per_row;
59+
let y = tile_n / tiles_per_row + bank * 12;
60+
61+
frame.draw_tile(&rom.chr_rom, bank, tile_n, (x * tile_size, y * tile_size));
6562
}
63+
}
64+
65+
// if read_screen_state(cpu, &mut screen_state.data) {
66+
// // redraw the screen
67+
// texture.update(None, &screen_state.d, 32 * 3).unwrap();
68+
// canvas.copy(&texture, None, None).unwrap();
69+
// canvas.present();
70+
// }
71+
texture.update(None, &frame.data, 256 * 3).unwrap();
72+
canvas.copy(&texture, None, None).unwrap();
73+
canvas.present();
74+
75+
loop {
76+
handle_user_input(&mut cpu, &mut event_pump);
77+
}
78+
// cpu.load_rom(rom);
79+
// cpu.reset();
80+
// cpu.run_with_callback(move |cpu| {
81+
// println!("{}", cpu.trace());
82+
83+
// // read user input and write it to mem[0xFF]
84+
// handle_user_input(cpu, &mut event_pump);
6685

67-
sleep(Duration::new(0, 70_000));
68-
});
86+
// // update mem[0xFE] with a new random number
87+
// cpu.mem_write(0xFE, random::<u8>());
88+
89+
// // read mem mapped screen state
90+
// if read_screen_state(cpu, &mut screen_state) {
91+
// // redraw the screen
92+
// texture.update(None, &screen_state, 32 * 3).unwrap();
93+
// canvas.copy(&texture, None, None).unwrap();
94+
// canvas.present();
95+
// }
96+
97+
// sleep(Duration::new(0, 70_000));
98+
// });
6999

70100
Ok(())
71101
}
@@ -106,21 +136,21 @@ fn color(byte: u8) -> Color {
106136
}
107137
}
108138

109-
fn read_screen_state(cpu: &mut Cpu, screen: &mut [u8; 32 * 3 * 32]) -> bool {
110-
let mut screen_idx = 0;
111-
let mut updated = false;
112-
for i in 0x0200..0x0600 {
113-
let color_idx = cpu.mem_read(i as u16);
114-
let (b1, b2, b3) = color(color_idx).rgb();
115-
if screen[screen_idx] != b1 || screen[screen_idx + 1] != b2 || screen[screen_idx + 2] != b3
116-
{
117-
screen[screen_idx] = b1;
118-
screen[screen_idx + 1] = b2;
119-
screen[screen_idx + 2] = b3;
120-
updated = true
121-
}
122-
screen_idx += 3;
123-
}
124-
125-
updated
126-
}
139+
// fn read_screen_state(cpu: &mut Cpu, screen: &mut [u8; 32 * 3 * 32]) -> bool {
140+
// let mut screen_idx = 0;
141+
// let mut updated = false;
142+
// for i in 0x0200..0x0600 {
143+
// let color_idx = cpu.mem_read(i as u16);
144+
// let (b1, b2, b3) = color(color_idx).rgb();
145+
// if screen[screen_idx] != b1 || screen[screen_idx + 1] != b2 || screen[screen_idx + 2] != b3
146+
// {
147+
// screen[screen_idx] = b1;
148+
// screen[screen_idx + 1] = b2;
149+
// screen[screen_idx + 2] = b3;
150+
// updated = true
151+
// }
152+
// screen_idx += 3;
153+
// }
154+
155+
// updated
156+
// }

src/ppu.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,122 @@ use crate::{
55
utility::{addr_from, split_addr},
66
};
77

8+
pub static SYSTEM_PALLETE: [(u8, u8, u8); 64] = [
9+
(0x80, 0x80, 0x80),
10+
(0x00, 0x3D, 0xA6),
11+
(0x00, 0x12, 0xB0),
12+
(0x44, 0x00, 0x96),
13+
(0xA1, 0x00, 0x5E),
14+
(0xC7, 0x00, 0x28),
15+
(0xBA, 0x06, 0x00),
16+
(0x8C, 0x17, 0x00),
17+
(0x5C, 0x2F, 0x00),
18+
(0x10, 0x45, 0x00),
19+
(0x05, 0x4A, 0x00),
20+
(0x00, 0x47, 0x2E),
21+
(0x00, 0x41, 0x66),
22+
(0x00, 0x00, 0x00),
23+
(0x05, 0x05, 0x05),
24+
(0x05, 0x05, 0x05),
25+
(0xC7, 0xC7, 0xC7),
26+
(0x00, 0x77, 0xFF),
27+
(0x21, 0x55, 0xFF),
28+
(0x82, 0x37, 0xFA),
29+
(0xEB, 0x2F, 0xB5),
30+
(0xFF, 0x29, 0x50),
31+
(0xFF, 0x22, 0x00),
32+
(0xD6, 0x32, 0x00),
33+
(0xC4, 0x62, 0x00),
34+
(0x35, 0x80, 0x00),
35+
(0x05, 0x8F, 0x00),
36+
(0x00, 0x8A, 0x55),
37+
(0x00, 0x99, 0xCC),
38+
(0x21, 0x21, 0x21),
39+
(0x09, 0x09, 0x09),
40+
(0x09, 0x09, 0x09),
41+
(0xFF, 0xFF, 0xFF),
42+
(0x0F, 0xD7, 0xFF),
43+
(0x69, 0xA2, 0xFF),
44+
(0xD4, 0x80, 0xFF),
45+
(0xFF, 0x45, 0xF3),
46+
(0xFF, 0x61, 0x8B),
47+
(0xFF, 0x88, 0x33),
48+
(0xFF, 0x9C, 0x12),
49+
(0xFA, 0xBC, 0x20),
50+
(0x9F, 0xE3, 0x0E),
51+
(0x2B, 0xF0, 0x35),
52+
(0x0C, 0xF0, 0xA4),
53+
(0x05, 0xFB, 0xFF),
54+
(0x5E, 0x5E, 0x5E),
55+
(0x0D, 0x0D, 0x0D),
56+
(0x0D, 0x0D, 0x0D),
57+
(0xFF, 0xFF, 0xFF),
58+
(0xA6, 0xFC, 0xFF),
59+
(0xB3, 0xEC, 0xFF),
60+
(0xDA, 0xAB, 0xEB),
61+
(0xFF, 0xA8, 0xF9),
62+
(0xFF, 0xAB, 0xB3),
63+
(0xFF, 0xD2, 0xB0),
64+
(0xFF, 0xEF, 0xA6),
65+
(0xFF, 0xF7, 0x9C),
66+
(0xD7, 0xE8, 0x95),
67+
(0xA6, 0xED, 0xAF),
68+
(0xA2, 0xF2, 0xDA),
69+
(0x99, 0xFF, 0xFC),
70+
(0xDD, 0xDD, 0xDD),
71+
(0x11, 0x11, 0x11),
72+
(0x11, 0x11, 0x11),
73+
];
74+
75+
// TODO: move UI rendering stuff that ties to SDL2 out of PPU
76+
pub struct Frame {
77+
pub data: Vec<u8>,
78+
}
79+
80+
impl Frame {
81+
const WIDTH: usize = 256;
82+
const HEIGHT: usize = 240;
83+
84+
pub fn new() -> Self {
85+
Self {
86+
data: vec![0; Frame::WIDTH * Frame::HEIGHT * 3],
87+
}
88+
}
89+
90+
pub fn set_pixel(&mut self, x: usize, y: usize, rgb: (u8, u8, u8)) {
91+
let base = y * 3 * Frame::WIDTH + x * 3;
92+
if base + 2 < self.data.len() {
93+
self.data[base] = rgb.0;
94+
self.data[base + 1] = rgb.1;
95+
self.data[base + 2] = rgb.2
96+
}
97+
}
98+
99+
pub fn draw_tile(&mut self, chr_rom: &[u8], bank: usize, tile_n: usize, pos: (usize, usize)) {
100+
assert!(bank <= 1);
101+
102+
let tile_size_bytes = 16;
103+
let bank_size_bytes: usize = 4096;
104+
105+
let (x, y) = pos;
106+
for row in 0..8 {
107+
let first_byte = chr_rom[bank * bank_size_bytes + tile_n * tile_size_bytes + row];
108+
let second_byte = chr_rom[bank * bank_size_bytes + tile_n * tile_size_bytes + 8 + row];
109+
110+
for col in 0..8 {
111+
let which_bit = 1 << (7 - col);
112+
let lo_bit = first_byte & which_bit > 0;
113+
let hi_bit = second_byte & which_bit > 0;
114+
let palette_idx: u8 = (hi_bit as u8) << 1 + (lo_bit as u8);
115+
// TODO: lookup palette color
116+
let color = SYSTEM_PALLETE[palette_idx as usize];
117+
118+
self.set_pixel(x + col, y + row, color);
119+
}
120+
}
121+
}
122+
}
123+
8124
#[derive(Default)]
9125
pub struct PpuRegisters {
10126
/// Controller (0x2000) - instructs PPU on general logic flow

src/rom.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ impl Rom {
5656
let mapper = match rom_mapper_type {
5757
0 => Mapper::Zero,
5858
_ => todo!(),
59+
// _ => Mapper::Zero, // TODO: Hack to get tiles viewing.. but should revert to TODO
5960
};
6061

6162
let mirroring = match (is_four_screen, is_vertical_screen) {

0 commit comments

Comments
 (0)