16 Commits
v0.2.2 ... next

19 changed files with 225 additions and 67 deletions

View File

@@ -30,9 +30,9 @@ jobs:
run: sudo apt-get install -y libxkbcommon-dev libasound2-dev run: sudo apt-get install -y libxkbcommon-dev libasound2-dev
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Cache build dirs - name: Cache build dirs
uses: actions/cache@v2 uses: actions/cache@v3
with: with:
path: | path: |
~/.cargo/bin/ ~/.cargo/bin/
@@ -44,7 +44,7 @@ jobs:
- name: Build - name: Build
run: cargo build --release --verbose run: cargo build --release --verbose
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: uw8-${{ matrix.build }} name: uw8-${{ matrix.build }}
path: target/release/${{ matrix.exe }} path: target/release/${{ matrix.exe }}

View File

@@ -8,12 +8,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: build_and_deploy - name: build_and_deploy
uses: shalzz/zola-deploy-action@v0.14.1 uses: shalzz/zola-deploy-action@70a101a14bbdeed13e7a42a9ed06b35c9e9e826e
env: env:
# Target branch # Target branch
PAGES_BRANCH: gh-pages PAGES_BRANCH: gh-pages
BUILD_DIR: site BUILD_DIR: site
# Provide personal access token # Provide personal access token
TOKEN: $GITHUB_ACTOR:${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

13
Cargo.lock generated
View File

@@ -2069,6 +2069,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "notify-debouncer-mini"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e23e9fa24f094b143c1eb61f90ac6457de87be6987bc70746e0179f7dbc9007b"
dependencies = [
"notify",
]
[[package]] [[package]]
name = "num-complex" name = "num-complex"
version = "0.4.3" version = "0.4.3"
@@ -3374,7 +3383,7 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "uw8" name = "uw8"
version = "0.2.1" version = "0.2.2"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"anyhow", "anyhow",
@@ -3382,7 +3391,7 @@ dependencies = [
"curlywas", "curlywas",
"env_logger", "env_logger",
"log", "log",
"notify", "notify-debouncer-mini",
"pico-args 0.5.0", "pico-args 0.5.0",
"rubato", "rubato",
"same-file", "same-file",

View File

@@ -16,7 +16,7 @@ anyhow = "1"
env_logger = "0.10" env_logger = "0.10"
log = "0.4" log = "0.4"
uw8-window = { path = "uw8-window", optional = true } uw8-window = { path = "uw8-window", optional = true }
notify = "5" notify-debouncer-mini = { version = "0.2.1", default-features = false }
pico-args = "0.5" pico-args = "0.5"
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "0e7ea50" } curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "0e7ea50" }
wat = "1" wat = "1"

View File

@@ -0,0 +1,21 @@
include "../include/microw8-api.cwa"
const SPRITE = 0x20000;
export fn upd() {
cls(0);
let t = time();
let i: i32;
loop spriteLoop {
let inline x = sin(t * -1.3 + i as f32 / 8_f) * 180_f + 160_f;
let inline y = sin(t * 1.7 + i as f32 / 9_f) * 140_f + 120_f;
blitSprite(SPRITE, 16, x as i32, y as i32, 0x100);
branch_if (i +:= 1) < 200: spriteLoop;
}
}
start fn start() {
printChar('OO');
circle(8_f, 8_f, 6_f, 75);
grabSprite(SPRITE, 16, 0, 0, 0);
}

View File

@@ -30,11 +30,13 @@ import "env.printInt" fn printInt(i32);
import "env.setTextColor" fn setTextColor(i32); import "env.setTextColor" fn setTextColor(i32);
import "env.setBackgroundColor" fn setBackgroundColor(i32); import "env.setBackgroundColor" fn setBackgroundColor(i32);
import "env.setCursorPosition" fn setCursorPosition(i32, i32); import "env.setCursorPosition" fn setCursorPosition(i32, i32);
import "env.rectangle_outline" fn rectangle_outline(f32, f32, f32, f32, i32); import "env.rectangleOutline" fn rectangleOutline(f32, f32, f32, f32, i32);
import "env.circle_outline" fn circle_outline(f32, f32, f32, i32); import "env.circleOutline" fn circleOutline(f32, f32, f32, i32);
import "env.exp" fn exp(f32) -> f32; import "env.exp" fn exp(f32) -> f32;
import "env.playNote" fn playNote(i32, i32); import "env.playNote" fn playNote(i32, i32);
import "env.sndGes" fn sndGes(i32) -> f32; import "env.sndGes" fn sndGes(i32) -> f32;
import "env.blitSprite" fn blitSprite(i32, i32, i32, i32, i32);
import "env.grabSprite" fn grabSprite(i32, i32, i32, i32, i32);
const TIME_MS = 0x40; const TIME_MS = 0x40;
const GAMEPAD = 0x44; const GAMEPAD = 0x44;

