about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2025-03-11 17:57:57 +0900
committerNguyễn Gia Phong <cnx@loang.net>2025-03-11 17:57:57 +0900
commitc5ad891da3d5cee9958a02d660db99a41fec111b (patch)
treea05a27125c1fa1acde723b4234dabf89997e4ead /src
parent30f666f3ada479974353cdd7f3be9cdcec497fa1 (diff)
downloadblackshades-main.tar.gz
Port to Zig 0.14 HEAD main
Awaiting upstream libraries to support Zig 0.14 to purge the submodules:
* ini: https://github.com/ziglibs/ini/pull/14#issuecomment-2712560632
* qoi: https://github.com/ikskuh/zig-qoi/pull/14
Diffstat (limited to 'src')
-rw-r--r--src/Decals.zig4
-rw-r--r--src/Skeleton.cpp2
-rw-r--r--src/config.zig15
-rw-r--r--src/geom.zig14
-rw-r--r--src/main.zig22
-rw-r--r--src/misc.zig6
-rw-r--r--src/model.zig14
7 files changed, 42 insertions, 35 deletions
diff --git a/src/Decals.zig b/src/Decals.zig
index ecbc71c..b81b030 100644
--- a/src/Decals.zig
+++ b/src/Decals.zig
@@ -1,7 +1,7 @@
 // Decal construction and drawing
 // Copyright (C) 2002  David Rosen
 // Copyright (C) 2003  Steven Fuller
-// Copyright (C) 2023  Nguyễn Gia Phong
+// Copyright (C) 2023, 2025  Nguyễn Gia Phong
 //
 // This file is part of Black Shades.
 //
