almost drawing
This commit is contained in:
parent
839429029d
commit
75c765b392
|
@ -151,7 +151,7 @@ impl Memory {
|
|||
}
|
||||
|
||||
fn set(&mut self, address: Address, data: u8) {
|
||||
verbose_println!("write addr: {:#X}, data: {:#X}", address, data);
|
||||
// verbose_println!("write addr: {:#X}, data: {:#X}", address, data);
|
||||
|
||||
match address {
|
||||
0x0..0x100 => {
|
||||
|
@ -184,7 +184,7 @@ impl Memory {
|
|||
// println!("empty space write: {:#X} to addr {:#X}", data, address);
|
||||
}
|
||||
0xFF00..0xFF4C => {
|
||||
verbose_print!("writing to addr {:#X}\r", address);
|
||||
// verbose_print!("writing to addr {:#X}\r", address);
|
||||
stdout().flush().unwrap();
|
||||
|
||||
if address == 0xFF02 && data == 0x81 {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{HEIGHT, WIDTH};
|
||||
|
||||
use super::{clear_bit, set_bit, set_or_clear_bit, CPU};
|
||||
use super::{clear_bit, get_bit, set_bit, set_or_clear_bit, CPU};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum DrawMode {
|
||||
|
@ -10,11 +10,69 @@ enum DrawMode {
|
|||
Mode3,
|
||||
}
|
||||
|
||||
enum TilemapArea {
|
||||
T9800,
|
||||
T9C00,
|
||||
}
|
||||
|
||||
enum TiledataArea {
|
||||
D8000,
|
||||
D8800,
|
||||
}
|
||||
|
||||
enum ObjSize {
|
||||
S8x8,
|
||||
S8x16,
|
||||
}
|
||||
|
||||
struct LCDC {
|
||||
enable: bool,
|
||||
window_tilemap: TilemapArea,
|
||||
window_enable: bool,
|
||||
tile_area: TiledataArea,
|
||||
bg_tilemap: TilemapArea,
|
||||
obj_size: ObjSize,
|
||||
obj_enable: bool,
|
||||
bg_window_enable: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Colour {
|
||||
White,
|
||||
LightGray,
|
||||
DarkGray,
|
||||
Black,
|
||||
}
|
||||
|
||||
impl Colour {
|
||||
fn to_rgb(&self) -> u32 {
|
||||
match self {
|
||||
Colour::White => Self::from_u8_rgb(255, 255, 255),
|
||||
Colour::LightGray => Self::from_u8_rgb(190, 190, 190),
|
||||
Colour::DarkGray => Self::from_u8_rgb(110, 110, 110),
|
||||
Colour::Black => Self::from_u8_rgb(20, 20, 20),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_u8_rgb(r: u8, g: u8, b: u8) -> u32 {
|
||||
let (r, g, b) = (r as u32, g as u32, b as u32);
|
||||
(r << 16) | (g << 8) | b
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Palette {
|
||||
zero: Colour,
|
||||
one: Colour,
|
||||
two: Colour,
|
||||
three: Colour,
|
||||
}
|
||||
|
||||
pub struct GPU {
|
||||
pub buffer: Vec<u32>,
|
||||
mode: DrawMode,
|
||||
mode_clock: usize,
|
||||
scanline: usize,
|
||||
scanline: u8,
|
||||
}
|
||||
|
||||
impl Default for GPU {
|
||||
|
@ -32,6 +90,9 @@ impl CPU {
|
|||
pub fn advance_gpu_clock(&mut self, steps: u8) {
|
||||
let real_steps = (steps as usize) * 4;
|
||||
self.gpu.mode_clock += real_steps;
|
||||
|
||||
let lcdc = self.get_lcdc();
|
||||
|
||||
match self.gpu.mode {
|
||||
DrawMode::HBlank => {
|
||||
// mode 0: hblank
|
||||
|
@ -39,7 +100,7 @@ impl CPU {
|
|||
self.gpu.mode_clock = 0;
|
||||
self.gpu.scanline += 1;
|
||||
if self.gpu.scanline == 143 {
|
||||
self.enter_vblank();
|
||||
self.enter_vblank(&lcdc);
|
||||
} else {
|
||||
self.gpu.mode = DrawMode::Mode2;
|
||||
}
|
||||
|
@ -67,29 +128,61 @@ impl CPU {
|
|||
// generate scanline
|
||||
if self.gpu.mode_clock >= 172 {
|
||||
self.gpu.mode_clock = 0;
|
||||
self.enter_hblank();
|
||||
self.enter_hblank(&lcdc);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.set_lcd_status();
|
||||
}
|
||||
|
||||
fn enter_hblank(&mut self) {
|
||||
self.gpu.mode = DrawMode::HBlank;
|
||||
self.render_scanline(self.gpu.scanline);
|
||||
fn get_lcdc(&self) -> LCDC {
|
||||
let reg = self.memory.get(0xFF40);
|
||||
LCDC {
|
||||
enable: get_bit(reg, 7),
|
||||
window_tilemap: if get_bit(reg, 6) {
|
||||
TilemapArea::T9C00
|
||||
} else {
|
||||
TilemapArea::T9800
|
||||
},
|
||||
window_enable: get_bit(reg, 5),
|
||||
tile_area: if get_bit(reg, 4) {
|
||||
TiledataArea::D8000
|
||||
} else {
|
||||
TiledataArea::D8800
|
||||
},
|
||||
bg_tilemap: if get_bit(reg, 3) {
|
||||
TilemapArea::T9C00
|
||||
} else {
|
||||
TilemapArea::T9800
|
||||
},
|
||||
obj_size: if get_bit(reg, 2) {
|
||||
ObjSize::S8x16
|
||||
} else {
|
||||
ObjSize::S8x8
|
||||
},
|
||||
obj_enable: get_bit(reg, 1),
|
||||
bg_window_enable: get_bit(reg, 0),
|
||||
}
|
||||
}
|
||||
|
||||
fn enter_vblank(&mut self) {
|
||||
fn enter_hblank(&mut self, lcdc: &LCDC) {
|
||||
self.gpu.mode = DrawMode::HBlank;
|
||||
self.render_scanline(self.gpu.scanline, lcdc);
|
||||
}
|
||||
|
||||
fn enter_vblank(&mut self, lcdc: &LCDC) {
|
||||
self.gpu.mode = DrawMode::VBlank;
|
||||
// if lcdc.enable {
|
||||
self.render_window();
|
||||
self.memory.set(0xFF0F, set_bit(self.memory.get(0xFF0F), 0));
|
||||
// }
|
||||
}
|
||||
|
||||
fn exit_vblank(&mut self) {
|
||||
self.gpu.mode = DrawMode::Mode2;
|
||||
self.gpu.scanline = 0;
|
||||
self.memory
|
||||
.set(0xFF0F, clear_bit(self.memory.get(0xFF0F), 0));
|
||||
// self.memory
|
||||
// .set(0xFF0F, clear_bit(self.memory.get(0xFF0F), 0));
|
||||
}
|
||||
|
||||
fn set_lcd_status(&mut self) {
|
||||
|
@ -106,9 +199,57 @@ impl CPU {
|
|||
(self.gpu.mode == DrawMode::VBlank) || (self.gpu.mode == DrawMode::Mode3),
|
||||
);
|
||||
self.memory.set(0xFF41, stat);
|
||||
self.memory.set(0xFF44, self.gpu.scanline);
|
||||
// println!("set scanline to {}", self.memory.get(0xFF44));
|
||||
}
|
||||
|
||||
fn render_scanline(&mut self, _scanline: usize) {}
|
||||
fn render_scanline(&mut self, scanline: u8, lcdc: &LCDC) {
|
||||
if lcdc.bg_window_enable {
|
||||
self.render_scanline_bg(scanline, lcdc);
|
||||
if lcdc.window_enable {
|
||||
self.render_scanline_window(scanline, lcdc);
|
||||
}
|
||||
}
|
||||
if lcdc.obj_enable {
|
||||
self.render_scanline_obj(scanline, lcdc);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_scanline_bg(&mut self, scanline: u8, lcdc: &LCDC) {
|
||||
let scroll_y = self.memory.get(0xFF42);
|
||||
let scroll_x = self.memory.get(0xFF43);
|
||||
let palette = byte_to_palette(self.memory.get(0xFF47));
|
||||
self.render_tiles(scanline, &lcdc.bg_tilemap, palette);
|
||||
}
|
||||
|
||||
fn render_scanline_window(&mut self, _scanline: u8, _lcdc: &LCDC) {
|
||||
let pos_y = self.memory.get(0xFF4A);
|
||||
// subtracting 7 to get the Real Number...
|
||||
let pos_x = self.memory.get(0xFF4B).wrapping_sub(7);
|
||||
if pos_y < 143 && pos_x < 166 {
|
||||
// within range!! render here
|
||||
}
|
||||
}
|
||||
|
||||
fn render_scanline_obj(&mut self, _scanline: u8, _lcdc: &LCDC) {}
|
||||
|
||||
fn render_tiles(&mut self, scanline: u8, tilemap: &TilemapArea, palette: Palette) {
|
||||
let tile_row = (scanline as usize) / 8;
|
||||
let row_addr = (tile_row * 32) as u16 + get_tilemap_offset(tilemap);
|
||||
for x in 0..32 {
|
||||
let lsbs = self.memory.get(row_addr + (x * 2));
|
||||
let msbs = self.memory.get(row_addr + (x * 2) + 1);
|
||||
for px_x in 0..8 {
|
||||
let lsb = get_bit(lsbs, px_x);
|
||||
let msb = get_bit(msbs, px_x);
|
||||
let colour = bits_to_mapped_colour(lsb, msb, palette);
|
||||
let x_coord = ((x * 8) + (px_x as u16)) as usize;
|
||||
if x_coord < WIDTH {
|
||||
self.gpu.buffer[(scanline as usize * WIDTH) + x_coord] = colour.to_rgb();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_window(&mut self) {
|
||||
self.window
|
||||
|
@ -116,3 +257,37 @@ impl CPU {
|
|||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_tilemap_offset(tilemap: &TilemapArea) -> u16 {
|
||||
match tilemap {
|
||||
TilemapArea::T9800 => 0x9800,
|
||||
TilemapArea::T9C00 => 0x9C00,
|
||||
}
|
||||
}
|
||||
|
||||
fn bits_to_mapped_colour(lsb: bool, msb: bool, palette: Palette) -> Colour {
|
||||
match (lsb, msb) {
|
||||
(true, true) => palette.three,
|
||||
(true, false) => palette.one,
|
||||
(false, true) => palette.two,
|
||||
(false, false) => palette.zero,
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_to_palette(byte: u8) -> Palette {
|
||||
Palette {
|
||||
zero: bits_to_colour(get_bit(byte, 0), get_bit(byte, 1)),
|
||||
one: bits_to_colour(get_bit(byte, 2), get_bit(byte, 3)),
|
||||
two: bits_to_colour(get_bit(byte, 4), get_bit(byte, 5)),
|
||||
three: bits_to_colour(get_bit(byte, 6), get_bit(byte, 7)),
|
||||
}
|
||||
}
|
||||
|
||||
fn bits_to_colour(first: bool, second: bool) -> Colour {
|
||||
match (first, second) {
|
||||
(true, true) => Colour::Black,
|
||||
(true, false) => Colour::DarkGray,
|
||||
(false, true) => Colour::LightGray,
|
||||
(false, false) => Colour::White,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue