diff --git a/examples/curlywas/skipahead.cwa b/examples/curlywas/skipahead.cwa index 978ce90..215f161 100644 --- a/examples/curlywas/skipahead.cwa +++ b/examples/curlywas/skipahead.cwa @@ -38,12 +38,6 @@ export fn upd() { if y == 180 & py > zero { if x > w | x < zero { - - if btn(5) { - pz = 5; - px = 2 as f32; - } - return; } py = zero; diff --git a/site/config.toml b/site/config.toml index 7eb32f1..f12febd 100644 --- a/site/config.toml +++ b/site/config.toml @@ -13,6 +13,7 @@ theme = "juice" # Whether to do syntax highlighting # Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola highlight_code = true +highlight_theme = "ascetic-white" [extra] # Put all your custom variables here diff --git a/site/content/_index.md b/site/content/_index.md index f509610..c793f22 100644 --- a/site/content/_index.md +++ b/site/content/_index.md @@ -5,13 +5,14 @@ * [v0.1pre1](v0.1pre1) * [v0.1pre2](v0.1pre2) +* [v0.1pre3](v0.1pre3) ## Spec MicroW8 loads WebAssembly modules with a maximum size of 256kb. You module needs to export -a function `fn tic(time: i32)` which will be called once per frame. -After calling `tic` MicroW8 will display the 320x256 8bpp framebuffer located -at offset 120 in memory with the 32bpp palette located at 82040. +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. The memory has to be imported as `"env" "memory"` and has a maximum size of 256kb (4 pages). @@ -40,6 +41,29 @@ Other imports provided by the platform, also all in module `env`: * `fn rectangle(x1: f32, y1: f32, x2: f32, y2: f32, color: i32)` * `fn circle(cx: f32, cy: f32, radius: f32, color: i32)` +* `fn time() -> f32` +* `fn isButtonPressed(btn: i32) -> i32` +* `fn isButtonTriggered(btn: i32) -> i32` + +* `fn printChar(char: i32)` +* `fn printString(ptr: i32)` +* `fn printInt(num: i32)` + +### Memory map + +``` +00000-00040: user memory +00040-00044: time since module start in ms +00044-0004c: gamepad state +0004c-00078: reserved +00078-12c78: frame buffer +12c78-13000: reserved +13000-13400: palette +13400-13c00: font +13c00-14000: reserved +14000-40000: user memory +``` + ## `.uw8` format The first byte of the file specifies the format version: @@ -62,7 +86,12 @@ types with up to 5 parameters (i32 or f32) where the Then it includes all imports that MicroW8 provides, a function section with a single function of type `(i32) -> void` and an export section that exports -the first function in the file under the name `tic`. +the first function in the file under the name `upd`. + +#### Format version `02`: + +Same as version `01` except everything after the first byte is compressed +using a [custom LZ compression scheme](https://github.com/exoticorn/upkr). ## Tooling @@ -82,7 +111,9 @@ Writing code for MicroW8 in C, Rust, AssemblyScript etc. should absolutely possible but no examples are provided, yet. ## Examples - -* [Technotunnel](v0.1pre2#AQrDAQHAAQIBfwp9A0AgAUEAsiABQcACb7JDmhkgQ5MiBCAEIASUIAFBwAJtQfgAa7IiBSAFlJKRIgaVIgcgByAAskHQD7KVIgIQAEPNzEw/lCIDlCAHIAeUIAOUIAOUQQGykiADIAOUk5GSIgiUIAOTQQqylCACkiIJqCAFIAaVIAiUQQqylCACkiIKqHMgCEEyspQgBpUiCyACkkEUspSocUEFcbJBArIgC5OUQRaylJeoOgB4IAFBAWoiAUGA2ARIDQALCw==) (199 bytes): A port of my [entry](https://tic80.com/play?cart=1873) in the Outline'21 bytebattle quater final -* [XorScroll](v0.1pre2#AQovAS0BAX8DQCABIAFBwAJvIABBCm1qIAFBwAJtczoAeCABQQFqIgFBgNgESA0ACws=) (50 bytes): A simple scrolling XOR pattern. Fun fact: This is the pre-loaded effect when entering a bytebattle. -* [CircleWorm](v0.1pre2#AQp7AXkCAX8CfUEgEA0DQCABskEEspUiAkECspUgALJBiCeylSIDQQWylJIQAEEBspJBoAGylCACQQOylSADQQSylJIQAEEBspJB+ACylCADQRGylCACQQKylJIQAEECspJBELKUIAFBAmxBP2oQEiABQQFqIgFBP0gNAAsL) (126 bytes): Just a test for the circle fill function. \ No newline at end of file +* [Skip Ahead](v0.1pre3#Agj9nQYWw+yYP6xi7SUL2urlNtvh2dOZFuYL4PUxAUz5qqATDey0JsAVat2VQKEOyXK1bE+3WiFK0GGhdi4VAd8Tlf3YuU7xfvvBwN4oNuIoY29jbbuEnEnPZFjC4ym9L2QDUmig+RsF++FubWcyqOt7CAFGNEaAiMISCIM43bfPQriE6sD3orstkMjH3LPOqeuUPpitgzaIsAf860CYHlrAG2t5CSjRGobcPLJ+CSeYjzZSLYs7+u2xpthsfoIvBnk1+xxwEWYfZOJ3Madfo5BME5nceVCQVOEBMCTLSE+xVCkyelOW) (231 bytes): A port of my [TIC-80 256byte game](http://tic80.com/play?cart=1735) from LoveByte'21 +* [OhNoAnotherTunnel](v0.1pre3#Apr9u4e6Rsy7tRABjq4o7dCGPLQR9dVTSGK9FWXemB7tybsZHT+TxtfHlarRbcekGcg7qZY/eK6/VVCp9ceNBXlh4v0QGS63LTzfEjb8XC4jg5KifbYBodSIS0DPVjwq32PbgjL2+C+QOCx6ZxqRYP0KQpcTxuBUKx1NXVM2EV4l0rEWBQW9SjLcbURKHYaRLcI4FOcLOfASFiQ4wFWgEBA0VD6hGdemN0tPYp9BfUaN) (177 bytes): A port of my [entry](http://tic80.com/play?cart=1871) in the Outline'21 bytebattle final +* [Technotunnel](v0.1pre3#AkL/tETJ+XRrvcB8gD9brftZ26zjwEsiATnAd+szCtw3Haq41srEMFO8aDS71c2CX8W87RQ9EY3V+YuTn/2CPRfn6CpgxMHUnIxOEWhVDRULXeYGP70dTiL8tYLAc8LrBWay9h8jCX/4Jbb39XVnISlZNd7In4Mts9LvSkSIz/E0sBfhjwp65aeoSU8BNFZpyKlxU+u5DdBtuxx3bFE=) (158 bytes): A port of my [entry](https://tic80.com/play?cart=1873) in the Outline'21 bytebattle quater final +* [Technotunnel B/W](v0.1pre2#AQrDAQHAAQIBfwp9A0AgAUEAsiABQcACb7JDmhkgQ5MiBCAEIASUIAFBwAJtQfgAa7IiBSAFlJKRIgaVIgcgByAAskHQD7KVIgIQAEPNzEw/lCIDlCAHIAeUIAOUIAOUQQGykiADIAOUk5GSIgiUIAOTQQqylCACkiIJqCAFIAaVIAiUQQqylCACkiIKqHMgCEEyspQgBpUiCyACkkEUspSocUEFcbJBArIgC5OUQRaylJeoOgB4IAFBAWoiAUGA2ARIDQALCw==) (199 bytes uncompressed): A port of my [entry](https://tic80.com/play?cart=1873) in the Outline'21 bytebattle quater final (older MicroW8 version with monochrome palette) +* [XorScroll](v0.1pre2#AQovAS0BAX8DQCABIAFBwAJvIABBCm1qIAFBwAJtczoAeCABQQFqIgFBgNgESA0ACws=) (50 bytes uncompressed): A simple scrolling XOR pattern. Fun fact: This is the pre-loaded effect when entering a bytebattle. +* [CircleWorm](v0.1pre2#AQp7AXkCAX8CfUEgEA0DQCABskEEspUiAkECspUgALJBiCeylSIDQQWylJIQAEEBspJBoAGylCACQQOylSADQQSylJIQAEEBspJB+ACylCADQRGylCACQQKylJIQAEECspJBELKUIAFBAmxBP2oQEiABQQFqIgFBP0gNAAsL) (126 bytes uncompressed): Just a test for the circle fill function. \ No newline at end of file diff --git a/site/static/v0.1pre3/index.html b/site/static/v0.1pre3/index.html new file mode 100644 index 0000000..63fd6d3 --- /dev/null +++ b/site/static/v0.1pre3/index.html @@ -0,0 +1 @@ +MicroW8
\ No newline at end of file diff --git a/site/templates/_variables.html b/site/templates/_variables.html index e61fb1e..7915337 100644 --- a/site/templates/_variables.html +++ b/site/templates/_variables.html @@ -7,8 +7,8 @@ /* Primary theme link color */ --primary-link-color: #8080a0; /* Secondary color: the background body color */ - --secondary-color: #e4dfd7; - --secondary-text-color: #303030; + --secondary-color: #e0e0e8; + --secondary-text-color: #1a1818; /* Highlight text color of table of content */ --toc-highlight-text-color: #d46e13; } diff --git a/site/templates/index.html b/site/templates/index.html index 6cbb8db..acfe2c5 100644 --- a/site/templates/index.html +++ b/site/templates/index.html @@ -4,7 +4,7 @@

A WebAssembly based sizecoding platform

- +
diff --git a/src/lib.rs b/src/lib.rs index 88be069..3af612e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ struct UW8Instance { end_frame: TypedFunc<(), ()>, update: TypedFunc<(), ()>, start_time: Instant, + module: Vec } impl MicroW8 { @@ -68,7 +69,7 @@ impl MicroW8 { self.load_from_memory(&module) } - pub fn load_from_memory(&mut self, module: &[u8]) -> Result<()> { + pub fn load_from_memory(&mut self, module_data: &[u8]) -> Result<()> { self.reset(); let mut store = wasmtime::Store::new(&self.engine, ()); @@ -88,8 +89,8 @@ impl MicroW8 { let platform_module = wasmtime::Module::new(&self.engine, &memory.data(&store)[..platform_length])?; - memory.data_mut(&mut store)[..module.len()].copy_from_slice(module); - let module_length = load_uw8.call(&mut store, module.len() as i32)? as u32 as usize; + memory.data_mut(&mut store)[..module_data.len()].copy_from_slice(module_data); + let module_length = load_uw8.call(&mut store, module_data.len() as i32)? as u32 as usize; let module = wasmtime::Module::new(&self.engine, &memory.data(&store)[..module_length])?; linker.func_wrap("env", "acos", |v: f32| v.acos())?; @@ -139,6 +140,7 @@ impl MicroW8 { end_frame, update, start_time: Instant::now(), + module: module_data.into() }); Ok(()) @@ -174,7 +176,11 @@ impl MicroW8 { | palette[offset + 2] as u32; } - self.instance = Some(instance); + if self.window.is_key_pressed(Key::R, minifb::KeyRepeat::No) { + self.load_from_memory(&instance.module)?; + } else { + self.instance = Some(instance); + } } self.window diff --git a/web/src/main.js b/web/src/main.js index cb028b6..3dfbcc8 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -15,7 +15,56 @@ let imageData = canvasCtx.createImageData(320, 240); let cancelFunction; +let currentData; + let U8 = (d) => new Uint8Array(d); +let U32 = (d) => new Uint32Array(d); + +let pad = 0; +let keyHandler = (e) => { + let isKeyDown = e.type == 'keydown'; + let mask; + switch(e.code) { + case 'ArrowUp': + mask = 1; + break; + case 'ArrowDown': + mask = 2; + break; + case 'ArrowLeft': + mask = 4; + break; + case 'ArrowRight': + mask = 8; + break; + case 'KeyZ': + mask = 16; + break; + case 'KeyX': + mask = 32; + break; + case 'KeyA': + mask = 64; + break; + case 'KeyS': + mask = 128; + break; + case 'KeyR': + if(isKeyDown) + { + runModule(currentData); + } + break; + } + + if(isKeyDown) { + pad |= mask; + } else { + pad &= ~mask; + } +}; +window.onkeydown = keyHandler; +window.onkeyup = keyHandler; async function runModule(data) { if (cancelFunction) { @@ -30,6 +79,8 @@ async function runModule(data) { return; } + currentData = data; + let newURL = window.location.pathname; if (cartridgeSize <= 1024) { let dataString = ''; @@ -94,27 +145,36 @@ async function runModule(data) { let instance = await instantiate(data); - let buffer = new Uint32Array(imageData.data.buffer); + let buffer = U32(imageData.data.buffer); let startTime = Date.now(); let keepRunning = true; cancelFunction = () => keepRunning = false; + const timePerFrame = 1000 / 60; + let nextFrame = startTime; + function mainloop() { if (!keepRunning) { return; } try { - new Uint32Array(memory.buffer)[16] = Date.now() - startTime; - instance.exports.upd(); + let now = Date.now(); + if(now >= nextFrame) { + let u32Mem = U32(memory.buffer); + u32Mem[16] = now - startTime; + u32Mem[17] = pad; + instance.exports.upd(); - let palette = new Uint32Array(memory.buffer.slice(0x13000, 0x13000 + 1024)); - for (let i = 0; i < 320 * 240; ++i) { - buffer[i] = palette[memU8[i + 120]] | 0xff000000; + let palette = U32(memory.buffer.slice(0x13000, 0x13000 + 1024)); + for (let i = 0; i < 320 * 240; ++i) { + buffer[i] = palette[memU8[i + 120]] | 0xff000000; + } + canvasCtx.putImageData(imageData, 0, 0); + nextFrame = Math.max(nextFrame + timePerFrame, now); } - canvasCtx.putImageData(imageData, 0, 0); window.requestAnimationFrame(mainloop); } catch (err) { diff --git a/web/src/style.css b/web/src/style.css index b0d3350..c481f1d 100644 --- a/web/src/style.css +++ b/web/src/style.css @@ -41,6 +41,7 @@ a:hover { margin-bottom: 8px; border: 4px solid #303040; box-shadow: 5px 5px 20px black; + cursor: none; } #message {