mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-08 10:30:21 +00:00
4cb423d85a
If the sim is running slower than 60Hz, it was using the frame limiter to not apply because no frame was drawn, and so it would end up running at full speed. Minifb can save the last frame without cloning it, and redraw the same frame if no new frame is ready, which allows the limiter to still delay the next frame, so slower speeds work. This was also preventing things that didn't update the screen from allowing inputs including escape to have any effect
144 lines
3.8 KiB
Rust
144 lines
3.8 KiB
Rust
|
|
use std::mem;
|
|
use std::sync::{Arc, Mutex};
|
|
use std::collections::VecDeque;
|
|
|
|
use crate::Clock;
|
|
use crate::Error;
|
|
use crate::host::traits::{WindowUpdater, BlitableSurface, ClockedQueue};
|
|
|
|
|
|
pub const MASK_COLOUR: u32 = 0xFFFFFFFF;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Frame {
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub bitmap: Vec<u32>,
|
|
}
|
|
|
|
impl Frame {
|
|
pub fn new(width: u32, height: u32) -> Self {
|
|
Self { width, height, bitmap: vec![0; (width * height) as usize] }
|
|
}
|
|
|
|
pub fn new_shared(width: u32, height: u32) -> Arc<Mutex<Frame>> {
|
|
Arc::new(Mutex::new(Frame::new(width, height)))
|
|
}
|
|
}
|
|
|
|
|
|
impl BlitableSurface for Frame {
|
|
fn set_size(&mut self, width: u32, height: u32) {
|
|
self.width = width;
|
|
self.height = height;
|
|
self.bitmap.resize((width * height) as usize, 0);
|
|
}
|
|
|
|
fn set_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: u32) {
|
|
match pixel {
|
|
MASK_COLOUR => { },
|
|
value if pos_x < self.width && pos_y < self.height => {
|
|
self.bitmap[(pos_x + (pos_y * self.width)) as usize] = value;
|
|
},
|
|
_ => { },
|
|
}
|
|
}
|
|
|
|
fn blit<B: Iterator<Item=u32>>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) {
|
|
for y in pos_y..(pos_y + height) {
|
|
for x in pos_x..(pos_x + width) {
|
|
match bitmap.next().unwrap() {
|
|
MASK_COLOUR => { },
|
|
value if x < self.width && y < self.height => { self.bitmap[(x + (y * self.width)) as usize] = value; },
|
|
_ => { },
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn clear(&mut self, value: u32) {
|
|
let value = if value == MASK_COLOUR { 0 } else { value };
|
|
for i in 0..((self.width as usize) * (self.height as usize)) {
|
|
self.bitmap[i] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct FrameSwapper {
|
|
pub current: Arc<Mutex<Frame>>,
|
|
pub previous: Arc<Mutex<Frame>>,
|
|
}
|
|
|
|
impl FrameSwapper {
|
|
pub fn new(width: u32, height: u32) -> FrameSwapper {
|
|
FrameSwapper {
|
|
current: Arc::new(Mutex::new(Frame::new(width, height))),
|
|
previous: Arc::new(Mutex::new(Frame::new(width, height))),
|
|
}
|
|
}
|
|
|
|
pub fn to_boxed(swapper: FrameSwapper) -> Box<dyn WindowUpdater> {
|
|
Box::new(swapper)
|
|
}
|
|
|
|
pub fn swap(&mut self) {
|
|
std::mem::swap(&mut self.current.lock().unwrap().bitmap, &mut self.previous.lock().unwrap().bitmap);
|
|
}
|
|
|
|
pub fn set_size(&mut self, width: u32, height: u32) {
|
|
self.previous.lock().unwrap().set_size(width, height);
|
|
self.current.lock().unwrap().set_size(width, height);
|
|
}
|
|
}
|
|
|
|
impl WindowUpdater for FrameSwapper {
|
|
fn max_size(&mut self) -> (u32, u32) {
|
|
let frame = self.current.lock().unwrap();
|
|
(frame.width, frame.height)
|
|
}
|
|
|
|
fn take_frame(&mut self) -> Result<Frame, Error> {
|
|
let mut previous = self.previous.lock().map_err(|_| Error::new("Lock error"))?;
|
|
let mut frame = Frame::new(previous.width, previous.height);
|
|
mem::swap(&mut *previous, &mut frame);
|
|
Ok(frame)
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Clone)]
|
|
pub struct FrameQueue {
|
|
max_size: (u32, u32),
|
|
queue: ClockedQueue<Frame>,
|
|
}
|
|
|
|
impl FrameQueue {
|
|
pub fn new(width: u32, height: u32) -> Self {
|
|
Self {
|
|
max_size: (width, height),
|
|
queue: ClockedQueue::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add(&self, clock: Clock, frame: Frame) {
|
|
self.queue.push(clock, frame);
|
|
}
|
|
|
|
pub fn latest(&self) -> Option<(Clock, Frame)> {
|
|
self.queue.pop_latest()
|
|
}
|
|
}
|
|
|
|
impl WindowUpdater for FrameQueue {
|
|
fn max_size(&mut self) -> (u32, u32) {
|
|
self.max_size
|
|
}
|
|
|
|
fn take_frame(&mut self) -> Result<Frame, Error> {
|
|
self.latest().map(|(_, f)| f).ok_or_else(|| Error::new("No frame available"))
|
|
}
|
|
}
|
|
|