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.zig91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/misc.zig b/src/misc.zig
index 2bbb9f0..7ff4680 100644
--- a/src/misc.zig
+++ b/src/misc.zig
@@ -24,12 +24,15 @@ usingnamespace @cImport({
 });
 
 const Dir = std.fs.Dir;
+const TokenIterator = std.mem.TokenIterator;
 const al = @import("zeal");
 const allocPrint = std.fmt.allocPrint;
 const allocator = std.heap.c_allocator;
+const assert = std.debug.assert;
 const count = std.mem.count;
 const cwd = std.fs.cwd;
 const data_dir = @import("build_options").data_dir ++ [_]u8{ sep };
+const endsWith = std.mem.endsWith;
 const eql = std.mem.eql;
 const free = std.c.free;
 const join = std.fs.path.joinZ;
@@ -38,6 +41,7 @@ const parseFloat = std.fmt.parseFloat;
 const parseInt = std.fmt.parseInt;
 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;
 
@@ -146,6 +150,93 @@ export fn loadJoints(joints: [*]Joint) void {
     }
 }
 
+const Vertex = extern struct {
+    x: f32, y: f32, z: f32,
+};
+
+const Face = extern struct {
+    // Only support triangles
+    v: [3]u16,
+    r: f32, g: f32, b: f32,
+};
+
+const OffIterator = struct {
+    token_iterator: TokenIterator,
+
+    pub fn init(buffer: []const u8) OffIterator {
+        var self = .{ .token_iterator = tokenize(buffer, "\n") };
+        if (!endsWith(u8, self.token_iterator.next().?, "OFF"))
+            self.token_iterator.reset();
+        return self;
+    }
+
+    pub fn next(self: *OffIterator) ?TokenIterator {
+        while (self.token_iterator.next()) |line| {
+            var words = tokenize(line, " ");
+            if (words.next()) |word| { // not empty
+                if (!startsWith(u8, word, "#")) { // not comment
+                    words.reset();
+                    return words;
+                }
+            }
+        }
+        return null;
+    }
+};
+
+/// Load model from given OFF file.
+export fn loadModel(path: [*:0]const u8) extern struct {
+    vertices: extern struct {
+        ptr: [*]Vertex,
+        len: usize,
+    },
+    faces: extern struct {
+        ptr: [*]Face,
+        len: usize,
+    },
+} {
+    var dir = cwd().openDir(data_dir ++ "models", .{}) catch unreachable;
+    defer dir.close();
+    const file = dir.readFileAlloc(allocator, span(path), max_size)
+        catch unreachable;
+    defer allocator.free(file);
+    var lines = OffIterator.init(file);
+    var counts = lines.next().?;
+    const vertex_count = parseInt(usize, counts.next().?, 10) catch unreachable;
+    const face_count = parseInt(usize, counts.next().?, 10) catch unreachable;
+
+    const vertices = allocator.alloc(Vertex, vertex_count) catch unreachable;
+    for (vertices) |*vertex| {
+        var numbers = lines.next().?;
+        vertex.* = .{
+            .x = parseFloat(f32, numbers.next().?) catch unreachable,
+            .y = parseFloat(f32, numbers.next().?) catch unreachable,
+            .z = parseFloat(f32, numbers.next().?) catch unreachable,
+        };
+    }
+
+    const faces = allocator.alloc(Face, face_count) catch unreachable;
+    for (faces) |*face| {
+        var numbers = lines.next().?;
+        assert(eql(u8, numbers.next().?, "3"));
+        face.* = .{
+            .v = .{
+                parseInt(u16, numbers.next().?, 10) catch unreachable,
+                parseInt(u16, numbers.next().?, 10) catch unreachable,
+                parseInt(u16, numbers.next().?, 10) catch unreachable,
+            },
+            .r = parseFloat(f32, numbers.next().?) catch unreachable,
+            .g = parseFloat(f32, numbers.next().?) catch unreachable,
+            .b = parseFloat(f32, numbers.next().?) catch unreachable,
+        };
+    }
+
+    return .{
+        .vertices = .{ .ptr = vertices.ptr , .len = vertices.len },
+        .faces = .{ .ptr = faces.ptr , .len = faces.len },
+    };
+}
+
 const Muscle = extern struct {
     length: f32,
     initlen: f32,