Started implementing graphics
This commit is contained in:
parent
396e87304e
commit
ea81305272
@ -4,3 +4,5 @@ version = "0.1.0"
|
|||||||
authors = ["Kevin Hamacher <kevin.hamacher@rub.de>"]
|
authors = ["Kevin Hamacher <kevin.hamacher@rub.de>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
sdl2 = "0.19.0"
|
||||||
|
libc = "*"
|
||||||
|
|||||||
131
src/display.rs
131
src/display.rs
@ -1,10 +1,20 @@
|
|||||||
|
extern crate sdl2;
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
// Internal ram size
|
||||||
const VRAM_SIZE: usize = 0x2000;
|
const VRAM_SIZE: usize = 0x2000;
|
||||||
|
|
||||||
|
// Timing values
|
||||||
const TICKS_END_SCANLINE: u16 = 80;
|
const TICKS_END_SCANLINE: u16 = 80;
|
||||||
const TICKS_END_READMODE: u16 = 172;
|
const TICKS_END_READMODE: u16 = 172;
|
||||||
const TICKS_END_HBLANK: u16 = 204;
|
const TICKS_END_HBLANK: u16 = 204;
|
||||||
const TICKS_END_VBLANK: u16 = 456;
|
const TICKS_END_VBLANK: u16 = 456;
|
||||||
|
|
||||||
|
// Display size
|
||||||
|
const GB_PIXELS_X: u16 = 160;
|
||||||
|
const GB_PIXELS_Y: u16 = 144;
|
||||||
|
const SCALE: u16 = 4;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum DisplayMode {
|
enum DisplayMode {
|
||||||
Scanline,
|
Scanline,
|
||||||
@ -19,7 +29,6 @@ impl Default for DisplayMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct Display {
|
pub struct Display {
|
||||||
control: u8,
|
control: u8,
|
||||||
status: u8,
|
status: u8,
|
||||||
@ -37,10 +46,22 @@ pub struct Display {
|
|||||||
current_ticks: u16,
|
current_ticks: u16,
|
||||||
current_mode: DisplayMode,
|
current_mode: DisplayMode,
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
|
||||||
|
// For creating a window:
|
||||||
|
// sdl_context: sdl2::Sdl,
|
||||||
|
// video_context: sdl2::VideoSubsystem,
|
||||||
|
// window: sdl2::video::Window,
|
||||||
|
renderer: sdl2::render::Renderer<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display {
|
impl Display {
|
||||||
pub fn new() -> Display {
|
pub fn new() -> Display {
|
||||||
|
let sdl_ctx = sdl2::init().unwrap();
|
||||||
|
let video_ctx = sdl_ctx.video().unwrap();
|
||||||
|
let wnd = video_ctx.window("RustBoy", (GB_PIXELS_X * SCALE) as u32, (GB_PIXELS_Y * SCALE) as u32).position_centered().build().expect("Failed to create window :<");
|
||||||
|
let mut renderer = wnd.renderer().build().expect("Could not build renderer");
|
||||||
|
|
||||||
Display {
|
Display {
|
||||||
control: 0,
|
control: 0,
|
||||||
status: 0,
|
status: 0,
|
||||||
@ -56,9 +77,18 @@ impl Display {
|
|||||||
current_ticks: 0,
|
current_ticks: 0,
|
||||||
current_mode: DisplayMode::default(),
|
current_mode: DisplayMode::default(),
|
||||||
vram: vec![0; VRAM_SIZE].into_boxed_slice(),
|
vram: vec![0; VRAM_SIZE].into_boxed_slice(),
|
||||||
|
// sdl_context: sdl_ctx,
|
||||||
|
// video_context: video_ctx,
|
||||||
|
// window: wnd,
|
||||||
|
renderer: renderer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_pixel(&mut self, x: u8, y: u8, color: sdl2::pixels::Color) {
|
||||||
|
self.renderer.set_draw_color(color);
|
||||||
|
self.renderer.fill_rect(sdl2::rect::Rect::new((x as i32) * SCALE as i32, (y as i32) * SCALE as i32, SCALE as u32, SCALE as u32));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
||||||
match addr {
|
match addr {
|
||||||
0x8000 ... 0x9FFF => self.vram[(addr - 0x8000) as usize] = val,
|
0x8000 ... 0x9FFF => self.vram[(addr - 0x8000) as usize] = val,
|
||||||
@ -107,6 +137,7 @@ impl Display {
|
|||||||
if self.current_ticks > TICKS_END_READMODE {
|
if self.current_ticks > TICKS_END_READMODE {
|
||||||
self.current_ticks = 0;
|
self.current_ticks = 0;
|
||||||
self.current_mode = DisplayMode::HBlank;
|
self.current_mode = DisplayMode::HBlank;
|
||||||
|
self.renderscan();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DisplayMode::HBlank => {
|
DisplayMode::HBlank => {
|
||||||
@ -125,6 +156,9 @@ impl Display {
|
|||||||
self.current_ticks = 0;
|
self.current_ticks = 0;
|
||||||
self.curline += 1;
|
self.curline += 1;
|
||||||
if self.curline > 153 {
|
if self.curline > 153 {
|
||||||
|
self.renderer.present();
|
||||||
|
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(0, 0, 0));
|
||||||
|
self.renderer.clear();
|
||||||
self.current_mode = DisplayMode::Scanline;
|
self.current_mode = DisplayMode::Scanline;
|
||||||
self.curline = 0;
|
self.curline = 0;
|
||||||
}
|
}
|
||||||
@ -134,24 +168,99 @@ impl Display {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn renderscan(&mut self) {
|
fn renderscan(&mut self) {
|
||||||
// TODO: Allow switching of tile map
|
// Points to the background map offset to use.
|
||||||
let tilemap: u16 = 0x1800;
|
let background_map: usize;
|
||||||
let map_offset_y: u8 = self.curline.wrapping_add(self.scrolly);
|
// verify!
|
||||||
|
if self.control & (1 << 3) > 0 {
|
||||||
|
background_map = 0x1C00;
|
||||||
|
} else {
|
||||||
|
background_map = 0x1800;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Those are pixel units, not tile units.
|
||||||
|
let map_offset_y: u8 = self.scrolly;
|
||||||
let map_offset_x: u8 = self.scrollx;
|
let map_offset_x: u8 = self.scrollx;
|
||||||
|
|
||||||
let tile_index_y: u8 = map_offset_y / 8;
|
let render_y: u8 = self.curline;
|
||||||
|
|
||||||
// Render line
|
if self.control & (1 << 1) > 0 {
|
||||||
for render_x in 0 .. 159 {
|
panic!("Switch OBJ not supported");
|
||||||
let tile_index_x: u8 = render_x / 8;
|
}
|
||||||
let tile_offset_x: u8 = render_x % 8;
|
|
||||||
|
|
||||||
// TODO: Draw bit
|
// Render background
|
||||||
|
if self.control & (1 << 0) > 0 {
|
||||||
|
println!("Render background");
|
||||||
|
// Render pixels (20 tiles)
|
||||||
|
for render_x in 0 .. 160 {
|
||||||
|
// Absolute render coordinates
|
||||||
|
let render_abs_x = map_offset_x.wrapping_add(render_x);
|
||||||
|
let render_abs_y = map_offset_y.wrapping_add(render_y);
|
||||||
|
|
||||||
|
let tile_index_x: u8 = render_abs_x / 8;
|
||||||
|
let tile_offset_x: u8 = render_abs_x % 8;
|
||||||
|
|
||||||
|
let tile_index_y: u8 = render_abs_y / 8;
|
||||||
|
let tile_offset_y: u8 = render_abs_y % 8;
|
||||||
|
|
||||||
|
let vram_offset: usize = background_map + (tile_index_y as usize) * 32 + tile_index_x as usize;
|
||||||
|
// Obtain tile ID in this area
|
||||||
|
// println!("Render absolute [{:03X}:{:03X}] -> {:03X}", render_abs_x, render_abs_y, vram_offset);
|
||||||
|
let mut tile_id = self.vram[vram_offset];
|
||||||
|
/*
|
||||||
|
if self.control & (1 << 4) > 0 {
|
||||||
|
// This tile dataset is from -127 to 127, not from 0 to 255
|
||||||
|
if (tile_id as i8) < 0 {
|
||||||
|
tile_id = (-(tile_id as i8)) as u8;
|
||||||
|
} else {
|
||||||
|
tile_id += 127;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
println!("vram offset: {:04X}", vram_offset);
|
||||||
|
if tile_id != 0 {
|
||||||
|
println!("Drawing tile {:02X}", tile_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtain tile information
|
||||||
|
let tile_base_addr: usize;
|
||||||
|
if self.control & (1 << 4) > 0 {
|
||||||
|
tile_base_addr = 0x0000;
|
||||||
|
} else {
|
||||||
|
tile_base_addr = 0x0800;
|
||||||
|
// This set goes from -127 to 127.
|
||||||
|
let s_tid: i8 = tile_id as i8;
|
||||||
|
if s_tid < 0 {
|
||||||
|
tile_id = (127 + s_tid) as u8;
|
||||||
|
} else {
|
||||||
|
tile_id = tile_id + 127;
|
||||||
|
}
|
||||||
|
panic!("OH MY GOD, this wasn't tested yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile_base_addr: usize = tile_base_addr + (tile_id as usize) * 16;
|
||||||
|
let tile_line_1 = self.vram[tile_base_addr + (tile_offset_y as usize) * 2];
|
||||||
|
let tile_line_2 = self.vram[tile_base_addr + (tile_offset_y as usize) * 2 + 1];
|
||||||
|
|
||||||
|
// Get the correct bit
|
||||||
|
let b1: bool = (tile_line_1 & 1 << (7 - tile_offset_x)) > 0;
|
||||||
|
let b2: bool = (tile_line_2 & 1 << (7 - tile_offset_x)) > 0;
|
||||||
|
|
||||||
|
let mut factor = 0;
|
||||||
|
if b1 {
|
||||||
|
factor += 64;
|
||||||
|
}
|
||||||
|
if b2 {
|
||||||
|
factor += 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw stuff
|
||||||
|
self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(factor, factor, factor));
|
||||||
|
// self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(255, 255, 255));
|
||||||
// let tile_base_addr = tilemap + tile_id*128
|
// let tile_base_addr = tilemap + tile_id*128
|
||||||
// pixel(render_x, map_offset_y) := *tile_base_addr + 2* *(tile_base_addr+1)
|
// pixel(render_x, map_offset_y) := *tile_base_addr + 2* *(tile_base_addr+1)
|
||||||
//[tile_index_x][tile_index_y]
|
//[tile_index_x][tile_index_y]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vblank_interrupt(&mut self) {
|
pub fn vblank_interrupt(&mut self) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user