41 Commits
Author SHA1 Message Date
dranke b3dbc026f3 Merge pull request #16 from zbyti/master
scope correction
2026-04-19 20:05:22 +02:00
Bartek Zbytniewski c2b7af94c1 scope correction 2026-04-19 11:51:58 +02:00
dranke b9b2c2c927 Merge pull request #14 from zbyti/master
custom Syntax Highlighting for Sublime Text
2025-04-24 10:06:54 +02:00
Bartek Zbytniewski 9208c0e652 new completions 2025-04-21 20:18:17 +02:00
Bartek Zbytniewski ede0484e9b Sublime Text refactor 2025-04-20 13:09:38 +02:00
Bartek Zbytniewski e14db77f26 more Sublime Text fetures 2025-04-20 10:53:26 +02:00
Bartek Zbytniewski 3ca10fc85a syntax & autocomplete refactor 2025-04-18 20:43:44 +02:00
Bartek Zbytniewski 3c4fd20d70 sublime text autocompletion 2025-04-18 19:45:16 +02:00
Bartek Zbytniewski 14e31d02fc expanded syntax with start() & upd() functions 2025-04-17 22:11:40 +02:00
Bartek Zbytniewski 5e54716007 add constant.numeric.float.curlywasm _f for hex 2025-04-17 21:27:42 +02:00
Bartek Zbytniewski 44566ce1a3 new commented examples 2025-04-17 20:03:42 +02:00
Bartek Zbytniewski 8d860a7a86 custom Syntax Highlighting for Sublime Text 2025-04-17 19:59:33 +02:00
dranke 9fc3353599 prepare for 0.4.1 release 2025-03-02 20:45:27 +01:00
dranke fd10378e4d add ScaleMode::Fill to fill screen without black borders 2025-03-02 20:34:43 +01:00
dranke 0659f8a57e update to upload-artifact@v4 2025-03-02 20:00:09 +01:00
dranke f4fa9e9c62 revert rubato to 0.12 to fix crackling at 48000
(probably some misuse on my side, need to investigate more)
2025-03-02 13:42:06 +01:00
dranke 4c1ce8075e revert to winit 0.28 and wgpu 0.17 to fix fps on windows 2025-03-02 12:57:22 +01:00
dranke 94764d631e fix download links in readme 2025-03-01 12:03:26 +01:00
dranke 8913fdaf6b update web runtime to 0.4.0 on homepage 2025-01-22 20:25:59 +01:00
dranke 195376cd28 forgot one additional change in 0.4.0 2025-01-22 19:53:22 +01:00
dranke bf14d4bd3f prepare release 0.4.0 2025-01-22 19:49:28 +01:00
dranke 0c68328700 add 6 and 7 parameter function types to base module 2025-01-21 22:23:08 +01:00
dranke fb3fd5e8bb add frame counter at memory location 72 2024-06-16 14:10:18 +02:00
dranke b85f96b0bb add support to output sound on devices that only offer surround configs 2024-06-16 13:21:23 +02:00
dranke b69055b58d update to git version of wasmtime
fixes performance regressions since microw8 0.2.1
2024-06-16 13:07:29 +02:00
dranke 0878aa3f02 add support for mono-only audio devices 2024-05-26 12:54:59 +02:00
dranke 5cd1ecb98a prepare for 0.3.0 release 2024-04-27 23:22:51 +02:00
dranke 842cf9f139 update some more dependencies 2024-04-10 00:04:12 +02:00
dranke d5ed809dc7 minimal text scale docs + reset on cls() 2024-04-10 00:03:54 +02:00
dranke 285d9aee2c add example for scaled text 2024-04-09 00:09:27 +02:00
dranke 4e18d38538 add untested implementation of text scale 2024-04-07 23:59:14 +02:00
dranke d4bad3ba8b add sprite flipping to example 2024-04-07 23:20:13 +02:00
dranke 6ddda24156 Merge branch 'sprites' 2024-04-07 22:58:26 +02:00
dranke 7003db3a05 update dependencies 2024-04-03 10:26:41 +02:00
dranke 8258bc1854 fix typo 2023-09-13 07:36:24 +02:00
dranke a651107104 add start and snd functions to filter exports exclude list 2023-09-03 10:19:30 +02:00
dranke 22c35e37f4 remove debug trace 2023-09-02 15:37:27 +02:00
dranke 805c939097 add support for sound devices that only accept 16bit audio 2023-08-23 23:03:23 +02:00
dranke 440e150896 update dependencies 2023-08-23 00:52:51 +02:00
dranke 77b2e27346 clamp snd samples into valid -1.0..1.0 range 2023-08-23 00:20:35 +02:00
dranke 09e4fcbf14 add --scale option 2023-08-11 23:52:19 +02:00
59 changed files with 6012 additions and 3786 deletions

No files matched your search

