diff options
-rw-r--r-- | build.zig | 91 | ||||
m--------- | lib/gfz | 0 | ||||
m--------- | lib/ini | 0 | ||||
m--------- | lib/loca | 0 | ||||
m--------- | lib/qoi | 0 | ||||
m--------- | lib/zeal | 0 | ||||
-rw-r--r-- | src/geom.zig | 36 | ||||
-rw-r--r-- | src/main.zig | 14 | ||||
-rw-r--r-- | src/misc.zig | 56 |
9 files changed, 96 insertions, 101 deletions
diff --git a/build.zig b/build.zig index 05f9e91..9f69257 100644 --- a/build.zig +++ b/build.zig @@ -16,63 +16,62 @@ // You should have received a copy of the GNU General Public License // along with Black Shades. If not, see <https://www.gnu.org/licenses/>. -const std = @import("std"); -const InstallDirectoryOptions = std.build.InstallDirectoryOptions; -const Builder = std.build.Builder; +const Build = @import("std").Build; +const Compile = Build.Step.Compile; +const InstallDirectoryOptions = Build.InstallDirectoryOptions; const data = InstallDirectoryOptions{ - .source_dir = "data", + .source_dir = .{ .path = "data" }, .install_dir = .{ .custom = "share" }, .install_subdir = "blackshades", }; -pub fn build(b: *Builder) void { +pub fn build(b: *Build) void { + const bin = b.addExecutable(.{ + .name = "blackshades", + .root_source_file = .{ .path = "src/main.zig" }, + .target = b.standardTargetOptions(.{}), + .optimize = b.standardOptimizeOption(.{}), + }); + bin.addIncludePath(.{ .path = "src" }); + bin.addCSourceFiles(&.{ + "src/Decals.cpp", + "src/GameDraw.cpp", + "src/GameInitDispose.cpp", + "src/GameLoop.cpp", + "src/GameTick.cpp", + "src/Globals.cpp", + "src/Models.cpp", + "src/Person.cpp", + "src/Quaternions.cpp", + "src/Skeleton.cpp", + "src/Sprites.cpp", + }, &.{ "--std=c++17", "-fno-sanitize=undefined" }); + + for ([_]struct { []const u8, []const u8 }{ + .{ "gfz", "lib/gfz/src/gfz.zig" }, + .{ "ini", "lib/ini/src/ini.zig" }, + .{ "loca", "lib/loca/src/main.zig" }, + .{ "qoi", "lib/qoi/src/qoi.zig" }, + .{ "zeal", "lib/zeal/src/zeal.zig" }, + }) |lib| + bin.addModule(lib[0], b.createModule(.{ + .source_file = .{ .path = lib[1] }, + })); + @import("lib/gfz/build.zig").link(bin); + @import("lib/zeal/build.zig").link(bin); + bin.linkSystemLibrary("GL"); + bin.linkSystemLibrary("GLU"); + bin.linkSystemLibrary("c++"); + b.installDirectory(data); const options = b.addOptions(); const data_dir = b.getInstallPath(data.install_dir, data.install_subdir); options.addOption([]const u8, "data_dir", data_dir); + bin.addOptions("build_options", options); + b.installArtifact(bin); - const exe = b.addExecutable("blackshades", "src/main.zig"); - exe.addIncludePath("src"); - - const cxxflags = [_][]const u8{ "--std=c++17", "-fno-sanitize=undefined" }; - exe.addCSourceFile("src/Decals.cpp", &cxxflags); - exe.addCSourceFile("src/GameDraw.cpp", &cxxflags); - exe.addCSourceFile("src/GameInitDispose.cpp", &cxxflags); - exe.addCSourceFile("src/GameLoop.cpp", &cxxflags); - exe.addCSourceFile("src/GameTick.cpp", &cxxflags); - exe.addCSourceFile("src/Globals.cpp", &cxxflags); - exe.addCSourceFile("src/Models.cpp", &cxxflags); - exe.addCSourceFile("src/Person.cpp", &cxxflags); - exe.addCSourceFile("src/Quaternions.cpp", &cxxflags); - exe.addCSourceFile("src/Skeleton.cpp", &cxxflags); - exe.addCSourceFile("src/Sprites.cpp", &cxxflags); - - exe.addPackagePath("gfz", "lib/gfz/src/gfz.zig"); - @import("lib/gfz/build.zig").link(exe); - exe.addPackagePath("ini", "lib/ini/src/ini.zig"); - exe.addPackagePath("loca", "lib/loca/src/main.zig"); - exe.addPackagePath("qoi", "lib/qoi/src/qoi.zig"); - exe.addPackagePath("zeal", "lib/zeal/src/zeal.zig"); - @import("lib/zeal/build.zig").link(exe); - - exe.linkSystemLibrary("GL"); - exe.linkSystemLibrary("GLU"); - exe.linkSystemLibrary("c++"); - - // Standard target options allows the person running `zig build` to choose - // what target to build for. Here we do not override the defaults, which - // means any target is allowed, and the default is native. Other options - // for restricting supported target set are available. - exe.setTarget(b.standardTargetOptions(.{})); - - // Standard release options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. - exe.setBuildMode(b.standardReleaseOptions()); - exe.addOptions("build_options", options); - exe.install(); - - const run_cmd = exe.run(); + const run_cmd = b.addRunArtifact(bin); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| run_cmd.addArgs(args); diff --git a/lib/gfz b/lib/gfz -Subproject 407f889cf60ecea2709b449cb9939168d0b795c +Subproject d30ae1d4a46ad4b1f7b3c45c59dee268ab95c6b diff --git a/lib/ini b/lib/ini -Subproject d980d828f5cd53fac19f474ffd8b7b368ebbd10 +Subproject 2b11e8fef86d0eefb225156e695be1c1d5c35cb diff --git a/lib/loca b/lib/loca -Subproject 011c179f2b2570264fc9eda07758a5e0615b0e2 +Subproject aac1315920bb9f2c1e3492825c69f764d4a8525 diff --git a/lib/qoi b/lib/qoi -Subproject b928d64f4a860212e7199f714ff5df2325a1942 +Subproject 524efec9e9522f8e2b72e9d67b36d5d5e69a767 diff --git a/lib/zeal b/lib/zeal -Subproject 592a28125a43ee9f396600a2ac8a418eb7631a5 +Subproject eb65c5633e1bfae26ae95c6183cc74c2b593794 diff --git a/src/geom.zig b/src/geom.zig index c84d2aa..af6bd21 100644 --- a/src/geom.zig +++ b/src/geom.zig @@ -30,7 +30,7 @@ fn dot(u: anytype, v: @TypeOf(u)) Child(@TypeOf(u)) { } export fn sqrlen(v: XYZ) f32 { - const u = @bitCast(@Vector(3, f32), v); + const u: @Vector(3, f32) = @bitCast(v); return dot(u, u); } @@ -39,7 +39,7 @@ fn norm(v: anytype) Child(@TypeOf(v)) { } export fn len(v: XYZ) f32 { - const u = @bitCast(@Vector(3, f32), v); + const u: @Vector(3, f32) = @bitCast(v); return norm(u); } @@ -53,16 +53,20 @@ export fn crossProduct(u: XYZ, v: XYZ) XYZ { }; } +inline fn splat(x: f32) @Vector(3, f32) { + return @splat(x); +} + export fn normalize(v: XYZ) XYZ { - const u = @bitCast(@Vector(3, f32), v); + const u: @Vector(3, f32) = @bitCast(v); const d = norm(u); - return if (d == 0) v else @bitCast(XYZ, u / @splat(3, d)); + return if (d == 0) v else @bitCast(u / splat(d)); } export fn reflect(v: XYZ, n: XYZ) XYZ { - const u = @bitCast(@Vector(3, f32), v); - const m = @bitCast(@Vector(3, f32), n); - return @bitCast(XYZ, u - m * @splat(3, dot(u, m) * 2)); + const u: @Vector(3, f32) = @bitCast(v); + const m: @Vector(3, f32) = @bitCast(n); + return @bitCast(u - m * splat(dot(u, m) * 2)); } fn rotate2d(i: *f32, j: *f32, a: f32) void { @@ -84,15 +88,15 @@ export fn rotate(v: XYZ, deg_x: f32, deg_y: f32, deg_z: f32) XYZ { export fn segmentIntersectsSphere(a: XYZ, b: XYZ, i: XYZ, r: f32) bool { // FIXME: call directly with vectors - const p = @bitCast(@Vector(3, f32), a); - const q = @bitCast(@Vector(3, f32), b); - const c = @bitCast(@Vector(3, f32), i); + const p: @Vector(3, f32) = @bitCast(a); + const q: @Vector(3, f32) = @bitCast(b); + const c: @Vector(3, f32) = @bitCast(i); - if (@reduce(.Or, @max(p, q) < c - @splat(3, r))) return false; - if (@reduce(.Or, @min(p, q) > c + @splat(3, r))) return false; + if (@reduce(.Or, @max(p, q) < c - splat(r))) return false; + if (@reduce(.Or, @min(p, q) > c + splat(r))) return false; // https://en.wikipedia.org/wiki/Line–sphere_intersection const d = q - p; // line's direction - const u = d / @splat(3, norm(d)); // unit vector + const u = d / splat(norm(d)); // unit vector return sqr(dot(u, (p - c))) >= @reduce(.Add, sqr(p - c)) - sqr(r); } @@ -242,8 +246,7 @@ export fn setFrustum(frustum: [*][4]f32, p: [*]const f32, export fn cubeInFrustum(frustum: [*][4]f32, x: f32, y: f32, z: f32, size: f32) bool { const delta = [_]f32{ -size, size }; - var i = @as(u8, 0); - loop: while (i < 6) : (i += 1) { + loop: for (0..6) |i| { for (delta) |dx| for (delta) |dy| for (delta) |dz| if (frustum[i][0] * (x + dx) + frustum[i][1] * (y + dy) + frustum[i][2] * (z + dz) + frustum[i][3] > 0) continue :loop; @@ -254,8 +257,7 @@ export fn cubeInFrustum(frustum: [*][4]f32, export fn sphereInFrustum(frustum: [*][4]f32, x: f32, y: f32, z: f32, r: f32) bool { - var i = @as(u8, 0); - while (i < 6) : (i += 1) + for (0..6) |i| if (frustum[i][0] * x + frustum[i][1] * y + frustum[i][2] * z + frustum[i][3] <= -r) return false; diff --git a/src/main.zig b/src/main.zig index 49f2b49..b44b592 100644 --- a/src/main.zig +++ b/src/main.zig @@ -49,7 +49,7 @@ fn handleKey(window: gf.Window, key: gf.Key, scancode: c_int, action: gf.KeyAction, mods: gf.Mods) void { _ = window; _ = scancode; - c.handleKey(game, @enumToInt(key), @enumToInt(action), mods.toInt()); + c.handleKey(game, @intFromEnum(key), @intFromEnum(action), mods.toInt()); } fn look(window: gf.Window, xpos: f64, ypos: f64) void { @@ -60,7 +60,7 @@ fn look(window: gf.Window, xpos: f64, ypos: f64) void { fn click(window: gf.Window, button: gf.MouseButton, action: gf.MouseButton.Action, mods: gf.Mods) void { _ = window; - c.click(game, @enumToInt(button), @enumToInt(action), mods.toInt()); + c.click(game, @intFromEnum(button), @intFromEnum(action), mods.toInt()); } /// Return a floating point value evenly distributed in the range [0, 1). @@ -92,14 +92,14 @@ pub fn main() !void { "Black Shades", .{}, .{}); try window.makeCurrent(); - prng = DefaultPrng.init(@bitCast(u64, try gf.getTime())); - game = c.makeGame(@bitCast(c.Config, config), - @bitCast(c.Scores, try loadScores(loca.user_data))).?; - defer saveScores(loca.user_data, @bitCast(Scores, c.getScores(game))) + prng = DefaultPrng.init(@bitCast(try gf.getTime())); + game = c.makeGame(@bitCast(config), + @bitCast(try loadScores(loca.user_data))).?; + defer saveScores(loca.user_data, @bitCast(c.getScores(game))) catch unreachable; try window.setSizeCallback(resizeWindow); - try gf.swapInterval(@boolToInt(config.vsync)); + try gf.swapInterval(@intFromBool(config.vsync)); c.initGl(game); if (try gf.rawMouseMotionSupported()) diff --git a/src/misc.zig b/src/misc.zig index 6f1d893..ebec4ef 100644 --- a/src/misc.zig +++ b/src/misc.zig @@ -18,7 +18,7 @@ // along with Black Shades. If not, see <https://www.gnu.org/licenses/>. const Dir = std.fs.Dir; -const TokenIterator = std.mem.TokenIterator(u8); +const TokenIterator = std.mem.TokenIterator(u8, .scalar); const allocPrint = std.fmt.allocPrint; const allocator = std.heap.c_allocator; const assert = std.debug.assert; @@ -36,7 +36,7 @@ const sep = std.fs.path.sep; const span = std.mem.span; const startsWith = std.mem.startsWith; const std = @import("std"); -const tokenize = std.mem.tokenize; +const tokenizeScalar = std.mem.tokenizeScalar; const al = @import("zeal"); const gf = @import("gfz"); @@ -49,7 +49,7 @@ const c = @import("cimport.zig"); /// Return whether the given keyboard key is pressed. export fn keyPress(key: c_int) bool { const window = (gf.Window.getCurrent() catch unreachable).?; - return (window.getKey(@intToEnum(gf.Key, key)) catch unreachable) == .press; + return (window.getKey(@enumFromInt(key)) catch unreachable) == .press; } /// Read given file to heap, allocated by C allocator. @@ -80,22 +80,22 @@ export fn loadAnimation(name: [*:0]const u8) extern struct { }) catch unreachable; defer allocator.free(anim_file); const length = count(u8, anim_file, "\t") - 1; - var anim = tokenize(u8, anim_file, "\n"); + var anim = tokenizeScalar(u8, anim_file, '\n'); _ = anim.next().?; // ignore field names const frames = allocator.alloc(Frame, length) catch unreachable; for (frames) |*frame| { - var values = tokenize(u8, anim.next().?, "\t"); + var values = tokenizeScalar(u8, anim.next().?, '\t'); const frame_file = readFile(dir, "{s}{c}frames{c}{s}.tsv", .{ name, sep, sep, values.next().?, // $animation/frames/$frame.tsv }) catch unreachable; defer allocator.free(frame_file); frame.speed = parseFloat(f32, values.next().?) catch unreachable; - var joints = tokenize(u8, frame_file, "\n"); + var joints = tokenizeScalar(u8, frame_file, '\n'); _ = joints.next().?; // ignore field names - for (frame.joints) |*joint| { - var coordinates = tokenize(u8, joints.next().?, "\t"); + for (&frame.joints) |*joint| { + var coordinates = tokenizeScalar(u8, joints.next().?, '\t'); joint.* = .{ .x = parseFloat(f32, coordinates.next().?) catch unreachable, .y = parseFloat(f32, coordinates.next().?) catch unreachable, @@ -126,7 +126,7 @@ const Joint = extern struct { parent: i8, pub fn load(self: *Joint, row: []const u8) !void { - var values = tokenize(u8, row, "\t"); + var values = tokenizeScalar(u8, row, '\t'); self.x = try parseFloat(f32, values.next().?); self.y = try parseFloat(f32, values.next().?); self.z = try parseFloat(f32, values.next().?); @@ -143,7 +143,7 @@ export fn loadJoints(joints: [*]Joint) void { const file = readFile(cwd(), data_dir ++ "joints.tsv", .{}) catch unreachable; defer allocator.free(file); - var tsv = tokenize(u8, file, "\n"); + var tsv = tokenizeScalar(u8, file, '\n'); _ = tsv.next().?; // ignore field names var i = @as(u8, 0); while (tsv.next()) |row| : (i += 1) @@ -164,7 +164,7 @@ const OffIterator = struct { token_iterator: TokenIterator, pub fn init(buffer: []const u8) OffIterator { - var self = .{ .token_iterator = tokenize(u8, buffer, "\n") }; + var self = .{ .token_iterator = tokenizeScalar(u8, buffer, '\n') }; if (!endsWith(u8, self.token_iterator.next().?, "OFF")) self.token_iterator.reset(); return self; @@ -172,7 +172,7 @@ const OffIterator = struct { pub fn next(self: *OffIterator) ?TokenIterator { while (self.token_iterator.next()) |line| { - var words = tokenize(u8, line, " "); + var words = tokenizeScalar(u8, line, ' '); if (words.next()) |word| { // not empty if (!startsWith(u8, word, "#")) { // not comment words.reset(); @@ -247,7 +247,7 @@ const Muscle = extern struct { parent2: i8, pub fn load(self: *Muscle, row: []const u8) !void { - var values = tokenize(u8, row, "\t"); + var values = tokenizeScalar(u8, row, '\t'); self.length = try parseFloat(f32, values.next().?); self.initlen = try parseFloat(f32, values.next().?); self.minlen = try parseFloat(f32, values.next().?); @@ -264,7 +264,7 @@ export fn loadMuscles(muscles: [*]Muscle) void { const file = readFile(cwd(), data_dir ++ "muscles.tsv", .{}) catch unreachable; defer allocator.free(file); - var tsv = tokenize(u8, file, "\n"); + var tsv = tokenizeScalar(u8, file, '\n'); _ = tsv.next().?; // ignore field names var i = @as(u8, 0); while (tsv.next()) |row| : (i += 1) @@ -306,7 +306,7 @@ export fn loadSound(filename: [*:0]const u8) u32 { const path = join(allocator, &.{ data_dir ++ "sounds", span(filename) }) catch unreachable; defer allocator.free(path); - const audio = al.Audio.read(allocator, span(path)) catch unreachable; + const audio = al.Audio.read(allocator, path) catch unreachable; defer audio.free(); const buffer = al.Buffer.init(audio) catch unreachable; return buffer.reference; @@ -315,7 +315,7 @@ export fn loadSound(filename: [*:0]const u8) u32 { fn check(comptime errorString: fn (c_uint) callconv(.C) [*c]const u8, status: anytype) void { if (status != 0) - @panic(span(errorString(@intCast(c_uint, status)))); + @panic(span(errorString(@intCast(status)))); } /// Load PNG file into an OpenGL buffer and return it. @@ -327,7 +327,7 @@ export fn loadTexture(filename: [*:0]const u8) u32 { var image = qoi.decodeBuffer(allocator, file) catch unreachable; defer image.deinit(allocator); - const data = @ptrCast([*c]const u8, image.pixels.ptr); + const data: [*c]const u8 = @ptrCast(image.pixels.ptr); var texture: u32 = undefined; c.glGenTextures(1, &texture); @@ -337,8 +337,8 @@ export fn loadTexture(filename: [*:0]const u8) u32 { c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MAG_FILTER, c.GL_LINEAR); c.glTexParameteri(c.GL_TEXTURE_2D, c.GL_TEXTURE_MIN_FILTER, c.GL_LINEAR); - const width = @intCast(i32, image.width); - const height = @intCast(i32, image.height); + const width: i32 = @intCast(image.width); + const height: i32 = @intCast(image.height); c.glPixelStorei(c.GL_UNPACK_ALIGNMENT, 1); c.glTexImage2D(c.GL_TEXTURE_2D, 0, 4, width, height, 0, c.GL_RGBA, c.GL_UNSIGNED_BYTE, data); @@ -356,11 +356,6 @@ export fn playSound(source: u32, x: f32, y: f32, z: f32) void { src.play() catch unreachable; } -// TODO: replace with @maximum from Zig 0.9+ -fn maximum(a: anytype, b: @TypeOf(a)) @TypeOf(a) { - return if (a > b) a else b; -} - /// Write scores to user data directory. pub fn saveScores(base_dir: []const u8, current: Scores) !void { const previous = try loadScores(base_dir); @@ -370,7 +365,7 @@ pub fn saveScores(base_dir: []const u8, current: Scores) !void { defer dir.close(); const format = "[scores]\nhigh score = {}\ncompleted = {}\n"; const data = try allocPrint(allocator, format, .{ - maximum(previous.high_score, current.high_score), + @max(previous.high_score, current.high_score), previous.completed or current.completed, }); defer allocator.free(data); @@ -385,12 +380,11 @@ const Text = struct { export fn buildFont(text: *Text) void { text.base = c.glGenLists(256); c.glBindTexture(c.GL_TEXTURE_2D, text.texture); - var i = @as(u16, 0); - while (i < 256) : (i += 1) { + for (0..256) |i| { // Character coords - const x = @intToFloat(f32, i % 16) / 16.0; - const y = @intToFloat(f32, i / 16) / 16.0; - c.glNewList(text.base + i, c.GL_COMPILE); + const x = @as(f32, @floatFromInt(i % 16)) / 16.0; + const y = @as(f32, @floatFromInt(i / 16)) / 16.0; + c.glNewList(@intCast(text.base + i), c.GL_COMPILE); // Use A Quad For Each Character c.glBegin(c.GL_QUADS); // Bottom left @@ -437,7 +431,7 @@ export fn glPrint(text: *const Text, x: f64, y: f64, str: [*:0]const u8, else c.glListBase(text.base -% 32); // Write to screen - c.glCallLists(@intCast(c_int, len(str)), c.GL_BYTE, str); + c.glCallLists(@intCast(len(str)), c.GL_BYTE, str); // Restore c.glMatrixMode(c.GL_PROJECTION); |