2 Commits

Author SHA1 Message Date
f21497dd2e implement more robust file watcher 2022-01-29 15:22:14 +01:00
381eaf970f Add first basic logo version 2022-01-29 15:21:35 +01:00
9 changed files with 164 additions and 105 deletions

1
Cargo.lock generated
View File

@@ -1524,6 +1524,7 @@ dependencies = [
"minifb", "minifb",
"notify", "notify",
"pico-args", "pico-args",
"same-file",
"uw8-tool", "uw8-tool",
"wasmtime", "wasmtime",
"wat", "wat",

View File

@@ -13,4 +13,5 @@ notify = "4"
pico-args = "0.4" pico-args = "0.4"
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "196719b" } curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "196719b" }
wat = "1" wat = "1"
uw8-tool = { path = "uw8-tool" } uw8-tool = { path = "uw8-tool" }
same-file = "1"

View File

@@ -1,102 +1,21 @@
import "env.memory" memory(4); import "env.memory" memory(4);
import "env.cls" fn cls(i32); import "env.cls" fn cls(i32);
import "env.setPixel" fn setPixel(i32, i32, i32);
import "env.time" fn time() -> f32; import "env.time" fn time() -> f32;
import "env.line" fn line(f32, f32, f32, f32, i32);
import "env.sin" fn sin(f32) -> f32; import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32; import "env.cos" fn cos(f32) -> f32;
fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
let swapTmp: f32;
if x1 > x2 {
swapTmp = x1;
x1 = x2;
x2 = swapTmp;
swapTmp = y1;
y1 = y2;
y2 = swapTmp;
}
if x1 < 0 as f32 & x2 >= 0 as f32 {
y1 = y1 + (y2 - y1) * -x1 / (x2 - x1);
x1 = 0 as f32;
}
if x1 < 320 as f32 & x2 >= 320 as f32 {
y2 = y2 + (y2 - y1) * (320 as f32 - x2) / (x2 - x1);
x2 = 320 as f32;
}
if y1 > y2 {
swapTmp = x1;
x1 = x2;
x2 = swapTmp;
swapTmp = y1;
y1 = y2;
y2 = swapTmp;
}
if y1 < 0 as f32 & y2 >= 0 as f32 {
x1 = x1 + (x2 - x1) * -y1 / (y2 - y1);
y1 = 0 as f32;
}
if y1 < 240 as f32 & y2 >= 240 as f32 {
x2 = x2 + (x2 - x1) * (240 as f32 - y2) / (y2 - y1);
y2 = 240 as f32;
}
let lazy dx = x2 - x1;
let lazy dy = y2 - y1;
let max_axis: f32;
let p: f32;
if abs(dx) >= dy {
max_axis = dx;
p = x1;
} else {
max_axis = dy;
p = y1;
}
let steps = floor(p + max_axis) as i32 - floor(p) as i32;
p = floor(p) + 0.5 - p;
if max_axis < 0 as f32 {
steps = -steps;
p = -p;
max_axis = -max_axis;
}
dx = dx / max_axis;
dy = dy / max_axis;
let f = min(max_axis, max(0 as f32, p));
setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col);
if !steps {
return;
}
x1 = x1 + (1 as f32 + p) * dx;
y1 = y1 + (1 as f32 + p) * dy;
p = p + steps as f32;
loop pixels {
if steps := steps - 1 {
setPixel(x1 as i32, y1 as i32, col);
x1 = x1 + dx;
y1 = y1 + dy;
branch pixels;
}
}
f = min(max_axis, p) - p;
setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col);
}
export fn upd() { export fn upd() {
cls(0); cls(0);
// line(0.0, 4.0, 7.0, -2.0, 15);
// return;
let i: i32; let i: i32;
loop lines { loop lines {
let angle = i as f32 * (3.1415 / 25.0) + time() * 0.1; let angle = i as f32 * (3.1415 / 25.0) + time() * 0.125;
line(160.0, 120.0, 160.0 + sin(angle) * 100.0, 120.0 + cos(angle) * 100.0, 47); line(
160 as f32, 120 as f32,
160 as f32 + sin(angle) * 100 as f32,
120 as f32 + cos(angle) * 100 as f32,
47);
branch_if (i := i + 1) < 50: lines; branch_if (i := i + 1) < 50: lines;
} }
} }

