diff options
Diffstat (limited to 'src/misc.zig')
-rw-r--r-- | src/misc.zig | 91 |
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, |