colour formats
This commit is contained in:
parent
3fcaca4654
commit
4bae07f165
|
@ -19,13 +19,13 @@ struct EmuParams {}
|
||||||
struct EmuVars {
|
struct EmuVars {
|
||||||
rx: AsyncHeapConsumer<[f32; 2]>,
|
rx: AsyncHeapConsumer<[f32; 2]>,
|
||||||
sender: Sender<EmulatorMessage>,
|
sender: Sender<EmulatorMessage>,
|
||||||
emulator_core: EmulatorCore,
|
emulator_core: EmulatorCore<[u8; 4]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct GameboyEmu {
|
pub struct GameboyEmu {
|
||||||
vars: Option<EmuVars>,
|
vars: Option<EmuVars>,
|
||||||
frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>,
|
frame_receiver: Arc<Mutex<Option<Receiver<Vec<[u8; 4]>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ROM: &[u8; 32768] = include_bytes!("../../test-roms/Tetris.gb");
|
const ROM: &[u8; 32768] = include_bytes!("../../test-roms/Tetris.gb");
|
||||||
|
|
|
@ -14,11 +14,11 @@ use nih_plug::prelude::*;
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
|
|
||||||
pub struct Emulator {
|
pub struct Emulator {
|
||||||
frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>,
|
frame_receiver: Arc<Mutex<Option<Receiver<Vec<[u8; 4]>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Emulator {
|
impl Emulator {
|
||||||
pub fn new(frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>) -> Self {
|
pub fn new(frame_receiver: Arc<Mutex<Option<Receiver<Vec<[u8; 4]>>>>>) -> Self {
|
||||||
Self { frame_receiver }
|
Self { frame_receiver }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,11 +61,14 @@ impl Editor for Emulator {
|
||||||
pub struct EmulatorWindow {
|
pub struct EmulatorWindow {
|
||||||
pix: Pixels,
|
pix: Pixels,
|
||||||
scale: usize,
|
scale: usize,
|
||||||
frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>,
|
frame_receiver: Arc<Mutex<Option<Receiver<Vec<[u8; 4]>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmulatorWindow {
|
impl EmulatorWindow {
|
||||||
fn new(window: &mut Window, frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>) -> Self {
|
fn new(
|
||||||
|
window: &mut Window,
|
||||||
|
frame_receiver: Arc<Mutex<Option<Receiver<Vec<[u8; 4]>>>>>,
|
||||||
|
) -> Self {
|
||||||
let info = WindowInfo::from_logical_size(Size::new(WIDTH as f64, HEIGHT as f64), 1.);
|
let info = WindowInfo::from_logical_size(Size::new(WIDTH as f64, HEIGHT as f64), 1.);
|
||||||
|
|
||||||
let (pix, scale) = init_pixbuf(info, window);
|
let (pix, scale) = init_pixbuf(info, window);
|
||||||
|
@ -105,7 +108,7 @@ impl WindowHandler for EmulatorWindow {
|
||||||
for (pixel, source) in
|
for (pixel, source) in
|
||||||
self.pix.get_frame_mut().chunks_exact_mut(4).zip(scaled_buf)
|
self.pix.get_frame_mut().chunks_exact_mut(4).zip(scaled_buf)
|
||||||
{
|
{
|
||||||
pixel.copy_from_slice(&source.to_be_bytes());
|
pixel.copy_from_slice(&source);
|
||||||
}
|
}
|
||||||
self.pix.render().unwrap();
|
self.pix.render().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -124,21 +127,21 @@ impl WindowHandler for EmulatorWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EmulatorRenderer {
|
pub struct EmulatorRenderer {
|
||||||
tx: Sender<Vec<u32>>,
|
tx: Sender<Vec<[u8; 4]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmulatorRenderer {
|
impl EmulatorRenderer {
|
||||||
pub(super) fn new() -> (Self, Receiver<Vec<u32>>) {
|
pub(super) fn new() -> (Self, Receiver<Vec<[u8; 4]>>) {
|
||||||
let (tx, rx) = mpsc::channel::<Vec<u32>>();
|
let (tx, rx) = mpsc::channel::<Vec<[u8; 4]>>();
|
||||||
(Self { tx }, rx)
|
(Self { tx }, rx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for EmulatorRenderer {
|
impl Renderer<[u8; 4]> for EmulatorRenderer {
|
||||||
fn prepare(&mut self, _width: usize, _height: usize) {}
|
fn prepare(&mut self, _width: usize, _height: usize) {}
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
#[allow(unused_must_use)]
|
||||||
fn display(&mut self, buffer: &[u32]) {
|
fn display(&mut self, buffer: &[[u8; 4]]) {
|
||||||
self.tx.send(buffer.to_vec());
|
self.tx.send(buffer.to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::processor::memory::mmio::gpu::Colour;
|
||||||
pub use crate::processor::memory::mmio::joypad::JoypadState;
|
pub use crate::processor::memory::mmio::joypad::JoypadState;
|
||||||
pub use crate::{HEIGHT, WIDTH};
|
pub use crate::{HEIGHT, WIDTH};
|
||||||
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};
|
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};
|
||||||
|
@ -12,10 +13,10 @@ pub enum RomFile {
|
||||||
Raw(Vec<u8>),
|
Raw(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Renderer: Send {
|
pub trait Renderer<Format: From<Colour>>: Send {
|
||||||
fn prepare(&mut self, width: usize, height: usize);
|
fn prepare(&mut self, width: usize, height: usize);
|
||||||
|
|
||||||
fn display(&mut self, buffer: &[u32]);
|
fn display(&mut self, buffer: &[Format]);
|
||||||
|
|
||||||
fn set_title(&mut self, _title: String) {}
|
fn set_title(&mut self, _title: String) {}
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,17 @@
|
||||||
let_chains,
|
let_chains,
|
||||||
slice_flatten,
|
slice_flatten,
|
||||||
async_closure,
|
async_closure,
|
||||||
bigint_helper_methods
|
bigint_helper_methods,
|
||||||
|
associated_type_defaults
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use crate::{processor::memory::Memory, util::pause};
|
use crate::{processor::memory::Memory, util::pause};
|
||||||
use connect::{AudioOutput, EmulatorMessage, Renderer, RomFile};
|
use connect::{AudioOutput, EmulatorMessage, Renderer, RomFile};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use processor::{memory::Rom, Cpu};
|
use processor::{
|
||||||
|
memory::{mmio::gpu::Colour, Rom},
|
||||||
|
Cpu,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self},
|
fs::{self},
|
||||||
io::{stdout, Write},
|
io::{stdout, Write},
|
||||||
|
@ -43,20 +47,20 @@ static VERBOSE: OnceCell<bool> = OnceCell::new();
|
||||||
pub const WIDTH: usize = 160;
|
pub const WIDTH: usize = 160;
|
||||||
pub const HEIGHT: usize = 144;
|
pub const HEIGHT: usize = 144;
|
||||||
|
|
||||||
pub struct EmulatorCore {
|
pub struct EmulatorCore<ColourFormat: From<Colour> + Clone> {
|
||||||
receiver: Receiver<EmulatorMessage>,
|
receiver: Receiver<EmulatorMessage>,
|
||||||
cpu: Cpu,
|
cpu: Cpu<ColourFormat>,
|
||||||
cycle_num: usize,
|
cycle_num: usize,
|
||||||
cycle_count: bool,
|
cycle_count: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmulatorCore {
|
impl<ColourFormat: From<Colour> + Clone> EmulatorCore<ColourFormat> {
|
||||||
pub fn init(
|
pub fn init(
|
||||||
receiver: Receiver<EmulatorMessage>,
|
receiver: Receiver<EmulatorMessage>,
|
||||||
options: Options,
|
options: Options,
|
||||||
mut window: Box<dyn Renderer>,
|
mut window: Box<dyn Renderer<ColourFormat>>,
|
||||||
output: AudioOutput,
|
output: AudioOutput,
|
||||||
tile_window: Option<Box<dyn Renderer>>,
|
tile_window: Option<Box<dyn Renderer<ColourFormat>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
VERBOSE.set(options.verbose).unwrap();
|
VERBOSE.set(options.verbose).unwrap();
|
||||||
|
|
||||||
|
@ -116,7 +120,7 @@ impl EmulatorCore {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(receiver: Receiver<EmulatorMessage>, cpu: Cpu, cycle_count: bool) -> Self {
|
fn new(receiver: Receiver<EmulatorMessage>, cpu: Cpu<ColourFormat>, cycle_count: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
receiver,
|
receiver,
|
||||||
cpu,
|
cpu,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::{Cpu, Direction, Flags, Reg8, SplitRegister},
|
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, Reg8, SplitRegister},
|
||||||
util::{clear_bit, get_bit, set_bit},
|
util::{clear_bit, get_bit, set_bit},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Cpu {
|
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
|
||||||
pub(crate) fn and(&mut self, first: u8, second: u8) -> u8 {
|
pub(crate) fn and(&mut self, first: u8, second: u8) -> u8 {
|
||||||
let result = first & second;
|
let result = first & second;
|
||||||
self.set_or_clear_flag(Flags::Zero, result == 0x0);
|
self.set_or_clear_flag(Flags::Zero, result == 0x0);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::{Cpu, Direction, Flags, SplitRegister},
|
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, SplitRegister},
|
||||||
util::{as_signed, get_bit, get_rotation_carry, rotate, Nibbles},
|
util::{as_signed, get_bit, get_rotation_carry, rotate, Nibbles},
|
||||||
};
|
};
|
||||||
use std::ops::{BitAnd, BitOr};
|
use std::ops::{BitAnd, BitOr};
|
||||||
|
|
||||||
impl Cpu {
|
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
|
||||||
pub(crate) fn pop_word(&mut self) -> u16 {
|
pub(crate) fn pop_word(&mut self) -> u16 {
|
||||||
let mut word: u16 = 0x0;
|
let mut word: u16 = 0x0;
|
||||||
word.set_low(self.memory.get(self.reg.sp));
|
word.set_low(self.memory.get(self.reg.sp));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use self::mmio::{Apu, Gpu, Joypad, Serial, Timer};
|
use self::mmio::{gpu::Colour, Apu, Gpu, Joypad, Serial, Timer};
|
||||||
pub use self::rom::Rom;
|
pub use self::rom::Rom;
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::{AudioOutput, JoypadState, Renderer},
|
connect::{AudioOutput, JoypadState, Renderer},
|
||||||
|
@ -13,7 +13,7 @@ pub(crate) mod rom;
|
||||||
|
|
||||||
pub(crate) type Address = u16;
|
pub(crate) type Address = u16;
|
||||||
|
|
||||||
pub struct Memory {
|
pub struct Memory<ColourFormat: From<Colour> + Clone> {
|
||||||
bootrom: Option<Vec<u8>>,
|
bootrom: Option<Vec<u8>>,
|
||||||
rom: Rom,
|
rom: Rom,
|
||||||
ram: [u8; 8192],
|
ram: [u8; 8192],
|
||||||
|
@ -23,20 +23,20 @@ pub struct Memory {
|
||||||
pub(super) ime_scheduled: u8,
|
pub(super) ime_scheduled: u8,
|
||||||
dma_addr: u8,
|
dma_addr: u8,
|
||||||
joypad: Joypad,
|
joypad: Joypad,
|
||||||
gpu: Gpu,
|
gpu: Gpu<ColourFormat>,
|
||||||
apu: Apu,
|
apu: Apu,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
timers: Timer,
|
timers: Timer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl<ColourFormat: From<Colour> + Clone> Memory<ColourFormat> {
|
||||||
pub fn init(
|
pub fn init(
|
||||||
bootrom: Option<Vec<u8>>,
|
bootrom: Option<Vec<u8>>,
|
||||||
rom: Rom,
|
rom: Rom,
|
||||||
window: Box<dyn Renderer>,
|
window: Box<dyn Renderer<ColourFormat>>,
|
||||||
output: AudioOutput,
|
output: AudioOutput,
|
||||||
connect_serial: bool,
|
connect_serial: bool,
|
||||||
tile_window: Option<Box<dyn Renderer>>,
|
tile_window: Option<Box<dyn Renderer<ColourFormat>>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let serial = if connect_serial {
|
let serial = if connect_serial {
|
||||||
Serial::default().connected()
|
Serial::default().connected()
|
||||||
|
@ -228,7 +228,7 @@ impl Memory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
|
||||||
pub fn increment_timers(&mut self, machine_cycles: u8) {
|
pub fn increment_timers(&mut self, machine_cycles: u8) {
|
||||||
let steps = (machine_cycles as usize) * 4;
|
let steps = (machine_cycles as usize) * 4;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use self::{
|
use self::{
|
||||||
tile_window::TileWindow,
|
tile_window::TileWindow,
|
||||||
types::{
|
types::{
|
||||||
Colour, DrawMode, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags,
|
DrawMode, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette,
|
||||||
Palette, Stat, TiledataArea, TilemapArea, Vram,
|
Stat, TiledataArea, TilemapArea, Vram,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
util::{clear_bit, get_bit},
|
util::{clear_bit, get_bit},
|
||||||
HEIGHT, WIDTH,
|
HEIGHT, WIDTH,
|
||||||
};
|
};
|
||||||
|
pub use types::Colour;
|
||||||
|
|
||||||
mod addresses;
|
mod addresses;
|
||||||
mod tile_window;
|
mod tile_window;
|
||||||
|
@ -19,18 +20,18 @@ mod types;
|
||||||
const TILE_WINDOW_WIDTH: usize = 16 * 8;
|
const TILE_WINDOW_WIDTH: usize = 16 * 8;
|
||||||
const TILE_WINDOW_HEIGHT: usize = 24 * 8;
|
const TILE_WINDOW_HEIGHT: usize = 24 * 8;
|
||||||
|
|
||||||
pub struct Gpu {
|
pub struct Gpu<Format: From<Colour>> {
|
||||||
pub buffer: Vec<u32>,
|
pub buffer: Vec<Format>,
|
||||||
pub vram: Vram,
|
pub vram: Vram,
|
||||||
pub oam: Oam,
|
pub oam: Oam,
|
||||||
pub window: Box<dyn Renderer>,
|
pub window: Box<dyn Renderer<Format>>,
|
||||||
is_bg_zero: Vec<bool>,
|
is_bg_zero: Vec<bool>,
|
||||||
lcdc: Lcdc,
|
lcdc: Lcdc,
|
||||||
stat: Stat,
|
stat: Stat,
|
||||||
mode_clock: usize,
|
mode_clock: usize,
|
||||||
scanline: u8,
|
scanline: u8,
|
||||||
lyc: u8,
|
lyc: u8,
|
||||||
tile_window: Option<TileWindow>,
|
tile_window: Option<TileWindow<Format>>,
|
||||||
window_lc: u8,
|
window_lc: u8,
|
||||||
has_window_been_enabled: bool,
|
has_window_been_enabled: bool,
|
||||||
bg_palette: Palette,
|
bg_palette: Palette,
|
||||||
|
@ -43,17 +44,21 @@ pub struct Gpu {
|
||||||
prev_stat: bool,
|
prev_stat: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gpu {
|
impl<Format: From<Colour> + Clone> Gpu<Format> {
|
||||||
pub fn new(window: Box<dyn Renderer>, tile_window_renderer: Option<Box<dyn Renderer>>) -> Self {
|
pub fn new(
|
||||||
|
window: Box<dyn Renderer<Format>>,
|
||||||
|
tile_window_renderer: Option<Box<dyn Renderer<Format>>>,
|
||||||
|
) -> Self {
|
||||||
let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer {
|
let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer {
|
||||||
tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT);
|
tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT);
|
||||||
Some(TileWindow::new(tile_window_renderer))
|
Some(TileWindow::new(tile_window_renderer))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
let buffer = vec![Colour::Error.into(); WIDTH * HEIGHT];
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
buffer: vec![0; WIDTH * HEIGHT],
|
buffer,
|
||||||
vram: Vram::default(),
|
vram: Vram::default(),
|
||||||
oam: Oam::default(),
|
oam: Oam::default(),
|
||||||
window,
|
window,
|
||||||
|
@ -162,7 +167,7 @@ impl Gpu {
|
||||||
*e = true;
|
*e = true;
|
||||||
}
|
}
|
||||||
for x in 0..WIDTH {
|
for x in 0..WIDTH {
|
||||||
self.buffer[(scanline as usize * WIDTH) + x] = Colour::from_u8_rgb(255, 0, 255);
|
self.buffer[(scanline as usize * WIDTH) + x] = Colour::Error.into();
|
||||||
}
|
}
|
||||||
if self.lcdc.bg_window_enable {
|
if self.lcdc.bg_window_enable {
|
||||||
self.render_scanline_bg(scanline);
|
self.render_scanline_bg(scanline);
|
||||||
|
@ -175,7 +180,7 @@ impl Gpu {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for x in 0..WIDTH {
|
for x in 0..WIDTH {
|
||||||
self.buffer[(scanline as usize * WIDTH) + x] = Colour::from_u8_rgb(255, 255, 255);
|
self.buffer[(scanline as usize * WIDTH) + x] = Colour::Error.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.lcdc.obj_enable {
|
if self.lcdc.obj_enable {
|
||||||
|
@ -295,7 +300,7 @@ impl Gpu {
|
||||||
if x_coord < WIDTH {
|
if x_coord < WIDTH {
|
||||||
let buffer_index = (scanline as usize * WIDTH) + x_coord;
|
let buffer_index = (scanline as usize * WIDTH) + x_coord;
|
||||||
if !object.flags.behind_bg_and_window || self.is_bg_zero[x_coord] {
|
if !object.flags.behind_bg_and_window || self.is_bg_zero[x_coord] {
|
||||||
self.buffer[buffer_index] = colour.as_rgb();
|
self.buffer[buffer_index] = colour.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +345,7 @@ impl Gpu {
|
||||||
let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb);
|
let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb);
|
||||||
self.is_bg_zero[x] = is_zero;
|
self.is_bg_zero[x] = is_zero;
|
||||||
|
|
||||||
self.buffer[(scanline as usize * WIDTH) + x] = colour.as_rgb();
|
self.buffer[(scanline as usize * WIDTH) + x] = colour.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@ use crate::util::{get_bit, set_or_clear_bit};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
types::{DrawMode, ObjSize, Palette, TiledataArea, TilemapArea},
|
types::{DrawMode, ObjSize, Palette, TiledataArea, TilemapArea},
|
||||||
Gpu,
|
Colour, Gpu,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Gpu {
|
impl<Format: From<Colour>> Gpu<Format> {
|
||||||
pub fn update_lcdc(&mut self, data: u8) {
|
pub fn update_lcdc(&mut self, data: u8) {
|
||||||
self.lcdc.enable = get_bit(data, 7);
|
self.lcdc.enable = get_bit(data, 7);
|
||||||
self.lcdc.window_tilemap = if get_bit(data, 6) {
|
self.lcdc.window_tilemap = if get_bit(data, 6) {
|
||||||
|
|
|
@ -4,23 +4,24 @@ use crate::{
|
||||||
util::get_bit,
|
util::get_bit,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::types::Vram;
|
use super::{types::Vram, Colour};
|
||||||
|
|
||||||
pub(super) struct TileWindow {
|
pub(super) struct TileWindow<Format: From<Colour>> {
|
||||||
sprite_buffer: Vec<u32>,
|
sprite_buffer: Vec<Format>,
|
||||||
sprite_renderer: Box<dyn Renderer>,
|
sprite_renderer: Box<dyn Renderer<Format>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileWindow {
|
impl<Format: From<Colour>> TileWindow<Format> {
|
||||||
pub(super) fn new(window: Box<dyn Renderer>) -> Self {
|
pub(super) fn new(window: Box<dyn Renderer<Format>>) -> Self {
|
||||||
|
let mut sprite_buffer = Vec::new();
|
||||||
|
sprite_buffer.reserve_exact(TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sprite_buffer: vec![0; TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT],
|
sprite_buffer,
|
||||||
sprite_renderer: window,
|
sprite_renderer: window,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl TileWindow {
|
|
||||||
pub(super) fn draw_sprite_window(&mut self, palette: Palette, memory: &Vram) {
|
pub(super) fn draw_sprite_window(&mut self, palette: Palette, memory: &Vram) {
|
||||||
for tile_y in 0..16 {
|
for tile_y in 0..16 {
|
||||||
self.draw_row(
|
self.draw_row(
|
||||||
|
@ -66,7 +67,7 @@ impl TileWindow {
|
||||||
let colour = palette.map_bits(lsb, msb);
|
let colour = palette.map_bits(lsb, msb);
|
||||||
|
|
||||||
self.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_WIDTH)] =
|
self.sprite_buffer[real_px_x + (real_px_y * TILE_WINDOW_WIDTH)] =
|
||||||
colour.0.as_rgb();
|
colour.0.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,28 +84,40 @@ impl Default for Lcdc {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub(super) enum Colour {
|
pub enum Colour {
|
||||||
White,
|
White,
|
||||||
LightGray,
|
LightGray,
|
||||||
DarkGray,
|
DarkGray,
|
||||||
Black,
|
Black,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Colour> for u32 {
|
||||||
|
fn from(value: Colour) -> Self {
|
||||||
|
let rgb = value.rgb_bytes();
|
||||||
|
let (r, g, b) = (rgb.0 as u32, rgb.1 as u32, rgb.2 as u32);
|
||||||
|
(r << 16) | (g << 8) | b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Colour> for [u8; 4] {
|
||||||
|
fn from(value: Colour) -> Self {
|
||||||
|
let (r, g, b) = value.rgb_bytes();
|
||||||
|
[r, g, b, 0xFF]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Colour {
|
impl Colour {
|
||||||
pub(super) fn as_rgb(&self) -> u32 {
|
fn rgb_bytes(&self) -> (u8, u8, u8) {
|
||||||
match self {
|
match self {
|
||||||
Colour::White => Self::from_u8_rgb(0xFF, 0xFF, 0xFF),
|
Colour::White => (0xFF, 0xFF, 0xFF),
|
||||||
Colour::LightGray => Self::from_u8_rgb(0xAA, 0xAA, 0xAA),
|
Colour::LightGray => (0xAA, 0xAA, 0xAA),
|
||||||
Colour::DarkGray => Self::from_u8_rgb(0x55, 0x55, 0x55),
|
Colour::DarkGray => (0x55, 0x55, 0x55),
|
||||||
Colour::Black => Self::from_u8_rgb(0x00, 0x00, 0x00),
|
Colour::Black => (0x00, 0x00, 0x00),
|
||||||
|
Colour::Error => (0xFF, 0x00, 0x00),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) 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
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn from_bits(first: bool, second: bool) -> Colour {
|
pub(super) fn from_bits(first: bool, second: bool) -> Colour {
|
||||||
match (first, second) {
|
match (first, second) {
|
||||||
(true, true) => Colour::Black,
|
(true, true) => Colour::Black,
|
||||||
|
@ -121,6 +133,7 @@ impl Colour {
|
||||||
Colour::LightGray => 0b10,
|
Colour::LightGray => 0b10,
|
||||||
Colour::DarkGray => 0b01,
|
Colour::DarkGray => 0b01,
|
||||||
Colour::Black => 0b11,
|
Colour::Black => 0b11,
|
||||||
|
Colour::Error => 0b00,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use self::memory::{Interrupt, Memory};
|
use self::memory::{mmio::gpu::Colour, Interrupt, Memory};
|
||||||
use crate::verbose_println;
|
use crate::verbose_println;
|
||||||
|
|
||||||
mod instructions;
|
mod instructions;
|
||||||
|
@ -18,8 +18,8 @@ pub(crate) enum Direction {
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Cpu {
|
pub struct Cpu<ColourFormat: From<Colour> + Clone> {
|
||||||
pub memory: Memory,
|
pub memory: Memory<ColourFormat>,
|
||||||
pub reg: Registers,
|
pub reg: Registers,
|
||||||
pub last_instruction: u8,
|
pub last_instruction: u8,
|
||||||
last_instruction_addr: u16,
|
last_instruction_addr: u16,
|
||||||
|
@ -27,8 +27,8 @@ pub struct Cpu {
|
||||||
should_halt_bug: bool,
|
should_halt_bug: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
|
||||||
pub fn new(mut memory: Memory, run_bootrom: bool) -> Self {
|
pub fn new(mut memory: Memory<ColourFormat>, run_bootrom: bool) -> Self {
|
||||||
if !run_bootrom {
|
if !run_bootrom {
|
||||||
memory.cpu_ram_init();
|
memory.cpu_ram_init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@ use crate::{
|
||||||
util::as_signed,
|
util::as_signed,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Cpu {
|
use super::memory::mmio::gpu::Colour;
|
||||||
|
|
||||||
|
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
|
||||||
pub fn run_opcode(&mut self, opcode: u8) -> u8 {
|
pub fn run_opcode(&mut self, opcode: u8) -> u8 {
|
||||||
match opcode {
|
match opcode {
|
||||||
0x00 => {
|
0x00 => {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::{processor::Direction, PAUSE_ENABLED, PAUSE_QUEUED, VERBOSE};
|
use crate::{
|
||||||
|
processor::{memory::mmio::gpu::Colour, Direction},
|
||||||
|
PAUSE_ENABLED, PAUSE_QUEUED, VERBOSE,
|
||||||
|
};
|
||||||
use std::{io, mem::transmute};
|
use std::{io, mem::transmute};
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -122,7 +125,12 @@ impl Nibbles for u8 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scale_buffer(buffer: &[u32], width: usize, height: usize, factor: usize) -> Vec<u32> {
|
pub fn scale_buffer<T: From<Colour> + Copy>(
|
||||||
|
buffer: &[T],
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
factor: usize,
|
||||||
|
) -> Vec<T> {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
for _ in 0..factor {
|
for _ in 0..factor {
|
||||||
|
|
Loading…
Reference in a new issue