View File

@@ -30,11 +30,13 @@
(import "env" "setTextColor" (func $setTextColor (param i32))) (import "env" "setTextColor" (func $setTextColor (param i32)))
(import "env" "setBackgroundColor" (func $setBackgroundColor (param i32))) (import "env" "setBackgroundColor" (func $setBackgroundColor (param i32)))
(import "env" "setCursorPosition" (func $setCursorPosition (param i32) (param i32))) (import "env" "setCursorPosition" (func $setCursorPosition (param i32) (param i32)))
(import "env" "rectangle_outline" (func $rectangle_outline (param f32) (param f32) (param f32) (param f32) (param i32))) (import "env" "rectangleOutline" (func $rectangleOutline (param f32) (param f32) (param f32) (param f32) (param i32)))
(import "env" "circle_outline" (func $circle_outline (param f32) (param f32) (param f32) (param i32))) (import "env" "circleOutline" (func $circleOutline (param f32) (param f32) (param f32) (param i32)))
(import "env" "exp" (func $exp (param f32) (result f32))) (import "env" "exp" (func $exp (param f32) (result f32)))
(import "env" "playNote" (func $playNote (param i32) (param i32))) (import "env" "playNote" (func $playNote (param i32) (param i32)))
(import "env" "sndGes" (func $sndGes (param i32) (result f32))) (import "env" "sndGes" (func $sndGes (param i32) (result f32)))
(import "env" "blitSprite" (func $blitSprite (param i32) (param i32) (param i32) (param i32) (param i32)))
(import "env" "grabSprite" (func $grabSprite (param i32) (param i32) (param i32) (param i32) (param i32)))
;; to use defines, include this file with a preprocessor ;; to use defines, include this file with a preprocessor
;; like gpp (https://logological.org/gpp). ;; like gpp (https://logological.org/gpp).

View File

@@ -5,11 +5,7 @@ pub fn build(b: *std.build.Builder) void {
const lib = b.addSharedLibrary("cart", "main.zig", .unversioned); const lib = b.addSharedLibrary("cart", "main.zig", .unversioned);
lib.setBuildMode(mode); lib.setBuildMode(mode);
lib.setTarget(.{ lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding, .cpu_features_add = std.Target.wasm.featureSet(&.{.nontrapping_fptoint}) });
.cpu_arch = .wasm32,
.os_tag = .freestanding,
.cpu_features_add = std.Target.wasm.featureSet(&.{ .nontrapping_fptoint })
});
lib.import_memory = true; lib.import_memory = true;
lib.initial_memory = 262144; lib.initial_memory = 262144;
lib.max_memory = 262144; lib.max_memory = 262144;
@@ -18,19 +14,13 @@ pub fn build(b: *std.build.Builder) void {
lib.install(); lib.install();
if (lib.install_step) |install_step| { if (lib.install_step) |install_step| {
const run_filter_exports = b.addSystemCommand(&[_][]const u8{ const run_filter_exports = b.addSystemCommand(&[_][]const u8{ "uw8", "filter-exports", "zig-out/lib/cart.wasm", "zig-out/lib/cart-filtered.wasm" });
"uw8", "filter-exports", "zig-out/lib/cart.wasm", "zig-out/lib/cart-filtered.wasm"
});
run_filter_exports.step.dependOn(&install_step.step); run_filter_exports.step.dependOn(&install_step.step);
const run_wasm_opt = b.addSystemCommand(&[_][]const u8{ const run_wasm_opt = b.addSystemCommand(&[_][]const u8{ "wasm-opt", "--enable-nontrapping-float-to-int", "-Oz", "-o", "zig-out/cart.wasm", "zig-out/lib/cart-filtered.wasm" });
"wasm-opt", "-Oz", "-o", "zig-out/cart.wasm", "zig-out/lib/cart-filtered.wasm"
});
run_wasm_opt.step.dependOn(&run_filter_exports.step); run_wasm_opt.step.dependOn(&run_filter_exports.step);
const run_uw8_pack = b.addSystemCommand(&[_][]const u8{ const run_uw8_pack = b.addSystemCommand(&[_][]const u8{ "uw8", "pack", "-l", "9", "zig-out/cart.wasm", "zig-out/cart.uw8" });
"uw8", "pack", "-l", "9", "zig-out/cart.wasm", "zig-out/cart.uw8"
});
run_uw8_pack.step.dependOn(&run_wasm_opt.step); run_uw8_pack.step.dependOn(&run_wasm_opt.step);
const make_opt = b.step("make_opt", "make size optimized cart"); const make_opt = b.step("make_opt", "make size optimized cart");

View File

@@ -1,11 +1,11 @@
extern fn atan2(x: f32, y: f32) f32; extern fn atan2(x: f32, y: f32) f32;
extern fn time() f32; extern fn time() f32;
pub const FRAMEBUFFER: *[320*240]u8 = @intToPtr(*[320*240]u8, 120); pub const FRAMEBUFFER: *[320 * 240]u8 = @intToPtr(*[320 * 240]u8, 120);
export fn upd() void { export fn upd() void {
var i: u32 = 0; var i: u32 = 0;
while(true) { while (true) {
var t = time() * 63.0; var t = time() * 63.0;
var x = @intToFloat(f32, (@intCast(i32, i % 320) - 160)); var x = @intToFloat(f32, (@intCast(i32, i % 320) - 160));
var y = @intToFloat(f32, (@intCast(i32, i / 320) - 120)); var y = @intToFloat(f32, (@intCast(i32, i / 320) - 120));
@@ -13,8 +13,10 @@ export fn upd() void {
var u = atan2(x, y) * 512.0 / 3.141; var u = atan2(x, y) * 512.0 / 3.141;
var c = @intCast(u8, (@floatToInt(i32, d + t * 2.0) ^ @floatToInt(i32, u + t)) & 255) >> 4; var c = @intCast(u8, (@floatToInt(i32, d + t * 2.0) ^ @floatToInt(i32, u + t)) & 255) >> 4;
FRAMEBUFFER[@as(usize, i)] = c; FRAMEBUFFER[i] = c;
i += 1; i += 1;
if(i >= 320*240) { break; } if (i >= 320 * 240) {
break;
}
} }
} }

Binary file not shown.

Binary file not shown.

View File

@@ -171,7 +171,7 @@ export fn rectangle(x: f32, y: f32, w: f32, h: f32, col: i32) {
} }
} }
export fn rectangle_outline(x: f32, y: f32, w: f32, h: f32, col: i32) { export fn rectangleOutline(x: f32, y: f32, w: f32, h: f32, col: i32) {
let xl = nearest(x) as i32; let xl = nearest(x) as i32;
let xr = nearest(x + w) as i32; let xr = nearest(x + w) as i32;
let yt = nearest(y) as i32; let yt = nearest(y) as i32;
@@ -212,7 +212,7 @@ export fn circle(cx: f32, cy: f32, radius: f32, col: i32) {
} }
} }
export fn circle_outline(cx: f32, cy: f32, radius: f32, col: i32) { export fn circleOutline(cx: f32, cy: f32, radius: f32, col: i32) {
let prev_w: f32; let prev_w: f32;
let y = clamp(nearest(cy - radius) as i32, -1, 241); let y = clamp(nearest(cy - radius) as i32, -1, 241);
let maxY = clamp(nearest(cy + radius) as i32, -1, 241); let maxY = clamp(nearest(cy + radius) as i32, -1, 241);
@@ -352,6 +352,92 @@ export fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
setPixel(i32.trunc_sat_f32_s(x1 + f * dx), i32.trunc_sat_f32_s(y1 + f * dy), col); setPixel(i32.trunc_sat_f32_s(x1 + f * dx), i32.trunc_sat_f32_s(y1 + f * dy), col);
} }
export fn blitSprite(sprite: i32, size: i32, x: i32, y: i32, control: i32) {
let lazy width = size & 65535;
let lazy height = select(size >> 16, size >> 16, width);
let lazy x0 = select(x < 0, -x, 0);
let lazy x1 = select(x + width > 320, 320 - x, width);
let lazy y0 = select(y < 0, -y, 0);
let lazy y1 = select(y + height > 240, 240 - y, height);
let lazy numRows = y1 - y0;
let lazy numCols = x1 - x0;
if numRows <= 0 | numCols <= 0 {
return;
}
let trans = (control & 511) - 256;
let lazy flip_x = 1 - ((control >> 8) & 2);
let lazy flip_y = 1 - ((control >> 9) & 2);
if flip_x < 0 {
sprite += width - 1;
}
if flip_y < 0 {
sprite += (height - 1) * width;
}
let spriteRow = sprite + x0 * flip_x + y0 * flip_y * width;
let screenRow = x + x0 + (y + y0) * 320;
loop yloop {
let lx = 0;
loop xloop {
let lazy col = (spriteRow + lx * flip_x)?0;
if col != trans {
(screenRow + lx)?120 = col;
}
branch_if (lx +:= 1) < numCols: xloop;
}
spriteRow += width * flip_y;
screenRow += 320;
branch_if numRows -:= 1: yloop;
}
}
export fn grabSprite(sprite: i32, size: i32, x: i32, y: i32, control: i32) {
let lazy width = size & 65535;
let lazy height = select(size >> 16, size >> 16, width);
let lazy x0 = select(x < 0, -x, 0);
let lazy x1 = select(x + width > 320, 320 - x, width);
let lazy y0 = select(y < 0, -y, 0);
let lazy y1 = select(y + height > 240, 240 - y, height);
let lazy numRows = y1 - y0;
let lazy numCols = x1 - x0;
if numRows <= 0 | numCols <= 0 {
return;
}
let trans = (control & 511) - 256;
let lazy flip_x = 1 - ((control >> 8) & 2);
let lazy flip_y = 1 - ((control >> 9) & 2);
if flip_x < 0 {
sprite += width - 1;
}
if flip_y < 0 {
sprite += (height - 1) * width;
}
let spriteRow = sprite + x0 * flip_x + y0 * flip_y * width;
let screenRow = x + x0 + (y + y0) * 320;
loop yloop {
let lx = 0;
loop xloop {
let lazy col = (screenRow + lx)?120;
if col != trans {
(spriteRow + lx * flip_x)?0 = col;
}
branch_if (lx +:= 1) < numCols: xloop;
}
spriteRow += width * flip_y;
screenRow += 320;
branch_if numRows -:= 1: yloop;
}
}
////////// //////////
// TEXT // // TEXT //
////////// //////////

