[cln] Code cleanup
Cleanup code Add a offset delay timer
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -191,7 +191,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "porcel8"
|
name = "porcel8"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"clap",
|
"clap",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "porcel8"
|
name = "porcel8"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@@ -37,28 +37,13 @@ impl Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Device {
|
impl Device {
|
||||||
const DEFAULT_FONT: [u8; 5 * 16] = [
|
|
||||||
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
|
||||||
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
|
||||||
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
|
||||||
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
|
||||||
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
|
||||||
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
|
||||||
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
|
||||||
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
|
||||||
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
|
||||||
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
|
||||||
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
|
||||||
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
|
||||||
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
|
||||||
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
|
||||||
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
|
||||||
0xF0, 0x80, 0xF0, 0x80, 0x80 // F
|
|
||||||
];
|
|
||||||
const FONT_DEFAULT_MEM_LOCATION_START: usize = 0x50;
|
|
||||||
const FONT_HEIGHT: u16 = 5;
|
const FONT_HEIGHT: u16 = 5;
|
||||||
|
const FONT_DEFAULT_MEM_LOCATION_START: usize = 0x50;
|
||||||
const FONT_DEFAULT_MEM_LOCATION_END: usize = 0x9F;
|
const FONT_DEFAULT_MEM_LOCATION_END: usize = 0x9F;
|
||||||
const ROM_START: usize = 0x200;
|
const ROM_START: usize = 0x200;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn cycle(&mut self) -> EmulatorResult<()> {
|
pub fn cycle(&mut self) -> EmulatorResult<()> {
|
||||||
self.device_keyboard.update_keyboard()?;
|
self.device_keyboard.update_keyboard()?;
|
||||||
|
|
||||||
@@ -312,8 +297,26 @@ impl Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_default_font(&mut self) {
|
pub fn set_default_font(&mut self) {
|
||||||
|
const DEFAULT_FONT: [u8; Device::FONT_HEIGHT as usize * 16] = [
|
||||||
|
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
||||||
|
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
||||||
|
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
||||||
|
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
||||||
|
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
||||||
|
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
||||||
|
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
||||||
|
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
||||||
|
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
||||||
|
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
||||||
|
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
||||||
|
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
||||||
|
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||||||
|
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||||||
|
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
||||||
|
0xF0, 0x80, 0xF0, 0x80, 0x80 // F
|
||||||
|
];
|
||||||
log::info!("Loaded default font from memory");
|
log::info!("Loaded default font from memory");
|
||||||
self.memory[Self::FONT_DEFAULT_MEM_LOCATION_START..=Self::FONT_DEFAULT_MEM_LOCATION_END].copy_from_slice(&Self::DEFAULT_FONT);
|
self.memory[Self::FONT_DEFAULT_MEM_LOCATION_START..=Self::FONT_DEFAULT_MEM_LOCATION_END].copy_from_slice(&DEFAULT_FONT);
|
||||||
}
|
}
|
||||||
/// load a rom from bytes
|
/// load a rom from bytes
|
||||||
pub fn load_rom(&mut self, rom: &[u8]) {
|
pub fn load_rom(&mut self, rom: &[u8]) {
|
||||||
|
@@ -2,13 +2,11 @@ use std::sync::mpsc::TryRecvError;
|
|||||||
use crate::util::{EmulatorError, EmulatorResult};
|
use crate::util::{EmulatorError, EmulatorResult};
|
||||||
|
|
||||||
|
|
||||||
// display thread sends these to the device thread.
|
/// An emulated keyboard that receives keyboard data as input
|
||||||
|
|
||||||
// device thread updates on key up and down?
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Keyboard {
|
pub struct Keyboard {
|
||||||
|
/// Current keyboard state
|
||||||
bitflags: u16,
|
bitflags: u16,
|
||||||
|
/// Receives keyboard events from main thread
|
||||||
keyboard_event_receiver: std::sync::mpsc::Receiver<KeyboardEvent>,
|
keyboard_event_receiver: std::sync::mpsc::Receiver<KeyboardEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +24,8 @@ impl Keyboard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update keyboard based on pending keyboard events
|
/// Update keyboard based on pending keyboard events.
|
||||||
|
/// If no events are presents, it will return without any action.
|
||||||
pub fn update_keyboard(&mut self) -> EmulatorResult<()> {
|
pub fn update_keyboard(&mut self) -> EmulatorResult<()> {
|
||||||
loop {
|
loop {
|
||||||
let keyboard_event_recv_res = self.keyboard_event_receiver.try_recv();
|
let keyboard_event_recv_res = self.keyboard_event_receiver.try_recv();
|
||||||
@@ -45,7 +44,6 @@ impl Keyboard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Query if key is down
|
/// Query if key is down
|
||||||
pub fn query_key_down(&self, key_num: u8) -> bool {
|
pub fn query_key_down(&self, key_num: u8) -> bool {
|
||||||
(self.bitflags | 1 << key_num) == (1 << key_num)
|
(self.bitflags | 1 << key_num) == (1 << key_num)
|
||||||
|
73
src/main.rs
73
src/main.rs
@@ -1,9 +1,8 @@
|
|||||||
use std::fs::File;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Sender;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::thread::JoinHandle;
|
||||||
|
use std::time::{Duration};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use sdl2::audio::{AudioQueue, AudioSpecDesired};
|
use sdl2::audio::{AudioQueue, AudioSpecDesired};
|
||||||
@@ -15,10 +14,10 @@ use sdl2::render::BlendMode;
|
|||||||
|
|
||||||
use sdl2::render::WindowCanvas;
|
use sdl2::render::WindowCanvas;
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
use device::timer::DeviceTimerManager;
|
|
||||||
use crate::args::Porcel8ProgramArgs;
|
use crate::args::Porcel8ProgramArgs;
|
||||||
use crate::device::Device;
|
use crate::device::Device;
|
||||||
use crate::device::keyboard::Keyboard;
|
|
||||||
use crate::util::EmulatorResult;
|
use crate::util::EmulatorResult;
|
||||||
use crate::kb_map::get_key_index;
|
use crate::kb_map::get_key_index;
|
||||||
use crate::sdl_adapters::sdl_audio_adapter::SdlAudioAdapter;
|
use crate::sdl_adapters::sdl_audio_adapter::SdlAudioAdapter;
|
||||||
@@ -30,26 +29,26 @@ mod device;
|
|||||||
mod kb_map;
|
mod kb_map;
|
||||||
mod util;
|
mod util;
|
||||||
mod sdl_adapters;
|
mod sdl_adapters;
|
||||||
|
mod rom;
|
||||||
|
|
||||||
fn main() -> EmulatorResult<()> {
|
fn main() -> EmulatorResult<()> {
|
||||||
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
|
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
|
||||||
let Porcel8ProgramArgs { filename, new_chip8_behaviour,draw_scale } = Porcel8ProgramArgs::parse();
|
let Porcel8ProgramArgs { filename, new_chip8_behaviour, draw_scale } = Porcel8ProgramArgs::parse();
|
||||||
|
|
||||||
log::info!("Started emulator");
|
log::info!("Started emulator");
|
||||||
|
|
||||||
|
let (mut canvas, mut event_pump, audio_queue) = try_initiate_sdl(draw_scale)?;
|
||||||
|
|
||||||
let (mut canvas, mut event_pump,audio_queue) = try_initiate_sdl(draw_scale)?;
|
let (mut timer, mut sdl_aud_adapter) = SdlAudioAdapter::new_timers(SdlAudioAdapter::AUDIO_FREQUENCY, 0.85, audio_queue);
|
||||||
|
|
||||||
let (mut timer,mut sdl_aud_adapter) = SdlAudioAdapter::new_timers(440.0,0.85,audio_queue);
|
|
||||||
|
|
||||||
let (frame_buffer_for_display, frame_buffer_for_device) = get_frame_buffer_references();
|
let (frame_buffer_for_display, frame_buffer_for_device) = get_frame_buffer_references();
|
||||||
let (sdl_kb_adapter, device_keyboard) = SdlKeyboardAdapter::new_keyboard();
|
let (sdl_kb_adapter, device_keyboard) = SdlKeyboardAdapter::new_keyboard();
|
||||||
|
|
||||||
let (device_termination_signal_sender, device_termination_signal_sender_receiver) = std::sync::mpsc::channel();
|
|
||||||
|
|
||||||
timer.start();
|
timer.start();
|
||||||
let compute_handle = thread::Builder::new().name("Compute".to_string()).spawn(move || {
|
|
||||||
do_device_loop(timer, frame_buffer_for_device, device_termination_signal_sender_receiver, device_keyboard, filename, new_chip8_behaviour);
|
let device = Device::new(timer, frame_buffer_for_device, device_keyboard, new_chip8_behaviour);
|
||||||
})?;
|
|
||||||
|
let (device_termination_signal_sender, compute_handle) = start_compute_thread(filename, device)?;
|
||||||
|
|
||||||
|
|
||||||
let mut sdl_graphics_adapter = SdlGraphicsAdapter::new();
|
let mut sdl_graphics_adapter = SdlGraphicsAdapter::new();
|
||||||
@@ -57,7 +56,11 @@ fn main() -> EmulatorResult<()> {
|
|||||||
canvas.set_draw_color(Color::BLACK);
|
canvas.set_draw_color(Color::BLACK);
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
|
|
||||||
|
// Compute a frame time offset
|
||||||
|
// Thread will sleep for 60fps - (time spent computing)
|
||||||
|
let mut frame_timer = std::time::Instant::now();
|
||||||
'running: loop {
|
'running: loop {
|
||||||
|
let last_time = frame_timer.elapsed();
|
||||||
for event in event_pump.poll_iter() {
|
for event in event_pump.poll_iter() {
|
||||||
match event {
|
match event {
|
||||||
Event::Quit { .. } |
|
Event::Quit { .. } |
|
||||||
@@ -79,34 +82,35 @@ fn main() -> EmulatorResult<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lock and draw framebuffer
|
||||||
// The rest of the game loop goes here...
|
|
||||||
{
|
{
|
||||||
let lock = frame_buffer_for_display.lock()?;
|
let lock = frame_buffer_for_display.lock()?;
|
||||||
sdl_graphics_adapter.draw_screen(lock, &mut canvas)?;
|
sdl_graphics_adapter.draw_screen(lock, &mut canvas)?;
|
||||||
}
|
}
|
||||||
canvas.present();
|
canvas.present();
|
||||||
sdl_aud_adapter.process_push_audio()?;
|
sdl_aud_adapter.process_push_audio()?;
|
||||||
// 60fps - small offset to consider for cpu cycle time
|
let sleep_duration = SdlGraphicsAdapter::FRAME_RATE_TIMING - last_time;
|
||||||
thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
thread::sleep(sleep_duration);
|
||||||
|
frame_timer = std::time::Instant::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
compute_handle.join().expect("Failed to close compute thread");
|
compute_handle.join().expect("Failed to close compute thread");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_device_loop(timer: DeviceTimerManager, frame_buffer: Arc<Mutex<Box<[bool; 2048]>>>, receiver: Receiver<()>, device_keyboard: Keyboard, rom_file_location_option: Option<String>, new_chip_behaviour: bool) {
|
fn start_compute_thread(filename: Option<String>, mut device: Device) -> EmulatorResult<(Sender<()>, JoinHandle<()>)> {
|
||||||
let mut device = Device::new(timer, frame_buffer, device_keyboard, new_chip_behaviour);
|
|
||||||
device.set_default_font();
|
device.set_default_font();
|
||||||
|
|
||||||
if let Some(rom_file_location) = rom_file_location_option {
|
if let Some(rom_file_location) = filename {
|
||||||
let rom = load_rom(rom_file_location);
|
let rom = rom::load_rom(rom_file_location)?;
|
||||||
device.load_rom(&rom);
|
device.load_rom(&rom);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (device_termination_signal_sender, device_termination_signal_sender_receiver) = std::sync::mpsc::channel();
|
||||||
|
let compute_handle = thread::Builder::new().name("Compute".to_string()).spawn(move || {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let val = receiver.try_recv();
|
let val = device_termination_signal_sender_receiver.try_recv();
|
||||||
if let Ok(()) = val {
|
if let Ok(()) = val {
|
||||||
break;
|
break;
|
||||||
} else if let Err(std::sync::mpsc::TryRecvError::Disconnected) = val {
|
} else if let Err(std::sync::mpsc::TryRecvError::Disconnected) = val {
|
||||||
@@ -116,6 +120,8 @@ fn do_device_loop(timer: DeviceTimerManager, frame_buffer: Arc<Mutex<Box<[bool;
|
|||||||
// Put a bit of delay to slow down execution
|
// Put a bit of delay to slow down execution
|
||||||
thread::sleep(Duration::from_millis(2))
|
thread::sleep(Duration::from_millis(2))
|
||||||
}
|
}
|
||||||
|
})?;
|
||||||
|
Ok((device_termination_signal_sender, compute_handle))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -125,15 +131,10 @@ fn get_frame_buffer_references() -> (Arc<Mutex<Box<[bool; 2048]>>>, Arc<Mutex<Bo
|
|||||||
(arc, arc2)
|
(arc, arc2)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ROM_SIZE: usize = 4096 - 0x200;
|
/// Initiate SDL resources:
|
||||||
|
/// 1. A window canvas for drawing
|
||||||
fn load_rom(rom_file_location: String) -> [u8; ROM_SIZE] {
|
/// 2. An event pump for use as an event loop,
|
||||||
let mut rom_slice = [0u8; ROM_SIZE];
|
/// 3. An Audio queue for sound
|
||||||
let mut file = File::open(rom_file_location).expect("could not open");
|
|
||||||
file.read(&mut rom_slice).expect("Unwrap");
|
|
||||||
rom_slice
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_initiate_sdl(draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump, AudioQueue<f32>)> {
|
fn try_initiate_sdl(draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump, AudioQueue<f32>)> {
|
||||||
let sdl_context = sdl2::init().unwrap();
|
let sdl_context = sdl2::init().unwrap();
|
||||||
let video_subsystem = sdl_context.video().unwrap();
|
let video_subsystem = sdl_context.video().unwrap();
|
||||||
@@ -144,7 +145,7 @@ fn try_initiate_sdl(draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump,
|
|||||||
freq: Some(SdlAudioAdapter::SAMPLING_FREQ),
|
freq: Some(SdlAudioAdapter::SAMPLING_FREQ),
|
||||||
};
|
};
|
||||||
|
|
||||||
let audio_queue = audio_subsystem.open_queue::<f32,_>(None, &wanted_spec)?;
|
let audio_queue = audio_subsystem.open_queue::<f32, _>(None, &wanted_spec)?;
|
||||||
|
|
||||||
let window_width = (Device::FRAME_BUFFER_WIDTH as f32 * draw_scale) as u32;
|
let window_width = (Device::FRAME_BUFFER_WIDTH as f32 * draw_scale) as u32;
|
||||||
let window_height = (Device::FRAME_BUFFER_HEIGHT as f32 * draw_scale) as u32;
|
let window_height = (Device::FRAME_BUFFER_HEIGHT as f32 * draw_scale) as u32;
|
||||||
@@ -160,7 +161,7 @@ fn try_initiate_sdl(draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump,
|
|||||||
canvas.clear();
|
canvas.clear();
|
||||||
canvas.present();
|
canvas.present();
|
||||||
let event_pump = sdl_context.event_pump()?;
|
let event_pump = sdl_context.event_pump()?;
|
||||||
Ok((canvas, event_pump,audio_queue))
|
Ok((canvas, event_pump, audio_queue))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
12
src/rom.rs
Normal file
12
src/rom.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use crate::util::EmulatorResult;
|
||||||
|
|
||||||
|
pub const ROM_SIZE: usize = 4096 - 0x200;
|
||||||
|
|
||||||
|
pub fn load_rom(rom_file_location: String) -> EmulatorResult<[u8; ROM_SIZE]> {
|
||||||
|
let mut rom_slice = [0u8; ROM_SIZE];
|
||||||
|
let mut file = File::open(rom_file_location)?;
|
||||||
|
file.read(&mut rom_slice)?;
|
||||||
|
Ok(rom_slice)
|
||||||
|
}
|
@@ -16,6 +16,7 @@ pub struct SdlAudioAdapter {
|
|||||||
impl SdlAudioAdapter {
|
impl SdlAudioAdapter {
|
||||||
/// Number of samples per second
|
/// Number of samples per second
|
||||||
pub const SAMPLING_FREQ:i32 = 15360;
|
pub const SAMPLING_FREQ:i32 = 15360;
|
||||||
|
pub const AUDIO_FREQUENCY: f32 = 440.0;
|
||||||
pub const SAMPLES_PER_FRAME: usize = (Self::SAMPLING_FREQ as usize / 60) * 2;
|
pub const SAMPLES_PER_FRAME: usize = (Self::SAMPLING_FREQ as usize / 60) * 2;
|
||||||
pub fn new_timers(freq: f32,
|
pub fn new_timers(freq: f32,
|
||||||
volume: f32,
|
volume: f32,
|
||||||
|
@@ -1,15 +1,16 @@
|
|||||||
use std::sync::MutexGuard;
|
use std::sync::MutexGuard;
|
||||||
|
use std::time::Duration;
|
||||||
use sdl2::pixels::PixelFormatEnum;
|
use sdl2::pixels::PixelFormatEnum;
|
||||||
use sdl2::render::{TextureAccess, WindowCanvas};
|
use sdl2::render::{TextureAccess, WindowCanvas};
|
||||||
use crate::device::Device;
|
use crate::device::Device;
|
||||||
use crate::util::EmulatorResult;
|
use crate::util::EmulatorResult;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SdlGraphicsAdapter {
|
pub struct SdlGraphicsAdapter {
|
||||||
rgb_frame_buffer: Vec<u8>,
|
rgb_frame_buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SdlGraphicsAdapter {
|
impl SdlGraphicsAdapter {
|
||||||
|
pub const FRAME_RATE_TIMING: Duration = Duration::new(0, 1_000_000_000u32 / 60);
|
||||||
pub const RGB_COMPONENTS: usize = 3;
|
pub const RGB_COMPONENTS: usize = 3;
|
||||||
pub const RGB_FRAMEBUFFER_SIZE: usize = Self::RGB_COMPONENTS * Device::FRAME_BUFFER_SIZE;
|
pub const RGB_FRAMEBUFFER_SIZE: usize = Self::RGB_COMPONENTS * Device::FRAME_BUFFER_SIZE;
|
||||||
pub fn new() -> SdlGraphicsAdapter {
|
pub fn new() -> SdlGraphicsAdapter {
|
||||||
@@ -18,7 +19,7 @@ impl SdlGraphicsAdapter {
|
|||||||
rgb_frame_buffer
|
rgb_frame_buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn draw_screen(&mut self, frame_buffer: MutexGuard<Box<[bool; Device::FRAME_BUFFER_SIZE]>>, window_canvas: &mut WindowCanvas) ->EmulatorResult<()> {
|
pub fn draw_screen(&mut self, frame_buffer: MutexGuard<Box<[bool; Device::FRAME_BUFFER_SIZE]>>, window_canvas: &mut WindowCanvas) -> EmulatorResult<()> {
|
||||||
for (i, pixel) in frame_buffer.iter().enumerate() {
|
for (i, pixel) in frame_buffer.iter().enumerate() {
|
||||||
let col_component = if *pixel { 0xff } else { 0 };
|
let col_component = if *pixel { 0xff } else { 0 };
|
||||||
self.rgb_frame_buffer[3 * i] = col_component;
|
self.rgb_frame_buffer[3 * i] = col_component;
|
||||||
|
Reference in New Issue
Block a user