mirror of
https://github.com/exoticorn/microw8.git
synced 2026-01-20 11:16:42 +01:00
add input to web runtime, add v0.1pre3 to site
This commit is contained in:
@@ -38,12 +38,6 @@ export fn upd() {
|
|||||||
|
|
||||||
if y == 180 & py > zero {
|
if y == 180 & py > zero {
|
||||||
if x > w | x < zero {
|
if x > w | x < zero {
|
||||||
|
|
||||||
if btn(5) {
|
|
||||||
pz = 5;
|
|
||||||
px = 2 as f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
py = zero;
|
py = zero;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ theme = "juice"
|
|||||||
# Whether to do syntax highlighting
|
# Whether to do syntax highlighting
|
||||||
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
|
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
|
||||||
highlight_code = true
|
highlight_code = true
|
||||||
|
highlight_theme = "ascetic-white"
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
# Put all your custom variables here
|
# Put all your custom variables here
|
||||||
|
|||||||
@@ -5,13 +5,14 @@
|
|||||||
|
|
||||||
* [v0.1pre1](v0.1pre1)
|
* [v0.1pre1](v0.1pre1)
|
||||||
* [v0.1pre2](v0.1pre2)
|
* [v0.1pre2](v0.1pre2)
|
||||||
|
* [v0.1pre3](v0.1pre3)
|
||||||
|
|
||||||
## Spec
|
## Spec
|
||||||
|
|
||||||
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. You module needs to export
|
||||||
a function `fn tic(time: i32)` which will be called once per frame.
|
a function `fn upd()` which will be called once per frame.
|
||||||
After calling `tic` MicroW8 will display the 320x256 8bpp framebuffer located
|
After calling `upd` MicroW8 will display the 320x240 8bpp framebuffer located
|
||||||
at offset 120 in memory with the 32bpp palette located at 82040.
|
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).
|
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 rectangle(x1: f32, y1: f32, x2: f32, y2: f32, color: i32)`
|
||||||
* `fn circle(cx: f32, cy: f32, radius: 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
|
## `.uw8` format
|
||||||
|
|
||||||
The first byte of the file specifies the format version:
|
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,
|
Then it includes all imports that MicroW8 provides,
|
||||||
a function section with a single function of type
|
a function section with a single function of type
|
||||||
`(i32) -> void` and an export section that exports
|
`(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
|
## Tooling
|
||||||
|
|
||||||
@@ -82,7 +111,9 @@ Writing code for MicroW8 in C, Rust, AssemblyScript etc. should absolutely
|
|||||||
possible but no examples are provided, yet.
|
possible but no examples are provided, yet.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
* [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
|
||||||
* [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
|
* [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
|
||||||
* [XorScroll](v0.1pre2#AQovAS0BAX8DQCABIAFBwAJvIABBCm1qIAFBwAJtczoAeCABQQFqIgFBgNgESA0ACws=) (50 bytes): A simple scrolling XOR pattern. Fun fact: This is the pre-loaded effect when entering a bytebattle.
|
* [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
|
||||||
* [CircleWorm](v0.1pre2#AQp7AXkCAX8CfUEgEA0DQCABskEEspUiAkECspUgALJBiCeylSIDQQWylJIQAEEBspJBoAGylCACQQOylSADQQSylJIQAEEBspJB+ACylCADQRGylCACQQKylJIQAEECspJBELKUIAFBAmxBP2oQEiABQQFqIgFBP0gNAAsL) (126 bytes): Just a test for the circle fill function.
|
* [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
site/static/v0.1pre3/index.html
Normal file
1
site/static/v0.1pre3/index.html
Normal file
File diff suppressed because one or more lines are too long
@@ -7,8 +7,8 @@
|
|||||||
/* Primary theme link color */
|
/* Primary theme link color */
|
||||||
--primary-link-color: #8080a0;
|
--primary-link-color: #8080a0;
|
||||||
/* Secondary color: the background body color */
|
/* Secondary color: the background body color */
|
||||||
--secondary-color: #e4dfd7;
|
--secondary-color: #e0e0e8;
|
||||||
--secondary-text-color: #303030;
|
--secondary-text-color: #1a1818;
|
||||||
/* Highlight text color of table of content */
|
/* Highlight text color of table of content */
|
||||||
--toc-highlight-text-color: #d46e13;
|
--toc-highlight-text-color: #d46e13;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<section>
|
<section>
|
||||||
<h1 class="text-center heading-text">A WebAssembly based sizecoding platform</h1>
|
<h1 class="text-center heading-text">A WebAssembly based sizecoding platform</h1>
|
||||||
</section>
|
</section>
|
||||||
<a href="v0.1pre2">
|
<a href="v0.1pre3">
|
||||||
<div class="demonstration-gif" style="width:640px;height:512px;background-color:black"></div>
|
<div class="demonstration-gif" style="width:640px;height:512px;background-color:black"></div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
12
src/lib.rs
12
src/lib.rs
@@ -24,6 +24,7 @@ struct UW8Instance {
|
|||||||
end_frame: TypedFunc<(), ()>,
|
end_frame: TypedFunc<(), ()>,
|
||||||
update: TypedFunc<(), ()>,
|
update: TypedFunc<(), ()>,
|
||||||
start_time: Instant,
|
start_time: Instant,
|
||||||
|
module: Vec<u8>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MicroW8 {
|
impl MicroW8 {
|
||||||
@@ -68,7 +69,7 @@ impl MicroW8 {
|
|||||||
self.load_from_memory(&module)
|
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();
|
self.reset();
|
||||||
|
|
||||||
let mut store = wasmtime::Store::new(&self.engine, ());
|
let mut store = wasmtime::Store::new(&self.engine, ());
|
||||||
@@ -88,8 +89,8 @@ impl MicroW8 {
|
|||||||
let platform_module =
|
let platform_module =
|
||||||
wasmtime::Module::new(&self.engine, &memory.data(&store)[..platform_length])?;
|
wasmtime::Module::new(&self.engine, &memory.data(&store)[..platform_length])?;
|
||||||
|
|
||||||
memory.data_mut(&mut store)[..module.len()].copy_from_slice(module);
|
memory.data_mut(&mut store)[..module_data.len()].copy_from_slice(module_data);
|
||||||
let module_length = load_uw8.call(&mut store, module.len() as i32)? as u32 as usize;
|
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])?;
|
let module = wasmtime::Module::new(&self.engine, &memory.data(&store)[..module_length])?;
|
||||||
|
|
||||||
linker.func_wrap("env", "acos", |v: f32| v.acos())?;
|
linker.func_wrap("env", "acos", |v: f32| v.acos())?;
|
||||||
@@ -139,6 +140,7 @@ impl MicroW8 {
|
|||||||
end_frame,
|
end_frame,
|
||||||
update,
|
update,
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
|
module: module_data.into()
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -174,8 +176,12 @@ impl MicroW8 {
|
|||||||
| palette[offset + 2] as u32;
|
| palette[offset + 2] as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.window.is_key_pressed(Key::R, minifb::KeyRepeat::No) {
|
||||||
|
self.load_from_memory(&instance.module)?;
|
||||||
|
} else {
|
||||||
self.instance = Some(instance);
|
self.instance = Some(instance);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.window
|
self.window
|
||||||
.update_with_buffer(&self.window_buffer, 320, 240)?;
|
.update_with_buffer(&self.window_buffer, 320, 240)?;
|
||||||
|
|||||||
@@ -15,7 +15,56 @@ let imageData = canvasCtx.createImageData(320, 240);
|
|||||||
|
|
||||||
let cancelFunction;
|
let cancelFunction;
|
||||||
|
|
||||||
|
let currentData;
|
||||||
|
|
||||||
let U8 = (d) => new Uint8Array(d);
|
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) {
|
async function runModule(data) {
|
||||||
if (cancelFunction) {
|
if (cancelFunction) {
|
||||||
@@ -30,6 +79,8 @@ async function runModule(data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentData = data;
|
||||||
|
|
||||||
let newURL = window.location.pathname;
|
let newURL = window.location.pathname;
|
||||||
if (cartridgeSize <= 1024) {
|
if (cartridgeSize <= 1024) {
|
||||||
let dataString = '';
|
let dataString = '';
|
||||||
@@ -94,27 +145,36 @@ async function runModule(data) {
|
|||||||
|
|
||||||
let instance = await instantiate(data);
|
let instance = await instantiate(data);
|
||||||
|
|
||||||
let buffer = new Uint32Array(imageData.data.buffer);
|
let buffer = U32(imageData.data.buffer);
|
||||||
|
|
||||||
let startTime = Date.now();
|
let startTime = Date.now();
|
||||||
|
|
||||||
let keepRunning = true;
|
let keepRunning = true;
|
||||||
cancelFunction = () => keepRunning = false;
|
cancelFunction = () => keepRunning = false;
|
||||||
|
|
||||||
|
const timePerFrame = 1000 / 60;
|
||||||
|
let nextFrame = startTime;
|
||||||
|
|
||||||
function mainloop() {
|
function mainloop() {
|
||||||
if (!keepRunning) {
|
if (!keepRunning) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new Uint32Array(memory.buffer)[16] = Date.now() - startTime;
|
let now = Date.now();
|
||||||
|
if(now >= nextFrame) {
|
||||||
|
let u32Mem = U32(memory.buffer);
|
||||||
|
u32Mem[16] = now - startTime;
|
||||||
|
u32Mem[17] = pad;
|
||||||
instance.exports.upd();
|
instance.exports.upd();
|
||||||
|
|
||||||
let palette = new Uint32Array(memory.buffer.slice(0x13000, 0x13000 + 1024));
|
let palette = U32(memory.buffer.slice(0x13000, 0x13000 + 1024));
|
||||||
for (let i = 0; i < 320 * 240; ++i) {
|
for (let i = 0; i < 320 * 240; ++i) {
|
||||||
buffer[i] = palette[memU8[i + 120]] | 0xff000000;
|
buffer[i] = palette[memU8[i + 120]] | 0xff000000;
|
||||||
}
|
}
|
||||||
canvasCtx.putImageData(imageData, 0, 0);
|
canvasCtx.putImageData(imageData, 0, 0);
|
||||||
|
nextFrame = Math.max(nextFrame + timePerFrame, now);
|
||||||
|
}
|
||||||
|
|
||||||
window.requestAnimationFrame(mainloop);
|
window.requestAnimationFrame(mainloop);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ a:hover {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
border: 4px solid #303040;
|
border: 4px solid #303040;
|
||||||
box-shadow: 5px 5px 20px black;
|
box-shadow: 5px 5px 20px black;
|
||||||
|
cursor: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#message {
|
#message {
|
||||||
|
|||||||
Reference in New Issue
Block a user