View File

@@ -146,13 +146,13 @@ Fills the circle at `cx, cy` and with `radius` with the given color index.
(Sets all pixels where the pixel center lies inside the circle.) (Sets all pixels where the pixel center lies inside the circle.)
### fn rectangle_outline(x: f32, y: f32, w: f32, h: f32, color: i32) ### fn rectangleOutline(x: f32, y: f32, w: f32, h: f32, color: i32)
Draws a one pixel outline on the inside of the given rectangle. Draws a one pixel outline on the inside of the given rectangle.
(Draws the outermost pixels that are still inside the rectangle area.) (Draws the outermost pixels that are still inside the rectangle area.)
### fn circle_outline(cx: f32, cy: f32, radius: f32, color: i32) ### fn circleOutline(cx: f32, cy: f32, radius: f32, color: i32)
Draws a one pixel outline on the inside of the given circle. Draws a one pixel outline on the inside of the given circle.
@@ -162,6 +162,21 @@ Draws a one pixel outline on the inside of the given circle.
Draws a line from `x1,y1` to `x2,y2` in the given color index. Draws a line from `x1,y1` to `x2,y2` in the given color index.
### fn blitSprite(spriteData: i32, size: i32, x: i32, y: i32, control: i32)
Copies the pixel data at `spriteData` onto the screen at `x`, `y`. The size of the sprite is passed as `width | (height << 16)`.
If the height is given as 0, the sprite is is treated as square (width x width).
The control parameter controls masking and flipping of the sprite:
* bits 0-7: color mask index
* bit 8: switch on masked blit (pixel with color mask index are treated as transparent)
* bit 9: flip sprite x
* bit 10: flip sprite y
### fn grabSprite(spriteData: i32, size: i32, x: i32, y: i32, control: i32)
Copies the pixel data on the screen at `x`, `y` to `spriteData`. Parameters are exactly the same as `blitSprite`.
## Input ## Input
MicroW8 provides input from a gamepad with one D-Pad and 4 buttons, or a keyboard emulation thereof. MicroW8 provides input from a gamepad with one D-Pad and 4 buttons, or a keyboard emulation thereof.