@@ -83,7 +83,7 @@ export fn addDecal(d: *Decals, kind: Kind, location: XYZ,
                    size: f32, normal: XYZ, poly: c_int,
                    m: *const Model, move: XYZ, rot: f32) void {
     const n: @Vector(3, f32) = @bitCast(normal);
-    const abs_n = @fabs(n);
+    const abs_n = @abs(n);
     var major: u2 = 0;
     if (abs_n[1] > abs_n[major])
         major = 1;
diff --git a/src/Skeleton.cpp b/src/Skeleton.cpp
index 8692213..b7f1684 100644
--- a/src/Skeleton.cpp
+++ b/src/Skeleton.cpp
@@ -450,7 +450,7 @@ void Skeleton::reload()
 	lowforwardjoints[2] = lefthip;
 
 	num_muscles = 29;
-	MuscleData muscles_data[num_muscles];
+	MuscleData muscles_data[29];
 	loadMuscles(muscles_data);
 	for (int i = 0; i < num_muscles; ++i) {
 		muscles[i].length = muscles_data[i].length;
diff --git a/src/config.zig b/src/config.zig
index 0d18223..723e95c 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -1,5 +1,5 @@
 // Configuration parser
-// Copyright (C) 2021-2022  Nguyễn Gia Phong
+// Copyright (C) 2021-2022, 2025  Nguyễn Gia Phong
 //
 // This file is part of Black Shades.
 //
@@ -23,6 +23,7 @@ const allocator = std.heap.c_allocator;
 const cwd = std.fs.cwd;
 const endian = @import("builtin").target.cpu.arch.endian();
 const eql = std.mem.eql;
+const free = std.c.free;
 const join = std.fs.path.join;
 const maxInt = std.math.maxInt;
 const mkdir = std.os.mkdir;
@@ -30,7 +31,7 @@ const parseFloat = std.fmt.parseFloat;
 const parseInt = std.fmt.parseInt;
 const std = @import("std");
 const stringToEnum = std.meta.stringToEnum;
-const tokenize = std.mem.tokenize;
+const tokenizeScalar = std.mem.tokenizeScalar;
 
 const Key = @import("gfz").Key;
 const ini = @import("ini");
@@ -69,7 +70,7 @@ fn parseLevels(dir_path: []const u8, length: usize) ![*]Level {
     defer input.close();
     const levels = try allocator.alloc(Level, length);
     errdefer allocator.free(levels);
-    var parser = ini.parse(allocator, input.reader());
+    var parser = ini.parse(allocator, input.reader(), "#;");
     defer parser.deinit();
 
     var i: usize = maxInt(usize);
@@ -92,7 +93,7 @@ fn parseLevels(dir_path: []const u8, length: usize) ![*]Level {
                 else return error.InvalidData;
             } else if (eql(u8, kv.key, "evil weapons")) {
                 var weapons = IntegerBitSet(8).initEmpty();
-                var enums = tokenize(u8, kv.value, " ");
+                var enums = tokenizeScalar(u8, kv.value, ' ');
                 while (enums.next()) |weapon|
                     weapons.set(try parseInt(u3, weapon, 10));
                 levels[i].evil_weapons = weapons.mask;
@@ -145,6 +146,10 @@ pub const Config = extern struct {
 
     levels: extern struct { ptr: [*]Level = undefined, len: usize = 0 } = .{},
     debug: bool = false,
+
+    pub fn deinit(self: Config) void {
+        defer free(self.levels.ptr);
+    }
 };
 
 /// Parse config.ini in the given base directory.
@@ -155,7 +160,7 @@ pub fn parse(base_dir: []const u8) !Config {
     defer dir.close();
     const input = try openData(dir, "config.ini");
     defer input.close();
-    var parser = ini.parse(allocator, input.reader());
+    var parser = ini.parse(allocator, input.reader(), "#;");
     defer parser.deinit();
 
     var config = Config{};
diff --git a/src/geom.zig b/src/geom.zig
index d86c682..4bb92e1 100644
--- a/src/geom.zig
+++ b/src/geom.zig
@@ -1,6 +1,6 @@
 // Geometry functions
 // Copyright (C) 2002  David Rosen
-// Copyright (C) 2023  Nguyễn Gia Phong
+// Copyright (C) 2023, 2025  Nguyễn Gia Phong
 //
 // This file is part of Black Shades.
 //
@@ -81,9 +81,9 @@ pub fn rotate2d(i: *f32, j: *f32, a: f32) void {
 export fn rotate(v: XYZ, deg_x: f32, deg_y: f32, deg_z: f32) XYZ {
     var u = v;
     // TODO: optimize
-    rotate2d(&u.x, &u.y, degreesToRadians(f32, deg_z));
-    rotate2d(&u.z, &u.x, degreesToRadians(f32, deg_y));
-    rotate2d(&u.y, &u.z, degreesToRadians(f32, deg_x));
+    rotate2d(&u.x, &u.y, degreesToRadians(deg_z));
+    rotate2d(&u.z, &u.x, degreesToRadians(deg_y));
+    rotate2d(&u.y, &u.z, degreesToRadians(deg_x));
     return u;
 }
 
@@ -106,7 +106,7 @@ pub export fn segCrossTrigon(start: XYZ, end: XYZ,
     const q: @Vector(3, f32) = @bitCast(end);
     const n: @Vector(3, f32) = @bitCast(normal.*);
     const denom = dot(q - p, n);
-    if (@fabs(denom) < floatEps(f32))
+    if (@abs(denom) < floatEps(f32))
         return false; // parallel segment and triangle
 
     const a: @Vector(3, f32) = @bitCast(p_a.*);
@@ -116,7 +116,7 @@ pub export fn segCrossTrigon(start: XYZ, end: XYZ,
         return false; // intersection not within segment
 
     // Check if intersection is in the triangle
-    const n_abs = @fabs(n);
+    const n_abs = @abs(n);
     const n_max = @reduce(.Max, n_abs);
     const k: struct { usize, usize } = if (n_max == n_abs[0])
         .{ 1, 2 }
@@ -132,7 +132,7 @@ pub export fn segCrossTrigon(start: XYZ, end: XYZ,
     const v = @Vector(3, f32){ i[k[1]], b[k[1]], c[k[1]] } - splat(3, a[k[1]]);
     intersection.* = @bitCast(i);
 
-    if (@fabs(u[1]) < floatEps(f32)) {
+    if (@abs(u[1]) < floatEps(f32)) {
         const s = u[0] / u[2];
         if (s >= 0 and s <= 1) {
             const t = (v[0] - s * v[2]) / v[1];
diff --git a/src/main.zig b/src/main.zig
index 9accfc8..08c84ab 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,5 +1,5 @@
 // Main function
-// Copyright (C) 2021-2023  Nguyễn Gia Phong
+// Copyright (C) 2021-2023, 2025  Nguyễn Gia Phong
 //
 // This file is part of Black Shades.
 //
@@ -16,13 +16,12 @@
 // 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 DefaultPrng = std.rand.DefaultPrng;
+const DefaultPrng = std.Random.DefaultPrng;
 const allocator = std.heap.c_allocator;
-const free = std.c.free;
 const std = @import("std");
 
-const Loca = @import("loca").Loca;
 const al = @import("zeal");
+const folders = @import("known-folders");
 const gf = @import("gfz");
 const gl = @import("zgl");
 
@@ -84,10 +83,10 @@ fn click(window: gf.Window, button: gf.MouseButton,
 }
 
 pub fn main() !void {
-    const loca = try Loca.init(allocator, .{});
-    defer loca.deinit();
-    const config = try configuration.parse(loca.user_config);
-    defer free(config.levels.ptr);
+    const user_config = (try folders.getPath(allocator, .local_configuration)).?;
+    defer allocator.free(user_config);
+    const config = try configuration.parse(user_config);
+    defer config.deinit();
 
     try gf.init();
     defer gf.deinit() catch unreachable;
@@ -100,10 +99,11 @@ pub fn main() !void {
     defer textures.deinit();
     var decals = Decals.init(allocator, &textures);
     defer decals.deinit();
+    const user_data = (try folders.getPath(allocator, .data)).?;
+    defer allocator.free(user_data);
     game = c.makeGame(&decals, @bitCast(config),
-                      @bitCast(try loadScores(loca.user_data))).?;
-    defer saveScores(loca.user_data, @bitCast(c.getScores(game)))
-        catch unreachable;
+                      @bitCast(try loadScores(user_data))).?;
+    defer saveScores(user_data, @bitCast(c.getScores(game))) catch unreachable;
 
     try window.setSizeCallback(resizeWindow);
     try gf.swapInterval(@intFromBool(config.vsync));
diff --git a/src/misc.zig b/src/misc.zig
index 46237cb..3bed694 100644
--- a/src/misc.zig
+++ b/src/misc.zig
@@ -1,6 +1,6 @@
 // Miscellaneous functions
 // Copyright (C) 2002  David Rosen
-// Copyright (C) 2021-2023  Nguyễn Gia Phong
+// Copyright (C) 2021-2023, 2025  Nguyễn Gia Phong
 //
 // This file is part of Black Shades.
 //
@@ -193,7 +193,7 @@ pub fn loadScores(base_dir: []const u8) !Scores {
     const path = "blackshades" ++ [_]u8{ sep } ++ "scores.ini";
     const input = dir.openFile(path, .{}) catch return scores;
     defer input.close();
-    var parser = ini.parse(allocator, input.reader());
+    var parser = ini.parse(allocator, input.reader(), "#;");
     defer parser.deinit();
 
     while (try parser.next()) |record|
@@ -241,7 +241,7 @@ pub fn saveScores(base_dir: []const u8, current: Scores) !void {
         previous.completed or current.completed,
     });
     defer allocator.free(data);
-    try dir.writeFile("scores.ini", data);
+    try dir.writeFile(.{ .sub_path = "scores.ini", .data = data });
 }
 
 const Text = struct {
diff --git a/src/model.zig b/src/model.zig
index 9773027..3acfe9d 100644
--- a/src/model.zig
+++ b/src/model.zig
@@ -1,6 +1,6 @@
 // 3D model
 // Copyright (C) 2002  David Rosen
-// Copyright (C) 2023  Nguyễn Gia Phong
+// Copyright (C) 2023, 2025  Nguyễn Gia Phong
 //
 // This file is part of Black Shades.
 //
@@ -25,7 +25,7 @@ const c = @import("cimport.zig");
 const crossProduct = geom.crossProduct;
 const cwd = std.fs.cwd;
 const data_dir = misc.data_dir;
-const degToRad = std.math.degreesToRadians;
+const degreesToRadians = std.math.degreesToRadians;
 const endsWith = std.mem.endsWith;
 const eql = std.mem.eql;
 const floatMax = std.math.floatMax;
@@ -63,7 +63,9 @@ const OffIterator = struct {
     token_iterator: TokenIterator,
 
     pub fn init(buffer: []const u8) OffIterator {
-        var self = .{ .token_iterator = tokenizeScalar(u8, buffer, '\n') };
+        var self = OffIterator{
+            .token_iterator = tokenizeScalar(u8, buffer, '\n'),
+        };
         if (!endsWith(u8, self.token_iterator.next().?, "OFF"))
             self.token_iterator.reset();
         return self;
@@ -198,12 +200,12 @@ pub export fn segCrossModelTrans(start: XYZ, end: XYZ, m: *const Model,
                                  intersection: *XYZ) c_int {
     const t: @Vector(3, f32) = @bitCast(move);
     var p = @as(@Vector(3, f32), @bitCast(start)) - t;
-    rotate2d(&p[2], &p[0], degToRad(f32, -rot));
+    rotate2d(&p[2], &p[0], degreesToRadians(-rot));
     var q = @as(@Vector(3, f32), @bitCast(end)) - t;
-    rotate2d(&q[2], &q[0], degToRad(f32, -rot));
+    rotate2d(&q[2], &q[0], degreesToRadians(-rot));
 
     defer {
-        rotate2d(&intersection.z, &intersection.x, degToRad(f32, rot));
+        rotate2d(&intersection.z, &intersection.x, degreesToRadians(rot));
         intersection.* = @bitCast(@as(@Vector(3, f32),
                                       @bitCast(intersection.*)) + t);
     }