fixes, graphic acceleration commands, upscaling pixels
This commit is contained in:
Generated
+1
-16
@@ -216,6 +216,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"crsn",
|
||||
"libc",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -366,22 +367,6 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "launcher_nox"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clappconfig",
|
||||
"crsn",
|
||||
"crsn_arith",
|
||||
"crsn_buf",
|
||||
"crsn_stdio",
|
||||
"log",
|
||||
"serde",
|
||||
"simple_logger",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"launcher",
|
||||
"launcher_nox",
|
||||
#"launcher_nox",
|
||||
"crsn",
|
||||
"crsn_arith",
|
||||
"crsn_screen",
|
||||
|
||||
@@ -738,7 +738,7 @@ To delete a buffer, use the `del` instruction - `(del @Obj)`
|
||||
|
||||
This module uses the minifb rust crate to provide a framebuffer with key and mouse input.
|
||||
|
||||
Colors use the `RRGGBB` hex format.
|
||||
Colors use the `0xRRGGBB` or `#RRGGBB` hex format.
|
||||
|
||||
If input events are required, then make sure to periodically call `(sc-blit)` or `(sc-poll)`.
|
||||
This may not be needed if the auto-blit function is enabled and the display is regularly written.
|
||||
@@ -753,17 +753,17 @@ such as animations.
|
||||
; Initialize the screen (opens a window)
|
||||
(sc-init WIDTH HEIGHT)
|
||||
|
||||
; Erase the screen (fill with black)
|
||||
(sc-erase)
|
||||
; Fill with a custom color
|
||||
(sc-erase 0xFF00FF)
|
||||
|
||||
; Set pixel color
|
||||
(sc-px X Y COLOR)
|
||||
(sc-wr Rd'x Rd'y Rd'color) ; legacy name: sc-px
|
||||
|
||||
; Get pixel color
|
||||
(sc-rd Wr'color Rd'x Rd'y)
|
||||
|
||||
; Set screen option. Constants are pre-defined.
|
||||
; SCREEN_AUTO_BLIT (1) ... auto-blit (blit automatically on pixel write when needed to achieve the target FPS)
|
||||
; SCREEN_FPS (2) ... frame rate
|
||||
; - SCREEN_AUTO_BLIT (1) ... auto-blit (blit automatically on pixel write when needed to achieve the target FPS)
|
||||
; - SCREEN_FPS (2) ......... frame rate
|
||||
; - SCREEN_UPSCALE (3) ..... upscaling factor (big pixels).
|
||||
; Scales coordinates for mouse and pixels and increases pixel area
|
||||
(sc-opt OPTION VALUE)
|
||||
|
||||
; Blit (render the pixel buffer).
|
||||
@@ -781,11 +781,24 @@ such as animations.
|
||||
|
||||
; Check key status. Keys are 0-127. Reads 1 if the key is pressed, 0 if not.
|
||||
; A list of supported keys can be found in the extension source code.
|
||||
(sc-key PRESSED KEY)
|
||||
(sc-key Wr'pressed Rd'num)
|
||||
|
||||
; Check mouse button state
|
||||
; Check mouse button state.
|
||||
; 0-left, 1-right, 2-middle
|
||||
(sc-mbtn PRESSED BTN)
|
||||
(sc-mbtn Wr'pressed Rd'btn)
|
||||
```
|
||||
|
||||
### Graphic acceleration commands
|
||||
|
||||
```
|
||||
; Fill a rectangle
|
||||
(sc-rect Rd'x Rd'y Rd'w Rd'h Rd'color)
|
||||
|
||||
; Erase the screen (fill with black)
|
||||
(sc-erase)
|
||||
|
||||
; Fill with a custom color
|
||||
(sc-erase Rd'color)
|
||||
```
|
||||
|
||||
## Stdio module
|
||||
|
||||
@@ -45,8 +45,12 @@ impl<'a> TokenParser<'a> {
|
||||
/// Get error if not empty.
|
||||
/// The argument is substituted into the phrase "Instruction needs ...!" - i.e. "one Wr argument and a list or string"
|
||||
pub fn ensure_empty(&self, what_arguments : &str) -> Result<(), CrsnError> {
|
||||
self.ensure_empty_custom(&format!("Instruction needs {}!", what_arguments))
|
||||
}
|
||||
|
||||
pub fn ensure_empty_custom(&self, msg : &str) -> Result<(), CrsnError> {
|
||||
if self.have_more() {
|
||||
Err(CrsnError::Parse(format!("Instruction needs {}!", what_arguments).into(), self.start_pos.clone()))
|
||||
Err(CrsnError::Parse(msg.to_string().into(), self.start_pos.clone()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -115,10 +115,12 @@ impl RunState {
|
||||
}
|
||||
|
||||
/// Read a `Rd` value
|
||||
#[inline]
|
||||
pub fn read(&mut self, rd: impl Into<Rd>) -> Result<Value, Fault> {
|
||||
let rd = rd.into();
|
||||
// TODO dedupe
|
||||
match rd.0 {
|
||||
RdData::Immediate(v) => Ok(v),
|
||||
RdData::Register(Register::Gen(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.gen[rn as usize]);
|
||||
@@ -135,7 +137,6 @@ impl RunState {
|
||||
Err(Fault::RegisterNotExist { reg: Register::Global(rn) })
|
||||
}
|
||||
}
|
||||
RdData::Immediate(v) => Ok(v),
|
||||
RdData::Register(Register::Arg(rn)) => {
|
||||
if likely(rn < REG_COUNT as u8) {
|
||||
trace!("Rd {:?} = {}", rd, self.frame.arg[rn as usize]);
|
||||
|
||||
@@ -12,6 +12,11 @@ pub enum ScreenOp {
|
||||
y: Rd,
|
||||
color: Rd,
|
||||
},
|
||||
GetPixel {
|
||||
color: Wr,
|
||||
x: Rd,
|
||||
y: Rd,
|
||||
},
|
||||
GetMouse {
|
||||
x: Wr,
|
||||
y: Wr,
|
||||
@@ -28,6 +33,13 @@ pub enum ScreenOp {
|
||||
Erase {
|
||||
color: Rd,
|
||||
},
|
||||
FillRect {
|
||||
x: Rd,
|
||||
y: Rd,
|
||||
w: Rd,
|
||||
h: Rd,
|
||||
color: Rd,
|
||||
},
|
||||
Blit {
|
||||
force: Rd,
|
||||
},
|
||||
|
||||
+134
-21
@@ -3,7 +3,9 @@ use std::time::{Duration, Instant};
|
||||
|
||||
use minifb::{Key, MouseButton, MouseMode, ScaleMode, Window, WindowOptions};
|
||||
|
||||
use crsn::asm::data::literal::Value;
|
||||
use crsn::asm::data::literal::{Value, is_negative};
|
||||
use crsn::asm::error::CrsnError;
|
||||
use crsn::asm::instr::cond::Flag;
|
||||
use crsn::module::{EvalRes, OpTrait};
|
||||
use crsn::runtime::fault::Fault;
|
||||
use crsn::runtime::run_thread::{state::RunState, ThreadInfo};
|
||||
@@ -12,18 +14,21 @@ use crsn::sexp::Sexp;
|
||||
use crsn::utils::A;
|
||||
|
||||
use crate::defs::ScreenOp;
|
||||
use crsn::asm::instr::cond::Flag;
|
||||
use std::mem;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Opts {
|
||||
auto_blit: bool,
|
||||
frame_rate: Duration,
|
||||
upscale: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Backend {
|
||||
width: usize,
|
||||
height: usize,
|
||||
width: Value,
|
||||
height: Value,
|
||||
log_width: Value,
|
||||
log_height: Value,
|
||||
buffer: Vec<u32>,
|
||||
window: Option<Window>,
|
||||
last_render: Instant,
|
||||
@@ -35,19 +40,33 @@ impl Default for Backend {
|
||||
Self {
|
||||
width: 0,
|
||||
height: 0,
|
||||
log_width: 0,
|
||||
log_height: 0,
|
||||
buffer: vec![],
|
||||
window: None,
|
||||
last_render: Instant::now().sub(Duration::from_secs(1)),
|
||||
opts: Opts {
|
||||
auto_blit: true,
|
||||
upscale: 1,
|
||||
frame_rate: Duration::from_micros(16600),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
pub fn draw_rect_log(&mut self, mut x: Value, mut y: Value, w: Value, h: Value, color: u32) {
|
||||
for yy in (y * self.opts.upscale)..((y + h) * self.opts.upscale).min(self.height) {
|
||||
for xx in (x * self.opts.upscale)..((x + w) * self.opts.upscale).min(self.width) {
|
||||
self.buffer[(yy * self.width + xx) as usize] = color as u32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const OPT_AUTO_BLIT: u64 = 1;
|
||||
pub const OPT_FRAME_RATE: u64 = 2;
|
||||
pub const OPT_UPSCALE: u64 = 3;
|
||||
|
||||
// Hack for Window
|
||||
unsafe impl std::marker::Send for Backend {}
|
||||
@@ -81,8 +100,22 @@ impl OpTrait for ScreenOp {
|
||||
debug!("Set auto blit to {:?}", backend.opts.auto_blit);
|
||||
}
|
||||
OPT_FRAME_RATE => {
|
||||
backend.opts.frame_rate = Duration::from_micros(1_000_000 as u64 / val);
|
||||
debug!("Set frame rate to {:?}", backend.opts.frame_rate);
|
||||
if val == 0 {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
} else {
|
||||
backend.opts.frame_rate = Duration::from_micros(1_000_000 as u64 / val);
|
||||
debug!("Set frame rate to {:?}", backend.opts.frame_rate);
|
||||
}
|
||||
}
|
||||
OPT_UPSCALE => {
|
||||
if val == 0 {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
} else {
|
||||
backend.opts.upscale = val;
|
||||
backend.log_width = backend.width / val;
|
||||
backend.log_height = backend.height / val;
|
||||
debug!("Set upscale to {:?}", val);
|
||||
}
|
||||
}
|
||||
_other => {
|
||||
unreachable!()
|
||||
@@ -106,8 +139,9 @@ impl OpTrait for ScreenOp {
|
||||
match &mut backend.window {
|
||||
Some(w) => {
|
||||
if !w.is_open() {
|
||||
// TODO...
|
||||
std::process::exit(0);
|
||||
debug!("Window is closed");
|
||||
let _ = backend.window.take();
|
||||
return Err(Fault::Halt);
|
||||
}
|
||||
|
||||
w.update();
|
||||
@@ -126,23 +160,46 @@ impl OpTrait for ScreenOp {
|
||||
|
||||
let backend: &mut Backend = state.ext_mut();
|
||||
|
||||
if x >= backend.width as u64 || y >= backend.height as u64 {
|
||||
if x >= backend.log_width as u64 || y >= backend.log_height as u64 {
|
||||
state.set_flag(Flag::Overflow, true);
|
||||
return Ok(eres);
|
||||
}
|
||||
|
||||
match &mut backend.window {
|
||||
Some(_w) => {
|
||||
let index = y * backend.width as u64 + x;
|
||||
backend.draw_rect_log(x, y, 1, 1, color as u32);
|
||||
if backend.opts.auto_blit {
|
||||
blit_maybe(backend)?;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScreenOp::GetPixel { color, x, y } => {
|
||||
state.clear_status();
|
||||
let x = state.read(x)?;
|
||||
let y = state.read(y)?;
|
||||
|
||||
let backend: &mut Backend = state.ext_mut();
|
||||
|
||||
if x >= backend.log_width as u64 || y >= backend.log_height as u64 {
|
||||
state.set_flag(Flag::Overflow, true);
|
||||
return Ok(eres);
|
||||
}
|
||||
|
||||
match &mut backend.window {
|
||||
Some(_w) => {
|
||||
let index = y * backend.opts.upscale * backend.width as u64 + x * backend.opts.upscale;
|
||||
if index as usize > backend.buffer.len() {
|
||||
warn!("Screen set pixel out of bounds");
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
} else {
|
||||
backend.buffer[index as usize] = color as u32;
|
||||
|
||||
if backend.opts.auto_blit {
|
||||
blit_maybe(backend)?;
|
||||
}
|
||||
let c = backend.buffer[index as usize];
|
||||
trace!("index {}, c {}", index, c);
|
||||
state.write(color, c as Value)?;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
@@ -163,8 +220,11 @@ impl OpTrait for ScreenOp {
|
||||
state.set_flag(Flag::Overflow, true);
|
||||
}
|
||||
Some((xf, yf)) => {
|
||||
let xval = xf.round() as u64;
|
||||
let yval = yf.round() as u64;
|
||||
let mut xval = xf.round() as u64;
|
||||
let mut yval = yf.round() as u64;
|
||||
|
||||
xval /= backend.opts.upscale;
|
||||
yval /= backend.opts.upscale;
|
||||
|
||||
state.write(x, xval)?;
|
||||
state.write(y, yval)?;
|
||||
@@ -227,6 +287,51 @@ impl OpTrait for ScreenOp {
|
||||
}
|
||||
}
|
||||
}
|
||||
ScreenOp::FillRect {
|
||||
x, y,
|
||||
w, h,
|
||||
color
|
||||
} => {
|
||||
let mut x = state.read(x)?;
|
||||
let mut y = state.read(y)?;
|
||||
let mut w = state.read(w)?;
|
||||
let mut h = state.read(h)?;
|
||||
let c = state.read(color)?;
|
||||
let backend: &mut Backend = state.ext_mut();
|
||||
|
||||
if is_negative(w) || is_negative(h) {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
return Ok(eres);
|
||||
}
|
||||
if w > backend.log_width {
|
||||
w = backend.log_width;
|
||||
}
|
||||
if h > backend.log_height {
|
||||
h = backend.log_height;
|
||||
}
|
||||
|
||||
if is_negative(x) {
|
||||
let xi : i64 = unsafe { mem::transmute(x) };
|
||||
let minus = xi.abs() as u64;
|
||||
w -= minus;
|
||||
x = 0;
|
||||
}
|
||||
if is_negative(y) {
|
||||
let yi : i64 = unsafe { mem::transmute(y) };
|
||||
let minus = yi.abs() as u64;
|
||||
h -= minus;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
match &mut backend.window {
|
||||
Some(_w) => {
|
||||
backend.draw_rect_log(x, y, w, h, c as u32);
|
||||
}
|
||||
None => {
|
||||
state.set_flag(Flag::Invalid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(eres)
|
||||
@@ -236,13 +341,17 @@ impl OpTrait for ScreenOp {
|
||||
match self {
|
||||
ScreenOp::SetOpt { opt, val } => sexp::list(&[A("sc-opt"), A(opt), A(val)]),
|
||||
ScreenOp::ScreenInit { width, height } => sexp::list(&[A("sc-init"), A(width), A(height)]),
|
||||
ScreenOp::SetPixel { x, y, color } => sexp::list(&[A("sc-px"), A(x), A(y), A(color)]),
|
||||
ScreenOp::SetPixel { x, y, color } => sexp::list(&[A("sc-wr"), A(x), A(y), A(color)]),
|
||||
ScreenOp::GetPixel { color, x, y } => sexp::list(&[A("sc-rd"), A(color), A(x), A(y)]),
|
||||
ScreenOp::Blit { force } => sexp::list(&[A("sc-blit"), A(force)]),
|
||||
ScreenOp::Update => sexp::list(&[A("sc-poll")]),
|
||||
ScreenOp::GetMouse { x, y } => sexp::list(&[A("sc-mouse"), A(x), A(y)]),
|
||||
ScreenOp::TestKey { pressed, code } => sexp::list(&[A("sc-key"), A(pressed), A(code)]),
|
||||
ScreenOp::TestMouse { pressed, button } => sexp::list(&[A("sc-mbtn"), A(pressed), A(button)]),
|
||||
ScreenOp::Erase { color } => sexp::list(&[A("sc-erase"), A(color)]),
|
||||
ScreenOp::FillRect { x, y, w, h, color } => {
|
||||
sexp::list(&[A("sc-rect"), A(x), A(y), A(w), A(h), A(color)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,8 +375,10 @@ fn init(state: &mut RunState, width: Value, height: Value) -> Result<(), Fault>
|
||||
return Err(Fault::NotAllowed("Screen already initialized".into()));
|
||||
}
|
||||
|
||||
backend.width = width as usize;
|
||||
backend.height = height as usize;
|
||||
backend.width = width;
|
||||
backend.height = height;
|
||||
backend.log_width = width;
|
||||
backend.log_height = height;
|
||||
backend.buffer = vec![0; (width * height) as usize];
|
||||
|
||||
backend.window = Some(window);
|
||||
@@ -289,10 +400,12 @@ fn blit(backend: &mut Backend) -> Result<(), Fault> {
|
||||
let w = backend.window.as_mut().unwrap();
|
||||
|
||||
if !w.is_open() {
|
||||
debug!("Window is closed");
|
||||
let _ = backend.window.take();
|
||||
return Err(Fault::Halt);
|
||||
}
|
||||
|
||||
w.update_with_buffer(&backend.buffer, backend.width, backend.height)
|
||||
w.update_with_buffer(&backend.buffer, backend.width as usize, backend.height as usize)
|
||||
.expect("Update screen"); // TODO fault
|
||||
|
||||
backend.last_render = Instant::now();
|
||||
|
||||
@@ -7,7 +7,7 @@ use crsn::asm::parse::arg_parser::TokenParser;
|
||||
use crsn::module::{CrsnExtension, ParseRes};
|
||||
use crsn::sexp::SourcePosition;
|
||||
use crsn::asm::data::literal::Value;
|
||||
use crate::exec::{OPT_AUTO_BLIT, OPT_FRAME_RATE};
|
||||
use crate::exec::{OPT_AUTO_BLIT, OPT_FRAME_RATE, OPT_UPSCALE};
|
||||
|
||||
mod defs;
|
||||
mod parse;
|
||||
@@ -38,6 +38,7 @@ impl CrsnExtension for ScreenOps {
|
||||
match name {
|
||||
"SCREEN_AUTO_BLIT" => Some(OPT_AUTO_BLIT),
|
||||
"SCREEN_FPS" => Some(OPT_FRAME_RATE),
|
||||
"SCREEN_UPSCALE" => Some(OPT_UPSCALE),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ use crate::defs::ScreenOp;
|
||||
|
||||
use super::exec::OPT_AUTO_BLIT;
|
||||
use super::exec::OPT_FRAME_RATE;
|
||||
use super::exec::OPT_UPSCALE;
|
||||
|
||||
pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenParser<'a>) -> Result<ParseRes<'a, OpKind>, CrsnError> {
|
||||
Ok(ParseRes::ext(match keyword {
|
||||
let rv = Ok(ParseRes::ext(match keyword {
|
||||
"sc-init" => {
|
||||
ScreenOp::ScreenInit {
|
||||
width: args.next_rd()?,
|
||||
@@ -29,7 +30,7 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
|
||||
}
|
||||
}
|
||||
|
||||
"sc-px" => {
|
||||
"sc-wr" | "sc-px" => {
|
||||
ScreenOp::SetPixel {
|
||||
x: args.next_rd()?,
|
||||
y: args.next_rd()?,
|
||||
@@ -37,6 +38,14 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
|
||||
}
|
||||
}
|
||||
|
||||
"sc-rd" => {
|
||||
ScreenOp::GetPixel {
|
||||
color: args.next_wr()?,
|
||||
x: args.next_rd()?,
|
||||
y: args.next_rd()?,
|
||||
}
|
||||
}
|
||||
|
||||
"sc-opt" => {
|
||||
let (val, valopt) = args.next_value()?;
|
||||
ScreenOp::SetOpt {
|
||||
@@ -47,6 +56,9 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
|
||||
OPT_FRAME_RATE => {
|
||||
OPT_FRAME_RATE
|
||||
}
|
||||
OPT_UPSCALE => {
|
||||
OPT_UPSCALE
|
||||
}
|
||||
_ => {
|
||||
return Err(CrsnError::Parse("Bad screen option".into(), valopt));
|
||||
}
|
||||
@@ -90,8 +102,20 @@ pub(crate) fn parse<'a>(_pos: &SourcePosition, keyword: &str, mut args: TokenPar
|
||||
}
|
||||
}
|
||||
|
||||
"sc-rect" => {
|
||||
ScreenOp::FillRect {
|
||||
x: args.next_rd()?,
|
||||
y: args.next_rd()?,
|
||||
w: args.next_rd()?,
|
||||
h: args.next_rd()?,
|
||||
color: args.next_rd()?
|
||||
}
|
||||
}
|
||||
|
||||
_other => {
|
||||
return Ok(ParseRes::Unknown(args));
|
||||
}
|
||||
}))
|
||||
}));
|
||||
args.ensure_empty_custom("Too many arguments for this instruction!")?;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -9,3 +9,4 @@ edition = "2018"
|
||||
[dependencies]
|
||||
crsn = { path = "../crsn" }
|
||||
libc = "0.2.79"
|
||||
log = "0.4.11"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use crsn::asm::data::literal::Value;
|
||||
use crsn::asm::error::CrsnError;
|
||||
use crsn::asm::instr::op::OpKind;
|
||||
@@ -134,6 +137,7 @@ impl StdioOps {
|
||||
|
||||
impl Drop for StdioOps {
|
||||
fn drop(&mut self) {
|
||||
debug!("stdin restore");
|
||||
// Un-break the terminal
|
||||
if let Some(tio) = self.old_tio.take() {
|
||||
let _ = unsafe { libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &tio) };
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
(
|
||||
(sc-init 512 512)
|
||||
(sc-opt SCREEN_UPSCALE 16)
|
||||
(def W 32)
|
||||
|
||||
(lds @cout "Drag colors to draw...\n")
|
||||
|
||||
(sc-wr 0 0 #ff00ff)
|
||||
(sc-wr 5 5 #ffff00)
|
||||
(sc-wr 15 15 #00ff00)
|
||||
(sc-blit)
|
||||
|
||||
(:l)
|
||||
(sc-poll)
|
||||
(sc-mbtn r0 0)
|
||||
(j.z :nope)
|
||||
|
||||
(sc-mouse r0 r1)
|
||||
(sc-rd r3 r0 r1)
|
||||
(sub r0 1)
|
||||
(sub r1 1)
|
||||
(sc-rect r0 r1 3 3 r3)
|
||||
(sc-blit)
|
||||
|
||||
(:nope)
|
||||
(mslp 10)
|
||||
(j :l)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
(
|
||||
(sc-init 512 512)
|
||||
(sc-opt SCREEN_UPSCALE 32)
|
||||
|
||||
(sc-wr 0 0 #ff00ff)
|
||||
(sc-wr 1 1 #ffff00)
|
||||
(sc-wr 15 15 #00ff00)
|
||||
(sc-blit)
|
||||
|
||||
(:l)
|
||||
(sc-poll)
|
||||
(mslp 100)
|
||||
(j :l)
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
(
|
||||
(sc-init 512 512)
|
||||
(sc-opt SCREEN_UPSCALE 16)
|
||||
(def W 32)
|
||||
|
||||
(:l)
|
||||
(sc-poll)
|
||||
(sc-erase)
|
||||
(sc-mouse r0 r1)
|
||||
(sc-rect 0 r1 W 1 #ff0000)
|
||||
(sc-rect r0 0 1 W #0066ff)
|
||||
(sc-wr r0 r1 #ffffff)
|
||||
(mslp 10)
|
||||
(j :l)
|
||||
)
|
||||
Reference in New Issue
Block a user