mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-10 07:29:31 +00:00
8c58903f73
In order to more accurately emulate the VDP, the main draw loop is now going through each pixel on the screen and calculates the various cells that should be displayed, gets the exact pixel data, and then draws lines them all up in priority-order, and whichever is the first non-mask pixel colour gets put into the frame buffer. It's rather verbose and duplicative, but I'll fix it up now that I have something working
133 lines
3.7 KiB
Rust
133 lines
3.7 KiB
Rust
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use crate::host::traits::{WindowUpdater, BlitableSurface};
|
|
|
|
|
|
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)))
|
|
}
|
|
|
|
pub fn new_updater(frame: Arc<Mutex<Frame>>) -> Box<dyn WindowUpdater> {
|
|
Box::new(FrameUpdateWrapper(frame))
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct FrameUpdateWrapper(Arc<Mutex<Frame>>);
|
|
|
|
impl WindowUpdater for FrameUpdateWrapper {
|
|
fn get_size(&mut self) -> (u32, u32) {
|
|
match self.0.lock() {
|
|
Ok(frame) => (frame.width, frame.height),
|
|
_ => (0, 0),
|
|
}
|
|
}
|
|
|
|
fn update_frame(&mut self, width: u32, _height: u32, bitmap: &mut [u32]) {
|
|
if let Ok(frame) = self.0.lock() {
|
|
for y in 0..frame.height {
|
|
for x in 0..frame.width {
|
|
bitmap[(x + (y * width)) as usize] = frame.bitmap[(x + (y * frame.width)) as usize];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#[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);
|
|
}
|
|
}
|
|
|
|
impl WindowUpdater for FrameSwapper {
|
|
fn get_size(&mut self) -> (u32, u32) {
|
|
if let Ok(frame) = self.current.lock() {
|
|
(frame.width, frame.height)
|
|
} else {
|
|
(0, 0)
|
|
}
|
|
}
|
|
|
|
fn update_frame(&mut self, width: u32, _height: u32, bitmap: &mut [u32]) {
|
|
if let Ok(frame) = self.previous.lock() {
|
|
for y in 0..frame.height {
|
|
for x in 0..frame.width {
|
|
bitmap[(x + (y * width)) as usize] = frame.bitmap[(x + (y * frame.width)) as usize];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|