65
logo.svg Normal file
View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="120"
height="120"
viewBox="0 0 120 120"
version="1.1"
id="svg5"
sodipodi:docname="logo.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="3.6041667"
inkscape:cx="21.780347"
inkscape:cy="63.260116"
inkscape:window-width="1916"
inkscape:window-height="1041"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#85a6b2;fill-rule:evenodd;fill-opacity:1"
id="rect31"
width="112.05161"
height="109.64198"
x="3.9731982"
y="6.3613" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:117.333px;line-height:1.25;font-family:'Fira Code';-inkscape-font-specification:'Fira Code Bold';fill:#ffffff;fill-opacity:1;stroke:none"
x="-6.2686396"
y="117.70291"
id="text2691"><tspan
sodipodi:role="line"
id="tspan2689"
x="-6.2686396"
y="117.70291">W8</tspan></text>
<circle
style="fill:#ffffff;stroke-width:1.32327"
id="path121"
cx="60.962471"
cy="6.7644148"
r="14.855442" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -18,7 +18,7 @@ highlight_theme = "ascetic-white"
[extra] [extra]
# Put all your custom variables here # Put all your custom variables here
juice_logo_name = "MicroW8" juice_logo_name = "MicroW8"
juice_logo_path = "microw8.svg" juice_logo_path = "img/microw8.svg"
juice_extra_menu = [ juice_extra_menu = [
{ title = "Github", link = "https://github.com/exoticorn/microw8" } { title = "Github", link = "https://github.com/exoticorn/microw8" }
] ]

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="120" height="120" version="1.1" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg">
<path d="m3.9727 6.3613v27.945h7.8691l2.8281 66.549 6.9199-56.922h16.969l6.4375 56.922 4.1523-66.549h17.148l-9.5488 81.697h27.195c-4.1759-2.1972-7.3595-5.016-9.5234-8.4707-2.2464-3.6905-3.3691-7.6805-3.3691-11.973 0-4.7735 1.3845-8.9251 4.1523-12.455 2.7679-3.53 6.4981-6.3194 11.191-8.3652-4.2521-2.7277-7.3402-5.4948-9.2656-8.3027-1.8854-2.8481-2.8281-6.5783-2.8281-11.191 0-4.7334 1.223-8.8256 3.6699-12.275 2.4469-3.4498 5.7559-6.0981 9.9277-7.9434 4.212-1.8854 8.9647-2.8262 14.26-2.8262 5.2203 0 9.8397 0.84602 13.867 2.5234v-28.363h-40.227a14.855 14.855 0 0 1 0.019531 0.40234 14.855 14.855 0 0 1-14.855 14.855 14.855 14.855 0 0 1-14.855-14.855 14.855 14.855 0 0 1 0.052734-0.40234zm98.186 38.775c-3.0888 0-5.4939 0.863-7.2187 2.5879-1.6848 1.6848-2.5273 4.192-2.5273 7.5215 0 2.9283 0.98169 5.3538 2.9473 7.2793 1.9656 1.8854 5.0352 3.6113 9.207 5.1758 2.7277-2.0057 4.5928-3.971 5.5957-5.8965 1.0028-1.9656 1.5039-4.1129 1.5039-6.4395 0-2.9684-0.8017-5.4144-2.4062-7.3398-1.5644-1.9255-3.9326-2.8887-7.1016-2.8887zm-72.203 12.938-6.4902 57.93h12.393zm68.113 21.781c-2.4469 1.5644-4.3938 3.5502-5.8379 5.957-1.4441 2.4068-2.166 5.2741-2.166 8.6035 0 3.4498 1.0041 6.2781 3.0098 8.4844 2.0458 2.1662 5.0726 3.25 9.084 3.25 4.1317 0 7.142-1.1043 9.0274-3.3106 1.8854-2.2464 2.8281-4.8723 2.8281-7.8809 0-2.7679-0.56235-5.0153-1.6856-6.7402-1.0831-1.7249-2.7886-3.2096-5.1152-4.4531-2.3266-1.2836-5.3738-2.5864-9.1445-3.9102z" fill="#85a6b2" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

70
src/filewatcher.rs Normal file
View File

