summary refs log tree commit diff
path: root/src/misc.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/misc.zig')
-rw-r--r--src/misc.zig98
1 files changed, 95 insertions, 3 deletions
diff --git a/src/misc.zig b/src/misc.zig
index 353dcac..f4021ac 100644
--- a/src/misc.zig
+++ b/src/misc.zig
@@ -27,15 +27,98 @@ const al = @import("zeal");
 const allocator = std.heap.c_allocator;
 const cwd = std.fs.cwd;
 const data_dir = @import("build_options").data_dir ++ [_]u8{ sep };
+const eql = std.mem.eql;
 const free = std.c.free;
 const join = std.fs.path.joinZ;
 const maxInt = std.math.maxInt;
+const parseFloat = std.fmt.parseFloat;
+const parseInt = std.fmt.parseInt;
 const sep = std.fs.path.sep;
 const span = std.mem.span;
 const std = @import("std");
+const tokenize = std.mem.tokenize;
+
+/// Parse boolean values.
+pub fn parseBool(s: []const u8) !bool {
+    if (eql(u8, s, "false"))
+        return false;
+    if (eql(u8, s, "true"))
+        return true;
+    return error.InvalidCharacter;
+}
+
+const Joint = extern struct {
+    label: i8,
+    x: f32,
+    y: f32,
+    z: f32,
+    length: f32,
+    model: u8,
+    visible: bool,
+    lower: bool,
+    parent: i8,
+
+    pub fn load(self: *Joint, row: []const u8) !void {
+        var values = tokenize(row, "\t");
+        self.label = try parseInt(i8, values.next().?, 10);
+        self.x = try parseFloat(f32, values.next().?);
+        self.y = try parseFloat(f32, values.next().?);
+        self.z = try parseFloat(f32, values.next().?);
+        self.length = try parseFloat(f32, values.next().?);
+        self.model = try parseInt(u8, values.next().?, 10);
+        self.visible = try parseBool(values.next().?);
+        self.lower = try parseBool(values.next().?);
+        self.parent = try parseInt(i8, values.next().?, 10);
+    }
+};
+
+/// Load joints in character's frame
+fn loadJoints(joints: [*]Joint) callconv(.C) void {
+    var tsv = tokenize(@embedFile("joints.tsv"), "\n");
+    _ = tsv.next().?; // ignore field names
+    var i = @as(u8, 0);
+    while (tsv.next()) |row| {
+        joints[i].load(row) catch unreachable;
+        i += 1;
+    }
+}
+
+const Muscle = extern struct {
+    length: f32,
+    initlen: f32,
+    minlen: f32,
+    maxlen: f32,
+    flag: bool,
+    visible: bool,
+    parent1: i8,
+    parent2: i8,
+
+    pub fn load(self: *Muscle, row: []const u8) !void {
+        var values = tokenize(row, "\t");
+        self.length = try parseFloat(f32, values.next().?);
+        self.initlen = try parseFloat(f32, values.next().?);
+        self.minlen = try parseFloat(f32, values.next().?);
+        self.maxlen = try parseFloat(f32, values.next().?);
+        self.flag = try parseBool(values.next().?);
+        self.visible = try parseBool(values.next().?);
+        self.parent1 = try parseInt(i8, values.next().?, 10);
+        self.parent2 = try parseInt(i8, values.next().?, 10);
+    }
+};
+
+/// Load muscles in character's frame
+fn loadMuscles(muscles: [*]Muscle) callconv(.C) void {
+    var tsv = tokenize(@embedFile("muscles.tsv"), "\n");
+    _ = tsv.next().?; // ignore field names
+    var i = @as(u8, 0);
+    while (tsv.next()) |row| {
+        muscles[i].load(row) catch unreachable;
+        i += 1;
+    }
+}
 
 /// Load audio file into an OpenAL buffer and return it.
-pub fn loadSound(filename: [*:0]const u8) callconv(.C) u32 {
+fn loadSound(filename: [*:0]const u8) callconv(.C) u32 {
     const path = join(allocator, &.{ data_dir ++ "sounds", span(filename) })
         catch unreachable;
     defer allocator.free(path);
@@ -52,7 +135,7 @@ fn check(errorString: fn (c_uint) callconv(.C) [*c]const u8,
 }
 
 /// Load PNG file into an OpenGL buffer and return it.
-pub fn loadTexture(filename: [*:0]const u8) callconv(.C) GLuint {
+fn loadTexture(filename: [*:0]const u8) callconv(.C) GLuint {
     var dir = cwd().openDir(data_dir ++ "textures", .{}) catch unreachable;
     defer dir.close();
     // Don't judge me, take care of me!
@@ -86,9 +169,18 @@ pub fn loadTexture(filename: [*:0]const u8) callconv(.C) GLuint {
 }
 
 /// Move sound source to given position and play it.
-pub fn playSound(source: u32, x: f32, y: f32, z: f32) callconv(.C) void {
+fn playSound(source: u32, x: f32, y: f32, z: f32) callconv(.C) void {
     const src = al.Source{ .reference = source };
     _ = alGetError(); // TODO: remove when completely migrate to zeal
     src.setPosition(.{ x / 32, y / 32, z / 32 }) catch unreachable;
     src.play() catch unreachable;
 }
+
+comptime {
+    // Work around lazy compilation.
+    @export(loadJoints, .{ .name = "loadJoints" });
+    @export(loadMuscles, .{ .name = "loadMuscles" });
+    @export(loadSound, .{ .name = "loadSound" });
+    @export(loadTexture, .{ .name = "loadTexture" });
+    @export(playSound, .{ .name = "playSound" });
+}