repo: hackvr-turbo
action: commit
revision: 
path_from: 
revision_from: 0a145719e1baa43bec16b2cf12ec36d8dffaf65f:
path_to: 
revision_to: 
git.thebackupbox.net
hackvr-turbo
git clone git://git.thebackupbox.net/hackvr-turbo
commit 0a145719e1baa43bec16b2cf12ec36d8dffaf65f
Author: Felix (xq) Queißner 
Date:   Thu Jun 25 00:32:08 2020 +0200

    Starts to implement the HackVR parser.

diff --git a/README.md b/README.md
index 63d99faeaa48176a35ff668ae73fd654a003db87..
index ..699cf1ed568df079bd2b01c206bf09e325fdbd73 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
 # hackvr-turbo

-Implementation of epochs hackvr
\ No newline at end of file
+Implementation of epochs hackvr
+
+
+## References
+- https://github.com/kkabrams/hackvr 
+- https://thebackupbox.net/cgi-bin/pageview.cgi?page=hackvr
diff --git a/SPEC.md b/SPEC.md
new file mode 100644
index 0000000000000000000000000000000000000000..6141a15d96250bb79c24f0ce35922b03b8c213fc
--- /dev/null
+++ b/SPEC.md
@@ -0,0 +1,50 @@
+# HackVR Specification
+
+**Note:**
+This specification is inofficial and based on the development of HackVR Turbo (which is based on the original hackvr)
+
+
+hackvr help output:
+
+# commands that don't get prepended with groupname: help, version
+# command format:
+# group names can be globbed in some cases to operate on multiple groups
+# some commands that take numbers as arguments can be made to behave relative
+# by putting + before the number. makes negative relative a bit odd like:
+#   user move +-2 +-2 0
+# groupnam* command arguments
+# commands:
+#   deleteallexcept grou*
+# _ deletegroup grou*
+#   assimilate grou*
+#   renamegroup group
+#   status  # old. just outputs a variable that is supposed to be loops per second.
+#   dump  # tries to let you output the various things that can be set.
+#   quit  #closes hackvr only if the id that is doing it is the same as yours.
+#   set
+#   physics
+#   control grou* [globbing this group could have fun effects]
+#   addshape color N x1 y1 z1 ... xN yN zN
+#   export grou*
+#   ping any-string-without-spaces
+# * scale x y z
+# * rotate [+]x [+]y [+]z
+#   periodic  # flushes out locally-cached movement and rotation
+#   flatten  # combines group attributes to the shapes.
+# * move [+]x [+]y [+]z
+# * move forward|backward|up|down|left|right
+hackvr also outputs
+
+name action targetgroup
+when a group is clicked on using the name set from the command line. usually $USER
+Here's some of the crap I've had hackvr do:
+
+
+so, this first converts an obj to hackvr format, appends a line to rescale it, and then export it
+
+
+
+## Changes
+
+- Encoding is assumed UTF-8
+- Max. line length excluding the `\n` is 1024 bytes
\ No newline at end of file
diff --git a/build.zig b/build.zig
index 63afb17f56e01cdab369d205557665e772a358a8..
index ..852b2f32237a7a8c291d8a7c369f2437ca64b0a8 100644
--- a/build.zig
+++ b/build.zig
@@ -27,6 +27,9 @@ pub fn build(b: *std.build.Builder) void {

     exe.install();

+    const test_step = b.step("test", "Runs all tests");
+    test_step.dependOn(&b.addTest("lib/hackvr/lib.zig").step);
+
     const run_cmd = exe.run();
     run_cmd.step.dependOn(b.getInstallStep());

diff --git a/lib/hackvr/lib.zig b/lib/hackvr/lib.zig
index 30cc3fa44ca9e46b339e135e9a7b7c8f8b2cd946..
index ..e67fbc81f2444e474339629a4ee147d74b7ef666 100644
--- a/lib/hackvr/lib.zig
+++ b/lib/hackvr/lib.zig
@@ -1,6 +1,13 @@
 const std = @import("std");

-const real = f32;
+pub const parser = @import("parser.zig");
+
+comptime {
+    // include the parser module for tests
+    _ = parser;
+}
+
+pub const real = f32;

 pub const Vec3D = struct {
     x: real, y: real, z: real
diff --git a/lib/hackvr/parser.zig b/lib/hackvr/parser.zig
new file mode 100644
index 0000000000000000000000000000000000000000..188ae5811c4f6218a0435a1e9e3258d73556c45a
--- /dev/null
+++ b/lib/hackvr/parser.zig
@@ -0,0 +1,98 @@
+const std = @import("std");
+
+const hvr = @import("lib.zig");
+
+/// A push-event based parser for HackVR input.
+/// Parses hackvr text into serialized, preparsed commands.
+/// It's not interactive and can eat any amount of data.
+/// When the parser encounters a line feed, it will process the
+/// line and return a Event or fail with "unknown command"
+pub const Parser = struct {
+    const Self = @This();
+
+    line_buffer: [1024]u8,
+    line_offset: usize,
+
+    pub fn init() Parser {
+        return Parser{
+            .line_buffer = undefined,
+            .line_offset = 0,
+        };
+    }
+
+    /// Pushes data into the parser.
+    pub fn push(self: *Self, source: []const u8) !PushResult {
+        var offset: usize = 0;
+
+        while (offset < source.len) {
+            defer offset += 1;
+            if (source[offset] == '\n') {
+                var line = self.line_buffer[0..self.line_offset];
+                if (!std.unicode.utf8ValidateSlice(line))
+                    return error.InvalidEncoding;
+
+                std.log.debug(.HackVR, "Emit event for line '{}'\n", .{line});
+
+                return PushResult{
+                    .event = .{
+                        .rest = source[0..offset],
+                        .event = Event{},
+                    },
+                };
+            }
+
+            if (self.line_offset > self.line_buffer.len)
+                return error.OutOfMemory;
+            self.line_buffer[self.line_offset] = source[offset];
+            self.line_offset += 1;
+        }
+
+        return PushResult{
+            .needs_data = {},
+        };
+    }
+};
+
+/// Result of a push operation on the Parser.
+/// Will contain information on how to proceed with the stream.
+pub const PushResult = union(enum) {
+    /// input was completly consumed, no event happened
+    needs_data,
+
+    /// An event happend while processing the data.
+    event: struct {
+        /// The portion of the input data that was not parsed
+        /// while encountering this event.
+        /// Feed it into `push` again until .needs_data happens.
+        rest: []const u8,
+        event: ?Event,
+    },
+
+    /// A format error happened while processing the data.
+    parse_error: struct {
+        const Error = enum {
+            syntax_error,
+            invalid_format,
+        };
+
+        /// The portion of the input data that was not parsed
+        /// while encountering this event.
+        /// Feed it into `push` again until .needs_data happens.
+        rest: []const u8,
+
+        /// The error that was encountered
+        error_type: Error,
+    },
+};
+
+pub const Event = struct {};
+
+test "parser: invalid encoding" {
+    var parser = Parser.init();
+
+    _ = parser.push("\xFF\n") catch |err| {
+        std.testing.expect(err == error.InvalidEncoding);
+        return;
+    };
+    unreachable;
+}

-----END OF PAGE-----