From a39ba72202761b062c8e7ffeaf26cd9f4783455a Mon Sep 17 00:00:00 2001 From: Locria Cyber <74560659+locriacyber@users.noreply.github.com> Date: Sun, 24 Apr 2022 17:46:36 +0800 Subject: [PATCH] Initial template --- .gitignore | 2 + README.md | 26 ++++++++++ build.zig | 18 +++++++ src/main.zig | 25 ++++++++++ src/wasm4.zig | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build.zig create mode 100644 src/main.zig create mode 100644 src/wasm4.zig diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a0641e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +zig-cache/ +zig-out/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3cfe2f2 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# snek + +A game written in Zig for the [WASM-4](https://wasm4.org) fantasy console. + +## Building + +Build the cart by running: + +```shell +zig build -Drelease-small=true +``` + +Then run it with: + +```shell +w4 run zig-out/lib/cart.wasm +``` + +For more info about setting up WASM-4, see the [quickstart guide](https://wasm4.org/docs/getting-started/setup?code-lang=zig#quickstart). + +## Links + +- [Documentation](https://wasm4.org/docs): Learn more about WASM-4. +- [Snake Tutorial](https://wasm4.org/docs/tutorials/snake/goal): Learn how to build a complete game + with a step-by-step tutorial. +- [GitHub](https://github.com/aduros/wasm4): Submit an issue or PR. Contributions are welcome! diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..7431b33 --- /dev/null +++ b/build.zig @@ -0,0 +1,18 @@ +const std = @import("std"); + +pub fn build(b: *std.build.Builder) !void { + const mode = b.standardReleaseOptions(); + const lib = b.addSharedLibrary("cart", "src/main.zig", .unversioned); + + lib.setBuildMode(mode); + lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }); + lib.import_memory = true; + lib.initial_memory = 65536; + lib.max_memory = 65536; + lib.stack_size = 14752; + + // Export WASM-4 symbols + lib.export_symbol_names = &[_][]const u8{ "start", "update" }; + + lib.install(); +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..15628b4 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,25 @@ +const w4 = @import("wasm4.zig"); + +const smiley = [8]u8{ + 0b11000011, + 0b10000001, + 0b00100100, + 0b00100100, + 0b00000000, + 0b00100100, + 0b10011001, + 0b11000011, +}; + +export fn update() void { + w4.DRAW_COLORS.* = 2; + w4.text("Hello from Zig!", 10, 10); + + const gamepad = w4.GAMEPAD1.*; + if (gamepad & w4.BUTTON_1 != 0) { + w4.DRAW_COLORS.* = 4; + } + + w4.blit(&smiley, 76, 76, 8, 8, w4.BLIT_1BPP); + w4.text("Press X to blink", 16, 90); +} diff --git a/src/wasm4.zig b/src/wasm4.zig new file mode 100644 index 0000000..0af8f20 --- /dev/null +++ b/src/wasm4.zig @@ -0,0 +1,135 @@ +// +// WASM-4: https://wasm4.org/docs + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Platform Constants │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +pub const SCREEN_SIZE: u32 = 160; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Memory Addresses │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +pub const PALETTE: *[4]u32 = @intToPtr(*[4]u32, 0x04); +pub const DRAW_COLORS: *u16 = @intToPtr(*u16, 0x14); +pub const GAMEPAD1: *const u8 = @intToPtr(*const u8, 0x16); +pub const GAMEPAD2: *const u8 = @intToPtr(*const u8, 0x17); +pub const GAMEPAD3: *const u8 = @intToPtr(*const u8, 0x18); +pub const GAMEPAD4: *const u8 = @intToPtr(*const u8, 0x19); +pub const MOUSE_X: *const i16 = @intToPtr(*const i16, 0x1a); +pub const MOUSE_Y: *const i16 = @intToPtr(*const i16, 0x1c); +pub const MOUSE_BUTTONS: *const u8 = @intToPtr(*const u8, 0x1e); +pub const SYSTEM_FLAGS: *u8 = @intToPtr(*u8, 0x1f); +pub const FRAMEBUFFER: *[6400]u8 = @intToPtr(*[6400]u8, 0xA0); + +pub const BUTTON_1: u8 = 1; +pub const BUTTON_2: u8 = 2; +pub const BUTTON_LEFT: u8 = 16; +pub const BUTTON_RIGHT: u8 = 32; +pub const BUTTON_UP: u8 = 64; +pub const BUTTON_DOWN: u8 = 128; + +pub const MOUSE_LEFT: u8 = 1; +pub const MOUSE_RIGHT: u8 = 2; +pub const MOUSE_MIDDLE: u8 = 4; + +pub const SYSTEM_PRESERVE_FRAMEBUFFER: u8 = 1; +pub const SYSTEM_HIDE_GAMEPAD_OVERLAY: u8 = 2; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Drawing Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/// Copies pixels to the framebuffer. +pub extern fn blit(sprite: [*]const u8, x: i32, y: i32, width: i32, height: i32, flags: u32) void; + +/// Copies a subregion within a larger sprite atlas to the framebuffer. +pub extern fn blitSub(sprite: [*]const u8, x: i32, y: i32, width: i32, height: i32, src_x: u32, src_y: u32, stride: i32, flags: u32) void; + +pub const BLIT_2BPP: u32 = 1; +pub const BLIT_1BPP: u32 = 0; +pub const BLIT_FLIP_X: u32 = 2; +pub const BLIT_FLIP_Y: u32 = 4; +pub const BLIT_ROTATE: u32 = 8; + +/// Draws a line between two points. +pub extern fn line(x1: i32, y1: i32, x2: i32, y2: i32) void; + +/// Draws an oval (or circle). +pub extern fn oval(x: i32, y: i32, width: i32, height: i32) void; + +/// Draws a rectangle. +pub extern fn rect(x: i32, y: i32, width: u32, height: u32) void; + +/// Draws text using the built-in system font. +pub fn text(str: []const u8, x: i32, y: i32) void { + textUtf8(str.ptr, str.len, x, y); +} +extern fn textUtf8(strPtr: [*]const u8, strLen: usize, x: i32, y: i32) void; + +/// Draws a vertical line +pub extern fn vline(x: i32, y: i32, len: u32) void; + +/// Draws a horizontal line +pub extern fn hline(x: i32, y: i32, len: u32) void; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Sound Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/// Plays a sound tone. +pub extern fn tone(frequency: u32, duration: u32, volume: u32, flags: u32) void; + +pub const TONE_PULSE1: u32 = 0; +pub const TONE_PULSE2: u32 = 1; +pub const TONE_TRIANGLE: u32 = 2; +pub const TONE_NOISE: u32 = 3; +pub const TONE_MODE1: u32 = 0; +pub const TONE_MODE2: u32 = 4; +pub const TONE_MODE3: u32 = 8; +pub const TONE_MODE4: u32 = 12; +pub const TONE_PAN_LEFT: u32 = 16; +pub const TONE_PAN_RIGHT: u32 = 32; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Storage Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/// Reads up to `size` bytes from persistent storage into the pointer `dest`. +pub extern fn diskr(dest: [*]u8, size: u32) u32; + +/// Writes up to `size` bytes from the pointer `src` into persistent storage. +pub extern fn diskw(src: [*]const u8, size: u32) u32; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Other Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/// Prints a message to the debug console. +pub fn trace(x: []const u8) void { + traceUtf8(x.ptr, x.len); +} +extern fn traceUtf8(strPtr: [*]const u8, strLen: usize) void; + +/// Use with caution, as there's no compile-time type checking. +/// +/// * %c, %d, and %x expect 32-bit integers. +/// * %f expects 64-bit floats. +/// * %s expects a *zero-terminated* string pointer. +/// +/// See https://github.com/aduros/wasm4/issues/244 for discussion and type-safe +/// alternatives. +pub extern fn tracef(x: [*:0]const u8, ...) void;