object rendering + usermode ram
This commit is contained in:
parent
94bb1a2bfb
commit
f0b2369c9d
11
src/main.rs
11
src/main.rs
|
@ -78,6 +78,7 @@ pub struct Memory {
|
|||
ime: bool,
|
||||
ime_scheduled: u8,
|
||||
io: [u8; 76],
|
||||
user_mode: bool,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
|
@ -95,6 +96,7 @@ impl Memory {
|
|||
ime: false,
|
||||
ime_scheduled: 0x0,
|
||||
io: [0xFF; 76],
|
||||
user_mode: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,7 +173,14 @@ impl Memory {
|
|||
0xFEA0..0xFF00 => {
|
||||
// println!("empty space write: {:#X} to addr {:#X}", data, address);
|
||||
}
|
||||
0xFF00..0xFF4C => {
|
||||
0xFF04 => {
|
||||
if self.user_mode {
|
||||
self.io[0xFF04 - 0xFF00] = 0;
|
||||
} else {
|
||||
self.io[0xFF04 - 0xFF00] = data;
|
||||
}
|
||||
}
|
||||
0xFF00..0xFF04 | 0xFF05..0xFF4C => {
|
||||
// verbose_print!("writing to addr {:#X}\r", address);
|
||||
stdout().flush().unwrap();
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ enum DrawMode {
|
|||
Mode3,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TilemapArea {
|
||||
T9800,
|
||||
T9C00,
|
||||
|
@ -28,6 +29,7 @@ impl TilemapArea {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum TiledataArea {
|
||||
D8000,
|
||||
D9000,
|
||||
|
@ -42,12 +44,22 @@ impl TiledataArea {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ObjSize {
|
||||
S8x8,
|
||||
S8x16,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl ObjSize {
|
||||
fn get_height(&self) -> u8 {
|
||||
match self {
|
||||
ObjSize::S8x8 => 8,
|
||||
ObjSize::S8x16 => 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LCDC {
|
||||
enable: bool,
|
||||
window_tilemap: TilemapArea,
|
||||
|
@ -91,6 +103,20 @@ struct Palette {
|
|||
three: Colour,
|
||||
}
|
||||
|
||||
struct ObjectFlags {
|
||||
behind_bg_and_window: bool,
|
||||
y_flip: bool,
|
||||
x_flip: bool,
|
||||
palette: Palette,
|
||||
}
|
||||
|
||||
struct Object {
|
||||
x: u8,
|
||||
y: u8,
|
||||
tile_index: u8,
|
||||
flags: ObjectFlags,
|
||||
}
|
||||
|
||||
const TILE_WINDOW_EDGE_LENGTH: usize = 16 * 8;
|
||||
const TILE_WINDOW_EDGE_LENGTH_SCALED: usize = TILE_WINDOW_EDGE_LENGTH * FACTOR;
|
||||
|
||||
|
@ -227,6 +253,7 @@ impl CPU {
|
|||
self.render_window();
|
||||
self.memory.set(0xFF0F, set_bit(self.memory.get(0xFF0F), 0));
|
||||
}
|
||||
// println!("lcdc: {:#?}", lcdc);
|
||||
}
|
||||
|
||||
fn exit_vblank(&mut self) {
|
||||
|
@ -297,7 +324,65 @@ impl CPU {
|
|||
}
|
||||
}
|
||||
|
||||
fn render_scanline_obj(&mut self, _scanline: u8, _lcdc: &LCDC) {}
|
||||
fn render_scanline_obj(&mut self, scanline: u8, lcdc: &LCDC) {
|
||||
let objs = self.parse_oam(scanline, &lcdc.obj_size);
|
||||
for object in objs {
|
||||
println!("rendering object");
|
||||
self.render_object(scanline, object, &lcdc.obj_size);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_oam(&mut self, scanline: u8, obj_size: &ObjSize) -> Vec<Object> {
|
||||
let mut objs = vec![];
|
||||
for i in (0xFE00..0xFE9F).step_by(4) {
|
||||
let y_pos = self.memory.get(i).wrapping_sub(16);
|
||||
if y_pos <= scanline && (y_pos + obj_size.get_height()) > scanline {
|
||||
// sprite is on line
|
||||
let x_pos = self.memory.get(i + 1);
|
||||
let tile_index = self.memory.get(i + 2);
|
||||
let flags = self.memory.get(i + 3);
|
||||
let palette_addr = if get_bit(flags, 4) { 0xFF49 } else { 0xFF48 };
|
||||
objs.push(Object {
|
||||
x: x_pos,
|
||||
y: y_pos,
|
||||
tile_index,
|
||||
flags: ObjectFlags {
|
||||
behind_bg_and_window: get_bit(flags, 7),
|
||||
y_flip: get_bit(flags, 6),
|
||||
x_flip: get_bit(flags, 5),
|
||||
palette: byte_to_palette(self.memory.get(palette_addr)),
|
||||
},
|
||||
});
|
||||
if objs.len() >= 10 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
objs
|
||||
}
|
||||
|
||||
fn render_object(&mut self, scanline: u8, object: Object, obj_size: &ObjSize) {
|
||||
let mut object_row = scanline - object.y;
|
||||
if object.flags.y_flip {
|
||||
object_row = obj_size.get_height() - object_row;
|
||||
}
|
||||
let tile_row = object_row % 8;
|
||||
let tile_addr = TiledataArea::D8000
|
||||
.get_addr(object.tile_index + if object_row >= 8 { 1 } else { 0 })
|
||||
+ (tile_row as u16 * 2);
|
||||
let lsbs = self.memory.get(tile_addr);
|
||||
let msbs = self.memory.get(tile_addr + 1);
|
||||
for px_x in 0..8 {
|
||||
let x_addr = if object.flags.x_flip { px_x } else { 7 - px_x };
|
||||
let lsb = get_bit(lsbs, x_addr);
|
||||
let msb = get_bit(msbs, x_addr);
|
||||
let colour = bits_to_mapped_colour(lsb, msb, object.flags.palette);
|
||||
let x_coord = (object.x as usize * 8) + (px_x as usize);
|
||||
if x_coord < WIDTH {
|
||||
self.gpu.buffer[(scanline as usize * WIDTH) + x_coord] = colour.to_rgb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_tiles(
|
||||
&mut self,
|
||||
|
|
|
@ -66,7 +66,9 @@ impl CPU {
|
|||
opcode,
|
||||
self.last_instruction_addr
|
||||
);
|
||||
self.memory.user_mode = true;
|
||||
let cycles = self.run_opcode(opcode);
|
||||
self.memory.user_mode = false;
|
||||
self.increment_timers(cycles);
|
||||
|
||||
let interrupt_cycles = self.handle_interrupts();
|
||||
|
|
Loading…
Reference in a new issue