View File

@@ -1,23 +1,35 @@
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use notify::{Event, EventKind, RecommendedWatcher, Watcher}; use notify_debouncer_mini::{
use std::{collections::BTreeSet, path::PathBuf, sync::mpsc}; new_debouncer,
notify::{self, RecommendedWatcher},
DebouncedEvent, DebouncedEventKind, Debouncer,
};
use std::{collections::BTreeSet, path::PathBuf, sync::mpsc, time::Duration};
pub struct FileWatcher { pub struct FileWatcher {
watcher: RecommendedWatcher, debouncer: Debouncer<RecommendedWatcher>,
watched_files: BTreeSet<PathBuf>, watched_files: BTreeSet<PathBuf>,
directories: BTreeSet<PathBuf>, directories: BTreeSet<PathBuf>,
rx: mpsc::Receiver<Event>, rx: mpsc::Receiver<DebouncedEvent>,
} }
impl FileWatcher { impl FileWatcher {
pub fn new() -> Result<FileWatcher> { pub fn new() -> Result<FileWatcher> {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let watcher = notify::recommended_watcher(move |res| match res { let debouncer = new_debouncer(Duration::from_millis(100), None, move |res| match res {
Ok(event) => _ = tx.send(event), Ok(events) => {
Err(err) => eprintln!("Error watching for file changes: {err}"), for event in events {
let _ = tx.send(event);
}
}
Err(errs) => {
for err in errs {
eprintln!("Error watching for file changes: {err}");
}
}
})?; })?;
Ok(FileWatcher { Ok(FileWatcher {
watcher, debouncer,
watched_files: BTreeSet::new(), watched_files: BTreeSet::new(),
directories: BTreeSet::new(), directories: BTreeSet::new(),
rx, rx,
@@ -29,7 +41,8 @@ impl FileWatcher {
let parent = path.parent().ok_or_else(|| anyhow!("File has no parent"))?; let parent = path.parent().ok_or_else(|| anyhow!("File has no parent"))?;
if !self.directories.contains(parent) { if !self.directories.contains(parent) {
self.watcher self.debouncer
.watcher()
.watch(parent, notify::RecursiveMode::NonRecursive)?; .watch(parent, notify::RecursiveMode::NonRecursive)?;
self.directories.insert(parent.to_path_buf()); self.directories.insert(parent.to_path_buf());
} }
@@ -41,13 +54,11 @@ impl FileWatcher {
pub fn poll_changed_file(&self) -> Result<Option<PathBuf>> { pub fn poll_changed_file(&self) -> Result<Option<PathBuf>> {
match self.rx.try_recv() { match self.rx.try_recv() {
Ok(event) => match event.kind { Ok(event) => match event.kind {
EventKind::Create(_) | EventKind::Modify(_) => { DebouncedEventKind::Any => {
for path in event.paths { let handle = same_file::Handle::from_path(&event.path)?;
let handle = same_file::Handle::from_path(&path)?;
for file in &self.watched_files { for file in &self.watched_files {
if handle == same_file::Handle::from_path(file)? { if handle == same_file::Handle::from_path(file)? {
return Ok(Some(path)); return Ok(Some(event.path));
}
} }
} }
} }

View File

@@ -181,10 +181,12 @@ impl super::Runtime for MicroW8 {
if let Some(mut instance) = self.instance.take() { if let Some(mut instance) = self.instance.take() {
let time = (now - instance.start_time).as_millis() as i32; let time = (now - instance.start_time).as_millis() as i32;
let next_frame = { let next_frame = {
let offset = ((time as u32 as i64 * 6) % 100 - 50) / 6; let frame = (time as u32 as u64 * 6 / 100) as u32;
let max = now + Duration::from_millis(17); let cur_offset = (time as u32).wrapping_sub((frame as u64 * 100 / 6) as u32);
let next_center = now + Duration::from_millis((16 - offset) as u64); let next_time =
next_center.min(max) ((frame as u64 + 1) * 100 / 6 + cur_offset.max(1).min(4) as u64) as u32;
let offset = next_time.wrapping_sub(time as u32);
now + Duration::from_millis(offset as u64)
}; };
{ {

View File

@@ -2,17 +2,18 @@ import "env.memory" memory(4);
import "env.pow" fn pow(f32, f32) -> f32; import "env.pow" fn pow(f32, f32) -> f32;
import "env.sin" fn sin(f32) -> f32; import "env.sin" fn sin(f32) -> f32;
import "env.cls" fn cls(i32); import "env.cls" fn cls(i32);
import "env.exp" fn exp(f32) -> f32;
import "env.rectangle" fn rectangle(f32, f32, f32, f32, i32); import "env.rectangle" fn rectangle(f32, f32, f32, f32, i32);
include "../platform/src/ges.cwa" include "../platform/src/ges.cwa"
export fn snd(t: i32) -> f32 { export fn snd(t: i32) -> f32 {
gesSnd(t) sndGes(t)
} }
export fn upd() { export fn upd() {
80?0 = 32!32 / 200 & 2 | 0x41; 80?0 = 32!32 / 200 & 2 | 0x41;
80?3 = (32!32 / 400)%7*12/7 + 40; 80?3 = (32!32 / 400)%8*12/7 + 40;
let pulse = (32!32 * 256 / 2000) & 511; let pulse = (32!32 * 256 / 2000) & 511;
if pulse >= 256 { if pulse >= 256 {
pulse = 511 - pulse; pulse = 511 - pulse;

View File

@@ -152,14 +152,14 @@ impl BaseModule {
add_function( add_function(
&mut functions, &mut functions,
&type_map, &type_map,
"rectangle_outline", "rectangleOutline",
&[F32, F32, F32, F32, I32], &[F32, F32, F32, F32, I32],
None, None,
); );
add_function( add_function(
&mut functions, &mut functions,
&type_map, &type_map,
"circle_outline", "circleOutline",
&[F32, F32, F32, I32], &[F32, F32, F32, I32],
None, None,
); );
@@ -169,6 +169,21 @@ impl BaseModule {
add_function(&mut functions, &type_map, "playNote", &[I32, I32], None); add_function(&mut functions, &type_map, "playNote", &[I32, I32], None);
add_function(&mut functions, &type_map, "sndGes", &[I32], Some(F32)); add_function(&mut functions, &type_map, "sndGes", &[I32], Some(F32));
add_function(
&mut functions,
&type_map,
"blitSprite",
&[I32, I32, I32, I32, I32],
None,
);
add_function(
&mut functions,
&type_map,
"grabSprite",
&[I32, I32, I32, I32, I32],
None,
);
for i in functions.len()..64 { for i in functions.len()..64 {
add_function( add_function(
&mut functions, &mut functions,

View File

@@ -767,7 +767,10 @@ fn remap_function(
De::End => En::End, De::End => En::End,
De::Br { relative_depth } => En::Br(relative_depth), De::Br { relative_depth } => En::Br(relative_depth),
De::BrIf { relative_depth } => En::BrIf(relative_depth), De::BrIf { relative_depth } => En::BrIf(relative_depth),
De::BrTable { .. } => todo!(), De::BrTable { targets } => En::BrTable(
targets.targets().collect::<Result<Vec<u32>, _>>()?.into(),
targets.default(),
),
De::Return => En::Return, De::Return => En::Return,
De::Call { function_index } => En::Call( De::Call { function_index } => En::Call(
*function_map *function_map

View File

@@ -274,7 +274,7 @@ export default function MicroW8(screen, config = {}) {
try { try {
let restart = false; let restart = false;
let thisFrame; let nextFrame = 0;
if (!isPaused) { if (!isPaused) {
let gamepads = navigator.getGamepads(); let gamepads = navigator.getGamepads();
let gamepad = 0; let gamepad = 0;
@@ -321,13 +321,12 @@ export default function MicroW8(screen, config = {}) {
} }
canvasCtx.putImageData(imageData, 0, 0); canvasCtx.putImageData(imageData, 0, 0);
let timeOffset = ((time * 6) % 100 - 50) / 6; let thisFrame = Math.floor(time * 6 / 100);
thisFrame = startTime + time - timeOffset / 8; let timeOffset = time - thisFrame * 100 / 6;
} else { nextFrame = Math.ceil(startTime + (thisFrame + 1) * 100 / 6 + Math.min(4, timeOffset));
thisFrame = Date.now();
} }
let now = Date.now(); let now = Date.now();
let nextFrame = Math.max(thisFrame + timePerFrame, now); nextFrame = Math.max(nextFrame, now);
if (restart) { if (restart) {
runModule(currentData); runModule(currentData);