@@ -0,0 +1,70 @@
use anyhow::{bail, Result};
use notify::{DebouncedEvent, Watcher, RecommendedWatcher};
use std::{
collections::BTreeSet,
path::{Path, PathBuf},
sync::mpsc,
time::Duration,
};
pub struct FileWatcher {
_watcher: RecommendedWatcher,
watched_files: BTreeSet<PathBuf>,
rx: mpsc::Receiver<DebouncedEvent>,
}
pub struct FileWatcherBuilder(BTreeSet<PathBuf>);
impl FileWatcher {
pub fn builder() -> FileWatcherBuilder {
FileWatcherBuilder(BTreeSet::new())
}
pub fn poll_changed_file(&self) -> Result<Option<PathBuf>> {
let event = self.rx.try_recv();
match event {
Ok(DebouncedEvent::Create(path) | DebouncedEvent::Write(path)) => {
let handle = same_file::Handle::from_path(&path)?;
for file in &self.watched_files {
if handle == same_file::Handle::from_path(file)? {
return Ok(Some(path));
}
}
}
Err(mpsc::TryRecvError::Disconnected) => bail!("File watcher disconnected"),
_ => (),
}
Ok(None)
}
}
impl FileWatcherBuilder {
pub fn add_file<P: Into<PathBuf>>(&mut self, path: P) -> &mut Self {
self.0.insert(path.into());
self
}
pub fn build(self) -> Result<FileWatcher> {
let mut directories: BTreeSet<&Path> = BTreeSet::new();
for file in &self.0 {
if let Some(directory) = file.parent() {
directories.insert(directory);
}
}
let (tx, rx) = mpsc::channel();
let mut watcher = notify::watcher(tx, Duration::from_millis(100))?;
for directory in directories {
watcher.watch(directory, notify::RecursiveMode::NonRecursive)?;
}
Ok(FileWatcher {
_watcher: watcher,
watched_files: self.0,
rx,
})
}
}

View File

@@ -10,6 +10,10 @@ use wasmtime::{
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType, Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
}; };
mod filewatcher;
pub use filewatcher::FileWatcher;
static GAMEPAD_KEYS: &'static [Key] = &[ static GAMEPAD_KEYS: &'static [Key] = &[
Key::Up, Key::Up,
Key::Down, Key::Down,

View File

@@ -1,17 +1,14 @@
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::process; use std::process;
use std::sync::mpsc;
use std::time::Duration;
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
process::exit, process::exit,
}; };
use anyhow::{bail, Result}; use anyhow::Result;
use notify::{DebouncedEvent, Watcher};
use pico_args::Arguments; use pico_args::Arguments;
use uw8::MicroW8; use uw8::{FileWatcher, MicroW8};
fn main() -> Result<()> { fn main() -> Result<()> {
let mut args = Arguments::from_env(); let mut args = Arguments::from_env();
@@ -72,13 +69,14 @@ fn run(mut args: Arguments) -> Result<()> {
uw8.set_timeout(timeout); uw8.set_timeout(timeout);
} }
let (tx, rx) = mpsc::channel(); let mut watcher = FileWatcher::builder();
let mut watcher = notify::watcher(tx, Duration::from_millis(100))?;
if watch_mode { if watch_mode {
watcher.watch(&filename, notify::RecursiveMode::NonRecursive)?; watcher.add_file(&filename);
} }
let watcher = watcher.build()?;
if let Err(err) = start_cart(&filename, &mut uw8, &config) { if let Err(err) = start_cart(&filename, &mut uw8, &config) {
eprintln!("Load error: {}", err); eprintln!("Load error: {}", err);
if !watch_mode { if !watch_mode {
@@ -87,14 +85,10 @@ fn run(mut args: Arguments) -> Result<()> {
} }
while uw8.is_open() { while uw8.is_open() {
match rx.try_recv() { if watcher.poll_changed_file()?.is_some() {
Ok(DebouncedEvent::Create(_) | DebouncedEvent::Write(_)) => { if let Err(err) = start_cart(&filename, &mut uw8, &config) {
if let Err(err) = start_cart(&filename, &mut uw8, &config) { eprintln!("Load error: {}", err);
eprintln!("Load error: {}", err);
}
} }
Err(mpsc::TryRecvError::Disconnected) => bail!("File watcher disconnected"),
_ => (),
} }
if let Err(err) = uw8.run_frame() { if let Err(err) = uw8.run_frame() {