diff --git a/examples/curlywas/skipahead.cwa b/examples/curlywas/skipahead.cwa index f353635..1062a78 100644 --- a/examples/curlywas/skipahead.cwa +++ b/examples/curlywas/skipahead.cwa @@ -6,6 +6,7 @@ import "env.isButtonPressed" fn btn(i32) -> i32; import "env.random" fn random() -> i32; import "env.randomSeed" fn randomSeed(i32); import "env.cls" fn cls(i32); +import "env.printInt" fn printInt(i32); global mut pz: i32 = 4; global mut px: f32 = 2.0; @@ -21,6 +22,8 @@ export fn upd() { s = s + 0.1 - (f + control_speed) * btn(4 <| cls(4)) as f32; f = f * 0.7; + printInt(pz); + loop lines { let lazy z = (4000 / (y := y + 1) + pz) / 20; let lazy x = px - ({randomSeed(z); random()} >> 30) as f32; @@ -57,4 +60,4 @@ export fn upd() { px = px + (btn(3) - btn(2)) as f32 * control_speed; py = py + s; pz = pz + 1; -} \ No newline at end of file +} diff --git a/platform/Cargo.lock b/platform/Cargo.lock index ff26b85..ed42583 100644 --- a/platform/Cargo.lock +++ b/platform/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "ahash" version = "0.3.8" @@ -11,6 +17,17 @@ dependencies = [ "const-random", ] +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "anyhow" version = "1.0.47" @@ -32,6 +49,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "bytemuck" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" + [[package]] name = "cc" version = "1.0.72" @@ -60,7 +83,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2d3efff85e8572b1c3fa0127706af58c4fff8458f8d9436d54b1e97573c7a3f" dependencies = [ - "ahash", + "ahash 0.3.8", ] [[package]] @@ -85,6 +108,15 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "crc32fast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3825b1e8580894917dc4468cb634a1b4e9745fddc854edad72d9c04644c0319f" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-channel" version = "0.5.1" @@ -123,6 +155,27 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "fallible_collections" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaefd4190151d458f16f0793d3452d7f13aeb3701566a4cefc4c37598876cc00" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -134,6 +187,15 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.6", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -152,6 +214,28 @@ version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +[[package]] +name = "lodepng" +version = "3.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24844d5c0b922ddd52fb5bf0964a4c7f8e799a946ec01bb463771eb04fc1a323" +dependencies = [ + "fallible_collections", + "flate2", + "libc", + "rgb", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -161,6 +245,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + [[package]] name = "pbr" version = "1.0.4" @@ -185,6 +275,7 @@ version = "0.1.0" dependencies = [ "anyhow", "curlywas", + "lodepng", "uw8-tool", ] @@ -194,6 +285,15 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +[[package]] +name = "rgb" +version = "0.8.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27fa03bb1e3e2941f52d4a555a395a72bf79b0a85fbbaab79447050c97d978c" +dependencies = [ + "bytemuck", +] + [[package]] name = "sacabase" version = "2.0.0" @@ -245,6 +345,12 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/platform/Cargo.toml b/platform/Cargo.toml index f06b90b..fb6e338 100644 --- a/platform/Cargo.toml +++ b/platform/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] curlywas = { git="https://github.com/exoticorn/curlywas.git", rev="c0140d0" } uw8-tool = { path="../uw8-tool" } -anyhow = "1" \ No newline at end of file +anyhow = "1" +lodepng = "3.4" \ No newline at end of file diff --git a/platform/bin/loader.wasm b/platform/bin/loader.wasm index 3cff3ce..0221d2f 100644 Binary files a/platform/bin/loader.wasm and b/platform/bin/loader.wasm differ diff --git a/platform/bin/platform.uw8 b/platform/bin/platform.uw8 index fafe324..75b074f 100644 Binary files a/platform/bin/platform.uw8 and b/platform/bin/platform.uw8 differ diff --git a/platform/src/font.png b/platform/src/font.png new file mode 100644 index 0000000..f87e348 Binary files /dev/null and b/platform/src/font.png differ diff --git a/platform/src/font.pxo b/platform/src/font.pxo new file mode 100644 index 0000000..f4bcb93 Binary files /dev/null and b/platform/src/font.pxo differ diff --git a/platform/src/main.rs b/platform/src/main.rs index 2804bf1..288465a 100644 --- a/platform/src/main.rs +++ b/platform/src/main.rs @@ -7,6 +7,9 @@ fn main() -> Result<()> { println!("Generating compressed base module"); uw8_tool::BaseModule::create_binary(&Path::new("target/base.upk"))?; + println!("Converting font"); + convert_font()?; + println!("Compiling loader module"); let loader = curlywas::compile_file("src/loader.cwa")?; File::create("bin/loader.wasm")?.write_all(&loader)?; @@ -25,3 +28,28 @@ fn main() -> Result<()> { Ok(()) } + +fn convert_font() -> Result<()> { + let image = lodepng::decode32_file("src/font.png")?; + + assert!(image.width == 128 && image.height == 128); + + let mut font = vec![]; + for char in 0..256 { + for y in 0..8 { + let mut byte = 0u8; + let base = (char % 16 * 8) + (char / 16 * 8 + y) * 128; + for x in 0..8 { + byte += byte; + if image.buffer[base + x].r > 128 { + byte |= 1; + } + } + font.push(byte); + } + } + + File::create("target/font.bin")?.write_all(&font)?; + + Ok(()) +} \ No newline at end of file diff --git a/platform/src/platform.cwa b/platform/src/platform.cwa index 26737d3..a53be17 100644 --- a/platform/src/platform.cwa +++ b/platform/src/platform.cwa @@ -6,6 +6,10 @@ export fn time() -> f32 { (0!64) as f32 / 1000 as f32 } +/////////// +// INPUT // +/////////// + export fn isButtonPressed(btn: i32) -> i32 { (68!0 >> btn) & 1 } @@ -14,6 +18,10 @@ export fn isButtonTriggered(btn: i32) -> i32 { ((68!0 & (-1 - 68!4)) >> btn) & 1 } +//////////// +// RANDOM // +//////////// + global mut randomState: i64 = 37i64; export fn random() -> i32 { @@ -43,8 +51,17 @@ export fn fmod(a: f32, b: f32) -> f32 { a - floor(a / b) * b } +///////////// +// DRAWING // +///////////// + +global mut textCursorX = 0; +global mut textCursorY = 0; + export fn cls(col: i32) { let i: i32; + textCursorX = 0; + textCursorY = 0; col = (col & 255) * 0x1010101; loop pixels { i!120 = col; @@ -121,6 +138,63 @@ export fn circle(cx: f32, cy: f32, radius: f32, col: i32) { } } +////////// +// TEXT // +////////// + +global mut textColor = 15; + +export fn printChar(char: i32) { + if char == 10 | textCursorX >= 320 { + textCursorX = 0; + textCursorY = textCursorY + 8; + return; + } + + let y: i32; + loop rows { + let bits = (char * 8 + y)?0x13400; + let x = 0; + loop pixels { + if (bits := bits << 1) & 256 { + setPixel(textCursorX + x, textCursorY + y, textColor); + } + branch_if (x := x + 1) < 8: pixels; + } + branch_if (y := y + 1) < 8: rows; + } + textCursorX = textCursorX + 8; +} + +export fn printString(ptr: i32) { + loop chars { + let lazy char = ptr?0; + if char { + printChar(char); + ptr = ptr + 1; + branch chars; + } + } +} + +export fn printInt(num: i32) { + let lazy p = 0x12fff; + p?0 = 0; + if num < 0 { + printChar(45); + num = -num; + } + loop digits { + (p := p - 1)?0 = 48 + num #% 10; + branch_if (num := num #/ 10): digits; + } + printString(p); +} + +/////////// +// SETUP // +/////////// + export fn endFrame() { 68!4 = 68!0; } @@ -137,7 +211,7 @@ start fn setup() { let lazy a = max(llimit, min(ulimit, c)) * (scale + 0.05); let lazy b = scale * scale * 0.8; let inline v = (select(i < 11*16*3, max(0 as f32, min(a + b - a * b, 1 as f32)), scale) * 255 as f32) as i32; - (i%3 + i/3*4)?(120+320*240) = v; + (i%3 + i/3*4)?0x13000 = v; avg = (avg + c) * 0.5; branch_if i := i - 1: gradients; @@ -150,9 +224,9 @@ start fn setup() { let lazy first_step = index >= 32; let inline src1 = select(first_step, index % 32 / 2, index * 2); let inline src2 = select(first_step, (index + 1) % 32 / 2, index * 2 + 1); - let inline c1 = (src1 * 4 + channel)?(120+320*240+192*4); - let inline c2 = (src2 * 4 + channel)?(120+320*240+192*4); - i?(120+320*240+192*4) = (c1 + c2) * (3 + first_step) / 8; + let inline c1 = (src1 * 4 + channel)?(0x13000+192*4); + let inline c2 = (src2 * 4 + channel)?(0x13000+192*4); + i?(0x13000+192*4) = (c1 + c2) * (3 + first_step) / 8; branch_if (i := i - 1) >= 0: expand_sweetie; } @@ -161,7 +235,7 @@ start fn setup() { randomSeed(random()); } -data 120+320*240+192*4 { +data 0x13000+192*4 { i32( 0x2c1c1a, 0x5d275d, @@ -181,3 +255,7 @@ data 120+320*240+192*4 { 0x573c33 ) } + +data 0x13400 { + file("../target/font.bin") +} diff --git a/src/lib.rs b/src/lib.rs index c1fe703..88be069 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,8 +163,9 @@ impl MicroW8 { instance.update.call(&mut instance.store, ())?; instance.end_frame.call(&mut instance.store, ())?; - let framebuffer = &instance.memory.data(&instance.store)[120..]; - let palette = &framebuffer[320 * 240..]; + let memory = instance.memory.data(&instance.store); + let framebuffer = &memory[120..]; + let palette = &memory[0x13000..]; for i in 0..320 * 240 { let offset = framebuffer[i] as usize * 4; self.window_buffer[i] = 0xff000000 diff --git a/uw8-tool/src/base_module.rs b/uw8-tool/src/base_module.rs index eaadc91..567bd6e 100644 --- a/uw8-tool/src/base_module.rs +++ b/uw8-tool/src/base_module.rs @@ -81,6 +81,10 @@ impl BaseModule { add_function(&mut functions, &type_map, "isButtonPressed", &[I32], Some(I32)); add_function(&mut functions, &type_map, "isButtonTriggered", &[I32], Some(I32)); + add_function(&mut functions, &type_map, "printChar", &[I32], None); + add_function(&mut functions, &type_map, "printString", &[I32], None); + add_function(&mut functions, &type_map, "printInt", &[I32], None); + for i in functions.len()..64 { add_function( &mut functions, diff --git a/web/src/main.js b/web/src/main.js index e31d85b..cb028b6 100644 --- a/web/src/main.js +++ b/web/src/main.js @@ -110,7 +110,7 @@ async function runModule(data) { new Uint32Array(memory.buffer)[16] = Date.now() - startTime; instance.exports.upd(); - let palette = new Uint32Array(memory.buffer.slice(76920, 76920 + 1024)); + 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; }