add experimental framebuffer extension using minifb
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
use crsn::asm::data::{Rd, RdObj, Wr};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ScreenOp {
|
||||
ScreenInit {
|
||||
width: Rd,
|
||||
height: Rd,
|
||||
},
|
||||
SetPixel {
|
||||
x: Rd,
|
||||
y: Rd,
|
||||
color: Rd,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use crsn::asm::data::literal::Value;
|
||||
use crsn::asm::instr::Cond;
|
||||
use crsn::module::{CrsnExtension, EvalRes, OpTrait};
|
||||
use crsn::runtime::fault::Fault;
|
||||
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
||||
|
||||
use crate::defs::ScreenOp;
|
||||
use minifb::{Window, WindowOptions, ScaleMode};
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Backend {
|
||||
width: usize,
|
||||
height: usize,
|
||||
buffer: Vec<u32>,
|
||||
window: Option<Window>,
|
||||
}
|
||||
|
||||
// Hack for Window
|
||||
unsafe impl std::marker::Send for Backend { }
|
||||
|
||||
impl OpTrait for ScreenOp {
|
||||
fn execute(&self, info: &ThreadInfo, state: &mut RunState) -> Result<EvalRes, Fault> {
|
||||
let eres = EvalRes::default();
|
||||
match self {
|
||||
ScreenOp::ScreenInit { width, height } => {
|
||||
let w = state.read(*width)?;
|
||||
let h = state.read(*height)?;
|
||||
init(state, w, h)?;
|
||||
}
|
||||
ScreenOp::SetPixel { x, y, color } => {
|
||||
let x = state.read(*x)?;
|
||||
let y = state.read(*y)?;
|
||||
let color = state.read(*color)?;
|
||||
|
||||
let backend : &mut Backend = state.ext_mut();
|
||||
match &mut backend.window {
|
||||
Some(w) => {
|
||||
let index = y * backend.width as u64 + x;
|
||||
if index as usize > backend.buffer.len() {
|
||||
warn!("Screen set pixel out of bounds");
|
||||
state.set_flag(Cond::Invalid, true);
|
||||
} else {
|
||||
backend.buffer[index as usize] = color as u32;
|
||||
|
||||
w
|
||||
.update_with_buffer(&backend.buffer, backend.width, backend.height)
|
||||
.expect("Update screen"); // TODO fault
|
||||
}
|
||||
}
|
||||
None => {
|
||||
state.set_flag(Cond::Invalid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(eres)
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault> {
|
||||
let mut window = Window::new(
|
||||
"Croissant",
|
||||
width as usize,
|
||||
height as usize,
|
||||
WindowOptions {
|
||||
resize: true,
|
||||
scale_mode: ScaleMode::AspectRatioStretch,
|
||||
..WindowOptions::default()
|
||||
},
|
||||
).expect("Unable to create window"); // TODO fault
|
||||
|
||||
|
||||
let backend : &mut Backend = state.ext_mut();
|
||||
|
||||
if backend.window.is_some() {
|
||||
return Err(Fault::NotAllowed("Screen already initialized".into()));
|
||||
}
|
||||
|
||||
backend.width = width as usize;
|
||||
backend.height = height as usize;
|
||||
backend.buffer = vec![0; (width * height) as usize];
|
||||
|
||||
// window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
|
||||
window.limit_update_rate(None);
|
||||
|
||||
window
|
||||
.update_with_buffer(&backend.buffer, backend.width, backend.height)
|
||||
.expect("Update screen"); // TODO fault
|
||||
|
||||
backend.window = Some(window);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use crsn::module::{CrsnExtension, ParseOpRes};
|
||||
use crsn::asm::parse::arg_parser::ArgParser;
|
||||
use crsn::asm::instr::Op;
|
||||
use crsn::asm::error::CrsnError;
|
||||
|
||||
mod defs;
|
||||
mod parse;
|
||||
mod exec;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ScreenOps;
|
||||
|
||||
impl ScreenOps {
|
||||
pub fn new() -> Box<dyn CrsnExtension> {
|
||||
Box::new(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl CrsnExtension for ScreenOps {
|
||||
fn name(&self) -> &'static str {
|
||||
"screen"
|
||||
}
|
||||
|
||||
fn parse_op(&self, keyword: &str, args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
||||
parse::parse(keyword, args)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
use crsn::asm::error::CrsnError;
|
||||
use crsn::asm::instr::Op;
|
||||
use crsn::asm::parse::arg_parser::ArgParser;
|
||||
use crsn::module::{ParseOpRes};
|
||||
|
||||
use crate::defs::ScreenOp;
|
||||
|
||||
pub(crate) fn parse(keyword: &str, mut args: ArgParser) -> Result<ParseOpRes<Op>, CrsnError> {
|
||||
Ok(ParseOpRes::ext(match keyword {
|
||||
"sc-init" => {
|
||||
ScreenOp::ScreenInit {
|
||||
width: args.next_rd()?,
|
||||
height: args.next_rd()?,
|
||||
}
|
||||
}
|
||||
|
||||
"sc-px" => {
|
||||
ScreenOp::SetPixel {
|
||||
x: args.next_rd()?,
|
||||
y: args.next_rd()?,
|
||||
color: args.next_rd()?,
|
||||
}
|
||||
}
|
||||
|
||||
_other => {
|
||||
return Ok(ParseOpRes::Unknown(args));
|
||||
}
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user