From 3424976d40ad4444b4908dbfa43779f118f283ee Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Mon, 10 Apr 2023 13:26:58 +0200 Subject: [PATCH] start implementing a pacman-like game in zig --- examples/zig/.gitignore | 4 +- examples/zig/game/build.zig | 31 ++++++++++ examples/zig/game/main.zig | 95 +++++++++++++++++++++++++++++ examples/zig/game/uw8.zig | 10 +++ examples/zig/{ => tunnel}/build.zig | 0 examples/zig/{ => tunnel}/main.zig | 0 uw8-tool/src/filter_exports.rs | 16 +++-- 7 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 examples/zig/game/build.zig create mode 100644 examples/zig/game/main.zig create mode 100644 examples/zig/game/uw8.zig rename examples/zig/{ => tunnel}/build.zig (100%) rename examples/zig/{ => tunnel}/main.zig (100%) diff --git a/examples/zig/.gitignore b/examples/zig/.gitignore index 7608bcb..4a0641e 100644 --- a/examples/zig/.gitignore +++ b/examples/zig/.gitignore @@ -1,2 +1,2 @@ -/zig-cache/ -/zig-out/ \ No newline at end of file +zig-cache/ +zig-out/ \ No newline at end of file diff --git a/examples/zig/game/build.zig b/examples/zig/game/build.zig new file mode 100644 index 0000000..31c43c2 --- /dev/null +++ b/examples/zig/game/build.zig @@ -0,0 +1,31 @@ +const std = @import("std"); + +pub fn build(b: *std.build.Builder) void { + const mode = std.builtin.Mode.ReleaseSmall; + + const lib = b.addSharedLibrary("cart", "main.zig", .unversioned); + lib.setBuildMode(mode); + lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding, .cpu_features_add = std.Target.wasm.featureSet(&.{.nontrapping_fptoint}) }); + lib.import_memory = true; + lib.initial_memory = 262144; + lib.max_memory = 262144; + lib.global_base = 81920; + lib.stack_size = 8192; + lib.install(); + + if (lib.install_step) |install_step| { + const run_filter_exports = b.addSystemCommand(&[_][]const u8{ "uw8", "filter-exports", "zig-out/lib/cart.wasm", "zig-out/lib/cart-filtered.wasm" }); + run_filter_exports.step.dependOn(&install_step.step); + + const run_wasm_opt = b.addSystemCommand(&[_][]const u8{ "wasm-opt", "--enable-nontrapping-float-to-int", "-Oz", "-o", "zig-out/cart.wasm", "zig-out/lib/cart-filtered.wasm" }); + run_wasm_opt.step.dependOn(&run_filter_exports.step); + + const run_uw8_pack = b.addSystemCommand(&[_][]const u8{ "uw8", "pack", "-l", "5", "zig-out/cart.wasm", "zig-out/cart.uw8" }); + run_uw8_pack.step.dependOn(&run_wasm_opt.step); + + const make_opt = b.step("make_opt", "make size optimized cart"); + make_opt.dependOn(&run_uw8_pack.step); + + b.default_step = make_opt; + } +} diff --git a/examples/zig/game/main.zig b/examples/zig/game/main.zig new file mode 100644 index 0000000..4c186a9 --- /dev/null +++ b/examples/zig/game/main.zig @@ -0,0 +1,95 @@ +const uw8 = @import("uw8.zig"); + +var redBallSprite: [16 * 16]u8 = undefined; +var greenBallSprite: [16 * 16]u8 = undefined; +var blueBallSprite: [16 * 16]u8 = undefined; +var wallSprite: [24 * 24]u8 = undefined; + +const SphereConfigStep = struct { size: u8, color: u8 }; +// zig fmt: off +const redSphereConfig: [4]SphereConfigStep = .{ + .{ .size = 0, .color = 0x3d }, + .{ .size = 2, .color = 0x48 }, + .{ .size = 6, .color = 0x65 }, + .{ .size = 9, .color = 0x55 } +}; +const greenSphereConfig: [4]SphereConfigStep = .{ + .{ .size = 0, .color = 0x7d }, + .{ .size = 2, .color = 0x88 }, + .{ .size = 6, .color = 0x96 }, + .{ .size = 9, .color = 0xa3 } +}; +const blueSphereConfig: [4]SphereConfigStep = .{ + .{ .size = 0, .color = 0x2e }, + .{ .size = 2, .color = 0x19 }, + .{ .size = 6, .color = 0x17 }, + .{ .size = 9, .color = 0x24 } +}; + +const levelData: [14] *const [19]u8 = .{ + "xxxxxxxxxxxxxxxxxxx", + "x x x x", + "x x xx x xx x x", + "x x xxx x xxx x x", + "x xx x x xx x", + "x xx xxxxx xx x", + "x x x x", + "x xx xx xxx xx xx x", + "x x xx xx x x", + "xx x x x x xx", + "x xx xxx xxx xx x", + "x xx x x xx x", + "x x x x x", + "xxxxxxxxxxxxxxxxxxx", +}; +// zig fmt: on + +export fn start() void { + blitSphere(&redBallSprite, &redSphereConfig); + blitSphere(&greenBallSprite, &greenSphereConfig); + blitSphere(&blueBallSprite, &blueSphereConfig); + + createWallSprite(); +} + +fn blitSphere(sprite: [*]u8, config: []const SphereConfigStep) void { + for (config) |circle| { + uw8.circle(8, 8, 8, circle.color); + uw8.circle(5, 6, @intToFloat(f32, circle.size), 0); + uw8.grabSprite(sprite, 16, 0, 0, 0x100); + } +} + +fn createWallSprite() void { + uw8.cls(0xe4); + var i: i32 = 0; + while (i < 50) : (i += 1) { + const x = uw8.randomf() * 16; + const y = uw8.randomf() * 16; + const radius = uw8.randomf() * 2 + 1; + const c = @intCast(u8, (uw8.random() & 3)) + 0x95; + var j: i32 = 0; + while (j < 9) : (j += 1) { + uw8.circle(x + @intToFloat(f32, @rem(j, 3) * 16), y + @intToFloat(f32, @divFloor(j, 3) * 16), radius, c); + } + } + uw8.grabSprite(&wallSprite, 16, 16, 16, 0); +} + +export fn upd() void { + uw8.cls(0); + + var y: usize = 0; + while (y < levelData.len) : (y += 1) { + var x: usize = 0; + while (x < levelData[y].len) : (x += 1) { + if (levelData[y][x] == 'x') { + uw8.blitSprite(&wallSprite, 16, 8 + @intCast(i32, x) * 16, @intCast(i32, y) * 16, 0); + } + } + } + + uw8.blitSprite(&redBallSprite, 16, 100, 100, 0x100); + uw8.blitSprite(&greenBallSprite, 16, 130, 100, 0x100); + uw8.blitSprite(&blueBallSprite, 16, 160, 100, 0x100); +} diff --git a/examples/zig/game/uw8.zig b/examples/zig/game/uw8.zig new file mode 100644 index 0000000..e7f1b07 --- /dev/null +++ b/examples/zig/game/uw8.zig @@ -0,0 +1,10 @@ +pub extern fn random() u32; +pub extern fn randomf() f32; +pub extern fn time() f32; +pub extern fn cls(color: u8) void; +pub extern fn circle(x: f32, y: f32, radiu: f32, color: u8) void; +pub extern fn blitSprite(spriteData: [*]u8, size: u32, x: i32, y: i32, ctrl: u32) void; +pub extern fn grabSprite(spriteData: [*]u8, size: u32, x: i32, y: i32, ctrl: u32) void; +pub extern fn printString(str: [*:0]u8) void; +pub extern fn printInt(value: i32) void; +pub extern fn printChar(char: u32) void; diff --git a/examples/zig/build.zig b/examples/zig/tunnel/build.zig similarity index 100% rename from examples/zig/build.zig rename to examples/zig/tunnel/build.zig diff --git a/examples/zig/main.zig b/examples/zig/tunnel/main.zig similarity index 100% rename from examples/zig/main.zig rename to examples/zig/tunnel/main.zig diff --git a/uw8-tool/src/filter_exports.rs b/uw8-tool/src/filter_exports.rs index 00f96c9..ad8a80d 100644 --- a/uw8-tool/src/filter_exports.rs +++ b/uw8-tool/src/filter_exports.rs @@ -1,13 +1,17 @@ -use std::path::Path; use anyhow::Result; +use std::path::Path; pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> { let mut module = walrus::Module::from_file(in_path)?; - let exports_to_delete: Vec<_> = module.exports.iter().filter_map(|export| match export.name.as_str() { - "upd" => None, - _ => Some(export.id()) - }).collect(); + let exports_to_delete: Vec<_> = module + .exports + .iter() + .filter_map(|export| match export.name.as_str() { + "upd" | "snd" | "start" => None, + _ => Some(export.id()), + }) + .collect(); for id in exports_to_delete { module.exports.delete(id); @@ -18,4 +22,4 @@ pub fn filter_exports(in_path: &Path, out_path: &Path) -> Result<()> { module.emit_wasm_file(out_path)?; Ok(()) -} \ No newline at end of file +}