+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
- name: Build
run: cargo build --release --verbose
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: uw8-${{ matrix.build }}
path: target/release/${{ matrix.exe }}
Generated
+1809 -1471
View File
File diff suppressed because it is too large. Load diff
+9 -9
View File
@@ -1,6 +1,6 @@
[package]
name = "uw8"
version = "0.2.2"
version = "0.4.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -11,21 +11,21 @@ native = ["wasmtime", "uw8-window", "cpal", "rubato" ]
browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
[dependencies]
wasmtime = { version = "5.0.0", optional = true }
wasmtime = { git = "https://github.com/bytecodealliance/wasmtime.git", rev = "0f48f939b9870036562ca02ff21253547a9f1a5c", optional = true }
anyhow = "1"
env_logger = "0.10"
env_logger = "0.11.3"
log = "0.4"
uw8-window = { path = "uw8-window", optional = true }
notify-debouncer-mini = { version = "0.2.1", default-features = false }
notify-debouncer-mini = { version = "0.4.1", default-features = false }
pico-args = "0.5"
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "0e7ea50" }
wat = "1"
uw8-tool = { path = "uw8-tool" }
same-file = "1"
warp = { version = "0.3.3", optional = true }
tokio = { version = "1.24.0", features = ["sync", "rt"], optional = true }
tokio-stream = { version = "0.1.11", features = ["sync"], optional = true }
webbrowser = { version = "0.8.6", optional = true }
warp = { version = "0.3.6", optional = true }
tokio = { version = "1.37.0", features = ["sync", "rt"], optional = true }
tokio-stream = { version = "0.1.15", features = ["sync"], optional = true }
webbrowser = { version = "0.8.13", optional = true }
ansi_term = "0.12.1"
cpal = { version = "0.14.2", optional = true }
cpal = { version = "0.15.3", optional = true }
rubato = { version = "0.12.0", optional = true }
+3 -3
View File
@@ -15,9 +15,9 @@ See [here](https://exoticorn.github.io/microw8/) for more information and docs.
## Downloads
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-windows.zip)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-windows.zip)
The download includes
+254
View File
@@ -0,0 +1,254 @@
/*
This program renders a rotating 3D wireframe cube on a 2D screen using the MicroW8 platform.
code : zbyti
date : 2025.04.15
platform : MicroW8 0.4.1
https://exoticorn.github.io/microw8/
https://exoticorn.github.io/microw8/docs/
https://github.com/exoticorn/microw8
https://github.com/exoticorn/curlywas
https://developer.mozilla.org/en-US/docs/WebAssembly
https://en.wikipedia.org/wiki/Rotation_matrix
*/
//-----------------------------------------------------------------------------
// MicroW8 API
//-----------------------------------------------------------------------------
//include "../include/microw8-api.cwa"
// Import memory allocation: 4 pages (64KB) of memory (256KB total)
import "env.memory" memory(4);
// Import MicroW8 API functions for graphics and math operations
import "env.cls" fn cls(i32); // Clears the screen
import "env.time" fn time() -> f32; // Returns the current time as a float for animation
import "env.sin" fn sin(f32) -> f32; // Computes the sine of an angle (in radians)
import "env.cos" fn cos(f32) -> f32; // Computes the cosine of an angle (in radians)
import "env.line" fn line(f32, f32, f32, f32, i32); // Draws a line between two 2D points with a color
// Define the starting address for user memory
const USER_MEM = 0x14000;
//-----------------------------------------------------------------------------
// CONSTANTS
//-----------------------------------------------------------------------------
// Screen and rendering constants
const CENTER_X = 320.0 / 2.0; // X-coordinate of the screen center (320px width)
const CENTER_Y = 240.0 / 2.0; // Y-coordinate of the screen center (240px height)
const ROTATE_SPEED = 0.5; // Speed at which the cube rotates
const PI = 3.14159265; // Mathematical constant Pi for angle conversions
const RADIAN = PI / 180.0; // Conversion factor from degrees to radians
const SCALE = 65.0; // Scaling factor to adjust the size of the cube on screen
const PERSPECTIVE = SCALE * 0.5; // Perspective factor
const LINE_COLOR = 0xBF; // Color value for drawing the cube's edges (hexadecimal)
// Memory layout for vertex data
const V_BASE = USER_MEM; // Base vertices stored as 8-bit integers (i8)
const V_ROT = V_BASE + (3 * 8); // Rotated vertices stored as 32-bit floats (f32), offset after V_BASE
// Offsets for accessing X, Y, Z coordinates in memory (in bytes)
const X = 0; // Offset for X coordinate
const Y = 4; // Offset for Y coordinate
const Z = 8; // Offset for Z coordinate
// Memory offsets for each rotated vertex (8 vertices, 3 floats each, 12 bytes per vertex)
const VA = V_ROT + (0 * 3 * 4); // Vertex A (front-top-left)
const VB = V_ROT + (1 * 3 * 4); // Vertex B (front-top-right)
const VC = V_ROT + (2 * 3 * 4); // Vertex C (front-bottom-right)
const VD = V_ROT + (3 * 3 * 4); // Vertex D (front-bottom-left)
const VE = V_ROT + (4 * 3 * 4); // Vertex E (back-top-left)
const VF = V_ROT + (5 * 3 * 4); // Vertex F (back-top-right)
const VG = V_ROT + (6 * 3 * 4); // Vertex G (back-bottom-right)
const VH = V_ROT + (7 * 3 * 4); // Vertex H (back-bottom-left)
//-----------------------------------------------------------------------------
// Function to rotate the cube around X, Y, and Z axes based on time
//-----------------------------------------------------------------------------
fn rotate() {
// Calculate the rotation angle using the current time for continuous animation
let angle = time() * ROTATE_SPEED;
// Precompute sine and cosine values once for efficiency
let sn = sin(angle);
let cs = cos(angle);
let calc = 0;
loop calc { // Iterate over all 8 vertices
// Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z)
let v = calc * 12;
let inline vX = v + X;
let inline vY = v + Y;
let inline vZ = v + Z;
// Load original vertex coordinates from V_BASE (stored as i8, converted to f32)
let x = i32.load8_s(V_BASE+(calc * 3 + 0)) as f32; // X coordinate
let y = i32.load8_s(V_BASE+(calc * 3 + 1)) as f32; // Y coordinate
let z = i32.load8_s(V_BASE+(calc * 3 + 2)) as f32; // Z coordinate
// Rotate around Z-axis: updates X and Y, Z stays the same
(vX)$V_ROT = x * cs - y * sn;
(vY)$V_ROT = x * sn + y * cs;
(vZ)$V_ROT = z;
// Rotate around Y-axis: updates X and Z, Y stays the same
x = (vX)$V_ROT;
z = (vZ)$V_ROT;
(vX)$V_ROT = x * cs + z * sn;
(vZ)$V_ROT = z * cs - x * sn;
// Rotate around X-axis: updates Y and Z, X stays the same
y = (vY)$V_ROT;
z = (vZ)$V_ROT;
(vY)$V_ROT = y * cs - z * sn;
(vZ)$V_ROT = y * sn + z * cs;
// Move to the next vertex until all 8 are processed
branch_if (calc +:= 1) < 8: calc;
}
}
//-----------------------------------------------------------------------------
// Function to project 3D vertices to 2D screen space and draw the cube's edges
//-----------------------------------------------------------------------------
fn drawLines() {
let scale = 0;
loop scale { // Scale and center each vertex for 2D projection
// Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z)
let v = scale * 12;
let inline vX = v + X;
let inline vY = v + Y;
// Load Z coordinate of current vertex (from rotated vertex data)
let inline z = (v + Z)$V_ROT;
// Calculate perspective factor:
// - When z=0 (midpoint), factor=1.0 (no scaling)
// - Positive z (farther away) → factor<1.0 (objects appear smaller)
// - Negative z (closer) → factor>1.0 (objects appear larger)
let lazy factor = PERSPECTIVE / (PERSPECTIVE + z) * SCALE;
// Apply perspective projection, scaling and shift to center for X and Y coordinats:
// 1. Multiply by perspective factor
// 2. Apply global scaling (SCALE constant)
// 3. Center on screen (CENTER_X, CENTER_Y)
(vX)$V_ROT = (vX)$V_ROT * factor + CENTER_X; // X
(vY)$V_ROT = (vY)$V_ROT * factor + CENTER_Y; // Y
// Continue until all 8 vertices are scaled
branch_if (scale +:= 1) < 8: scale;
}
// Draw the front face of the cube (vertices A-B-C-D)
line(VA$X, VA$Y, VB$X, VB$Y, LINE_COLOR);
line(VB$X, VB$Y, VC$X, VC$Y, LINE_COLOR);
line(VC$X, VC$Y, VD$X, VD$Y, LINE_COLOR);
line(VD$X, VD$Y, VA$X, VA$Y, LINE_COLOR);
// Draw the back face of the cube (vertices E-F-G-H)
line(VE$X, VE$Y, VF$X, VF$Y, LINE_COLOR);
line(VF$X, VF$Y, VG$X, VG$Y, LINE_COLOR);
line(VG$X, VG$Y, VH$X, VH$Y, LINE_COLOR);
line(VH$X, VH$Y, VE$X, VE$Y, LINE_COLOR);
// Draw edges connecting front and back faces
line(VA$X, VA$Y, VE$X, VE$Y, LINE_COLOR);
line(VB$X, VB$Y, VF$X, VF$Y, LINE_COLOR);
line(VC$X, VC$Y, VG$X, VG$Y, LINE_COLOR);
line(VD$X, VD$Y, VH$X, VH$Y, LINE_COLOR);
}
//-----------------------------------------------------------------------------
// Entry point for INIT type function, starts first
//-----------------------------------------------------------------------------
/*
export fn start() {
let init = 0;
loop init {
// Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z)
let v = init * 12;
(v + X)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 0) as f32;
(v + Y)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 1) as f32;
(v + Z)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 2) as f32;
branch_if (init +:= 1) < 8: init;
}
}
*/
//-----------------------------------------------------------------------------
// Main update function called every frame to refresh the screen
//-----------------------------------------------------------------------------
export fn upd() {
cls(0); // Clear the screen with color 0 (black)
rotate(); // Perform cube rotation calculations
drawLines(); // Draw the rotated cube on the screen
}
//-----------------------------------------------------------------------------
// DATA
//-----------------------------------------------------------------------------
/*
Initial vertex data for the cube (8 vertices, each with X, Y, Z as 8-bit signed integers)
Each vertex represents a corner of a unit cube centered at the origin
F - front, B - back, L - left, R - right, U - up, D - down
*/
data V_BASE { // 3 * 8 -> 3 bytes per vertex * 8 vertices = 24 bytes
i8(
// X Y Z
-1, -1, 1, // FLU Vertex A
1, -1, 1, // FRU Vertex B
1, 1, 1, // FRD Vertex C
-1, 1, 1, // FLD Vertex D
-1, -1, -1, // BLU Vertex E
1, -1, -1, // BRU Vertex F
1, 1, -1, // BRD Vertex G
-1, 1, -1 // BLD Vertex H
)
}
//-----------------------------------------------------------------------------
/*
Storage for rotated vertex data (8 vertices, each with X, Y, Z as 32-bit signed floats)
Initialized to zero and updated during rotation
*/
data V_ROT { // 4 * 3 * 8 -> 12 bytes per vertex * 8 vertices = 96 bytes
f32(
// X Y Z
0.0, 0.0, 0.0, // VA -> Vertex A
0.0, 0.0, 0.0, // VB -> Vertex B
0.0, 0.0, 0.0, // VC -> Vertex C
0.0, 0.0, 0.0, // VD -> Vertex D
0.0, 0.0, 0.0, // VE -> Vertex E
0.0, 0.0, 0.0, // VF -> Vertex F
0.0, 0.0, 0.0, // VG -> Vertex G
0.0, 0.0, 0.0 // VH -> Vertex H
)
}
//-----------------------------------------------------------------------------
// SNIPPETS
//-----------------------------------------------------------------------------
/*
let tmp: f32;
tmp = -123.0;
f32.store(tmp, V_ROT);
tmp = f32.load(V_ROT);
printInt(tmp as i32);
*/
//-----------------------------------------------------------------------------
+51
View File
@@ -0,0 +1,51 @@
/*
Plasma effect (sizecoding)
Combines sine waves to create a 2D pixel pattern with intensity-based colors.
code : zbyti & Grok 3
date : 2025.04.17
platform : MicroW8 0.4.1
*/
include "../include/microw8-api.cwa"
// Constants for color, math, and screen dimensions
const BASE_COLOR = 0xF0; // Base color value for pixel coloring
const PI = 3.14159265; // Mathematical constant π
const RAD = PI / 180.0; // Conversion factor from degrees to radians
const SCR_X = 320; // Screen width in pixels
const SCR_Y = 240; // Screen height in pixels
const SCR_SIZE = SCR_X * SCR_Y; // Screen size in bytes
// Global variables to track animation phases
global mut phaseX = 0; // Phase offset for X-axis wave animation
global mut phaseY = 0; // Phase offset for Y-axis wave animation
// Update function called each frame to render the plasma effect
export fn upd() {
let i = 0;
loop i {
// Calculate pixel coordinates from linear index
let lazy x = i % SCR_X; // X-coordinate (column)
let lazy y = i / SCR_X; // Y-coordinate (row)
// Compute three sine waves with different frequencies and phases
let inline val1 = sin(RAD * 2.25 * (x + phaseX) as f32); // Wave along X-axis
let inline val2 = sin(RAD * 3.25 * (y + phaseY) as f32); // Wave along Y-axis
let inline val3 = sin(RAD * 1.25 * (x + y + phaseX) as f32); // Diagonal wave
// Combine waves, scale to color range, and convert to integer
let inline c = BASE_COLOR + ((val1 + val2 + val3) * 4.75) as i32;
// Set pixel color based on computed intensity
setPixel(x, y, c);
// Continue loop until all pixels are processed
branch_if (i +:= 1) < (SCR_SIZE): i;
}
// Update phase offsets for animation (different speeds for dynamic effect)
phaseX += 1; // Increment X-phase for horizontal wave movement
phaseY += 2; // Increment Y-phase for vertical wave movement
}
+168
View File
@@ -0,0 +1,168 @@
/*
Plasma effect (chars)
Combines sine waves to create a 2D pattern, maps to custom characters,
and renders to the 40x30 character grid with intensity-based colors.
code : zbyti (conversion & optimizations)
original : https://github.com/tebe6502/Mad-Pascal/blob/origin/samples/a8/demoeffects/plasma_2.pas
date : 2025.04.16
platform : MicroW8 0.4.1
*/
include "../include/microw8-api.cwa"
//-----------------------------------------------------------------------------
// Constants defining memory layout, screen dimensions, and effect parameters
//-----------------------------------------------------------------------------
const MEM_END = 0x40000;
const CUSTOM_FONT = FONT + 0x100;
const CHARS = 0x20;
const BASE_COLOR = 0xF0;
const PI = 3.14159265;
const RAD = PI / 180.0;
const SCR_X = 320;
const SCR_Y = 240;
const SCR_W = SCR_X / 8; // 40
const SCR_H = SCR_Y / 8; // 30
const SCR_SIZE = SCR_X * SCR_Y;
const SIN_TABLE_SIZE = 128; // Number of entries in the sine lookup table
const SIN_TABLE_MASK = SIN_TABLE_SIZE - 1;
const SIN_TABLE = MEM_END - SIN_TABLE_SIZE; // Memory address for sine table
const ROW_BUFFER = SIN_TABLE - SCR_W; // Memory address for precomputed row buffer
//-----------------------------------------------------------------------------
// Global variables to track animation state
//-----------------------------------------------------------------------------
global mut phaseA = 1; // Phase offset for the first sine wave, controls animation
global mut phaseB = 5; // Phase offset for the second sine wave, controls animation
//-----------------------------------------------------------------------------
/*
Logs a value to the console (STDOUT) with a prefix for debugging purposes
Args:
prefix : 4-character identifier (i32) to label the output
log : Integer value to log (i32)
Prints to console and returns to screen output
*/
fn console(prefix: i32, log: i32) {
printChar('\6'); // Switch output to console
printChar(prefix); // Print the prefix
printInt(log); // Print the integer value
printChar('\n\4'); // Print newline and switch back to screen output
}
//-------------------------------------
/*
Fills a sine table with precomputed values for fast lookups
Args:
adr : Memory address where the sine table is stored
size : Number of entries in the table
Computes: sin(i * 180/size * radians) * 255 for i = 0 to size-1, scaled to 0-255
*/
fn fillSin(adr: i32, size: i32) {
let i = 0;
let inline f = 180.00 / size as f32 * RAD;
loop i {
(adr+i)?0 = (sin(f * i as f32) * 255.0) as i32;
branch_if (i +:= 1) < size: i;
}
}
//-----------------------------------------------------------------------------
/*
Initialization function called when the program starts
*/
export fn start() {
// Populate the sine table with values for fast wave calculations
fillSin(SIN_TABLE, SIN_TABLE_SIZE);
}
//-------------------------------------
/*
Update function called each frame to render the plasma effect
*/
export fn upd() {
let pA = phaseA; // Local copy of phaseA to avoid modifying global during frame
let pB = phaseB; // Local copy of phaseB for the same reason
let i = 0;
loop i {
// Wrap phase values to stay within sine table bounds using bitwise AND
pA &= SIN_TABLE_MASK;
pB &= SIN_TABLE_MASK;
// Combine two sine waves and store in row buffer
i?ROW_BUFFER = pA?SIN_TABLE + pB?SIN_TABLE;
pA += 3; // Shift phase for first sine wave (controls wave speed)
pB += 7; // Shift phase for second sine wave (different speed for variety)
branch_if (i +:= 1) < SCR_W: i;
}
i = 0;
loop i {
let j = 0;
loop j {
// Combine wave values from row buffer for current position
// Use bitwise AND to clamp to 0-255, then scale to 0-15 for character index
let c = ((j?ROW_BUFFER + i?ROW_BUFFER) & 255) >> 4;
// Set text color based on intensity (base color + scaled value)
setTextColor(BASE_COLOR + c);
// Draw custom character corresponding to intensity
printChar(CHARS + c);
branch_if (j +:= 1) < SCR_W: j;
}
branch_if (i +:= 1) < SCR_H: i;
}
// Update global phase offsets for the next frame to animate the pattern
phaseA += 0; // Increment phaseA to shift the pattern (+/- speed move)
phaseB += 1; // Increment phaseB to shift the pattern (+/- right/left move)
}
//-----------------------------------------------------------------------------
/*
Custom font data defining 16 characters (8x8 pixels each)
Each character represents a different intensity level for the plasma effect
Pixels range from empty (0x00) to nearly full (0xFE or 0x7F) to simulate gradients
*/
data CUSTOM_FONT {
i8(
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00,
0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00,
0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00,
0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
0x00, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
)
}
+14
View File
@@ -0,0 +1,14 @@
include "../include/microw8-api.cwa"
export fn upd() {
printString(USER_MEM);
}
data USER_MEM {
// clear screen, switch to graphics text mode, text scale 4
i8(12, 5, 30, 4)
// text color, position, print two lines
i8(15, 86, 31, 8, 80) "Hello," i8(8, 8, 8, 8, 8, 10) "MicroW8!"
// print same two lines with different color and slight offset
i8(15, 47, 31, 10, 82) "Hello," i8(8, 8, 8, 8, 8, 10) "MicroW8!" i8(0)
}
+5 -5
View File
@@ -4,13 +4,13 @@ const SPRITE = 0x20000;
export fn upd() {
cls(0);
let t = time();
let t = time() / 2_f;
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;
let inline x = sin(t * -1.3 + i as f32 * (3.141 / 30_f)) * 180_f + 160_f;
let inline y = sin(t * 1.7 + i as f32 * (3.141 / 40_f)) * 140_f + 120_f;
blitSprite(SPRITE, 16, x as i32, y as i32, (i & 3) * 0x200 + 0x100);
branch_if (i +:= 1) < 100: spriteLoop;
}
}
+8 -6
View File
@@ -3,12 +3,14 @@ include "../include/microw8-api.cwa"
export fn upd() {
let i: i32;
loop pixels {
let inline t = time() * 63 as f32;
let lazy x = (i % 320 - 160) as f32;
let lazy y = (i / 320 - 120) as f32;
let inline d = 40000 as f32 / sqrt(x * x + y * y);
let inline u = atan2(x, y) * (512.0 / 3.141);
let inline c = ((i32.trunc_sat_f32_s(d + t * 2 as f32) ^ i32.trunc_sat_f32_s(u + t)) & 255) >> 4;
let inline t = 16!56;
let inline x = (i % 320 - 160) as f32;
let inline y = (i #/ 320 - 120) as f32;
let inline d = 0xa000 as f32 / sqrt(x * x + y * y);
let inline a = atan2(x, y) * 163_f; // (512 / pi)
let inline u = i32.trunc_sat_f32_s(a) + t;
let inline v = i32.trunc_sat_f32_s(d) + t * 2;
let inline c = ((v ^ u) #/ 16) % 16;
i?FRAMEBUFFER = c;
branch_if (i := i + 1) < 320*240: pixels;
+2 -2
View File
@@ -1,2 +1,2 @@
zig-cache/
zig-out/
/zig-cache/
/zig-out/
@@ -5,7 +5,11 @@ pub fn build(b: *std.build.Builder) void {
const lib = b.addSharedLibrary("cart", "main.zig", .unversioned);
lib.setBuildMode(mode);
lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding, .cpu_features_add = std.Target.wasm.featureSet(&.{.nontrapping_fptoint}) });
lib.setTarget(.{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
.cpu_features_add = std.Target.wasm.featureSet(&.{ .nontrapping_fptoint })
});
lib.import_memory = true;
lib.initial_memory = 262144;
lib.max_memory = 262144;
@@ -14,13 +18,19 @@ pub fn build(b: *std.build.Builder) void {
lib.install();
if (lib.install_step) |install_step| {
const run_filter_exports = b.addSystemCommand(&[_][]const u8{ "uw8", "filter-exports", "zig-out/lib/cart.wasm", "zig-out/lib/cart-filtered.wasm" });
const run_filter_exports = b.addSystemCommand(&[_][]const u8{
"uw8", "filter-exports", "zig-out/lib/cart.wasm", "zig-out/lib/cart-filtered.wasm"
});
run_filter_exports.step.dependOn(&install_step.step);
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" });
const run_wasm_opt = b.addSystemCommand(&[_][]const u8{
"wasm-opt", "-Oz", "-o", "zig-out/cart.wasm", "zig-out/lib/cart-filtered.wasm"
});
run_wasm_opt.step.dependOn(&run_filter_exports.step);
const run_uw8_pack = b.addSystemCommand(&[_][]const u8{ "uw8", "pack", "-l", "5", "zig-out/cart.wasm", "zig-out/cart.uw8" });
const run_uw8_pack = b.addSystemCommand(&[_][]const u8{
"uw8", "pack", "-l", "9", "zig-out/cart.wasm", "zig-out/cart.uw8"
});
run_uw8_pack.step.dependOn(&run_wasm_opt.step);
const make_opt = b.step("make_opt", "make size optimized cart");
-142
View File
@@ -1,142 +0,0 @@
const uw8 = @import("uw8.zig");
var redBallSprite: [16 * 16]u8 = undefined;
var greenBallSprite: [16 * 16]u8 = undefined;
var blueBallSprite: [16 * 16]u8 = undefined;
var wallSprite: [24 * 24]u8 = undefined;
const SphereConfigStep = struct { size: u8, color: u8 };
// zig fmt: off
const redSphereConfig: [4]SphereConfigStep = .{
.{ .size = 0, .color = 0x3d },
.{ .size = 2, .color = 0x48 },
.{ .size = 6, .color = 0x65 },
.{ .size = 9, .color = 0x55 }
};
const greenSphereConfig: [4]SphereConfigStep = .{
.{ .size = 0, .color = 0x7d },
.{ .size = 2, .color = 0x88 },
.{ .size = 6, .color = 0x96 },
.{ .size = 9, .color = 0xa3 }
};
const blueSphereConfig: [4]SphereConfigStep = .{
.{ .size = 0, .color = 0x2e },
.{ .size = 2, .color = 0x19 },
.{ .size = 6, .color = 0x17 },
.{ .size = 9, .color = 0x24 }
};
const levelData: [14] *const [19]u8 = .{
"xxxxxxxxxxxxxxxxxxx",
"x x x x",
"x x xx x xx x x",
"x x xxx x xxx x x",
"x xx x x xx x",
"x xx xxxxx xx x",
"x x x x",
"x xx xx xxx xx xx x",
"x x xx xx x x",
"xx x x x x xx",
"x xx xxx xxx xx x",
"x xx x x xx x",
"x x x x x",
"xxxxxxxxxxxxxxxxxxx",
};
// zig fmt: on
export fn start() void {
blitSphere(&redBallSprite, &redSphereConfig);
blitSphere(&greenBallSprite, &greenSphereConfig);
blitSphere(&blueBallSprite, &blueSphereConfig);
createWallSprite();
}
fn blitSphere(sprite: [*]u8, config: []const SphereConfigStep) void {
for (config) |circle| {
uw8.circle(8, 8, 8, circle.color);
uw8.circle(5, 6, @intToFloat(f32, circle.size), 0);
uw8.grabSprite(sprite, 16, 0, 0, 0x100);
}
}
fn createWallSprite() void {
uw8.cls(0xe4);
var i: i32 = 0;
while (i < 50) : (i += 1) {
const x = uw8.randomf() * 16;
const y = uw8.randomf() * 16;
const radius = uw8.randomf() * 2 + 1;
const c = @intCast(u8, (uw8.random() & 3)) + 0x95;
var j: i32 = 0;
while (j < 9) : (j += 1) {
uw8.circle(x + @intToFloat(f32, @rem(j, 3) * 16), y + @intToFloat(f32, @divFloor(j, 3) * 16), radius, c);
}
}
uw8.grabSprite(&wallSprite, 16, 16, 16, 0);
}
export fn upd() void {
uw8.cls(0);
var y: usize = 0;
while (y < levelData.len) : (y += 1) {
var x: usize = 0;
while (x < levelData[y].len) : (x += 1) {
if (levelData[y][x] == 'x') {
uw8.blitSprite(&wallSprite, 16, 8 + @intCast(i32, x) * 16, @intCast(i32, y) * 16, 0);
}
}
}
updateEnemy(&enemies[0], &redBallSprite);
updateEnemy(&enemies[1], &greenBallSprite);
updateEnemy(&enemies[2], &blueBallSprite);
}
const EntityState = struct { x: i32, y: i32, dir: u2 };
var enemies: [3]EntityState = .{
.{ .x = 16, .y = 16, .dir = 1 },
.{ .x = 16 * 18, .y = 16, .dir = 3 },
.{ .x = 16, .y = 16 * 12, .dir = 1 },
};
fn updateEnemy(enemy: *EntityState, sprite: [*]u8) void {
switch (enemy.dir) {
0 => enemy.y -= 1,
1 => enemy.x += 1,
2 => enemy.y += 1,
3 => enemy.x -= 1,
}
if (((enemy.x | enemy.y) & 15) == 0) {
const tx = @intCast(usize, enemy.x) / 16;
const ty = @intCast(usize, enemy.y) / 16;
var dir = enemy.dir;
var count: u32 = 0;
if (enemy.dir != 2 and levelData[ty - 1][tx] == ' ') {
dir = 0;
count += 1;
}
if (enemy.dir != 3 and levelData[ty][tx + 1] == ' ') {
count += 1;
if (uw8.random() % count == 0) {
dir = 1;
}
}
if (enemy.dir != 0 and levelData[ty + 1][tx] == ' ') {
count += 1;
if (uw8.random() % count == 0) {
dir = 2;
}
}
if (enemy.dir != 1 and levelData[ty][tx - 1] == ' ') {
count += 1;
if (uw8.random() % count == 0) {
dir = 3;
}
}
enemy.dir = dir;
}
uw8.blitSprite(sprite, 16, 8 + enemy.x, enemy.y, 0x100);
}
-10
View File
@@ -1,10 +0,0 @@
pub extern fn random() u32;
pub extern fn randomf() f32;
pub extern fn time() f32;
pub extern fn cls(color: u8) void;
pub extern fn circle(x: f32, y: f32, radiu: f32, color: u8) void;
pub extern fn blitSprite(spriteData: [*]u8, size: u32, x: i32, y: i32, ctrl: u32) void;
pub extern fn grabSprite(spriteData: [*]u8, size: u32, x: i32, y: i32, ctrl: u32) void;
pub extern fn printString(str: [*:0]u8) void;
pub extern fn printInt(value: i32) void;
pub extern fn printChar(char: u32) void;
@@ -13,10 +13,8 @@ export fn upd() void {
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;
FRAMEBUFFER[i] = c;
FRAMEBUFFER[@as(usize, i)] = c;
i += 1;
if (i >= 320 * 240) {
break;
}
if(i >= 320*240) { break; }
}
}
-31
View File
@@ -1,31 +0,0 @@
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
const mode = std.builtin.Mode.ReleaseSmall;
const lib = b.addSharedLibrary("cart", "main.zig", .unversioned);
lib.setBuildMode(mode);
lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding, .cpu_features_add = std.Target.wasm.featureSet(&.{.nontrapping_fptoint}) });
lib.import_memory = true;
lib.initial_memory = 262144;
lib.max_memory = 262144;
lib.global_base = 81920;
lib.stack_size = 8192;
lib.install();
if (lib.install_step) |install_step| {
const run_filter_exports = b.addSystemCommand(&[_][]const u8{ "uw8", "filter-exports", "zig-out/lib/cart.wasm", "zig-out/lib/cart-filtered.wasm" });
run_filter_exports.step.dependOn(&install_step.step);
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" });
run_wasm_opt.step.dependOn(&run_filter_exports.step);
const run_uw8_pack = b.addSystemCommand(&[_][]const u8{ "uw8", "pack", "-l", "9", "zig-out/cart.wasm", "zig-out/cart.uw8" });
run_uw8_pack.step.dependOn(&run_wasm_opt.step);
const make_opt = b.step("make_opt", "make size optimized cart");
make_opt.dependOn(&run_uw8_pack.step);
b.default_step = make_opt;
}
}
+194 -186
View File
@@ -19,47 +19,54 @@ dependencies = [
[[package]]
name = "ahash"
version = "0.7.6"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"getrandom",
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "anyhow"
version = "1.0.52"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
[[package]]
name = "ariadne"
version = "0.1.3"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7080ae01b2f0c312065d4914cd0f0de045eb8832e9415b355106a6cff3073cb4"
checksum = "f1cb2a2046bea8ce5e875551f5772024882de0b540c7f93dfc5d6cf1ca8b030c"
dependencies = [
"yansi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "bytemuck"
version = "1.7.3"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
[[package]]
name = "cc"
version = "1.0.72"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
[[package]]
name = "cdivsufsort"
@@ -88,54 +95,47 @@ dependencies = [
[[package]]
name = "const-random"
version = "0.1.13"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
"proc-macro-hack",
]
[[package]]
name = "const-random-macro"
version = "0.1.13"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom",
"lazy_static",
"proc-macro-hack",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "crunchy"
@@ -157,53 +157,79 @@ dependencies = [
]
[[package]]
name = "fallible_collections"
version = "0.4.6"
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f57ccc32870366ae684be48b32a1a2e196f98a42a9b4361fe77e13fd4a34755"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible_collections"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a88c69768c0a15262df21899142bc6df9b9b823546d4b4b9a7bc2d6c448ec6fd"
dependencies = [
"hashbrown",
"hashbrown 0.13.2",
]
[[package]]
name = "flate2"
version = "1.0.25"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "form_urlencoded"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
dependencies = [
"percent-encoding",
]
[[package]]
name = "getrandom"
version = "0.2.3"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gimli"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
"fallible-iterator",
"indexmap 1.9.3",
"stable_deref_trait",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash 0.7.6",
"ahash 0.8.11",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heck"
version = "0.3.3"
@@ -220,31 +246,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "idna"
version = "0.3.0"
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"unicode-bidi",
"unicode-normalization",
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "1.9.2"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"autocfg",
"hashbrown",
"equivalent",
"hashbrown 0.14.3",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "leb128"
version = "0.2.5"
@@ -259,15 +279,15 @@ checksum = "478ee9e62aaeaf5b140bd4138753d1f109765488581444218d3ddda43234f3e8"
[[package]]
name = "libc"
version = "0.2.139"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "lodepng"
version = "3.7.2"
version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0ad39f75bbaa4b10bb6f2316543632a8046a5bcf9c785488d79720b21f044f8"
checksum = "a42d298694b14401847de29abd44adf278b42e989e516deac7b72018400002d8"
dependencies = [
"crc32fast",
"fallible_collections",
@@ -278,55 +298,45 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.14"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "miniz_oxide"
version = "0.6.2"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [
"adler",
]
[[package]]
name = "num-traits"
version = "0.2.14"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.9.0"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "pbr"
version = "1.0.4"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff5751d87f7c00ae6403eb1fcbba229b9c76c9a30de8c1cf87182177b168cea2"
checksum = "ed5827dfa0d69b6c92493d6c38e633bbaa5937c153d0d7c28bf12313f8c6d514"
dependencies = [
"crossbeam-channel",
"libc",
"time",
"winapi",
]
[[package]]
name = "percent-encoding"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pico-args"
version = "0.4.2"
@@ -349,35 +359,29 @@ dependencies = [
"uw8-tool",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.36"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.15"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rgb"
version = "0.8.34"
version = "0.8.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3603b7d71ca82644f79b5a06d1220e9a58ede60bd32255f698cb1af8838b8db3"
checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8"
dependencies = [
"bytemuck",
]
@@ -392,44 +396,57 @@ dependencies = [
]
[[package]]
name = "syn"
version = "1.0.86"
name = "semver"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.38"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.38"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
"winapi",
"syn 2.0.58",
]
[[package]]
@@ -442,46 +459,16 @@ dependencies = [
]
[[package]]
name = "tinyvec"
version = "1.6.0"
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "unicode-bidi"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "upkr"
@@ -494,17 +481,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "url"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "uw8-tool"
version = "0.1.0"
@@ -514,28 +490,30 @@ dependencies = [
"pico-args 0.5.0",
"upkr",
"walrus",
"wasm-encoder 0.22.0",
"wasmparser 0.99.0",
"wasm-encoder 0.201.0",
"wasmparser 0.201.0",
]
[[package]]
name = "version_check"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walrus"
version = "0.19.0"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8"
checksum = "2c03529cd0c4400a2449f640d2f27cd1b48c3065226d15e26d98e4429ab0adb7"
dependencies = [
"anyhow",
"gimli",
"id-arena",
"leb128",
"log",
"walrus-macro",
"wasmparser 0.77.0",
"wasm-encoder 0.29.0",
"wasmparser 0.80.2",
]
[[package]]
@@ -547,14 +525,14 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
"syn 1.0.109",
]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-encoder"
@@ -567,18 +545,27 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.22.0"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef126be0e14bdf355ac1a8b41afc89195289e5c7179f80118e3abddb472f0810"
checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881"
dependencies = [
"leb128",
]
[[package]]
name = "wasm-encoder"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a"
dependencies = [
"leb128",
]
[[package]]
name = "wasmparser"
version = "0.77.0"
version = "0.80.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6"
checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b"
[[package]]
name = "wasmparser"
@@ -588,12 +575,13 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a"
[[package]]
name = "wasmparser"
version = "0.99.0"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ef3b717afc67f848f412d4f02c127dd3e35a0eecd58c684580414df4fde01d3"
checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708"
dependencies = [
"indexmap",
"url",
"bitflags",
"indexmap 2.2.6",
"semver",
]
[[package]]
@@ -620,6 +608,26 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yansi"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
]
Binary file not shown.
Binary file not shown.
+1 -2
View File
@@ -62,7 +62,6 @@ export fn sndGes(t: i32) -> f32 {
let phase = channelState!GesChannelState.Phase;
let inline pulseWidth = channelReg?1;
let phaseShift = (pulseWidth - 128) * 255;
let invPhaseInc = 1 as f32 / phaseInc as f32;
i = 0;
@@ -131,7 +130,7 @@ export fn sndGes(t: i32) -> f32 {
let phaseInc = (freq * (65536.0 / 44100.0)) as i32;
let phase = channelState!GesChannelState.Phase;
if modSrc > ch {
if modSrc < ch {
phase = phase - (phaseInc << 6);
}
+32 -20
View File
@@ -62,6 +62,7 @@ export fn cls(col: i32) {
textCursorX = 0;
textCursorY = 0;
outputChannel = 0;
textScale = 1;
memory.fill(120, col, 320*240);
}
@@ -447,6 +448,7 @@ global mut textCursorY = 0;
global mut textColor = 15;
global mut bgColor = 0;
global mut outputChannel = 0;
global mut textScale = 1;
export fn printChar(char: i32) {
loop chars {
@@ -458,6 +460,8 @@ export fn printChar(char: i32) {
global mut controlCodeLength = 0;
fn printSingleChar(char: i32) {
let charSize = 8 * textScale;
if outputChannel >= 2 & (char < 4 | char > 6) {
logChar(char);
return;
@@ -491,9 +495,9 @@ fn printSingleChar(char: i32) {
}
if char == 8 {
textCursorX = textCursorX - 8;
textCursorX = textCursorX - charSize;
if !outputChannel & textCursorX < 0 {
textCursorX = 320-8;
textCursorX = 320-charSize;
printSingleChar(11);
}
return;
@@ -503,34 +507,34 @@ fn printSingleChar(char: i32) {
if !outputChannel & textCursorX >= 320 {
printChar(0xd0a);
}
textCursorX = textCursorX + 8;
textCursorX = textCursorX + charSize;
return;
}
if char == 10 {
textCursorY = textCursorY + 8;
textCursorY = textCursorY + charSize;
if !outputChannel & textCursorY >= 240 {
textCursorY = 240 - 8;
textCursorY = 240 - charSize;
let i: i32;
loop scroll_copy {
i!120 = i!(120 + 320 * 8);
branch_if (i := i + 4) < 320 * (240 - 8): scroll_copy;
i!120 = (i + 320 * charSize)!120;
branch_if (i := i + 4) < 320 * (240 - charSize): scroll_copy;
}
rectangle(0 as f32, (240 - 8) as f32, 320 as f32, 8 as f32, bgColor);
rectangle(0 as f32, (240 - charSize) as f32, 320 as f32, charSize as f32, bgColor);
}
return;
}
if char == 11 {
textCursorY = textCursorY - 8;
textCursorY = textCursorY - charSize;
if !outputChannel & textCursorY < 0 {
textCursorY = 0;
let i = 320 * (240 - 8);
let i = 320 * (240 - charSize);
loop scroll_copy {
i!(116 + 320 * 8) = i!116;
(i + 320 * charSize)!116 = i!116;
branch_if (i := i - 4): scroll_copy;
}
rectangle(0 as f32, 0 as f32, 320 as f32, 8 as f32, bgColor);
rectangle(0 as f32, 0 as f32, 320 as f32, charSize as f32, bgColor);
}
return;
}
@@ -562,6 +566,12 @@ fn printSingleChar(char: i32) {
return;
}
if char == 30 {
let scale = 0x12d20?1;
textScale = select(scale > 0 & scale <= 16, scale, 1);
return;
}
if char == 31 {
textCursorX = 0x12d20?1 * (8 - outputChannel * 6);
textCursorY = 0x12d20?2 * (8 - outputChannel * 7);
@@ -584,7 +594,7 @@ data(0x12d00) {
1, 1, 1, 1, // 16-19,
1, 1, 1, 1, // 20-23,
1, 1, 1, 1, // 24-27,
1, 1, 1, 3 // 28-31
1, 1, 2, 3 // 28-31
)
}
@@ -593,26 +603,28 @@ fn drawChar(char: i32) {
printChar(0xd0a);
}
let charSize = 8 * textScale;
let y: i32;
loop rows {
let bits = (char * 8 + y)?0x13400;
let bits = (char * 8 + y / textScale)?0x13400;
let x = 0;
if outputChannel {
loop pixels {
if (bits := bits << 1) & 256 {
if (bits << (x / textScale)) & 128 {
setPixel(textCursorX + x, textCursorY + y, textColor);
}
branch_if (x := x + 1) < 8: pixels;
branch_if (x := x + 1) < charSize: pixels;
}
} else {
loop pixels {
setPixel(textCursorX + x, textCursorY + y, select((bits := bits << 1) & 256, textColor, bgColor));
branch_if (x := x + 1) < 8: pixels;
setPixel(textCursorX + x, textCursorY + y, select((bits << (x / textScale)) & 128, textColor, bgColor));
branch_if (x := x + 1) < charSize: pixels;
}
}
branch_if (y := y + 1) < 8: rows;
branch_if (y := y + 1) < charSize: rows;
}
textCursorX = textCursorX + 8;
textCursorX = textCursorX + charSize;
}
export fn printString(ptr: i32) {
+8 -39
View File
@@ -31,50 +31,19 @@ Examplers for older versions:
## Versions
### v0.2.2
### v0.4.1
* [Web runtime](v0.2.2)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-windows.zip)
* [Web runtime](../v0.4.1)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-windows.zip)
Changes:
* call `start` function after loading cart if the cart exports one
* fix `sndGes` having the wrong name and not being included in the auto imports
* fix control codes 4-6 (change text output mode) being invoked when used as parameters in other control sequences
* only open browser window once a cart was compiled sucessfully when running with `-b`
* Windows: fix bad/inconsistent frame rate
* fix choppy sound on devices with sample rates != 44100 kHz
* add scale mode 'fill' option
### v0.2.1
* [Web runtime](v0.2.1)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-windows.zip)
Changes:
* new gpu accelerated renderer with (optional) crt filter
* optimized `hline` function, a big speed-up when drawing large filled circles or rectangles
* print fractional size of packed `uw8` cart
### v0.2.0
* [Web runtime](v0.2.0)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-windows.zip)
Changes:
* [add sound support!](docs#sound)
* add support to redirect text output to the console for debugging using control code 6
* update curlywas:
* add support for `else if`
* add support for escape sequences in strings
* add support for char literals
* add support for binop-assignment, eg. `+=`, `^=`, `<<=` etc. (also support for the tee operator: `+:=`)
* "integer constant cast to float" literal syntax in CurlyWas (ex. `1_f` is equivalent to `1 as f32`)
### Older versions
+15 -6
View File
@@ -5,7 +5,7 @@ description = "Docs"
# Overview
MicroW8 loads WebAssembly modules with a maximum size of 256kb. You module needs to export
MicroW8 loads WebAssembly modules with a maximum size of 256kb. Your module needs to export
a function `fn upd()` which will be called once per frame.
After calling `upd` MicroW8 will display the 320x240 8bpp framebuffer located
at offset 120 in memory with the 32bpp palette located at 0x13000.
@@ -21,7 +21,7 @@ loaded.
00000-00040: user memory
00040-00044: time since module start in ms
00044-0004c: gamepad state
0004c-00050: reserved
0004c-00050: number of frames since module start
00050-00070: sound data (synced to sound thread)
00070-00078: reserved
00078-12c78: frame buffer
@@ -238,6 +238,13 @@ When printing characters only the foreground pixels are set, the background is "
Moving/printing past any border does not cause any special operation, the cursor just goes off-screen.
### Text scale
An integer text scale factor in the range 1x-16x can be set with control char 30. An attempt to
set a scale outside that range will reset the scale to 1x.
After startup and `cls` the scale is initialized to 1x.
### Control chars
Characters 0-31 are control characters and don't print by default. They take the next 0-2 following characters as parameters.
@@ -262,7 +269,8 @@ Avoid the reserved control chars, they are currently NOPs but their behavior can
| 15 | color | Set the text color |
| 16-23 | - | Reserved |
| 24 | - | Swap text/background colors |
| 25-30 | - | Reserved |
| 25-29 | - | Reserved |
| 30 | scale | Set text scale (1-16) |
| 31 | x, y | Set cursor position (*) |
(*) In graphics mode, the x coordinate is doubled when using control char 31 to be able to cover the whole screen with one byte.
@@ -271,7 +279,7 @@ Avoid the reserved control chars, they are currently NOPs but their behavior can
Control code 6 switches all text output (except codes 4 and 5 to switch output back to the screen) to the console. Where exactly this ends
up (if at all) is an implementation detail of the runtimes. The native dev-runtime writes the debug output to `stdout`, the web runtime to
the debug console using `console.log`. Both implementation buffer the output until they encounter a newline character (10) in the output stream.
the debug console using `console.log`. Both implementations buffer the output until they encounter a newline character (10) in the output stream.
There may be future runtimes that ignore the debug output completely.
@@ -460,6 +468,7 @@ when using the native runtime:
* `--no-gpu`: Force old cpu-only window code
* `--filter FILTER`: Select an upscale filter at startup
* `--fullscreen`: Start in fullscreen mode
* `--scale-fill`: Scale to fill whole screen, potentially cropping parts of the frame buffer.
Note that the cpu-only window does not support fullscreen nor upscale filters.
@@ -476,7 +485,7 @@ The upscale filter options are:
5, auto_crt (default) : ss_crt below 960x720, chromatic_crt otherwise
```
You can switch the upscale filter at any time using the keys 1-5. You can toggle fullscreen with F.
You can switch the upscale filter at any time using the keys 1-5. You can toggle fullscreen with F. You can toggle between scale modes 'fit' and 'fill' with M.
## `uw8 pack`
@@ -586,7 +595,7 @@ a base module provided by MicroW8.
You can generate this base module yourself using
`uw8-tool`. As a quick summary, it provides all function
types with up to 5 parameters (i32 or f32) where the
types with up to 7 parameters (i32 or f32) where the
`f32` parameters always preceed the `i32` parameters.
Then it includes all imports that MicroW8 provides,
a function section with a single function of type
+78 -10
View File
@@ -2,9 +2,77 @@
description = "Versions"
+++
### v0.4.1
* [Web runtime](../v0.4.1)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.4.1/microw8-0.4.1-windows.zip)
Changes:
* Windows: fix bad/inconsistent frame rate
* fix choppy sound on devices with sample rates != 44100 kHz
* add scale mode 'fill' option
### v0.4.0
* [Web runtime](../v0.4.0)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.4.0/microw8-0.4.0-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.4.0/microw8-0.4.0-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.4.0/microw8-0.4.0-windows.zip)
Changes:
* add support for sound on mono- and surround-only devices
* update wasmtime dependency to fix performance regression in 0.3.0
* add frame counter since module start at location 72
* add 6 and 7 parameter function types to base module
### v0.3.0
* [Web runtime](../v0.3.0)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.3.0/microw8-0.3.0-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.3.0/microw8-0.3.0-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.3.0/microw8-0.3.0-windows.zip)
Changes:
* add blitSprite and grabSprite API calls
* add support for integer scaling up to 16x for printing text
* fix incompatibility with sound devices only offering 16bit audio formats
* add support for br_table instruction in packed carts
### v0.2.2
* [Web runtime](../v0.2.2)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.2/microw8-0.2.2-windows.zip)
Changes:
* call `start` function after loading cart if the cart exports one
* fix `sndGes` having the wrong name and not being included in the auto imports
* fix control codes 4-6 (change text output mode) being invoked when used as parameters in other control sequences
* only open browser window once a cart was compiled sucessfully when running with `-b`
### v0.2.1
* [Web runtime](../v0.2.1)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.1/microw8-0.2.1-windows.zip)
Changes:
* new gpu accelerated renderer with (optional) crt filter
* optimized `hline` function, a big speed-up when drawing large filled circles or rectangles
* print fractional size of packed `uw8` cart
### v0.2.0
* [Web runtime](v0.2.0)
* [Web runtime](../v0.2.0)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0/microw8-0.2.0-windows.zip)
@@ -22,7 +90,7 @@ Changes:
### v0.2.0-rc3
* [Web runtime](v0.2.0-rc3)
* [Web runtime](../v0.2.0-rc3)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc3/microw8-0.2.0-rc3-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc3/microw8-0.2.0-rc3-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc3/microw8-0.2.0-rc3-windows.zip)
@@ -40,7 +108,7 @@ Changes:
### v0.2.0-rc2
* [Web runtime](v0.2.0-rc2)
* [Web runtime](../v0.2.0-rc2)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc2/microw8-0.2.0-rc2-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc2/microw8-0.2.0-rc2-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc2/microw8-0.2.0-rc2-windows.zip)
@@ -51,7 +119,7 @@ Changes:
### v0.2.0-rc1
* [Web runtime](v0.2.0-rc1)
* [Web runtime](../v0.2.0-rc1)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc1/microw8-0.2.0-rc1-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc1/microw8-0.2.0-rc1-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.2.0-rc1/microw8-0.2.0-rc1-windows.zip)
@@ -67,7 +135,7 @@ Known issues:
### v0.1.2
* [Web runtime](v0.1.2)
* [Web runtime](../v0.1.2)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-windows.zip)
@@ -75,13 +143,13 @@ Known issues:
Changes:
* add option to `uw8 run` to run the cart in the browser using the web runtime
* CurlyWas: implement `include` support
*../ CurlyWas: implement `include` support
* CurlyWas: implement support for constants
* fix crash when trying to draw zero sized line
### v0.1.1
* [Web runtime](v0.1.1)
* [Web runtime](../v0.1.1)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.1/microw8-0.1.1-windows.zip)
@@ -90,16 +158,16 @@ Changes:
* implement more robust file watcher
* add basic video recording on F10 in web runtime
* add screenshot on F9
*../ add screenshot on F9
* add watchdog to interrupt hanging update in native runtime
* add devkit mode to web runtime
* add unpack and compile commands to uw8
*../ add unpack and compile commands to uw8
* add support for table/element section in pack command
* disable wayland support (caused missing window decorations in gnome)
### v0.1.0
* [Web runtime](v0.1.0)
* [Web runtime](../v0.1.0)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-windows.zip)
+1
View File
@@ -0,0 +1 @@
<!doctype html><html><head><meta charset="utf8"><title>MicroW8</title><link href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@500&display=swap" rel="stylesheet"><style>html,body,canvas{margin:0;padding:0}html{color:#808070;background-color:#202024;height:100%;font-family:Josefin Sans,Verdana,Arial Black,sans-serif}body{grid-template-rows:1fr 0fr;height:100%;display:grid}#uw8{position:absolute}#uw8 a{font-size:130%}#centered{place-self:center}a{color:#303630}a:hover{color:#405040}.screen{image-rendering:pixelated;background-color:#202428;border:4px solid #303040;width:320px;height:240px;margin-bottom:8px;box-shadow:5px 5px 20px #000}#screen{cursor:none}#start{font-size:150%}#timer:before{content:"";background-color:red;border-radius:6px;width:12px;height:12px;margin-right:3px;display:inline-block}#message{margin-bottom:8px}.error{color:#e04030}button{color:#808070;background-color:#303440;border:1px solid #404040;border-radius:4px;padding:4px;font-family:inherit}button:hover{background-color:#202010}button:active{background-color:#504450}@media (width>=680px) and (height>=620px){.screen{width:640px;height:480px}}@media (width>=1000px) and (height>=800px){.screen{width:960px;height:720px}}@media (width:640px) and (height:480px){.screen{border:0;width:640px;height:480px;margin:0}body{overflow:hidden}}</style></head><body> <div id="uw8"> <a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.3.0 </div> <div id="centered"> <canvas class="screen" id="screen" width="320" height="240"> </canvas> <button class="screen" id="start" style="display:none">Click to start</button> <div id="timer" hidden></div> <div id="message"></div> <button id="cartButton" style="visibility:hidden">Load cart...</button> </div> <div id="footer"> <a href="http://unlicense.org/" ref="license">Unlicense</a> </div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}var t={};t="data:application/wasm;base64,AGFzbQEAAAABFQRgAX8Bf2ACf38Bf2ADf39%2FAGAAAAIPAQNlbnYGbWVtb3J5AgAEAwkIAAABAgEAAAMGEAN%2FAUEAC38BQQALfwFBAAsHGQIIbG9hZF91dzgAAAp1bmNvbXByZXNzAAQIAQcKngUIxwEBB39BAC0AAEEBayIBQQBIBEAgAA8LQYDAByAAaiECIAFBAXEEQEEBQYHABxAEIQIFQYDAB0EAIAAQAwtBAEGAhA9BCBADQYiEDyEDQQghBEGBwAchBQNAIAUgAkggAyMATiAFLQAAIAMtAABMcnEEQCAEIAQgBRACIgZqIQQgAyMASCAFLQAAIAMtAABGcQRAIAMgAxABaiEDCyAFIAZqIQUMAQsgAyMASARAIAQgBCADEAIiB2ohBCADIAdqIQMMAQsLIAQLPAEEfyAAIQEDQCACIAFBAWoiAS0AACIEQf8AcSADdHIhAiADQQdqIQMgBEEHdQ0ACyABQQFqIABrIAJqCxIBAX8gACABIAEQASICEAMgAgskAANAIAJBAEoEQCAAIAJBAWsiAmogASACai0AADoAAAwBCwsLqQEBBn8gACQBQQAkAgNAIANBgAE6AICADyADQQFqIgNBgQNIDQALAkADQEEAEAYiBQRAIAQEf0EBBUGAAhAGCwRAQYECEAVBAWsiAkUNAwtBwQIQBSEGA0AgASABIAJrLQAAOgAAIAFBAWohASAGQQFrIgYNAAsFQQEhBwNAIAdBAXQgBxAGciIHQYACSA0ACyABIAc6AAAgAUEBaiEBCyAFIQQMAAsLIAELNAECfwNAIAAgAmoQBgRAIAEgACACakEgahAGIAJ0ciEBIAJBAWohAgwBCwsgAUEBIAJ0cgtxAQR%2FA0AjAkGAIEgEQCMCQQh0IwEtAAByJAIjAUEBaiQBDAELCyMCQf8BcSICIAAtAICADyIBIwJBCHUiA2xBgAIgAWsgA2wgAWsgAiABSCIEG2okAiAAIAFBByAEQYECbGogAWtBBHVqOgCAgA8gBAsMAEEAQYCEDxAEJAALC%2FMDAQBBAAvsA%2F%2Bfl7wzZsoSLKqmsehkfJ%2BoXizXJ8krjBr6Mx5dWkR96aZnQyWWGaXzQdWZfpcd9XFpdN9brE8ZBQo0n3Wr%2Fs%2BwcdFUW6079DEcDwjYmrxg5ptF4o7IlImwxEhJSWrBbtJepjaeC4PojV7Jghr1VPwDsc83RsuuCyL03791uwlwi0T8mJR%2BslH82ckKlC5TK6wnPyoB908kSeLY%2BEhunDhtWHA7EWwwdQvigYMhTQ6Cyi%2BXelkSq6CnCQnZrAqXrvEsSe7%2BYNt3Hg0MFycXedDIoFANBDyfPayn0VpyJB%2FigcLSUVngClYh6qibj%2FqMUJp3UMooPK9GHgeBn5L4EMDKto29nKMzuGul%2FU%2FcsrTpGvMsNhvP9oiRbGLT%2BtKN9Y08k3umAuKgZuPejhSaRu79ibrTYsFmp%2BjM%2Brr4qsTtbl3vja0Dt7VJRQGqxv7QJUhYkdtsCTqAzeflbQedZ%2FLk8GqBGmx%2F1xH7%2BmtrYLi8V%2FcpWd8a890NTAXJ80KPWJciuREplmTFtGa64gqCDRwwbOzsf8cmf6kXjcByItR9q057ZaXi0FuFXm35mohkeovFYeSXK%2FcVwzOmxlRyMiUTnsaQ299ys%2Bz4RHmnHPKsPhWT42j%2Fn1uicDm5gVxw4bSPORZK9Nzvk9y3%2Bg%3D%3D";var a={};a="data:;base64,AiHfzO34vaTkrd2eAWsXmnk6O0saNxyBOKpKJ4gIZgTFyYLQaErZlwVOzFHSIEwVOdwimalCVY189KvAjT1MA27zTIMgHP7UatKxjcsK5BFbXOHvjhm%2FLesv0gorLh3%2Bp4VSOVvsomIiXDlLL175jQw%2FbY3NPCAhv3e8gH24nzYFr4u3WeQHbVbcFOTxKFGLYMNOsU2QjF2XaPOdZFP32e58qAST0gBwmSKO6tuZq7JVC68uBldt4wWCJEbQqqENSUe5rtcAfyaSRf3gzZ3t3PgnwZHp6%2Fr0cjPo8rqIhvmzkLWI2m4jPwHc8k4s87Gjgpc4YQeipZW9q4PGqym6pnlfUAA8lRaqIo9U%2BnyqAMiI37LAL%2FqtHCi8JG1ByCyw6d9Pf7TLrazkjNNHPa5IJV%2BD8KUJQcCDLquYfrU2baSeirg4QH64Pxevmuo5j9pF97P%2FrfT18mBqcFoba%2Bc1jAeWPRoOSmD9M%2FPIsO1a%2F4bjFd0Uuru95ilanB4yFg4tk9FRqP2zJPk0T4LAzWMXzSX8%2F0VBgOogv%2BniB0XHFmaXv%2BG0PqGrx2sDO2N%2Fi98A3DdQyry%2Fs1%2Bb8mid6w7g5mptwhx561baq1syBSrGSJLqcDAutTh8uXZYvVXbFVzmxfLpAxsR898NHK51FkzqvkxeaNnYbCkC19jhJaslZ1E0vdpidtMzv1uwHCp986mNDT3qK4nWbwOpG52kVtkmac18T9g428D%2BeyJW82GG1hJmGV%2F39FlEB5hxbyFZINNLLAfNwG08itW25ATJ7QxZ%2FAX8zoz%2FT7oLugeHUeMBtvBF%2Bt40Wh2n%2FvjehShTKyMYUvlDZTTzBq34hcaBhCNCHTEHV8bRzoBK3%2Fx0qmeTW2l8vG7KCizhl8VoxALJiY84Isnu1OAS8vKw35FHVUWXDfXLUJw0WooJ%2BdxHnwkxlGBfeNGdWY0zJyRe3CgvsBiGlxC5nABF4pFYBMEOIGR6ev%2F3rrkXL34LdvKr2PkRuMr1gjvb8gGszxhBS40uxdOoWZLRyLA5OZ07W5nHTFbL5l6wKfJrIbrl8ZRamKdD5IXHETRJZq%2BlF3KOS0Jug3R8cjVTtBWYH4QDRXEym7uWNetxnlA5tTOl9kl811ZJeAM2A8TwUY%2FZdnIoPSqf5gUCE%2BcUvdRo55HwOX%2FONuPrPGxNEYIklsAJJlz0ElLine truncated
+1
View File
@@ -0,0 +1 @@
<!doctype html><html><head><meta charset="utf8"><title>MicroW8</title><link href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@500&display=swap" rel="stylesheet"><style>html,body,canvas{margin:0;padding:0}html{color:#808070;background-color:#202024;height:100%;font-family:Josefin Sans,Verdana,Arial Black,sans-serif}body{grid-template-rows:1fr 0fr;height:100%;display:grid}#uw8{position:absolute}#uw8 a{font-size:130%}#centered{place-self:center}a{color:#303630}a:hover{color:#405040}.screen{image-rendering:pixelated;background-color:#202428;border:4px solid #303040;width:320px;height:240px;margin-bottom:8px;box-shadow:5px 5px 20px #000}#screen{cursor:none}#start{font-size:150%}#timer:before{content:"";background-color:red;border-radius:6px;width:12px;height:12px;margin-right:3px;display:inline-block}#message{margin-bottom:8px}.error{color:#e04030}button{color:#808070;background-color:#303440;border:1px solid #404040;border-radius:4px;padding:4px;font-family:inherit}button:hover{background-color:#202010}button:active{background-color:#504450}@media (width>=680px) and (height>=620px){.screen{width:640px;height:480px}}@media (width>=1000px) and (height>=800px){.screen{width:960px;height:720px}}@media (width:640px) and (height:480px){.screen{border:0;width:640px;height:480px;margin:0}body{overflow:hidden}}</style></head><body> <div id="uw8"> <a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.4.0 </div> <div id="centered"> <canvas class="screen" id="screen" width="320" height="240"> </canvas> <button class="screen" id="start" style="display:none">Click to start</button> <div id="timer" hidden></div> <div id="message"></div> <button id="cartButton" style="visibility:hidden">Load cart...</button> </div> <div id="footer"> <a href="http://unlicense.org/" ref="license">Unlicense</a> </div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}var t={};t="data:application/wasm;base64,AGFzbQEAAAABFQRgAX8Bf2ACf38Bf2ADf39%2FAGAAAAIPAQNlbnYGbWVtb3J5AgAEAwkIAAABAgEAAAMGEAN%2FAUEAC38BQQALfwFBAAsHGQIIbG9hZF91dzgAAAp1bmNvbXByZXNzAAQIAQcKngUIxwEBB39BAC0AAEEBayIBQQBIBEAgAA8LQYDAByAAaiECIAFBAXEEQEEBQYHABxAEIQIFQYDAB0EAIAAQAwtBAEGAhA9BCBADQYiEDyEDQQghBEGBwAchBQNAIAUgAkggAyMATiAFLQAAIAMtAABMcnEEQCAEIAQgBRACIgZqIQQgAyMASCAFLQAAIAMtAABGcQRAIAMgAxABaiEDCyAFIAZqIQUMAQsgAyMASARAIAQgBCADEAIiB2ohBCADIAdqIQMMAQsLIAQLPAEEfyAAIQEDQCACIAFBAWoiAS0AACIEQf8AcSADdHIhAiADQQdqIQMgBEEHdQ0ACyABQQFqIABrIAJqCxIBAX8gACABIAEQASICEAMgAgskAANAIAJBAEoEQCAAIAJBAWsiAmogASACai0AADoAAAwBCwsLqQEBBn8gACQBQQAkAgNAIANBgAE6AICADyADQQFqIgNBgQNIDQALAkADQEEAEAYiBQRAIAQEf0EBBUGAAhAGCwRAQYECEAVBAWsiAkUNAwtBwQIQBSEGA0AgASABIAJrLQAAOgAAIAFBAWohASAGQQFrIgYNAAsFQQEhBwNAIAdBAXQgBxAGciIHQYACSA0ACyABIAc6AAAgAUEBaiEBCyAFIQQMAAsLIAELNAECfwNAIAAgAmoQBgRAIAEgACACakEgahAGIAJ0ciEBIAJBAWohAgwBCwsgAUEBIAJ0cgtxAQR%2FA0AjAkGAIEgEQCMCQQh0IwEtAAByJAIjAUEBaiQBDAELCyMCQf8BcSICIAAtAICADyIBIwJBCHUiA2xBgAIgAWsgA2wgAWsgAiABSCIEG2okAiAAIAFBByAEQYECbGogAWtBBHVqOgCAgA8gBAsMAEEAQYCEDxAEJAALC60EAQBBAAumBBf%2FyMx3cvbPLfDyK1Bb4IburZYc9i%2BGTsS3j6O4M0o%2Bl2NUQ%2B88SSzybjKLNViVnmhuM%2FZ6LyqKG10doX6mhidmH1yW84EJfcqSXy6pUuF8h7prEGKBJPbIG0yhSUUWuzMrdRxzE4okeNRo4cs%2FsVhtCh4Vai9OQbuu9AZbIpuNDXWOFbj927WcryfPy4dsdT0B%2BA3x1gqXPq2rgI2fI0dNid3EJDTBr3SZWQObkiDldI5YJ17KFwjme3ofejUZT6xP3cNY2XdcosNxULga5hpnvQxV%2F1YKYfeYBVnZ6mAPyIx6Ayl4uxPFNpFdkNv28D%2Bv4X4QS%2BMYgr%2BrLsNAjif5Pz0lVPDBHkx%2BuqJN9SHrb6uRHqvwoVNuRbgn4alMggAWdV0rqmwCXlsmJyzwX%2BrWtH7BoosSlavxs%2BMUTI%2BFXunhVtt5mz3HYy3%2BxBJXF%2FhLWKUPw8vHxoEt%2BBpGDuMK8%2B1ew3pagPiQ7PV7YPWeoHyEKBM92UbyjbJx7HBp7Gh31ZwL9x%2B1sj0ogjs4HLke4hPdXR2o%2F%2BO67SYnX8CPp6YygTuddCxYwU6eHzYFFpwQuzKCVNPXyJKX4HVPJnysHBj5ygPItuS0NZqGlhpzEbgDf%2FJbIQgHzmNotsi6ErQdaigmn0dopO1ybwjbUWZ1kcZmOiBxcoNYSZVtW9mWKfn52kTNDn0QlwZz1slXrqIcx%2BMVVGeIZ9Y5hThIK3lyj%2BL9o%2Fo%3D";var a={};a="data:;base64,AiHfzO34vaTkrd2eAWsXmnk6O0saNxyBOKpKJ4gIZgTFyYLQaErZlwVOzFHSIEwVOdwimalCVY189KvAjT1MA27zTIMgHP7UatKxjcsK5BFbXOHvjhm%2FLesv0gorLh3%2Bp4VSOVvsomIiXDlLL175jQw%2FbY3NPCAhv3e8gH24nzYFr4u3WeQHbVbcFOTxKFGLYMNOsU2QjF2XaPOdZFP32e58qAST0gBwmSKO6tuZq7JVC68uBldt4wWCJEbQqqENSUe5rtcAfyaSRf3gzZ3t3PgnwZHp6%2Fr0cjPo8rqIhvmzkLWI2m4jPwHc8k4s87Gjgpc4YQeipZW9q4PGqym6pnlfUAA8lRaqIo9U%2BnyqAMiI37LAL%2FqtHCi8JG1ByCyw6d9Pf7TLrazkjNNHPa5IJV%2BD8KUJQcCDLquYfrU2baSeirg4QH64Pxevmuo5j9pF97P%2FrfT18mBqcFoba%2Bc1jAeWPRoOSmD9M%2FPIsO1a%2F4bjFd0Uuru95ilanB4yFg4tk9FRqP2zJPk0T4LAzWMXzSX8%2F0VBgOogv%2BniB0XHFmaXv%2BG0PqGrx2sDO2N%2Fi98A3DdQyry%2Fs1%2Bb8mid6w7g5mptwhx561baq1syBSrGSJLqcDAutTh8uXZYvVXbFVzmxfLpAxsR898NHK51FkzqvkxeaNnYbCkC19jhJaslZ1E0vdpidtMzv1uwHCp986mNDT3qK4nWbwOpG52kVtkmac18T9g428D%2BeyJW82GG1hJmGV%2F39FlEB5hxbyFZINNLLAfNwG08itW25ATJ7QxZ%2FAX8zoz%2FT7oLugeHUeMBtvBF%2Bt40Wh2n%2FvjehShTKyMYUvlDZTTzBq34hcaBhCNCHTEHV8bRzoBK3%2Fx0qmeTW2l8vG7KCizhl8VoxALJiY84Isnu1OAS8vKw35FHVUWXDfXLUJw0WooJ%2BdxHnwkxlGBfeNGdWY0zJyRe3CgvsBiGlxC5nABF4pFYBMEOIGR6ev%2F3rrkXL34LdvKr2PkRuMr1gjvb8gGszxhBS40uxdOoWZLRyLA5OZ07W5nHTFbL5l6wKfJrIbrl8ZRamKdD5IXHETRJZq%2BlF3KOS0Jug3R8cjVTtBWYH4QDRXEym7uWNetxnlA5tTOlLine truncated
+1
View File
@@ -0,0 +1 @@
<!doctype html><html><head><meta charset="utf8"><title>MicroW8</title><link href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@500&display=swap" rel="stylesheet"><style>html,body,canvas{margin:0;padding:0}html{color:#808070;background-color:#202024;height:100%;font-family:Josefin Sans,Verdana,Arial Black,sans-serif}body{grid-template-rows:1fr 0fr;height:100%;display:grid}#uw8{position:absolute}#uw8 a{font-size:130%}#centered{place-self:center}a{color:#303630}a:hover{color:#405040}.screen{image-rendering:pixelated;background-color:#202428;border:4px solid #303040;width:320px;height:240px;margin-bottom:8px;box-shadow:5px 5px 20px #000}#screen{cursor:none}#start{font-size:150%}#timer:before{content:"";background-color:red;border-radius:6px;width:12px;height:12px;margin-right:3px;display:inline-block}#message{margin-bottom:8px}.error{color:#e04030}button{color:#808070;background-color:#303440;border:1px solid #404040;border-radius:4px;padding:4px;font-family:inherit}button:hover{background-color:#202010}button:active{background-color:#504450}@media (width>=680px) and (height>=620px){.screen{width:640px;height:480px}}@media (width>=1000px) and (height>=800px){.screen{width:960px;height:720px}}@media (width:640px) and (height:480px){.screen{border:0;width:640px;height:480px;margin:0}body{overflow:hidden}}</style></head><body> <div id="uw8"> <a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.4.1 </div> <div id="centered"> <canvas class="screen" id="screen" width="320" height="240"> </canvas> <button class="screen" id="start" style="display:none">Click to start</button> <div id="timer" hidden></div> <div id="message"></div> <button id="cartButton" style="visibility:hidden">Load cart...</button> </div> <div id="footer"> <a href="http://unlicense.org/" ref="license">Unlicense</a> </div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}var t={};t="data:application/wasm;base64,AGFzbQEAAAABFQRgAX8Bf2ACf38Bf2ADf39%2FAGAAAAIPAQNlbnYGbWVtb3J5AgAEAwkIAAABAgEAAAMGEAN%2FAUEAC38BQQALfwFBAAsHGQIIbG9hZF91dzgAAAp1bmNvbXByZXNzAAQIAQcKngUIxwEBB39BAC0AAEEBayIBQQBIBEAgAA8LQYDAByAAaiECIAFBAXEEQEEBQYHABxAEIQIFQYDAB0EAIAAQAwtBAEGAhA9BCBADQYiEDyEDQQghBEGBwAchBQNAIAUgAkggAyMATiAFLQAAIAMtAABMcnEEQCAEIAQgBRACIgZqIQQgAyMASCAFLQAAIAMtAABGcQRAIAMgAxABaiEDCyAFIAZqIQUMAQsgAyMASARAIAQgBCADEAIiB2ohBCADIAdqIQMMAQsLIAQLPAEEfyAAIQEDQCACIAFBAWoiAS0AACIEQf8AcSADdHIhAiADQQdqIQMgBEEHdQ0ACyABQQFqIABrIAJqCxIBAX8gACABIAEQASICEAMgAgskAANAIAJBAEoEQCAAIAJBAWsiAmogASACai0AADoAAAwBCwsLqQEBBn8gACQBQQAkAgNAIANBgAE6AICADyADQQFqIgNBgQNIDQALAkADQEEAEAYiBQRAIAQEf0EBBUGAAhAGCwRAQYECEAVBAWsiAkUNAwtBwQIQBSEGA0AgASABIAJrLQAAOgAAIAFBAWohASAGQQFrIgYNAAsFQQEhBwNAIAdBAXQgBxAGciIHQYACSA0ACyABIAc6AAAgAUEBaiEBCyAFIQQMAAsLIAELNAECfwNAIAAgAmoQBgRAIAEgACACakEgahAGIAJ0ciEBIAJBAWohAgwBCwsgAUEBIAJ0cgtxAQR%2FA0AjAkGAIEgEQCMCQQh0IwEtAAByJAIjAUEBaiQBDAELCyMCQf8BcSICIAAtAICADyIBIwJBCHUiA2xBgAIgAWsgA2wgAWsgAiABSCIEG2okAiAAIAFBByAEQYECbGogAWtBBHVqOgCAgA8gBAsMAEEAQYCEDxAEJAALC60EAQBBAAumBBf%2FyMx3cvbPLfDyK1Bb4IburZYc9i%2BGTsS3j6O4M0o%2Bl2NUQ%2B88SSzybjKLNViVnmhuM%2FZ6LyqKG10doX6mhidmH1yW84EJfcqSXy6pUuF8h7prEGKBJPbIG0yhSUUWuzMrdRxzE4okeNRo4cs%2FsVhtCh4Vai9OQbuu9AZbIpuNDXWOFbj927WcryfPy4dsdT0B%2BA3x1gqXPq2rgI2fI0dNid3EJDTBr3SZWQObkiDldI5YJ17KFwjme3ofejUZT6xP3cNY2XdcosNxULga5hpnvQxV%2F1YKYfeYBVnZ6mAPyIx6Ayl4uxPFNpFdkNv28D%2Bv4X4QS%2BMYgr%2BrLsNAjif5Pz0lVPDBHkx%2BuqJN9SHrb6uRHqvwoVNuRbgn4alMggAWdV0rqmwCXlsmJyzwX%2BrWtH7BoosSlavxs%2BMUTI%2BFXunhVtt5mz3HYy3%2BxBJXF%2FhLWKUPw8vHxoEt%2BBpGDuMK8%2B1ew3pagPiQ7PV7YPWeoHyEKBM92UbyjbJx7HBp7Gh31ZwL9x%2B1sj0ogjs4HLke4hPdXR2o%2F%2BO67SYnX8CPp6YygTuddCxYwU6eHzYFFpwQuzKCVNPXyJKX4HVPJnysHBj5ygPItuS0NZqGlhpzEbgDf%2FJbIQgHzmNotsi6ErQdaigmn0dopO1ybwjbUWZ1kcZmOiBxcoNYSZVtW9mWKfn52kTNDn0QlwZz1slXrqIcx%2BMVVGeIZ9Y5hThIK3lyj%2BL9o%2Fo%3D";var a={};a="data:;base64,AiHfzO34vaTkrd2eAWsXmnk6O0saNxyBOKpKJ4gIZgTFyYLQaErZlwVOzFHSIEwVOdwimalCVY189KvAjT1MA27zTIMgHP7UatKxjcsK5BFbXOHvjhm%2FLesv0gorLh3%2Bp4VSOVvsomIiXDlLL175jQw%2FbY3NPCAhv3e8gH24nzYFr4u3WeQHbVbcFOTxKFGLYMNOsU2QjF2XaPOdZFP32e58qAST0gBwmSKO6tuZq7JVC68uBldt4wWCJEbQqqENSUe5rtcAfyaSRf3gzZ3t3PgnwZHp6%2Fr0cjPo8rqIhvmzkLWI2m4jPwHc8k4s87Gjgpc4YQeipZW9q4PGqym6pnlfUAA8lRaqIo9U%2BnyqAMiI37LAL%2FqtHCi8JG1ByCyw6d9Pf7TLrazkjNNHPa5IJV%2BD8KUJQcCDLquYfrU2baSeirg4QH64Pxevmuo5j9pF97P%2FrfT18mBqcFoba%2Bc1jAeWPRoOSmD9M%2FPIsO1a%2F4bjFd0Uuru95ilanB4yFg4tk9FRqP2zJPk0T4LAzWMXzSX8%2F0VBgOogv%2BniB0XHFmaXv%2BG0PqGrx2sDO2N%2Fi98A3DdQyry%2Fs1%2Bb8mid6w7g5mptwhx561baq1syBSrGSJLqcDAutTh8uXZYvVXbFVzmxfLpAxsR898NHK51FkzqvkxeaNnYbCkC19jhJaslZ1E0vdpidtMzv1uwHCp986mNDT3qK4nWbwOpG52kVtkmac18T9g428D%2BeyJW82GG1hJmGV%2F39FlEB5hxbyFZINNLLAfNwG08itW25ATJ7QxZ%2FAX8zoz%2FT7oLugeHUeMBtvBF%2Bt40Wh2n%2FvjehShTKyMYUvlDZTTzBq34hcaBhCNCHTEHV8bRzoBK3%2Fx0qmeTW2l8vG7KCizhl8VoxALJiY84Isnu1OAS8vKw35FHVUWXDfXLUJw0WooJ%2BdxHnwkxlGBfeNGdWY0zJyRe3CgvsBiGlxC5nABF4pFYBMEOIGR6ev%2F3rrkXL34LdvKr2PkRuMr1gjvb8gGszxhBS40uxdOoWZLRyLA5OZ07W5nHTFbL5l6wKfJrIbrl8ZRamKdD5IXHETRJZq%2BlF3KOS0Jug3R8cjVTtBWYH4QDRXEym7uWNetxnlA5tTOlLine truncated
+1 -1
View File
@@ -4,7 +4,7 @@
<section>
<h1 class="text-center heading-text">A WebAssembly based fantasy console</h1>
</section>
<a href="v0.2.2">
<a href="v0.4.1">
<img class="demonstration-gif" style="width:640px;height:480px;image-rendering:pixelated" src="img/technotunnel.png"></img>
</a>
</div>
+2 -4
View File
@@ -16,17 +16,15 @@ pub struct FileWatcher {
impl FileWatcher {
pub fn new() -> Result<FileWatcher> {
let (tx, rx) = mpsc::channel();
let debouncer = new_debouncer(Duration::from_millis(100), None, move |res| match res {
let debouncer = new_debouncer(Duration::from_millis(100), move |res| match res {
Ok(events) => {
for event in events {
let _ = tx.send(event);
}
}
Err(errs) => {
for err in errs {
Err(err) => {
eprintln!("Error watching for file changes: {err}");
}
}
})?;
Ok(FileWatcher {
debouncer,
+1 -1
View File
@@ -1 +1 @@
<!doctype html><html><head><meta charset="utf8"><title>uw8-run</title><style>html,body,canvas{background-color:#202024;margin:0;padding:0}html{height:100%}body{height:100%;grid-template-rows:1fr;display:grid}#screen{image-rendering:pixelated;border:4px solid #303040;place-self:center}#message{width:calc(100% - 16px);color:#c64;z-index:2;background-color:#0006;padding:8px;font:700 12pt sans-serif;position:absolute}@media (min-width:648px) and (min-height:488px){#screen{width:640px;height:480px}}@media (min-width:968px) and (min-height:728px){#screen{width:960px;height:720px}}</style></head><body> <canvas id="screen" width="320" height="240" tabindex="1"> </canvas> <div id="message"></div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}class t extends AudioWorkletNode{constructor(e){super(e,"apu",{outputChannelCount:[2]})}}let A=(...e)=>new Uint8Array(...e),a=(...e)=>new Uint32Array(...e);let s=function(s,B={}){B.setMessage||(B.setMessage=(e,t)=>{t&&console.log("error: "+t)});let n,r,o,i,l,F,d,C,D=s.getContext("2d"),u=D.createImageData(320,240),c=B.devkitMode,Q=0,f=null==B.keyboardElement?s:B.keyboardElement;if(f){let e=e=>{let t,A="keydown"==e.type;switch(e.code){case"ArrowUp":t=1;break;case"ArrowDown":t=2;break;case"ArrowLeft":t=4;break;case"ArrowRight":t=8;break;case"KeyZ":t=16;break;case"KeyX":t=32;break;case"KeyA":t=64;break;case"KeyS":t=128;break;case"KeyR":A&&g(r,!0);break;case"F9":A&&s.toBlob((e=>{h(e,".png")})),e.preventDefault();break;case"F10":A&&function(){if(l)return l.stop(),l=null,d.disconnect(C),d=null,void(C=null);let e=s.captureStream();C=o.createMediaStreamDestination(),d=i,i.connect(C),e.addTrack(C.stream.getAudioTracks()[0]),l=new MediaRecorder(e,{mimeType:"video/webm",videoBitsPerSecond:25e6});let t=[];l.ondataavailable=e=>{t.push(e.data)};let A=B.timerElement;A&&(A.hidden=!1,A.innerText="00:00");function a(){if(F){if(A){let e=Math.floor((Date.now()-F)/1e3);A.innerText=Math.floor(e/60).toString().padStart(2,"0")+":"+(e%60).toString().padStart(2,"0")}setTimeout(a,1e3)}}l.onstop=()=>{A&&(A.hidden=!0),h(new Blob(t,{type:"video/webm"}),".webm")},l.start(),F=Date.now(),setTimeout(a,1e3)}(),e.preventDefault()}A?Q|=t:Q&=~t};f.onkeydown=e,f.onkeyup=e}async function g(l,F){n&&(n(),n=null),o=new AudioContext({sampleRate:44100});let d=!0,C=new AbortController;n=()=>{o.close(),d=!1,C.abort()};let f=l.byteLength;if(B.setMessage(f),0==f)return;await o.audioWorklet.addModule(e("data:application/javascript,let%20e%3D%28...e%29%3D%3Enew%20Uint8Array%28...e%29%3Bclass%20s%20extends%20AudioWorkletProcessor%7Bconstructor%28%29%7Bsuper%28%29%2Cthis.sampleIndex%3D0%2Cthis.currentTime%3D0%2Cthis.isFirstMessage%3D%210%2Cthis.pendingUpdates%3D%5B%5D%2Cthis.port.onmessage%3De%3D%3E%7Bthis.memory%3F%28this.isFirstMessage%26%26%28this.currentTime%2B%3D%28e.data.t-this.currentTime%29%2F8%2Cthis.isFirstMessage%3D%211%29%2Cthis.pendingUpdates.push%28e.data%29%29%3Athis.load%28e.data%5B0%5D%2Ce.data%5B1%5D%29%7D%7Dasync%20load%28e%2Cs%29%7Blet%20t%3Dnew%20WebAssembly.Memory%28%7Binitial%3A4%2Cmaximum%3A4%7D%29%2Ci%3D%7Benv%3A%7Bmemory%3At%7D%7D%3Bfor%28let%20e%20of%5B%22acos%22%2C%22asin%22%2C%22atan%22%2C%22atan2%22%2C%22cos%22%2C%22exp%22%2C%22log%22%2C%22sin%22%2C%22tan%22%2C%22pow%22%5D%29i.env%5Be%5D%3DMath%5Be%5D%3Bfor%28let%20e%3D9%3Be%3C64%3B%2B%2Be%29i.env%5B%22reserved%22%2Be%5D%3D%28%29%3D%3E%7B%7D%3Blet%20r%3D%22%22%3Bi.env.logChar%3De%3D%3E%7B10%3D%3De%3F%28console.log%28r%29%2Cr%3D%22%22%29%3Ar%2B%3DString.fromCharCode%28e%29%7D%3Bfor%28let%20e%3D0%3Be%3C16%3B%2B%2Be%29i.env%5B%22g_reserved%22%2Be%5D%3D0%3Blet%20n%3Dasync%20e%3D%3E%28await%20WebAssembly.instantiate%28e%2Ci%29%29.instance%2Ca%3Dawait%20n%28e%29%3Bfor%28let%20e%20in%20a.exports%29i.env%5Be%5D%3Da.exports%5Be%5D%3Blet%20o%3Dawait%20n%28s%29%3Bthis.memory%3Dt%2Cthis.snd%3Do.exports.snd%7C%7Ca.exports.sndGes%2Cthis.port.postMessage%282%29%7Dprocess%28s%2Ct%2Ci%29%7Bif%28this.isFirstMessage%3D%210%2Cthis.snd%29%7Bfor%28%3Bthis.pendingUpdates.length%3E0%26%26this.pendingUpdates%5B0%5D.t%3C%3Dthis.currentTime%3B%29e%28this.memory.buffer%2C80%2C32%29.set%28e%28this.pendingUpdates.shift%28%29.r%29%29%3Bnew%20Uint32Array%28this.memory.buffer%29%5B16%5D%3Dthis.currentTime%3Blet%20s%3Dt%5B0%5D%2Ci%3Dthis.sampleIndex%2Cr%3Ds%5B0%5D.length%3Bfor%28let%20e%3D0%3Be%3Cr%3B%2B%2Be%29s%5B0%5D%5Be%5D%3Dthis.snd%28i%2B%2B%29%2Cs%5B1%5D%5Be%5D%3Dthis.snd%28i%2B%2B%29%3Bthis.sampleIndex%3D4294967295%26i%2Cthis.currentTime%2B%3Dr%2F44.1%7Dreturn%210%7D%7DregisterProcessor%28%22apu%22%2Cs%29%3B")),i=new t(o);let h,m=0,w=new Promise((e=>h=e)),p=e=>{m|=e,3==m&&h&&(h(!0),h=null)},y=()=>{"suspended"==o.state?(B.startButton&&(B.startButton.style="",s.style="display:none"),(B.startButton||s).onclick=()=>{o.resume()}):(B.startButton&&(B.startButton.style="display:none",s.style=""),p(1))};o.onstatechange=y,y(),r=l;let E=window.location.pathname;if(f<=1024&&!F){let e="";for(let t of A(l))e+=String.fromCharCode(t);E+="#"+btoa(e),E!=window.locLine truncated
<!doctype html><html><head><meta charset="utf8"><title>uw8-run</title><style>html,body,canvas{background-color:#202024;margin:0;padding:0}html{height:100%}body{grid-template-rows:1fr;height:100%;display:grid}#screen{image-rendering:pixelated;border:4px solid #303040;place-self:center}#message{color:#c64;z-index:2;background-color:#0006;width:calc(100% - 16px);padding:8px;font:700 12pt sans-serif;position:absolute}@media (width>=648px) and (height>=488px){#screen{width:640px;height:480px}}@media (width>=968px) and (height>=728px){#screen{width:960px;height:720px}}</style></head><body> <canvas id="screen" width="320" height="240" tabindex="1"> </canvas> <div id="message"></div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}var t={};t="data:application/wasm;base64,AGFzbQEAAAABFQRgAX8Bf2ACf38Bf2ADf39%2FAGAAAAIPAQNlbnYGbWVtb3J5AgAEAwkIAAABAgEAAAMGEAN%2FAUEAC38BQQALfwFBAAsHGQIIbG9hZF91dzgAAAp1bmNvbXByZXNzAAQIAQcKngUIxwEBB39BAC0AAEEBayIBQQBIBEAgAA8LQYDAByAAaiECIAFBAXEEQEEBQYHABxAEIQIFQYDAB0EAIAAQAwtBAEGAhA9BCBADQYiEDyEDQQghBEGBwAchBQNAIAUgAkggAyMATiAFLQAAIAMtAABMcnEEQCAEIAQgBRACIgZqIQQgAyMASCAFLQAAIAMtAABGcQRAIAMgAxABaiEDCyAFIAZqIQUMAQsgAyMASARAIAQgBCADEAIiB2ohBCADIAdqIQMMAQsLIAQLPAEEfyAAIQEDQCACIAFBAWoiAS0AACIEQf8AcSADdHIhAiADQQdqIQMgBEEHdQ0ACyABQQFqIABrIAJqCxIBAX8gACABIAEQASICEAMgAgskAANAIAJBAEoEQCAAIAJBAWsiAmogASACai0AADoAAAwBCwsLqQEBBn8gACQBQQAkAgNAIANBgAE6AICADyADQQFqIgNBgQNIDQALAkADQEEAEAYiBQRAIAQEf0EBBUGAAhAGCwRAQYECEAVBAWsiAkUNAwtBwQIQBSEGA0AgASABIAJrLQAAOgAAIAFBAWohASAGQQFrIgYNAAsFQQEhBwNAIAdBAXQgBxAGciIHQYACSA0ACyABIAc6AAAgAUEBaiEBCyAFIQQMAAsLIAELNAECfwNAIAAgAmoQBgRAIAEgACACakEgahAGIAJ0ciEBIAJBAWohAgwBCwsgAUEBIAJ0cgtxAQR%2FA0AjAkGAIEgEQCMCQQh0IwEtAAByJAIjAUEBaiQBDAELCyMCQf8BcSICIAAtAICADyIBIwJBCHUiA2xBgAIgAWsgA2wgAWsgAiABSCIEG2okAiAAIAFBByAEQYECbGogAWtBBHVqOgCAgA8gBAsMAEEAQYCEDxAEJAALC60EAQBBAAumBBf%2FyMx3cvbPLfDyK1Bb4IburZYc9i%2BGTsS3j6O4M0o%2Bl2NUQ%2B88SSzybjKLNViVnmhuM%2FZ6LyqKG10doX6mhidmH1yW84EJfcqSXy6pUuF8h7prEGKBJPbIG0yhSUUWuzMrdRxzE4okeNRo4cs%2FsVhtCh4Vai9OQbuu9AZbIpuNDXWOFbj927WcryfPy4dsdT0B%2BA3x1gqXPq2rgI2fI0dNid3EJDTBr3SZWQObkiDldI5YJ17KFwjme3ofejUZT6xP3cNY2XdcosNxULga5hpnvQxV%2F1YKYfeYBVnZ6mAPyIx6Ayl4uxPFNpFdkNv28D%2Bv4X4QS%2BMYgr%2BrLsNAjif5Pz0lVPDBHkx%2BuqJN9SHrb6uRHqvwoVNuRbgn4alMggAWdV0rqmwCXlsmJyzwX%2BrWtH7BoosSlavxs%2BMUTI%2BFXunhVtt5mz3HYy3%2BxBJXF%2FhLWKUPw8vHxoEt%2BBpGDuMK8%2B1ew3pagPiQ7PV7YPWeoHyEKBM92UbyjbJx7HBp7Gh31ZwL9x%2B1sj0ogjs4HLke4hPdXR2o%2F%2BO67SYnX8CPp6YygTuddCxYwU6eHzYFFpwQuzKCVNPXyJKX4HVPJnysHBj5ygPItuS0NZqGlhpzEbgDf%2FJbIQgHzmNotsi6ErQdaigmn0dopO1ybwjbUWZ1kcZmOiBxcoNYSZVtW9mWKfn52kTNDn0QlwZz1slXrqIcx%2BMVVGeIZ9Y5hThIK3lyj%2BL9o%2Fo%3D";var B={};B="data:;base64,AiHfzO34vaTkrd2eAWsXmnk6O0saNxyBOKpKJ4gIZgTFyYLQaErZlwVOzFHSIEwVOdwimalCVY189KvAjT1MA27zTIMgHP7UatKxjcsK5BFbXOHvjhm%2FLesv0gorLh3%2Bp4VSOVvsomIiXDlLL175jQw%2FbY3NPCAhv3e8gH24nzYFr4u3WeQHbVbcFOTxKFGLYMNOsU2QjF2XaPOdZFP32e58qAST0gBwmSKO6tuZq7JVC68uBldt4wWCJEbQqqENSUe5rtcAfyaSRf3gzZ3t3PgnwZHp6%2Fr0cjPo8rqIhvmzkLWI2m4jPwHc8k4s87Gjgpc4YQeipZW9q4PGqym6pnlfUAA8lRaqIo9U%2BnyqAMiI37LAL%2FqtHCi8JG1ByCyw6d9Pf7TLrazkjNNHPa5IJV%2BD8KUJQcCDLquYfrU2baSeirg4QH64Pxevmuo5j9pF97P%2FrfT18mBqcFoba%2Bc1jAeWPRoOSmD9M%2FPIsO1a%2F4bjFd0Uuru95ilanB4yFg4tk9FRqP2zJPk0T4LAzWMXzSX8%2F0VBgOogv%2BniB0XHFmaXv%2BG0PqGrx2sDO2N%2Fi98A3DdQyry%2Fs1%2Bb8mid6w7g5mptwhx561baq1syBSrGSJLqcDAutTh8uXZYvVXbFVzmxfLpAxsR898NHK51FkzqvkxeaNnYbCkC19jhJaslZ1E0vdpidtMzv1uwHCp986mNDT3qK4nWbwOpG52kVtkmac18T9g428D%2BeyJW82GG1hJmGV%2F39FlEB5hxbyFZINNLLAfNwG08itW25ATJ7QxZ%2FAX8zoz%2FT7oLugeHUeMBtvBF%2Bt40Wh2n%2FvjehShTKyMYUvlDZTTzBq34hcaBhCNCHTEHV8bRzoBK3%2Fx0qmeTW2l8vG7KCizhl8VoxALJiY84Isnu1OAS8vKw35FHVUWXDfXLUJw0WooJ%2BdxHnwkxlGBfeNGdWY0zJyRe3CgvsBiGlxC5nABF4pFYBMEOIGR6ev%2F3rrkXL34LdvKr2PkRuMr1gjvb8gGszxhBS40uxdOoWZLRyLA5OZ07W5nHTFbL5l6wKfJrIbrl8ZRamKdD5IXHETRJZq%2BlF3KOS0Jug3R8cjVTtBWYH4QDRXEym7uWNetxnlA5tTOl9kl811ZJeAM2A8TwUY%2FZdnIoPSqf5gUCE%2BcUvdRo55HwOX%2FONuPrPGxNEYIklsAJJlz0ElYqE3NVSphMj3u7re%2F5b%2Fpdf2kWhkJNIdLvvXng6YXb5RM4%2BtqFvQDNV%2FYrEnk4RuFORPr2gwu6%2FllhKTq8RPiV%2FblJi2QsxJnwlFraEsbG3l4E%2FXsovrzL38DcEhBo7wfBSc8JHfs4tMYKHDxzrkUp0Ge01YMKzvvWjrpXrS0Dszq5B5WUA3JOuIBrq6GPuOdFhrJ6Fj7kX3iuWhGxpXrxiyMP%2BE4ax9UTCBGnvV7Nz1wE1gHFVe%2FN%2FoVjMZqV4vhzuVyf%2FEifKcdy1P4dVr6JG6Dw%2FcYvPlvqTtfCo1Khl5In1IrxmO5Hhq8ytKIKG9vTeeCqFXjVMCR9vfkCGyMi%2FbOdvNj6b%2Bq0ijT%2FyxZEp0kb7RSaN%2BihR75CGv7qkh8fy5qZmNYTNxFB5K%2F95iN70AZ8xZwKmOMJ7qbBzNj4j7fyl2zFz2SBLEWrSxhsGXkGjJ7OJmKJhLv8YQNTZij5u4F%2BUGB8GQhVZxmd381jEs4J2fsfbymks0lLC9BhIuCjK%2FTD28z1r7Kw%2Fnk97YXukMfBrNql3Bgh84neyaijJtxmMtuY6rb3CxPYBBQ0xMF%2FI7y6GqQL3xC9SuH5T0q%2FUjPliNfNsZEPgQ7o33%2BM80WMQELh8YeQsBIagyeql1ifqUUZ7hbSygRpIw76Fi7cVCJtaSZzH%2F8CzuoIjbHHWASBtQfLFB2vboh6UuhkyQB4igq0JskQIpQUMQB3wfXs%2BX4La3LtcQfiLkrMDRuqEn0LBhq8pktJvJZvpDtTShpTWpe0F6N43zx0Tk7lxF1awWFSz%2Bw%2B8PR%2BDd70VPEdaOWGxaSXZfnvo5R5wGccKJl0xsCkCZPuh%2BoK5OSHSOQr4eKb561cvGfpj0oO2dpCuIgaDs0r%2B%2BiDwdP2FQkQjyLZKE%2F4OF%2BuzbR9U47GeWrcF0n%2FBUd1VmNDibVX9Fue6C6ssuz8DeiRfXr1gy1w6MeBFXipcCqPm4tDpLbjyncb1A6tXEpAG4kJff0WFLsALine truncated
+186 -42
View File
@@ -2,12 +2,12 @@ use std::sync::{mpsc, Arc, Mutex};
use std::time::Duration;
use std::{thread, time::Instant};
use anyhow::{anyhow, Result};
use anyhow::{anyhow, bail, Result};
use cpal::traits::*;
use rubato::Resampler;
use uw8_window::{Window, WindowConfig};
use wasmtime::{
Engine, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
Engine, Func, GlobalType, Memory, MemoryType, Module, Mutability, Store, TypedFunc, ValType,
};
pub struct MicroW8 {
@@ -27,6 +27,7 @@ struct UW8Instance {
end_frame: TypedFunc<(), ()>,
update: Option<TypedFunc<(), ()>>,
start_time: Instant,
frame_counter: u32,
watchdog: Arc<Mutex<UW8WatchDog>>,
sound_tx: Option<mpsc::SyncSender<RegisterUpdate>>,
}
@@ -90,7 +91,7 @@ impl super::Runtime for MicroW8 {
let memory = wasmtime::Memory::new(&mut store, MemoryType::new(4, Some(4)))?;
let mut linker = wasmtime::Linker::new(&self.engine);
linker.define("env", "memory", memory)?;
linker.define(&store, "env", "memory", memory)?;
let loader_instance = linker.instantiate(&mut store, &self.loader_module)?;
let load_uw8 = loader_instance.get_typed_func::<i32, i32>(&mut store, "load_uw8")?;
@@ -159,6 +160,7 @@ impl super::Runtime for MicroW8 {
end_frame,
update,
start_time: Instant::now(),
frame_counter: 0,
watchdog,
sound_tx,
});
@@ -181,20 +183,21 @@ impl super::Runtime for MicroW8 {
if let Some(mut instance) = self.instance.take() {
let time = (now - instance.start_time).as_millis() as i32;
let next_frame = {
let frame = (time as u32 as u64 * 6 / 100) as u32;
let cur_offset = (time as u32).wrapping_sub((frame as u64 * 100 / 6) as u32);
let next_time =
((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)
let offset = ((time as u32 as i64 * 6) % 100 - 50) / 6;
let max = now + Duration::from_millis(17);
let next_center = now + Duration::from_millis((16 - offset) as u64);
next_center.min(max)
};
{
let mem = instance.memory.data_mut(&mut instance.store);
mem[64..68].copy_from_slice(&time.to_le_bytes());
mem[68..72].copy_from_slice(&input.gamepads);
mem[72..76].copy_from_slice(&instance.frame_counter.to_le_bytes());
}
instance.frame_counter = instance.frame_counter.wrapping_add(1);
instance.store.set_epoch_deadline(self.timeout as u64);
if let Some(ref update) = instance.update {
if let Err(err) = update.call(&mut instance.store, ()) {
@@ -257,15 +260,12 @@ fn add_native_functions(
}
})?;
for i in 0..16 {
linker.define(
"env",
&format!("g_reserved{}", i),
wasmtime::Global::new(
let global = wasmtime::Global::new(
&mut *store,
GlobalType::new(ValType::I32, Mutability::Const),
0.into(),
)?,
)?;
linker.define(&store, "env", &format!("g_reserved{}", i), global)?;
}
Ok(())
@@ -278,14 +278,18 @@ fn instantiate_platform(
) -> Result<wasmtime::Instance> {
let platform_instance = linker.instantiate(&mut *store, &platform_module)?;
for export in platform_instance.exports(&mut *store) {
linker.define(
"env",
export.name(),
export
.into_func()
let exports: Vec<(String, Func)> = platform_instance
.exports(&mut *store)
.map(|e| {
(
e.name().to_owned(),
e.into_func()
.expect("platform surely only exports functions"),
)?;
)
})
.collect();
for (name, func) in exports {
linker.define(&store, "env", &name, func)?;
}
Ok(platform_instance)
@@ -312,7 +316,7 @@ fn init_sound(
let memory = wasmtime::Memory::new(&mut store, MemoryType::new(4, Some(4)))?;
let mut linker = wasmtime::Linker::new(engine);
linker.define("env", "memory", memory)?;
linker.define(&store, "env", "memory", memory)?;
add_native_functions(&mut linker, &mut store)?;
let platform_instance = instantiate_platform(&mut linker, &mut store, platform_module)?;
@@ -329,23 +333,37 @@ fn init_sound(
let mut configs: Vec<_> = device
.supported_output_configs()?
.filter(|config| {
config.channels() == 2 && config.sample_format() == cpal::SampleFormat::F32
config.sample_format() == cpal::SampleFormat::F32
|| config.sample_format() == cpal::SampleFormat::I16
})
.collect();
if configs.is_empty() {
eprintln!(
"No suitable audio output config found on device \"{}\", available configs:",
device.name()?
);
for config in device.supported_output_configs()? {
eprintln!(" {}ch {}", config.channels(), config.sample_format());
}
bail!("Failed to configure audio out");
}
configs.sort_by_key(|config| {
let rate = 44100
.max(config.min_sample_rate().0)
.min(config.max_sample_rate().0);
if rate >= 44100 {
let rate_prio = if rate >= 44100 {
rate - 44100
} else {
(44100 - rate) * 1000
}
};
let format_prio = (config.sample_format() == cpal::SampleFormat::I16) as u32;
let channels_prio = (config.channels() != 2) as u32 * 16777216;
rate_prio + format_prio + channels_prio
});
let config = configs
.into_iter()
.next()
.ok_or_else(|| anyhow!("Could not find float output config"))?;
let config = configs.into_iter().next().unwrap();
let sample_rate = cpal::SampleRate(44100)
.max(config.min_sample_rate())
.min(config.max_sample_rate());
@@ -356,6 +374,8 @@ fn init_sound(
cpal::BufferSize::Fixed(256.max(min).min(max))
}
};
let sample_format = config.sample_format();
let num_channels = config.channels();
let config = cpal::StreamConfig {
buffer_size,
..config.config()
@@ -388,9 +408,8 @@ fn init_sound(
let mut sample_index = 0;
let mut pending_updates: Vec<RegisterUpdate> = Vec::with_capacity(30);
let mut current_time = 0;
let stream = device.build_output_stream(
&config,
move |mut outer_buffer: &mut [f32], _| {
let mut callback = move |mut outer_buffer: &mut [f32]| {
let mut first_update = true;
while let Ok(update) = rx.try_recv() {
if first_update {
@@ -425,6 +444,14 @@ fn init_sound(
mem[64..68].copy_from_slice(&current_time.to_le_bytes());
}
fn clamp_sample(s: f32) -> f32 {
if s.is_nan() {
0.0
} else {
s.max(-1.0).min(1.0)
}
}
if let Some(ref mut resampler) = resampler {
while !buffer.is_empty() {
let copy_size = resampler.output_buffers[0]
@@ -435,10 +462,12 @@ fn init_sound(
resampler.input_buffers[0].clear();
resampler.input_buffers[1].clear();
for _ in 0..resampler.resampler.input_frames_next() {
resampler.input_buffers[0]
.push(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
resampler.input_buffers[1]
.push(snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0));
resampler.input_buffers[0].push(clamp_sample(
snd.call(&mut store, (sample_index,)).unwrap_or(0.0),
));
resampler.input_buffers[1].push(clamp_sample(
snd.call(&mut store, (sample_index + 1,)).unwrap_or(0.0),
));
sample_index = sample_index.wrapping_add(2);
}
@@ -453,8 +482,7 @@ fn init_sound(
resampler.output_index = 0;
} else {
for i in 0..copy_size {
buffer[i * 2] =
resampler.output_buffers[0][resampler.output_index + i];
buffer[i * 2] = resampler.output_buffers[0][resampler.output_index + i];
buffer[i * 2 + 1] =
resampler.output_buffers[1][resampler.output_index + i];
}
@@ -464,20 +492,136 @@ fn init_sound(
}
} else {
for v in buffer {
*v = snd.call(&mut store, (sample_index,)).unwrap_or(0.0);
*v = clamp_sample(snd.call(&mut store, (sample_index,)).unwrap_or(0.0));
sample_index = sample_index.wrapping_add(1);
}
}
outer_buffer = &mut outer_buffer[step_size..];
current_time =
current_time.wrapping_add((step_size * 500 / sample_rate).max(1) as i32);
current_time = current_time.wrapping_add((step_size * 500 / sample_rate).max(1) as i32);
}
};
fn f32_to_i16<F>(mut buffer: &mut [i16], callback: &mut F)
where
F: FnMut(&mut [f32]),
{
let mut float_buffer = [0f32; 256];
while !buffer.is_empty() {
let step_size = buffer.len().min(float_buffer.len());
let step_buffer = &mut float_buffer[..step_size];
callback(step_buffer);
for (dest, src) in buffer.iter_mut().take(step_size).zip(step_buffer.iter()) {
*dest = (src.max(-1.0).min(1.0) * 32767.0) as i16;
}
buffer = &mut buffer[step_size..];
}
}
fn stereo_to_mono<F>(mut buffer: &mut [f32], callback: &mut F)
where
F: FnMut(&mut [f32]),
{
let mut in_buffer = [0f32; 256];
while !buffer.is_empty() {
let step_size = buffer.len().min(in_buffer.len() / 2);
let step_buffer = &mut in_buffer[..step_size * 2];
callback(step_buffer);
for (index, dest) in buffer.iter_mut().take(step_size).enumerate() {
*dest = (step_buffer[index * 2] + step_buffer[index * 2 + 1]) * 0.5;
}
buffer = &mut buffer[step_size..];
}
}
fn stereo_to_surround<F>(mut buffer: &mut [f32], num_channels: usize, callback: &mut F)
where
F: FnMut(&mut [f32]),
{
let mut in_buffer = [0f32; 256];
buffer.fill(0.);
while !buffer.is_empty() {
let step_size = (buffer.len() / num_channels).min(in_buffer.len() / 2);
let step_buffer = &mut in_buffer[..step_size * 2];
callback(step_buffer);
for index in 0..step_size {
buffer[index * num_channels + 0] = step_buffer[index * 2 + 0];
buffer[index * num_channels + 1] = step_buffer[index * 2 + 1];
}
buffer = &mut buffer[step_size * num_channels..];
}
}
let stream = if sample_format == cpal::SampleFormat::F32 {
if num_channels == 2 {
device.build_output_stream(
&config,
move |buffer: &mut [f32], _| callback(buffer),
move |err| {
dbg!(err);
},
None,
)?
} else if num_channels == 1 {
device.build_output_stream(
&config,
move |buffer: &mut [f32], _| stereo_to_mono(buffer, &mut callback),
move |err| {
dbg!(err);
},
None,
)?
} else {
device.build_output_stream(
&config,
move |buffer: &mut [f32], _| {
stereo_to_surround(buffer, num_channels as usize, &mut callback)
},
move |err| {
dbg!(err);
},
)?;
None,
)?
}
} else {
if num_channels == 2 {
device.build_output_stream(
&config,
move |buffer: &mut [i16], _| f32_to_i16(buffer, &mut callback),
move |err| {
dbg!(err);
},
None,
)?
} else if num_channels == 1 {
device.build_output_stream(
&config,
move |buffer: &mut [i16], _| {
f32_to_i16(buffer, &mut |b| stereo_to_mono(b, &mut callback))
},
move |err| {
dbg!(err);
},
None,
)?
} else {
device.build_output_stream(
&config,
move |buffer: &mut [i16], _| {
f32_to_i16(buffer, &mut |b| {
stereo_to_surround(b, num_channels as usize, &mut callback)
})
},
move |err| {
dbg!(err);
},
None,
)?
}
};
Ok(Uw8Sound { stream, tx })
}
@@ -0,0 +1,789 @@
{
"scope": "source.curlywasm",
"completions": [
// Keywords
{
"trigger": "if",
"contents": "if ${1:condition} {\n\t${2:// Your start code here}\n}",
"details": "if (condition) { block }",
"kind": "keyword"
},
{
"trigger": "else",
"contents": "else {\n\t${1:// Your start code here}\n}",
"details": "else { block }",
"kind": "keyword"
},
{
"trigger": "loop",
"contents": "loop ${1:label} {\n\t${2:// Your start code here}\n}",
"details": "loop label { block }",
"kind": "keyword"
},
{
"trigger": "fn",
"contents": "fn ${1:name}(${2:params}) {\n\t${3:// Your start code here}\n}",
"details": "fn name(params) [-> return_type] { block }",
"kind": "keyword"
},
{
"trigger": "let",
"contents": "let ${1:variable} = ${2:value};",
"details": "let variable[: type] = value;",
"kind": "keyword"
},
{
"trigger": "const",
"contents": "const ${1:name} = ${2:value};",
"details": "const name[: type] = value;",
"kind": "keyword"
},
{
"trigger": "branch_if",
"contents": "branch_if ${1:condition}: ${2:label};",
"details": "branch_if (condition): label;",
"kind": "keyword"
},
{
"trigger": "global",
"contents": "global mut ${1:name} = ${2:value};",
"details": "global mut name[: type] = value;",
"kind": "keyword"
},
{
"trigger": "import",
"contents": "import \"${1:module.name}\" ${2:|memory(min_pages)|global var_name: type|fn fun_name(param_types) [-> return_type]};",
"details": "import \"module.name\" memory(min_pages); import \"module.name\" global var_name: type; import \"module.name\" fn fun_name(param_types) [-> return_type];",
"kind": "keyword"
},
{
"trigger": "include",
"contents": "include \"${1:path}\"",
"details": "include \"path\"",
"kind": "keyword"
},
{
"trigger": "api",
"contents": "include \"../include/microw8-api.cwa\"",
"details": "include \"path\"",
"kind": "keyword"
},
{
"trigger": "common",
"contents": "include \"../include/common.cwa\"",
"details": "include \"path\"",
"kind": "keyword"
},
{
"trigger": "export",
"contents": "export fn ${1:name}(${2:params}) ${3:-> ${4:return_type}} { ${5:block} }",
"details": "export fn name(params) [-> return_type] { block }",
"kind": "keyword"
},
{
"trigger": "block",
"contents": "block ${1:label} {\n\t${2://content}\n}",
"details": "block label { block }",
"kind": "keyword"
},
{
"trigger": "branch",
"contents": "branch ${1:label};",
"details": "branch label;",
"kind": "keyword"
},
{
"trigger": "data",
"contents": "data ${1:address} {\n\t${2:type}(\n\t\t${3:values}\n\t)\n}",
"details": "data address { content }",
"kind": "keyword"
},
{
"trigger": "mut",
"contents": "mut",
"details": "Mutable variable modifier",
"kind": "storage.modifier"
},
{
"trigger": "lazy",
"contents": "lazy",
"details": "Lazy variable modifier",
"kind": "storage.modifier"
},
{
"trigger": "inline",
"contents": "inline",
"details": "Inline variable modifier",
"kind": "storage.modifier"
},
// Operators
{
"trigger": "as",
"contents": "as",
"details": "Type cast",
"kind": "keyword.operator.type"
},
{
"trigger": "?",
"contents": "?",
"details": "Load byte",
"kind": "keyword.operator.memory"
},
{
"trigger": "!",
"contents": "!",
"details": "Load word",
"kind": "keyword.operator.memory"
},
{
"trigger": "$",
"contents": "$",
"details": "Load float",
"kind": "keyword.operator.memory"
},
{
"trigger": "<|",
"contents": "<|",
"details": "Take first (sequencing operator)",
"kind": "keyword.operator.misc"
},
// Memory access intrinsic functions (i32 and f32 only)
{
"trigger": "i32.load",
"contents": "i32.load(${1:base}, ${2:offset}${3:, ${4:align}})",
"details": "i32.load(base: i32, offset: i32 = 0, align: i32 = 2) -> i32: Load 32-bit word",
"kind": "support.function"
},
{
"trigger": "i32.load8_u",
"contents": "i32.load8_u(${1:base}, ${2:offset}${3:, ${4:align}})",
"details": "i32.load8_u(base: i32, offset: i32 = 0, align: i32 = 0) -> i32: Load 8-bit unsigned",
"kind": "support.function"
},
{
"trigger": "i32.load8_s",
"contents": "i32.load8_s(${1:base}, ${2:offset}${3:, ${4:align}})",
"details": "i32.load8_s(base: i32, offset: i32 = 0, align: i32 = 0) -> i32: Load 8-bit signed",
"kind": "support.function"
},
{
"trigger": "i32.load16_u",
"contents": "i32.load16_u(${1:base}, ${2:offset}${3:, ${4:align}})",
"details": "i32.load16_u(base: i32, offset: i32 = 0, align: i32 = 1) -> i32: Load 16-bit unsigned",
"kind": "support.function"
},
{
"trigger": "i32.load16_s",
"contents": "i32.load16_s(${1:base}, ${2:offset}${3:, ${4:align}})",
"details": "i32.load16_s(base: i32, offset: i32 = 0, align: i32 = 1) -> i32: Load 16-bit signed",
"kind": "support.function"
},
{
"trigger": "i32.store",
"contents": "i32.store(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});",
"details": "i32.store(value: i32, base: i32, offset: i32 = 0, align: i32 = 2): Store 32-bit word",
"kind": "support.function"
},
{
"trigger": "i32.store8",
"contents": "i32.store8(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});",
"details": "i32.store8(value: i32, base: i32, offset: i32 = 0, align: i32 = 0): Store 8-bit",
"kind": "support.function"
},
{
"trigger": "i32.store16",
"contents": "i32.store16(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});",
"details": "i32.store16(value: i32, base: i32, offset: i32 = 0, align: i32 = 1): Store 16-bit",
"kind": "support.function"
},
{
"trigger": "f32.load",
"contents": "f32.load(${1:base}, ${2:offset}${3:, ${4:align}})",
"details": "f32.load(base: i32, offset: i32 = 0, align: i32 = 2) -> f32: Load 32-bit float",
"kind": "support.function"
},
{
"trigger": "f32.store",
"contents": "f32.store(${1:value}, ${2:base}, ${3:offset}${4:, ${5:align}});",
"details": "f32.store(value: f32, base: i32, offset: i32 = 0, align: i32 = 2): Store 32-bit float",
"kind": "support.function"
},
// API functions
{
"trigger": "sin",
"contents": "sin(${1:x})",
"details": "sin(x: f32) -> f32: Returns the sine of x (radians)",
"kind": "support.function"
},
{
"trigger": "cos",
"contents": "cos(${1:x})",
"details": "cos(x: f32) -> f32: Returns the cosine of x (radians)",
"kind": "support.function"
},
{
"trigger": "tan",
"contents": "tan(${1:x})",
"details": "tan(x: f32) -> f32: Returns the tangent of x (radians)",
"kind": "support.function"
},
{
"trigger": "asin",
"contents": "asin(${1:x})",
"details": "asin(x: f32) -> f32: Returns the arcsine of x (radians)",
"kind": "support.function"
},
{
"trigger": "acos",
"contents": "acos(${1:x})",
"details": "acos(x: f32) -> f32: Returns the arccosine of x (radians)",
"kind": "support.function"
},
{
"trigger": "atan",
"contents": "atan(${1:x})",
"details": "atan(x: f32) -> f32: Returns the arctangent of x (radians)",
"kind": "support.function"
},
{
"trigger": "atan2",
"contents": "atan2(${1:y}, ${2:x})",
"details": "atan2(y: f32, x: f32) -> f32: Returns the angle in radians of the point (x, y)",
"kind": "support.function"
},
{
"trigger": "pow",
"contents": "pow(${1:x}, ${2:y})",
"details": "pow(x: f32, y: f32) -> f32: Returns x raised to the power of y",
"kind": "support.function"
},
{
"trigger": "log",
"contents": "log(${1:x})",
"details": "log(x: f32) -> f32: Returns the natural logarithm of x",
"kind": "support.function"
},
{
"trigger": "fmod",
"contents": "fmod(${1:x}, ${2:y})",
"details": "fmod(x: f32, y: f32) -> f32: Returns the remainder of x/y",
"kind": "support.function"
},
{
"trigger": "random",
"contents": "random()",
"details": "random() -> i32: Returns a random 32-bit integer",
"kind": "support.function"
},
{
"trigger": "randomf",
"contents": "randomf()",
"details": "randomf() -> f32: Returns a random float [0, 1)",
"kind": "support.function"
},
{
"trigger": "randomSeed",
"contents": "randomSeed(${1:seed});",
"details": "randomSeed(seed: i32): Seeds the random number generator",
"kind": "support.function"
},
{
"trigger": "cls",
"contents": "cls(${1:color});",
"details": "cls(color: i32): Clears the screen with the given color, resets cursor to 0,0, disables graphics mode",
"kind": "support.function"
},
{
"trigger": "setPixel",
"contents": "setPixel(${1:x}, ${2:y}, ${3:color});",
"details": "setPixel(x: i32, y: i32, color: i32): Sets the pixel at (x, y) to color",
"kind": "support.function"
},
{
"trigger": "getPixel",
"contents": "getPixel(${1:x}, ${2:y})",
"details": "getPixel(x: i32, y: i32) -> i32: Gets the color of the pixel at (x, y) (returns 0 if out of bounds)",
"kind": "support.function"
},
{
"trigger": "hline",
"contents": "hline(${1:left}, ${2:right}, ${3:y}, ${4:color});",
"details": "hline(left: i32, right: i32, y: i32, color: i32): Fills the horizontal line [left, right), y",
"kind": "support.function"
},
{
"trigger": "rectangle",
"contents": "rectangle(${1:x}, ${2:y}, ${3:width}, ${4:height}, ${5:color});",
"details": "rectangle(x: f32, y: f32, w: f32, h: f32, color: i32): Fills the rectangle x,y - x+w,y+h",
"kind": "support.function"
},
{
"trigger": "circle",
"contents": "circle(${1:cx}, ${2:cy}, ${3:radius}, ${4:color});",
"details": "circle(cx: f32, cy: f32, radius: f32, color: i32): Fills the circle at cx, cy with radius",
"kind": "support.function"
},
{
"trigger": "line",
"contents": "line(${1:x1}, ${2:y1}, ${3:x2}, ${4:y2}, ${5:color});",
"details": "line(x1: f32, y1: f32, x2: f32, y2: f32, color: i32): Draws a line from x1,y1 to x2,y2",
"kind": "support.function"
},
{
"trigger": "time",
"contents": "time()",
"details": "time() -> f32: Returns the current time in seconds",
"kind": "support.function"
},
{
"trigger": "isButtonPressed",
"contents": "isButtonPressed(${1:button})",
"details": "isButtonPressed(button: i32) -> bool: Checks if a button is pressed this frame (returns i32)",
"kind": "support.function"
},
{
"trigger": "isButtonTriggered",
"contents": "isButtonTriggered(${1:button})",
"details": "isButtonTriggered(button: i32) -> bool: Checks if a button is newly pressed this frame (returns i32)",
"kind": "support.function"
},
{
"trigger": "printChar",
"contents": "printChar(${1:char});",
"details": "printChar(char: i32): Prints the character in the lower 8 bits",
"kind": "support.function"
},
{
"trigger": "printString",
"contents": "printString(${1:ptr});",
"details": "printString(ptr: i32): Prints the zero-terminated string at memory address ptr",
"kind": "support.function"
},
{
"trigger": "printInt",
"contents": "printInt(${1:value});",
"details": "printInt(value: i32): Prints an integer as a signed decimal number",
"kind": "support.function"
},
{
"trigger": "setTextColor",
"contents": "setTextColor(${1:color});",
"details": "setTextColor(color: i32): Sets the text color",
"kind": "support.function"
},
{
"trigger": "setBackgroundColor",
"contents": "setBackgroundColor(${1:color});",
"details": "setBackgroundColor(color: i32): Sets the background color",
"kind": "support.function"
},
{
"trigger": "setCursorPosition",
"contents": "setCursorPosition(${1:x}, ${2:y});",
"details": "setCursorPosition(x: i32, y: i32): Sets the cursor position (character or pixel coords depending on mode)",
"kind": "support.function"
},
{
"trigger": "rectangleOutline",
"contents": "rectangleOutline(${1:x}, ${2:y}, ${3:width}, ${4:height}, ${5:color});",
"details": "rectangleOutline(x: f32, y: f32, w: f32, h: f32, color: i32): Draws a rectangle outline",
"kind": "support.function"
},
{
"trigger": "circleOutline",
"contents": "circleOutline(${1:cx}, ${2:cy}, ${3:radius}, ${4:color});",
"details": "circleOutline(cx: f32, cy: f32, radius: f32, color: i32): Draws a circle outline",
"kind": "support.function"
},
{
"trigger": "exp",
"contents": "exp(${1:x})",
"details": "exp(x: f32) -> f32: Returns e raised to the power of x",
"kind": "support.function"
},
{
"trigger": "playNote",
"contents": "playNote(${1:channel}, ${2:note}${3:, ${4:duration}${5:, ${6:volume}}});",
"details": "playNote(channel: i32, note: i32): Triggers a note on the given channel (note 0 stops, 128-255 triggers attack+release)",
"kind": "support.function"
},
{
"trigger": "sndGes",
"contents": "sndGes(${1:sampleIndex})",
"details": "sndGes(sampleIndex: i32) -> f32: Sound generator function (uses 32 bytes at 0x50 by default)",
"kind": "support.function"
},
{
"trigger": "blitSprite",
"contents": "blitSprite(${1:spriteData}, ${2:size}, ${3:x}, ${4:y}, ${5:control});",
"details": "blitSprite(spriteData: i32, size: i32, x: i32, y: i32, control: i32): Copies sprite data to screen",
"kind": "support.function"
},
{
"trigger": "grabSprite",
"contents": "grabSprite(${1:spriteData}, ${2:size}, ${3:x}, ${4:y}, ${5:control});",
"details": "grabSprite(spriteData: i32, size: i32, x: i32, y: i32, control: i32): Copies screen data to sprite",
"kind": "support.function"
},
// Built-in functions (or commonly used intrinsics)
{
"trigger": "start",
"contents": "export fn start() {\n\t${1:// Your start code here}\n}",
"details": "export fn start(): Called once after module is loaded",
"kind": "support.function"
},
{
"trigger": "upd",
"contents": "export fn upd() {\n\t${1:// Your update code here}\n}",
"details": "export fn upd(): Called once per frame",
"kind": "support.function"
},
{
"trigger": "memory.fill",
"contents": "memory.fill(${1:dest}, ${2:value}, ${3:size});",
"details": "memory.fill(dest: i32, value: i32, size: i32): Fills a memory area",
"kind": "support.function"
},
{
"trigger": "memory.copy",
"contents": "memory.copy(${1:dest}, ${2:src}, ${3:size});",
"details": "memory.copy(dest: i32, src: i32, size: i32): Copies a memory block",
"kind": "support.function"
},
{
"trigger": "sqrt",
"contents": "sqrt(${1:x})",
"details": "sqrt(x: f32) -> f32: Returns the square root of x",
"kind": "support.function"
},
{
"trigger": "min",
"contents": "min(${1:x}, ${2:y})",
"details": "min(x: f32, y: f32) -> f32: Returns the minimum of x and y",
"kind": "support.function"
},
{
"trigger": "max",
"contents": "max(${1:x}, ${2:y})",
"details": "max(x: f32, y: f32) -> f32: Returns the maximum of x and y",
"kind": "support.function"
},
{
"trigger": "ceil",
"contents": "ceil(${1:x})",
"details": "ceil(x: f32) -> f32: Returns the smallest integer >= x",
"kind": "support.function"
},
{
"trigger": "floor",
"contents": "floor(${1:x})",
"details": "floor(x: f32) -> f32: Returns the largest integer <= x",
"kind": "support.function"
},
{
"trigger": "trunc",
"contents": "trunc(${1:x})",
"details": "trunc(x: f32) -> f32: Returns the nearest integer to x toward zero",
"kind": "support.function"
},
{
"trigger": "nearest",
"contents": "nearest(${1:x})",
"details": "nearest(x: f32) -> f32: Returns the nearest integer to x (round to nearest, ties to even)",
"kind": "support.function"
},
{
"trigger": "abs",
"contents": "abs(${1:x})",
"details": "abs(x: f32) -> f32: Returns the absolute value of x",
"kind": "support.function"
},
{
"trigger": "copysign",
"contents": "copysign(${1:x}, ${2:y})",
"details": "copysign(x: f32, y: f32) -> f32: Returns x with the sign of y",
"kind": "support.function"
},
{
"trigger": "select",
"contents": "select(${1:a}, ${2:b}, ${3:c})",
"details": "select(a: f32, b: f32, c: f32) -> f32: Selects b if a is non-zero, otherwise selects c (equivalent to a != 0 ? b : c)",
"kind": "support.function"
},
{
"trigger": "i32.clz",
"contents": "i32.clz(${1:value})",
"details": "i32.clz(value: i32) -> i32: Count Leading Zeros",
"kind": "support.function"
},
{
"trigger": "i32.ctz",
"contents": "i32.ctz(${1:value})",
"details": "i32.ctz(value: i32) -> i32: Count Trailing Zeros",
"kind": "support.function"
},
{
"trigger": "i32.popcnt",
"contents": "i32.popcnt(${1:value})",
"details": "i32.popcnt(value: i32) -> i32: Population Count (number of set bits)",
"kind": "support.function"
},
{
"trigger": "i32.bswap",
"contents": "i32.bswap(${1:value})",
"details": "i32.bswap(value: i32) -> i32: Byte Swap",
"kind": "support.function"
},
{
"trigger": "i32.trunc_sat_f32_u",
"contents": "i32.trunc_sat_f32_u(${1:value})",
"details": "i32.trunc_sat_f32_u(value: f32) -> i32: Truncate f32 to i32 unsigned, saturating",
"kind": "support.function"
},
{
"trigger": "i32.trunc_sat_f32_s",
"contents": "i32.trunc_sat_f32_s(${1:value})",
"details": "i32.trunc_sat_f32_s(value: f32) -> i32: Truncate f32 to i32 signed, saturating",
"kind": "support.function"
},
// Added Constants
{
"trigger": "TIME_MS",
"contents": "TIME_MS",
"details": "0x40 Time since module start in ms",
"kind": "constant"
},
{
"trigger": "GAMEPAD",
"contents": "GAMEPAD",
"details": "0x44 Gamepad state",
"kind": "constant"
},
{
"trigger": "FRAMEBUFFER",
"contents": "FRAMEBUFFER",
"details": "0x78 Frame buffer address",
"kind": "constant"
},
{
"trigger": "PALETTE",
"contents": "PALETTE",
"details": "0x13000 Palette address",
"kind": "constant"
},
{
"trigger": "FONT",
"contents": "FONT",
"details": "0x13400 Font address",
"kind": "constant"
},
{
"trigger": "USER_MEM",
"contents": "USER_MEM",
"details": "0x14000 Start of general user memory",
"kind": "constant"
},
{
"trigger": "BUTTON_UP",
"contents": "BUTTON_UP",
"details": "0x00 Gamepad button Up",
"kind": "constant"
},
{
"trigger": "BUTTON_DOWN",
"contents": "BUTTON_DOWN",
"details": "0x01 Gamepad button Down",
"kind": "constant"
},
{
"trigger": "BUTTON_LEFT",
"contents": "BUTTON_LEFT",
"details": "0x02 Gamepad button Left",
"kind": "constant"
},
{
"trigger": "BUTTON_RIGHT",
"contents": "BUTTON_RIGHT",
"details": "0x03 Gamepad button Right",
"kind": "constant"
},
{
"trigger": "BUTTON_A",
"contents": "BUTTON_A",
"details": "0x04 Gamepad button A (Z on keyboard)",
"kind": "constant"
},
{
"trigger": "BUTTON_B",
"contents": "BUTTON_B",
"details": "0x05 Gamepad button B (X on keyboard)",
"kind": "constant"
},
{
"trigger": "BUTTON_X",
"contents": "BUTTON_X",
"details": "0x06 Gamepad button X (A on keyboard)",
"kind": "constant"
},
{
"trigger": "BUTTON_Y",
"contents": "BUTTON_Y",
"details": "0x07 Gamepad button Y (S on keyboard)",
"kind": "constant"
},
{
"trigger": "PI",
"contents": "PI",
"details": "Mathematical constant π",
"kind": "constant"
},
{
"trigger": "RAD",
"contents": "RAD",
"details": "One radian value",
"kind": "constant"
},
{
"trigger": "SCR_X",
"contents": "SCR_X",
"details": "Screen width in pixels",
"kind": "constant"
},
{
"trigger": "SCR_Y",
"contents": "SCR_Y",
"details": "Screen height in pixels",
"kind": "constant"
},
{
"trigger": "SCR_W",
"contents": "SCR_W",
"details": "Screen width in chars (40)",
"kind": "constant"
},
{
"trigger": "SCR_H",
"contents": "SCR_H",
"details": "Screen height in chars (30)",
"kind": "constant"
},
{
"trigger": "CENTER_X",
"contents": "CENTER_X",
"details": "X-coordinate of the screen center (160)",
"kind": "constant"
},
{
"trigger": "CENTER_Y",
"contents": "CENTER_Y",
"details": "Y-coordinate of the screen center (120)",
"kind": "constant"
},
{
"trigger": "SCR_SIZE",
"contents": "SCR_SIZE",
"details": "Total screen size in pixels (76800)",
"kind": "constant"
},
{
"trigger": "MEM_END",
"contents": "MEM_END",
"details": "End of available memory",
"kind": "constant"
},
{
"trigger": "CUSTOM_FONT",
"contents": "CUSTOM_FONT",
"details": "Address for a custom font",
"kind": "constant"
},
{
"trigger": "COLOR_BLACK",
"contents": "COLOR_BLACK",
"details": "0x00 Black",
"kind": "constant"
},
{
"trigger": "COLOR_DARK_BLUE",
"contents": "COLOR_DARK_BLUE",
"details": "0x17 Dark Blue",
"kind": "constant"
},
{
"trigger": "COLOR_DARK_PURPLE",
"contents": "COLOR_DARK_PURPLE",
"details": "0x27 Dark Purple",
"kind": "constant"
},
{
"trigger": "COLOR_CYAN",
"contents": "COLOR_CYAN",
"details": "0x37 Cyan",
"kind": "constant"
},
{
"trigger": "COLOR_BRIGHT_RED",
"contents": "COLOR_BRIGHT_RED",
"details": "0x47 Bright Red",
"kind": "constant"
},
{
"trigger": "COLOR_MAGENTA",
"contents": "COLOR_MAGENTA",
"details": "0x57 Magenta",
"kind": "constant"
},
{
"trigger": "COLOR_ORANGE",
"contents": "COLOR_ORANGE",
"details": "0x58 Orange",
"kind": "constant"
},
{
"trigger": "COLOR_BRIGHT_YELLOW",
"contents": "COLOR_BRIGHT_YELLOW",
"details": "0x67 Bright Yellow",
"kind": "constant"
},
{
"trigger": "COLOR_MEDIUM_GREY",
"contents": "COLOR_MEDIUM_GREY",
"details": "0x78 Medium Grey",
"kind": "constant"
},
{
"trigger": "COLOR_LIGHT_GREY",
"contents": "COLOR_LIGHT_GREY",
"details": "0x7C Light Grey",
"kind": "constant"
},
{
"trigger": "COLOR_WHITE",
"contents": "COLOR_WHITE",
"details": "0xF8 White",
"kind": "constant"
},
{
"trigger": "COLOR_BRIGHT_GREEN",
"contents": "COLOR_BRIGHT_GREEN",
"details": "0x87 Bright Green",
"kind": "constant"
},
{
"trigger": "COLOR_BROWN",
"contents": "COLOR_BROWN",
"details": "0xD4 Brown",
"kind": "constant"
},
{
"trigger": "COLOR_DARK_GREY",
"contents": "COLOR_DARK_GREY",
"details": "0xE1 Dark Grey",
"kind": "constant"
}
]
}
+234
View File
@@ -0,0 +1,234 @@
%YAML 1.2
---
# ==========================================================
# http://www.sublimetext.com/docs/syntax.html
# created by: zbyti & various AI
# ==========================================================
# For best results, use with Rust-themed color schemes like:
# - "RustEnhanced"
# - "Atomized"
# - "Solarized Rust"
# ==========================================================
name: CurlyWASM
file_extensions: [cwa]
scope: source.curlywasm
contexts:
main:
# Comments
- match: /\*
scope: comment.block.curlywasm
push: block_comment
- match: //
scope: comment.line.curlywasm
push: line_comment
# Module system
- match: \b(import|include|export)\b
scope: keyword.control.import.curlywasm
# Declarations and definitions
- match: \b(fn)\b
scope: keyword.declaration.function.curlywasm
- match: \b(const)\b
scope: storage.modifier.const.curlywasm
- match: \b(global|mut|let|lazy|inline)\b
scope: storage.modifier.curlywasm
# Control flow
- match: \b(if|else|block|loop|branch|branch_if)\b
scope: keyword.control.flow.curlywasm
# Type conversion
- match: \b(as)\b
scope: keyword.operator.type.curlywasm
# WASM memory access operators
- match: \b(load|store)\b
scope: keyword.operator.memory.curlywasm
# API functions
- match: \b(sin|cos|tan|asin|acos|atan|atan2|pow|log|fmod|random|randomf|randomSeed|cls|setPixel|getPixel|hline|rectangle|circle|line|time|isButtonPressed|isButtonTriggered|printChar|printString|printInt|setTextColor|setBackgroundColor|setCursorPosition|rectangleOutline|circleOutline|exp|playNote|sndGes|blitSprite|grabSprite)\b
scope: support.function.curlywasm
# Built-in functions
- match: \b(start|upd|sqrt|min|max|ceil|floor|trunc|nearest|abs|copysign|select)\b
scope: support.function.curlywasm
# Data blocks - Match 'data {' together and push context
- match: \b(data)\s*(\{)
captures:
1: storage.type.data.curlywasm
2: punctuation.section.block.begin.curlywasm
push: data_content
# Base types
- match: \b(i8|i16|i32|i64|f32|f64)\b
scope: storage.type.primitive.curlywasm
# Memory access operators
- match: (\?|\$|\!)
scope: keyword.operator.memory.curlywasm
# Operators
- match: (->)
scope: keyword.operator.arrow.curlywasm
# Assignment operators
- match: (=|:=|\+=|-=|\*=|/=|%=|&=|\|=|\^=|#/=)
scope: keyword.operator.assignment.curlywasm
# Arithmetic operators
- match: (\+|-|\*|/|%|#/|#%)
scope: keyword.operator.arithmetic.curlywasm
# Bitwise operators
- match: (\&|\||\^|<<|>>|#>>)
scope: keyword.operator.bitwise.curlywasm
# Comparison operators
- match: (<|>|<=|>=|#<|#<=|#>|#>=|==|!=)
scope: keyword.operator.comparison.curlywasm
# Other operators
- match: (<\|)
scope: keyword.operator.misc.curlywasm
# Numeric literals
- match: \b(0x[0-9a-fA-F]+)\b
scope: constant.numeric.hex.curlywasm
- match: '\b\d+(_f)\b'
scope: constant.numeric.float.curlywasm
- match: \b0x[0-9a-fA-F]+_f\b
scope: constant.numeric.float.curlywasm
- match: \b([0-9]+\.[0-9]+)\b
scope: constant.numeric.float.curlywasm
- match: \b([0-9]+)\b
scope: constant.numeric.integer.curlywasm
# String literals
- match: \"
scope: punctuation.definition.string.begin.curlywasm
push: double_quoted_string
- match: \'
scope: punctuation.definition.string.begin.curlywasm
push: single_quoted_string
# Function calls
- match: \b([a-zA-Z_][a-zA-Z0-9_]*)\s*\(
captures:
1: entity.name.function.call.curlywasm
# Function declarations
- match: \bfn\s+([a-zA-Z_][a-zA-Z0-9_]*)\b
captures:
1: entity.name.function.declaration.curlywasm
# Constants (Upper case convention)
- match: \b([A-Z_][A-Z0-9_]*)\b
scope: constant.other.curlywasm
# Variables (Lower case convention)
- match: \b([a-z_][a-zA-Z0-9_]*)\b
scope: variable.other.curlywasm
# Punctuation
- match: \{
scope: punctuation.section.block.begin.curlywasm
- match: \}
scope: punctuation.section.block.end.curlywasm
- match: \(
scope: punctuation.section.group.begin.curlywasm
- match: \)
scope: punctuation.section.group.end.curlywasm
- match: \[
scope: punctuation.section.brackets.begin.curlywasm
- match: \]
scope: punctuation.section.brackets.end.curlywasm
- match: ;
scope: punctuation.terminator.curlywasm
- match: \,
scope: punctuation.separator.curlywasm
- match: ':'
scope: punctuation.separator.type.curlywasm
# Context for /* ... */ block comments
block_comment:
- meta_scope: comment.block.curlywasm
- match: \*/
scope: punctuation.definition.comment.end.curlywasm
pop: true
# Context for // ... line comments
line_comment:
- meta_scope: comment.line.double-slash.curlywasm
- match: $ # Pop at the end of the line
pop: true
# Context for "..." strings
double_quoted_string:
- meta_scope: string.quoted.double.curlywasm
- match: \"
scope: punctuation.definition.string.end.curlywasm
pop: true
- match: \\. # Escape sequences
scope: constant.character.escape.curlywasm
# Context for '...' strings
single_quoted_string:
- meta_scope: string.quoted.single.curlywasm
- match: \'
scope: punctuation.definition.string.end.curlywasm
pop: true
- match: \\. # Escape sequences
scope: constant.character.escape.curlywasm
# Context for the content inside data { ... }
data_content:
- meta_scope: meta.data.content.curlywasm
# Match the closing brace to pop the context
- match: \}
scope: punctuation.section.block.end.curlywasm
pop: true
# Include rules for literals within the data block
- include: literals
# Specific types/keywords allowed inside data blocks
- match: \b(i8|i16|i32|i64|f32|f64)\b
scope: storage.type.primitive.curlywasm
- match: \b(file)\b
scope: keyword.control.curlywasm
# Punctuation inside data blocks
- match: \(
scope: punctuation.section.group.begin.curlywasm
- match: \)
scope: punctuation.section.group.end.curlywasm
- match: \,
scope: punctuation.separator.curlywasm
# Potentially allow comments inside data blocks
- include: block_comment
- include: line_comment
# Reusable patterns for literals (used via include)
literals:
# Numeric literals
- match: \b(0x[0-9a-fA-F]+)\b
scope: constant.numeric.hex.curlywasm
- match: '\b\d+(_f)\b'
scope: constant.numeric.float.curlywasm
- match: \b([0-9]+\.[0-9]+)\b
scope: constant.numeric.float.curlywasm
- match: \b([0-9]+)\b
scope: constant.numeric.integer.curlywasm
# String literals
- match: \"
scope: punctuation.definition.string.begin.curlywasm
push: double_quoted_string
- match: \'
scope: punctuation.definition.string.begin.curlywasm
push: single_quoted_string
@@ -0,0 +1,12 @@
<snippet>
<content><![CDATA[
data ${1:address} {
${2:type}(
${3:values}
)
}
]]></content>
<tabTrigger>datatype</tabTrigger>
<description>Data block definition</description>
<scope>source.curlywasm</scope>
</snippet>
@@ -0,0 +1,10 @@
<snippet>
<content><![CDATA[
export fn ${1:name}(${2:params}) -> ${3:return_type} {
${4:// Function body}
}
]]></content>
<tabTrigger>fnexport</tabTrigger>
<description>Exported function definition</description>
<scope>source.curlywasm</scope>
</snippet>
@@ -0,0 +1,12 @@
<snippet>
<content><![CDATA[
if ${1:condition} {
${2:// Your if code here}
} else {
${3:// Your else code here}
}
]]></content>
<tabTrigger>ifelse</tabTrigger>
<description>If-else statement</description>
<scope>source.curlywasm</scope>
</snippet>
@@ -0,0 +1,8 @@
<snippet>
<content><![CDATA[
let inline ${1:variable} = ${2:value};
]]></content>
<tabTrigger>letinline</tabTrigger>
<description>Lazy variable declaration</description>
<scope>source.curlywasm</scope>
</snippet>
@@ -0,0 +1,8 @@
<snippet>
<content><![CDATA[
let lazy ${1:variable} = ${2:value};
]]></content>
<tabTrigger>letlazy</tabTrigger>
<description>Lazy variable declaration</description>
<scope>source.curlywasm</scope>
</snippet>
@@ -0,0 +1,12 @@
<snippet>
<content><![CDATA[
${1:label} = 0;
loop ${1:label} {
${2:// Your loop code here}
branch_if ${3:condition}: ${1:label};
}
]]></content>
<tabTrigger>loopbr</tabTrigger>
<description>Loop with branch_if</description>
<scope>source.curlywasm</scope>
</snippet>
+1
View File
@@ -0,0 +1 @@
* add support for 16bit sound (not just float)
+122 -146
View File
@@ -4,21 +4,27 @@ version = 3
[[package]]
name = "anyhow"
version = "1.0.52"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
[[package]]
name = "autocfg"
version = "1.0.1"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "cc"
version = "1.0.72"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
[[package]]
name = "cdivsufsort"
@@ -30,39 +36,42 @@ dependencies = [
"sacabase",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "form_urlencoded"
version = "1.1.0"
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "gimli"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
dependencies = [
"percent-encoding",
"fallible-iterator",
"indexmap 1.9.3",
"stable_deref_trait",
]
[[package]]
@@ -71,6 +80,12 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heck"
version = "0.3.3"
@@ -87,31 +102,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]]
name = "idna"
version = "0.3.0"
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"unicode-bidi",
"unicode-normalization",
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "1.9.2"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"autocfg",
"hashbrown",
"equivalent",
"hashbrown 0.14.3",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "leb128"
version = "0.2.5"
@@ -126,46 +135,36 @@ checksum = "478ee9e62aaeaf5b140bd4138753d1f109765488581444218d3ddda43234f3e8"
[[package]]
name = "libc"
version = "0.2.112"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "log"
version = "0.4.14"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "num-traits"
version = "0.2.14"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]]
name = "pbr"
version = "1.0.4"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff5751d87f7c00ae6403eb1fcbba229b9c76c9a30de8c1cf87182177b168cea2"
checksum = "ed5827dfa0d69b6c92493d6c38e633bbaa5937c153d0d7c28bf12313f8c6d514"
dependencies = [
"crossbeam-channel",
"libc",
"time",
"winapi",
]
[[package]]
name = "percent-encoding"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pico-args"
version = "0.5.0"
@@ -174,18 +173,18 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "proc-macro2"
version = "1.0.36"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.14"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@@ -200,88 +199,70 @@ dependencies = [
]
[[package]]
name = "syn"
version = "1.0.84"
name = "semver"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.38"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.38"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.58",
]
[[package]]
name = "time"
version = "0.1.44"
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "unicode-bidi"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
[[package]]
name = "upkr"
@@ -294,17 +275,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "url"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "uw8-tool"
version = "0.1.0"
@@ -314,22 +284,24 @@ dependencies = [
"pico-args",
"upkr",
"walrus",
"wasm-encoder",
"wasmparser 0.99.0",
"wasm-encoder 0.201.0",
"wasmparser 0.201.0",
]
[[package]]
name = "walrus"
version = "0.19.0"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8"
checksum = "2c03529cd0c4400a2449f640d2f27cd1b48c3065226d15e26d98e4429ab0adb7"
dependencies = [
"anyhow",
"gimli",
"id-arena",
"leb128",
"log",
"walrus-macro",
"wasmparser 0.77.0",
"wasm-encoder 0.29.0",
"wasmparser 0.80.2",
]
[[package]]
@@ -341,38 +313,42 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
"syn 1.0.109",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
name = "wasm-encoder"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
checksum = "18c41dbd92eaebf3612a39be316540b8377c871cb9bde6b064af962984912881"
dependencies = [
"leb128",
]
[[package]]
name = "wasm-encoder"
version = "0.22.0"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef126be0e14bdf355ac1a8b41afc89195289e5c7179f80118e3abddb472f0810"
checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a"
dependencies = [
"leb128",
]
[[package]]
name = "wasmparser"
version = "0.77.0"
version = "0.80.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6"
checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b"
[[package]]
name = "wasmparser"
version = "0.99.0"
version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ef3b717afc67f848f412d4f02c127dd3e35a0eecd58c684580414df4fde01d3"
checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708"
dependencies = [
"indexmap",
"url",
"bitflags",
"indexmap 2.2.6",
"semver",
]
[[package]]
+3 -3
View File
@@ -6,9 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
wasmparser = "0.99"
wasm-encoder = "0.22"
walrus = "0.19"
wasmparser = "0.201"
wasm-encoder = "0.201"
walrus = { version = "0.20.3", default-features = false }
anyhow = "1"
pico-args = "0.5"
upkr = { git = "https://github.com/exoticorn/upkr.git", rev = "080db40d0088bbee2bdf3c5c75288ac7853d6b7a" }
+1 -1
View File
@@ -37,7 +37,7 @@ impl BaseModule {
let mut types = vec![];
let mut type_map = HashMap::new();
for num_params in 0..6 {
for num_params in 0..8 {
for num_f32 in 0..=num_params {
for &result in &[None, Some(ValType::I32), Some(ValType::F32)] {
let mut params = vec![];
+1 -1
View File
@@ -8,7 +8,7 @@ pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> {
.exports
.iter()
.filter_map(|export| match export.name.as_str() {
"upd" | "snd" | "start" => None,
"start" | "upd" | "snd" => None,
_ => Some(export.id()),
})
.collect();
+12 -7
View File
@@ -490,7 +490,6 @@ impl<'a> ParsedModule<'a> {
element_section.active(
None,
&wasm_encoder::ConstExpr::i32_const(element.start_index as i32),
ValType::FuncRef,
wasm_encoder::Elements::Functions(&functions),
);
}
@@ -536,9 +535,10 @@ fn copy_section(module: &mut wasm_encoder::Module, data: &[u8]) -> Result<()> {
fn read_type_section(reader: TypeSectionReader) -> Result<Vec<base_module::FunctionType>> {
let mut function_types = vec![];
for type_def in reader {
match type_def? {
wasmparser::Type::Func(fnc) => {
for rec_group in reader {
for sub_type in rec_group?.into_types() {
match sub_type.composite_type {
wasmparser::CompositeType::Func(fnc) => {
if fnc.results().len() > 1 {
bail!("Multi-value not supported");
}
@@ -546,6 +546,8 @@ fn read_type_section(reader: TypeSectionReader) -> Result<Vec<base_module::Funct
let result = to_val_type_vec(fnc.results())?.into_iter().next();
function_types.push(FunctionType { params, result });
}
_ => bail!("Only function types are supported"),
}
}
}
@@ -557,8 +559,8 @@ fn validate_table_section(reader: TableSectionReader) -> Result<()> {
bail!("Only up to one table supported");
}
let type_ = reader.into_iter().next().unwrap()?;
if type_.element_type != wasmparser::ValType::FuncRef {
let table = reader.into_iter().next().unwrap()?;
if !table.ty.element_type.is_func_ref() {
bail!("Only one funcref table is supported");
}
@@ -647,9 +649,12 @@ impl Element {
wasmparser::ElementItems::Functions(funcs_reader) => {
let start_index = if let wasmparser::ElementKind::Active {
offset_expr,
table_index: 0,
table_index,
} = element.kind
{
if table_index.map(|i| i > 0).unwrap_or(false) {
bail!("Only function table with index 0 is supported");
}
let mut init_reader = offset_expr.get_operators_reader();
if let wasmparser::Operator::I32Const { value: start_index } =
init_reader.read()?
+831 -775
View File
File diff suppressed because it is too large. Load diff
+6 -6
View File
@@ -6,13 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
winit = "0.27.5"
env_logger = "0.10"
env_logger = "0.11.3"
winit = "0.28.6"
log = "0.4"
pico-args = "0.5"
wgpu = "0.15"
pollster = "0.2.5"
bytemuck = { version = "1.13", features = [ "derive" ] }
wgpu = "0.17"
pollster = "0.3.0"
bytemuck = { version = "1.15", features = [ "derive" ] }
anyhow = "1"
minifb = { version = "0.23.0", default-features = false, features = ["x11"] }
minifb = { version = "0.25.0", default-features = false, features = ["x11"] }
winapi = { version = "0.3.9", features = [ "timeapi" ] }
+5 -14
View File
@@ -1,7 +1,7 @@
use wgpu::util::DeviceExt;
use winit::dpi::PhysicalSize;
use super::Filter;
use super::{scale_mode::ScaleMode, Filter};
pub struct CrtFilter {
uniform_buffer: wgpu::Buffer,
@@ -15,9 +15,10 @@ impl CrtFilter {
screen: &wgpu::TextureView,
resolution: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
scale_mode: ScaleMode,
) -> CrtFilter {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(resolution),
texture_scale: scale_mode.texture_scale_from_resolution(resolution),
};
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
@@ -112,9 +113,9 @@ impl CrtFilter {
}
impl Filter for CrtFilter {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>, scale_mode: ScaleMode) {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(new_size),
texture_scale: scale_mode.texture_scale_from_resolution(new_size),
};
queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[uniforms]));
}
@@ -126,16 +127,6 @@ impl Filter for CrtFilter {
}
}
fn texture_scale_from_resolution(res: PhysicalSize<u32>) -> [f32; 4] {
let scale = ((res.width as f32) / 160.0).min((res.height as f32) / 120.0);
[
res.width as f32 / scale,
res.height as f32 / scale,
2.0 / scale,
0.0,
]
}
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct Uniforms {
+1 -1
View File
@@ -17,7 +17,7 @@ fn vs_main(
let i = in_vertex_index / 3u + in_vertex_index % 3u;
let x = -1.0 + f32(i % 2u) * 322.0;
let y = -1.0 + f32(i / 2u) * 242.0;
out.clip_position = vec4<f32>((vec2<f32>(x, y) - vec2<f32>(160.0, 120.0)) / uniforms.texture_scale.xy, 0.0, 1.0);
out.clip_position = vec4<f32>((vec2<f32>(x, y) - vec2<f32>(160.0, 120.0)) * uniforms.texture_scale.xy, 0.0, 1.0);
out.tex_coords = vec2<f32>(x, y);
return out;
}
+5 -14
View File
@@ -1,7 +1,7 @@
use wgpu::util::DeviceExt;
use winit::dpi::PhysicalSize;
use super::Filter;
use super::{scale_mode::ScaleMode, Filter};
pub struct FastCrtFilter {
uniform_buffer: wgpu::Buffer,
@@ -16,9 +16,10 @@ impl FastCrtFilter {
resolution: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
chromatic: bool,
scale_mode: ScaleMode,
) -> FastCrtFilter {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(resolution),
texture_scale: scale_mode.texture_scale_from_resolution(resolution),
};
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
@@ -131,9 +132,9 @@ impl FastCrtFilter {
}
impl Filter for FastCrtFilter {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>, scale_mode: ScaleMode) {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(new_size),
texture_scale: scale_mode.texture_scale_from_resolution(new_size),
};
queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[uniforms]));
}
@@ -145,16 +146,6 @@ impl Filter for FastCrtFilter {
}
}
fn texture_scale_from_resolution(res: PhysicalSize<u32>) -> [f32; 4] {
let scale = ((res.width as f32) / 160.0).min((res.height as f32) / 120.0);
[
scale / res.width as f32,
scale / res.height as f32,
2.0 / scale,
0.0,
]
}
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct Uniforms {
+2 -2
View File
@@ -30,8 +30,8 @@ fn row_factor(offset: f32) -> f32 {
}
fn col_factor(offset: f32) -> f32 {
let offset = max(0.0, abs(offset) - 0.4);
return 1.0 / (1.0 + offset * offset * 16.0);
let o = max(0.0, abs(offset) - 0.4);
return 1.0 / (1.0 + o * o * 16.0);
}
fn sample_screen(tex_coords: vec2<f32>) -> vec4<f32> {
+52 -15
View File
@@ -1,6 +1,7 @@
use crate::{Input, WindowConfig, WindowImpl};
use anyhow::{anyhow, Result};
use std::{num::NonZeroU32, time::Instant};
use scale_mode::ScaleMode;
use std::time::Instant;
use winit::{
dpi::PhysicalSize,
@@ -13,6 +14,7 @@ use winit::platform::run_return::EventLoopExtRunReturn;
mod crt;
mod fast_crt;
pub mod scale_mode;
mod square;
use crt::CrtFilter;
@@ -34,6 +36,7 @@ pub struct Window {
next_frame: Instant,
is_fullscreen: bool,
is_open: bool,
scale_mode: ScaleMode,
}
impl Window {
@@ -41,7 +44,10 @@ impl Window {
async fn create(window_config: WindowConfig) -> Result<Window> {
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_inner_size(PhysicalSize::new(640u32, 480))
.with_inner_size(PhysicalSize::new(
(320. * window_config.scale).round() as u32,
(240. * window_config.scale).round() as u32,
))
.with_min_inner_size(PhysicalSize::new(320u32, 240))
.with_title("MicroW8")
.with_fullscreen(if window_config.fullscreen {
@@ -72,7 +78,13 @@ impl Window {
let surface_config = wgpu::SurfaceConfiguration {
present_mode: wgpu::PresentMode::AutoNoVsync,
..surface.get_default_config(&adapter, window.inner_size().width, window.inner_size().height).expect("Surface incompatible with adapter")
..surface
.get_default_config(
&adapter,
window.inner_size().width,
window.inner_size().height,
)
.expect("Surface incompatible with adapter")
};
let filter: Box<dyn Filter> = create_filter(
@@ -81,6 +93,7 @@ impl Window {
window.inner_size(),
surface_config.format,
window_config.filter,
window_config.scale_mode,
);
surface.configure(&device, &surface_config);
@@ -100,6 +113,7 @@ impl Window {
next_frame: Instant::now(),
is_fullscreen: window_config.fullscreen,
is_open: true,
scale_mode: window_config.scale_mode,
})
}
@@ -119,7 +133,7 @@ impl WindowImpl for Window {
self.surface_config.width = new_size.width;
self.surface_config.height = new_size.height;
self.surface.configure(&self.device, &self.surface_config);
self.filter.resize(&self.queue, new_size);
self.filter.resize(&self.queue, new_size, self.scale_mode);
}
WindowEvent::CloseRequested => {
self.is_open = false;
@@ -156,6 +170,20 @@ impl WindowImpl for Window {
self.is_fullscreen = fullscreen.is_some();
self.window.set_fullscreen(fullscreen);
}
Some(VirtualKeyCode::M) => {
self.scale_mode = match self.scale_mode {
ScaleMode::Fit => ScaleMode::Fill,
ScaleMode::Fill => ScaleMode::Fit,
};
self.filter.resize(
&self.queue,
PhysicalSize {
width: self.surface_config.width,
height: self.surface_config.height,
},
self.scale_mode,
);
}
Some(VirtualKeyCode::R) => reset = true,
Some(VirtualKeyCode::Key1) => new_filter = Some(1),
Some(VirtualKeyCode::Key2) => new_filter = Some(2),
@@ -189,6 +217,7 @@ impl WindowImpl for Window {
self.window.inner_size(),
self.surface_config.format,
new_filter,
self.scale_mode,
);
}
});
@@ -251,6 +280,7 @@ fn create_filter(
window_size: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
filter: u32,
scale_mode: ScaleMode,
) -> Box<dyn Filter> {
match filter {
1 => Box::new(SquareFilter::new(
@@ -258,6 +288,7 @@ fn create_filter(
screen_texture,
window_size,
surface_format,
scale_mode,
)),
2 => Box::new(FastCrtFilter::new(
device,
@@ -265,12 +296,14 @@ fn create_filter(
window_size,
surface_format,
false,
scale_mode,
)),
3 => Box::new(CrtFilter::new(
device,
screen_texture,
window_size,
surface_format,
scale_mode,
)),
4 => Box::new(FastCrtFilter::new(
device,
@@ -278,18 +311,20 @@ fn create_filter(
window_size,
surface_format,
true,
scale_mode,
)),
_ => Box::new(AutoCrtFilter::new(
device,
screen_texture,
window_size,
surface_format,
scale_mode,
)),
}
}
trait Filter {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>);
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>, scale_mode: ScaleMode);
fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>);
}
@@ -305,9 +340,11 @@ impl AutoCrtFilter {
screen: &wgpu::TextureView,
resolution: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
scale_mode: ScaleMode,
) -> AutoCrtFilter {
let small = CrtFilter::new(device, screen, resolution, surface_format);
let large = FastCrtFilter::new(device, screen, resolution, surface_format, true);
let small = CrtFilter::new(device, screen, resolution, surface_format, scale_mode);
let large =
FastCrtFilter::new(device, screen, resolution, surface_format, true, scale_mode);
AutoCrtFilter {
small,
large,
@@ -317,9 +354,9 @@ impl AutoCrtFilter {
}
impl Filter for AutoCrtFilter {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
self.small.resize(queue, new_size);
self.large.resize(queue, new_size);
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>, scale_mode: ScaleMode) {
self.small.resize(queue, new_size, scale_mode);
self.large.resize(queue, new_size, scale_mode);
self.resolution = new_size;
}
@@ -354,7 +391,7 @@ impl PaletteScreenMode {
format: wgpu::TextureFormat::R8Uint,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
label: None,
view_formats: &[]
view_formats: &[],
});
let palette_texture = device.create_texture(&wgpu::TextureDescriptor {
@@ -369,7 +406,7 @@ impl PaletteScreenMode {
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
label: None,
view_formats: &[]
view_formats: &[],
});
let screen_texture = device.create_texture(&wgpu::TextureDescriptor {
@@ -384,7 +421,7 @@ impl PaletteScreenMode {
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
label: None,
view_formats: &[]
view_formats: &[],
});
let framebuffer_texture_view =
@@ -491,7 +528,7 @@ impl PaletteScreenMode {
&bytemuck::cast_slice(pixels),
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: NonZeroU32::new(320),
bytes_per_row: Some(320),
rows_per_image: None,
},
wgpu::Extent3d {
@@ -513,7 +550,7 @@ impl PaletteScreenMode {
&bytemuck::cast_slice(palette),
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: NonZeroU32::new(256 * 4),
bytes_per_row: Some(256 * 4),
rows_per_image: None,
},
wgpu::Extent3d {
+28
View File
@@ -0,0 +1,28 @@
use winit::dpi::PhysicalSize;
#[derive(Debug, Copy, Clone)]
pub enum ScaleMode {
Fit,
Fill,
}
impl Default for ScaleMode {
fn default() -> ScaleMode {
ScaleMode::Fit
}
}
impl ScaleMode {
pub fn texture_scale_from_resolution(&self, res: PhysicalSize<u32>) -> [f32; 4] {
let scale = match self {
ScaleMode::Fit => ((res.width as f32) / 160.0).min((res.height as f32) / 120.0),
ScaleMode::Fill => ((res.width as f32) / 160.0).max((res.height as f32) / 120.0),
};
[
scale / res.width as f32,
scale / res.height as f32,
2.0 / scale,
0.0,
]
}
}
+5 -14
View File
@@ -1,7 +1,7 @@
use wgpu::util::DeviceExt;
use winit::dpi::PhysicalSize;
use super::Filter;
use super::{scale_mode::ScaleMode, Filter};
pub struct SquareFilter {
uniform_buffer: wgpu::Buffer,
@@ -15,9 +15,10 @@ impl SquareFilter {
screen: &wgpu::TextureView,
resolution: PhysicalSize<u32>,
surface_format: wgpu::TextureFormat,
scale_mode: ScaleMode,
) -> SquareFilter {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(resolution),
texture_scale: scale_mode.texture_scale_from_resolution(resolution),
};
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
@@ -126,9 +127,9 @@ impl SquareFilter {
}
impl Filter for SquareFilter {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>) {
fn resize(&mut self, queue: &wgpu::Queue, new_size: PhysicalSize<u32>, scale_mode: ScaleMode) {
let uniforms = Uniforms {
texture_scale: texture_scale_from_resolution(new_size),
texture_scale: scale_mode.texture_scale_from_resolution(new_size),
};
queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[uniforms]));
}
@@ -140,16 +141,6 @@ impl Filter for SquareFilter {
}
}
fn texture_scale_from_resolution(res: PhysicalSize<u32>) -> [f32; 4] {
let scale = ((res.width as f32) / 160.0).min((res.height as f32) / 120.0);
[
scale / res.width as f32,
scale / res.height as f32,
2.0 / scale,
0.0,
]
}
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct Uniforms {
+14 -1
View File
@@ -1,4 +1,5 @@
use anyhow::Result;
use gpu::scale_mode::ScaleMode;
use std::time::Instant;
mod cpu;
@@ -15,7 +16,7 @@ struct FpsCounter {
}
impl Window {
pub fn new(config: WindowConfig) -> Result<Window> {
pub fn new(mut config: WindowConfig) -> Result<Window> {
let fps_counter = if config.fps_counter {
Some(FpsCounter {
start: Instant::now(),
@@ -24,6 +25,7 @@ impl Window {
} else {
None
};
config.scale = config.scale.max(1.).min(20.);
if config.enable_gpu {
match gpu::Window::new(config) {
Ok(window) => {
@@ -71,6 +73,8 @@ pub struct WindowConfig {
filter: u32,
fullscreen: bool,
fps_counter: bool,
scale: f32,
scale_mode: ScaleMode,
}
impl Default for WindowConfig {
@@ -80,6 +84,8 @@ impl Default for WindowConfig {
filter: 5,
fullscreen: false,
fps_counter: false,
scale: 2.,
scale_mode: ScaleMode::Fit,
}
}
}
@@ -102,6 +108,13 @@ impl WindowConfig {
}
self.fullscreen = args.contains("--fullscreen");
self.fps_counter = args.contains("--fps");
self.scale = args
.opt_value_from_str("--scale")
.unwrap()
.unwrap_or(self.scale);
if args.contains("--scale-fill") {
self.scale_mode = ScaleMode::Fill;
}
}
}
+2 -1
View File
@@ -4,5 +4,6 @@
"@parcel/optimizer-data-url": "^2.0.0",
"@parcel/transformer-inline-string": "^2.0.0",
"parcel": "^2.0.0"
}
},
"dependencies": {}
}
+1 -1
View File
@@ -10,7 +10,7 @@
</head>
<body>
<div id="uw8">
<a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.2.2
<a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.4.1
</div>
<div id="centered">
<canvas class="screen" id="screen" width="320" height="240">
+8 -5
View File
@@ -240,6 +240,7 @@ export default function MicroW8(screen, config = {}) {
await audioReadyPromise;
let startTime = Date.now();
let frameCounter = 0;
const timePerFrame = 1000 / 60;
@@ -274,7 +275,7 @@ export default function MicroW8(screen, config = {}) {
try {
let restart = false;
let nextFrame = 0;
let thisFrame;
if (!isPaused) {
let gamepads = navigator.getGamepads();
let gamepad = 0;
@@ -306,6 +307,7 @@ export default function MicroW8(screen, config = {}) {
let time = Date.now() - startTime;
u32Mem[16] = time;
u32Mem[17] = pad | gamepad;
u32Mem[18] = frameCounter++;
if(instance.exports.upd) {
instance.exports.upd();
}
@@ -321,12 +323,13 @@ export default function MicroW8(screen, config = {}) {
}
canvasCtx.putImageData(imageData, 0, 0);
let thisFrame = Math.floor(time * 6 / 100);
let timeOffset = time - thisFrame * 100 / 6;
nextFrame = Math.ceil(startTime + (thisFrame + 1) * 100 / 6 + Math.min(4, timeOffset));
let timeOffset = ((time * 6) % 100 - 50) / 6;
thisFrame = startTime + time - timeOffset / 8;
} else {
thisFrame = Date.now();
}
let now = Date.now();
nextFrame = Math.max(nextFrame, now);
let nextFrame = Math.max(thisFrame + timePerFrame, now);
if (restart) {
runModule(currentData);
+966 -780
View File
File diff suppressed because it is too large. Load diff