add input to web runtime, add v0.1pre3 to site

This commit is contained in:
dranke committed 2021-12-01 23:36:39 +01:00
1 parent 04c2c1aeb0
commit aba00b1cae
9 files changed
+122 -28

No files matched your search

-6
View File
@@ -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;
+1
View File
@@ -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
+39 -8
View File
@@ -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.
* [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.
+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>body,canvas,html{margin:0;padding:0}html{background-color:#202024;color:#808070;font-family:Josefin Sans,Verdana,Arial Black,sans-serif}body,html{height:100%}body{display:grid;grid-template-rows:1fr 0fr}#centered{align-self:center;justify-self:center}.footer{color:#202420}a{color:#303630}a:hover{color:#405040}#screen{background-color:#202428;border:4px solid #303040;box-shadow:5px 5px 20px #000;cursor:none;height:240px;image-rendering:pixelated;width:320px}#message,#screen{margin-bottom:8px}.error{color:#e04030}button{background-color:#303440;border:1px solid #404040;border-radius:4px;color:#808070;font-family:inherit;padding:4px}button:hover{background-color:#202010}button:active{background-color:#504450}@media (min-width:680px) and (min-height:560px){#screen{height:480px;width:640px}}@media (min-width:1000px) and (min-height:800px){#screen{height:720px;width:960px}}</style></head><body> <div id="centered"> <canvas id="screen" width="320" height="240"></canvas> <div id="message"></div> <button id="cartButton">Load cart...</button> </div> <div id="footer"> <a href="http://unlicense.org/" ref="license">Unlicense</a> </div> </body><script type="module">function A(A){return A&&A.__esModule?A.default:A}function e(A,e){let t=A?`${A} bytes`:"Insert cart";e&&(t+=` - <span class="error">${e.replaceAll("<","&lt;")}</span>`),document.getElementById("message").innerHTML=t}let t,a,B=document.getElementById("screen"),n=B.getContext("2d"),o=n.createImageData(320,240),Q=A=>new Uint8Array(A),i=A=>new Uint32Array(A),r=0,s=A=>{let e,t="keydown"==A.type;switch(A.code){case"ArrowUp":e=1;break;case"ArrowDown":e=2;break;case"ArrowLeft":e=4;break;case"ArrowRight":e=8;break;case"KeyZ":e=16;break;case"KeyX":e=32;break;case"KeyA":e=64;break;case"KeyS":e=128;break;case"KeyR":t&&c(a)}t?r|=e:r&=~e};async function c(s){t&&(t(),t=null);let c=s.byteLength;if(e(c),0==c)return;a=s;let w=window.location.pathname;if(c<=1024){let A="";for(let e of Q(s))A+=String.fromCharCode(e);w+="#"+btoa(A)}w!=window.location.pathname+window.location.hash&&history.pushState(null,null,w),B.width=B.width;try{let a,B=new WebAssembly.Memory({initial:4,maximum:4}),w=Q(B.buffer),I={env:{memory:B}},E=A=>{if(0!=Q(A)[0]){w.set(Q(A));let e=a.exports.load_uw8(A.byteLength);A=new ArrayBuffer(e),Q(A).set(w.slice(0,e))}return A},g=async A=>new WebAssembly.Instance(await WebAssembly.compile(A),I),l=async A=>g(E(await(await fetch(A)).arrayBuffer()));a=await l(A("data:application/wasm;base64,AGFzbQEAAAABFQRgAX8Bf2ACf38Bf2ADf39%2FAGAAAAIPAQNlbnYGbWVtb3J5AgAEAwkIAAABAgEAAAMGEAN%2FAUEAC38BQQALfwFBAAsHGQIIbG9hZF91dzgAAAp1bmNvbXByZXNzAAQIAQcKxwUIxwEBB39BAC0AAEEBayIBQQBIBEAgAA8LQYDAByAAaiECIAFBAXEEQEEBQYHABxAEIQIFQYDAB0EAIAAQAwtBAEGAkA9BCBADQYiQDyEDQQghBEGBwAchBQNAIAUgAkggAyMATiAFLQAAIAMtAABMcnEEQCAEIAQgBRACIgZqIQQgAyMASCAFLQAAIAMtAABGcQRAIAMgAxABaiEDCyAFIAZqIQUMAQsgAyMASARAIAQgBCADEAIiB2ohBCADIAdqIQMMAQsLIAQLRwEEfyAAQQFqIQFBACECQQAhAwNAIAIgAS0AACIEQf8AcSADdHIhAiADQQdqIQMgAUEBaiEBIARBgAFxDQALIAEgAGsgAmoLEgEBfyAAIAEgARABIgIQAyACCyYAIAJBAEoEQANAIAAgAkEBayICaiABIAJqLQAAOgAAIAINAAsLC6cBAQR%2FIAAkAUEAJAIDQCAEQYAQNgKAgA8gBEEEaiIEQYQMSA0ACwJAA0BBABAGBEBBgAIQBgRAQYECEAVBAWshAiACRQ0DC0HBAhAFIQUDQCABIAEgAmstAAA6AAAgAUEBaiEBIAVBAWsiBQ0ACwVBACEEQQEhAwNAIANBAXQgAxAGciEDIARBAWoiBEEISA0ACyABIAM6AAAgAUEBaiEBCwwACwsgAQs1AQJ%2FA0AgABAGBEAgASAAQQFqEAYgAnRyIQEgAEECaiEAIAJBAWohAgwBCwsgAUEBIAJ0cguNAQEDfyAAQQRsKAKAgA8hAQNAIwJBgIAESARAIwJBCHQjAS0AAHIkAiMBQQFqJAEMAQsLIwJB%2Fx9xIgIgAUghAyADBEAgASMCQQx1bCACaiQCIAFBgCAgAWtBBHVqIQEFQYAgIAFrIwJBDHVsIAJqIAFrJAIgASABQQR1ayEBCyAAQQRsIAE2AoCADyADCwwAQQBBgJAPEAQkAAsLowMBAEEAC5wDB3v59FcZoAI7mCitTJSZSOWtKzoBW6JIrDZYF1%2FesWuNYDvyk9d%2F8%2BETEuIqpGSjTPa14Ux09aUDW0ipoTypDKubKn1EsOc9qfp80AozM6iwVO6lNxiLdB8GLSCRDa9OxEyyvUrTQ6Jw3vm7Stv8Q0PC4uLr%2BOZltzh59ubzeQBw%2BaUBKmTURiM8Mz8s1QWzrPWIPgy6UL4xD4YGClEY7%2B8HPyAWsyMuqFzyMQq0JZ7KiZ1ka%2Bz5tK2EjmMS2JAK%2BMp1DV6UOoZX3SD6IjmLPq5CtVvvxHbcGN9bzKTxTOHoValxjTO6KCanYHMbHa%2FKh6IN54GXufzOqPr8CAK8mS2rbaAg4oZ3G%2Bx8fKWQULcD3jK7t9GuNEXbVvjPcaAhrFcdhwmhLHNDrpyfwdZCMl0Y6jHYYJ7jsrC3NWfnAQp5pjO9uB8EcCaib%2FQ0069RwJJGVXEpuskBKVDcH%2BcuWp%2FVG6qFOF8FawL%2BkbkeWggQ97XARmHYeW2DEUtsUc6LqsvIlvOLmtHMyIX6pHRym%2B%2Bj5ZiOzZV8MdYnwA%3D%3D"));for(let A of["acos","asin","atan","atan2","cos","exp","log","sin","tan","pow"])I.env[A]=Math[A];for(let A=9;A<64;++A)I.env["reserved"+A]=()=>{};for(let A=0;A<16;++A)I.env["g_reserved"+A]=0;s=E(s);let y=await l(A("data:;base64,Ahn%2Bv8r9pWTLs%2BBkc6gWAmI81dApfo5qs1VuM3H1BjjcuP%2B3C1zurwgMKGzjUBUcg2j3RaMu0JOyGisd6YxMnyvTjSmpujQoQ2RctRsxWmdqiH8fDlwSYtbCyZdkOrk9iWPCJ4apdA7KcO%2FmtTLOJPAbZvNTQ%2BvKK2lyfRIxtOmP%2BH%2Fo36EhPESIugZr%2BP3RAtUurxtqTLe%2FlO2WSkV5K%2B3o%2B%2BH52Pn5hdF3DNjdLq7JXdYBFRtzKExqMbXVS5i4dzxy38faxjRgNpdmzui37Hr5sqQ%2FfJ4Q0UwFY6QwAjskqBVIHIGwcrA8YeytCCwIezmxi1jMxXK5P6VwrsTw7pUVRt1yYjNNh0akkvJOUY1NtdaOFPtZ0foHwEk7ml8GQ7Line truncated
+2 -2
View File
@@ -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;
}
+1 -1
View File
@@ -4,7 +4,7 @@
<section>
<h1 class="text-center heading-text">A WebAssembly based sizecoding platform</h1>
</section>
<a href="v0.1pre2">
<a href="v0.1pre3">
<div class="demonstration-gif" style="width:640px;height:512px;background-color:black"></div>
</a>
</div>
+10 -4
View File
@@ -24,6 +24,7 @@ struct UW8Instance {
end_frame: TypedFunc<(), ()>,
update: TypedFunc<(), ()>,
start_time: Instant,
module: Vec<u8>
}
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
+67 -7
View File
@@ -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) {
+1
View File
@@ -41,6 +41,7 @@ a:hover {
margin-bottom: 8px;
border: 4px solid #303040;
box-shadow: 5px 5px 20px black;
cursor: none;
}
#message {