repo: hackvr-turbo
action: commit
revision: 
path_from: 
revision_from: 7668423d34c6fc09f53c5fed590670318f1a1bd3:
path_to: 
revision_to: 
git.thebackupbox.net
hackvr-turbo
git clone git://git.thebackupbox.net/hackvr-turbo
commit 7668423d34c6fc09f53c5fed590670318f1a1bd3
Author: Felix (xq) Queißner 
Date:   Sat Jul 4 02:27:50 2020 +0200

    Basic rendering, no translation/rotation yet.

diff --git a/.gitmodules b/.gitmodules
index 98863a0254ffaf0a7359c20ebd1fc339d66d58f0..
index ..fc16d9a53eb35aae662c86a97ac7363a022a3d06 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
 [submodule "lib/zlm"]
 	path = lib/zlm
 	url = https://github.com/ziglibs/zlm
+[submodule "lib/zgl"]
+	path = lib/zgl
+	url = https://github.com/ziglibs/zgl
diff --git a/LICENSE b/LICENSE
index 204b93da48d02900098ced21c54062ffbff36b9c..
index ..d7ae146c288121c2ba6ac81d7114a1f6e48bc114 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-MIT License Copyright (c)  
+MIT License Copyright (c) 2020 Felix Queißner

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/build.zig b/build.zig
index 7af04957f9f9879c1cbf1efd5226d74981638cd9..
index ..f0d50c2702617169ea67e94ce49eef7d241e3dab 100644
--- a/build.zig
+++ b/build.zig
@@ -19,6 +19,11 @@ const zlm = std.build.Pkg{
     .path = "lib/zlm/zlm.zig",
 };

+const zgl = std.build.Pkg{
+    .name = "zgl",
+    .path = "lib/zgl/zgl.zig",
+};
+
 pub fn build(b: *std.build.Builder) void {
     // Standard target options allows the person running `zig build` to choose
     // what target to build for. Here we do not override the defaults, which
@@ -39,6 +44,7 @@ pub fn build(b: *std.build.Builder) void {

     exe.addPackage(hackvr);
     exe.addPackage(zlm);
+    exe.addPackage(zgl);

     exe.install();

diff --git a/lib/hackvr/lib.zig b/lib/hackvr/lib.zig
index c7b2096cfa5eff8978c6640ad35fdf4f68bd02f7..
index ..7abfff29fe009f3ed19ec253b1f09f4043064907 100644
--- a/lib/hackvr/lib.zig
+++ b/lib/hackvr/lib.zig
@@ -158,10 +158,16 @@ pub fn applyEventToState(state: *State, event: parsing.Event) !void {
             };
         },
         .move => |cmd| {
-            // semantics unclear
+            var iter = state.findGroups(cmd.selector.groups);
+            while (iter.next()) |*grp| {
+                // semantics unclear
+            }
         },
         .rotate => |cmd| {
-            // semantics unclear
+            var iter = state.findGroups(cmd.selector.groups);
+            while (iter.next()) |*grp| {
+                // semantics unclear
+            }
         },
         else => {
             std.debug.print("Event {} not implemented yet!\n", .{@as(parsing.EventType, event)});
diff --git a/lib/zgl b/lib/zgl
new file mode 160000
index 0000000000000000000000000000000000000000..c37cf0cfbeeab94cc07121ce3c817cc6813c15fd
--- /dev/null
+++ b/lib/zgl
@@ -0,0 +1 @@
+Subproject commit c37cf0cfbeeab94cc07121ce3c817cc6813c15fd
diff --git a/notes/chatlog.txt b/notes/chatlog.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6ee868e0934a228d0aec0fb92240d054bff940a4
--- /dev/null
+++ b/notes/chatlog.txt
@@ -0,0 +1,48 @@
+ merpkz hat die Verbindung getrennt (Ping timeout: 20 seconds).
+ rotation /should/ be group-relative, but I don't have the code for that in my version yet
+ those movements are absolute
+ if you put a + before them, they're relative
+ rotate 0 90 0 #sets rotation to 90
+ rotate 0 45 0 #sets rotation to 45, not 90 + 45
+ rotate 0 +45 0 #sets rotation to 45 more than what it was
+ rotate 0 +-45 0 #sets rotation to 45 less than what it was
+ and those 0s are absolutes too
+ so if there was a rotation on the x or z before any of those, they'd get reset to 0
+ the moves are in the global directions probably
+ and they set absolute too
+ unless using + before the values
+ if you do "forward" it is the group's positive z after rotation
+ so you can have something loop on: "rotate 0 +5 0" and "move forward" and it'll walk in a circle
+ "circle"
+ n-gon of 360/5 sides or something
+ thanks  for clarification :)
+ so move forward is relative, but move +0 +0 +1 is absolute *grin*
+ I'm kind of AFK doing cleaning, so leave questions and I'll answer when I check my screen.
+ (so to speak: without rotation)
+ but makes implementation easier for me :
+ *girn*
+ no fancy transforms
+ this allows me to display the maze soonish *joy*
+ the fancy transforms can usually be done by building up multiple commands.
+ om mani padme hum
+ ...
+ someone said something about an "Abort, Retry, Fail" keychain
+ but made me think of other situtations where those three options would apply.
+ > your fetus has Fetal Alcohol Syndrome.
+ > Abort, Retry, Fail
+ *cough*
+ anyway
+* epoch wanders off again
+* ice hat die Verbindung getrennt (Ping timeout: 20 seconds).
+* ice (~ice@loud.house) ist beigetreten.
+* SegFault gibt Channel-Operator-Status an ice
+ hackvr over gemini.
+ not just static either
+ gemini-get gemini://gemini.thebackupbox.net/hackvr-stream | hackvr | tr '\n' '\0' | uriescape | tr '\n' '\0' | xargs -0 -I{} gemini-get 'gemini://gemini.thebackupbox.net/hackvr-input?{}'
+-except/#default- hxxini://gemini.thebackupbox.net/hackvr-stream https://epo.k.vu/9a4d
+-except/#default- title:
+ or whatever it is
+ similar would work for http
+ as long as the protocol can stay open forever.
+ still not sure if gemini will support that
+ solderpunk liked that idea of doing tail -f over gemini though
\ No newline at end of file
diff --git a/src/main.zig b/src/main.zig
index 4da82fe67e2d4c597e0c8ad02aa6d69ff81dead3..
index ..51a299aad5245a01988e7b2471ffa32bc61f20c8 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -1,11 +1,11 @@
 const std = @import("std");

+const zlm = @import("zlm");
 const hackvr = @import("hackvr");
+const gl = @import("zgl");

 const c = @cImport({
-    @cInclude("epoxy/gl.h");
     @cInclude("SDL.h");
-    // @cInclude("SDL_opengl.h");
 });

 const SdlError = error{SdlFailure};
@@ -28,7 +28,48 @@ const cli_options = CliOptions{
     .multisampling = null,
 };

+fn parseColor(comptime col: []const u8) zlm.Vec3 {
+    std.debug.assert(col.len == 7);
+    std.debug.assert(col[0] == '#');
+    return zlm.Vec3{
+        .x = @intToFloat(f32, std.fmt.parseInt(u8, col[1..3], 16) catch unreachable) / 255.0,
+        .y = @intToFloat(f32, std.fmt.parseInt(u8, col[3..5], 16) catch unreachable) / 255.0,
+        .z = @intToFloat(f32, std.fmt.parseInt(u8, col[5..7], 16) catch unreachable) / 255.0,
+    };
+}
+
+// https://lospec.com/palette-list/dawnbringer-16
+const palette = [_]zlm.Vec3{
+    parseColor("#140c1c"),
+    parseColor("#442434"),
+    parseColor("#30346d"),
+    parseColor("#4e4a4e"),
+    parseColor("#854c30"),
+    parseColor("#346524"),
+    parseColor("#d04648"),
+    parseColor("#757161"),
+    parseColor("#597dce"),
+    parseColor("#d27d2c"),
+    parseColor("#8595a1"),
+    parseColor("#6daa2c"),
+    parseColor("#d2aa99"),
+    parseColor("#6dc2ca"),
+    parseColor("#dad45e"),
+    parseColor("#deeed6"),
+};
+
+const Vertex = extern struct {
+    position: zlm.Vec3,
+    color: zlm.Vec3,
+};
+
 pub fn main() anyerror!void {
+    var gpa_backing = std.testing.LeakCountAllocator.init(std.heap.c_allocator);
+    defer {
+        gpa_backing.validate() catch |err| {};
+    }
+    const gpa = &gpa_backing.allocator;
+
     if (c.SDL_Init(c.SDL_INIT_EVERYTHING) < 0) {
         return makeSdlError();
     }
@@ -58,7 +99,123 @@ pub fn main() anyerror!void {

     try sdlCheck(c.SDL_GL_MakeCurrent(window, context));

-    c.glDebugMessageCallback(openGlDebugCallback, null);
+    try gl.debugMessageCallback({}, openGlDebugCallback);
+
+    var state = hackvr.State.init(std.testing.allocator);
+    defer state.deinit();
+
+    var parser = hackvr.parsing.Parser.init();
+
+    // Good enough for now, should be changed later!
+    {
+        var src: []const u8 = @embedFile("../lib/hackvr/data/test.hackvr");
+        while (src.len > 0) {
+            var item = try parser.push(src);
+            switch (item) {
+                // should never be reached as the test.hackvr is a complete file, terminated by a LF
+                .needs_data => unreachable,
+
+                // should never be reached as the test.hackvr file is correct
+                .parse_error => unreachable,
+
+                .event => |ev| {
+                    src = ev.rest;
+                    try hackvr.applyEventToState(&state, ev.event);
+                },
+            }
+        }
+    }
+
+    var vao = try gl.createVertexArray();
+    defer vao.delete();
+
+    try vao.enableVertexAttribute(0);
+    try vao.enableVertexAttribute(1);
+
+    try vao.attribFormat(
+        0,
+        3,
+        .float,
+        false,
+        @byteOffsetOf(Vertex, "position"),
+    );
+    try vao.attribFormat(
+        1,
+        3,
+        .float,
+        false,
+        @byteOffsetOf(Vertex, "color"),
+    );
+
+    try vao.attribBinding(0, 0);
+    try vao.attribBinding(1, 0);
+
+    var vertex_buffer = try gl.createBuffer();
+    defer vertex_buffer.delete();
+
+    var vertex_list = std.ArrayList(Vertex).init(gpa);
+    defer vertex_list.deinit();
+
+    try vao.vertexBuffer(0, vertex_buffer, 0, @sizeOf(Vertex));
+
+    var shader_program = try gl.createProgram();
+    defer shader_program.delete();
+
+    {
+        var vertex_shader = try gl.createShader(.vertex);
+        defer vertex_shader.delete();
+
+        var fragment_shader = try gl.createShader(.fragment);
+        defer fragment_shader.delete();
+
+        try vertex_shader.source(1, &[_][]const u8{
+            @embedFile("./shader/flat.vert"),
+        });
+
+        try fragment_shader.source(1, &[_][]const u8{
+            @embedFile("./shader/flat.frag"),
+        });
+
+        try vertex_shader.compile();
+        if ((try vertex_shader.get(.compile_status)) == 0) {
+            const compile_log = try vertex_shader.getCompileLog(gpa);
+            defer gpa.free(compile_log);
+
+            std.debug.print("failed to compile vertex shader:\n{}\n", .{compile_log});
+            return;
+        }
+
+        try fragment_shader.compile();
+        if ((try fragment_shader.get(.compile_status)) == 0) {
+            const compile_log = try fragment_shader.getCompileLog(gpa);
+            defer gpa.free(compile_log);
+
+            std.debug.print("failed to compile fragment shader:\n{}\n", .{compile_log});
+            return;
+        }
+
+        try shader_program.attach(vertex_shader);
+        defer shader_program.detach(vertex_shader);
+
+        try shader_program.attach(fragment_shader);
+        defer shader_program.detach(fragment_shader);
+
+        try shader_program.link();
+        if ((try shader_program.get(.link_status)) == 0) {
+            const link_log = try shader_program.getCompileLog(gpa);
+            defer gpa.free(link_log);
+
+            std.debug.print("failed to compile fragment shader:\n{}\n", .{link_log});
+            return;
+        }
+    }
+
+    const transform_loc = (try shader_program.uniformLocation("uTransform")) orelse {
+        std.log.crit(.Exe, "Failed to query uniform uTransform!\n", .{});
+        return;
+    };
+
+    try gl.enable(.depth_test);

     mainLoop: while (true) {
         // process events
@@ -72,10 +229,71 @@ pub fn main() anyerror!void {
             }
         }

+        // Render scene from HackVR dataset
         {
-            // render
-            c.glClearColor(1.0, 0.0, 0.0, 1.0);
-            c.glClear(c.GL_COLOR_BUFFER_BIT);
+            vertex_list.shrink(0);
+
+            var groups = state.iterator();
+            while (groups.next()) |group| {
+                for (group.shapes.items) |shape| {
+                    if (shape.points.len < 3) {
+                        std.debug.print("count: {}\n", .{shape.points.len});
+                    } else {
+                        // Simple fan-out triangulation.
+                        // Not beautiful, but very simple
+                        var i: usize = 2;
+                        while (i < shape.points.len) {
+                            try vertex_list.append(Vertex{
+                                .position = shape.points[0],
+                                .color = palette[shape.attributes.color],
+                            });
+                            try vertex_list.append(Vertex{
+                                .position = shape.points[i - 1],
+                                .color = palette[shape.attributes.color],
+                            });
+                            try vertex_list.append(Vertex{
+                                .position = shape.points[i],
+                                .color = palette[shape.attributes.color],
+                            });
+
+                            i += 1;
+                        }
+                    }
+                }
+            }
+        }
+
+        try gl.namedBufferData(vertex_buffer, Vertex, vertex_list.items, .dynamic_draw);
+
+        const mat_proj = zlm.Mat4.createPerspective(1.0, 16.0 / 9.0, 0.1, 10000.0);
+        const mat_view = zlm.Mat4.createLookAt(
+            .{ .x = -20, .y = 0, .z = 0 },
+            .{ .x = 0, .y = 0, .z = 0 },
+            .{ .x = 0, .y = 1, .z = 0 },
+        );
+
+        const mat_view_proj = zlm.Mat4.mul(mat_view, mat_proj);
+
+        // render graphics
+        {
+            try gl.clearColor(0.0, 0.0, 0.3, 1.0);
+            try gl.clearDepth(1.0);
+            try gl.clear(.{
+                .color = true,
+                .depth = true,
+            });
+
+            try vao.bind();
+            try shader_program.use();
+
+            try gl.programUniformMatrix4(
+                shader_program,
+                transform_loc,
+                false,
+                @ptrCast([*]const [4][4]f32, &mat_view_proj.fields)[0..1],
+            );
+
+            try gl.drawArrays(.triangles, 0, vertex_list.items.len);

             c.SDL_GL_SwapWindow(window);
             c.SDL_Delay(10);
@@ -84,24 +302,20 @@ pub fn main() anyerror!void {
 }

 fn openGlDebugCallback(
-    source: c.GLenum,
-    msg_type: c.GLenum,
-    id: c.GLuint,
-    severity: c.GLenum,
-    length: c.GLsizei,
-    message: [*c]const c.GLchar,
-    userParam: ?*const c_void,
-) callconv(.C) void {
-    const msg_fmt = "{}\n";
-    const msg_arg = .{
-        message.?[0..@intCast(usize, length)],
-    };
+    source: gl.DebugSource,
+    msg_type: gl.DebugMessageType,
+    id: usize,
+    severity: gl.DebugSeverity,
+    message: []const u8,
+) void {
+    const msg_fmt = "[{}/{}] {}\n";
+    const msg_arg = .{ @tagName(source), @tagName(msg_type), message };

     switch (severity) {
-        c.GL_DEBUG_SEVERITY_HIGH => std.log.err(.OpenGL, msg_fmt, msg_arg),
-        c.GL_DEBUG_SEVERITY_MEDIUM => std.log.warn(.OpenGL, msg_fmt, msg_arg),
-        c.GL_DEBUG_SEVERITY_LOW => std.log.notice(.OpenGL, msg_fmt, msg_arg),
-        c.GL_DEBUG_SEVERITY_NOTIFICATION => std.log.notice(.OpenGL, msg_fmt, msg_arg),
+        .high => std.log.crit(.OpenGL, msg_fmt, msg_arg),
+        .medium => std.log.err(.OpenGL, msg_fmt, msg_arg),
+        .low => std.log.warn(.OpenGL, msg_fmt, msg_arg),
+        .notification => std.log.notice(.OpenGL, msg_fmt, msg_arg),
         else => std.log.crit(.OpenGL, msg_fmt, msg_arg),
     }
 }
diff --git a/src/shader/flat.frag b/src/shader/flat.frag
new file mode 100644
index 0000000000000000000000000000000000000000..5c6ddd46d636e44dba774d3b8da825221017db28
--- /dev/null
+++ b/src/shader/flat.frag
@@ -0,0 +1,7 @@
+#version 330
+
+layout(location = 0) out vec4 fColor;
+
+in vec3 color;
+
+void main() { fColor = vec4(color, 1.0); }
\ No newline at end of file
diff --git a/src/shader/flat.vert b/src/shader/flat.vert
new file mode 100644
index 0000000000000000000000000000000000000000..184f764e3bd870c7c21caeda93f0d38c0729d797
--- /dev/null
+++ b/src/shader/flat.vert
@@ -0,0 +1,13 @@
+#version 330
+
+layout(location = 0) in vec3 vPosition;
+layout(location = 1) in vec3 vColor;
+
+out vec3 color;
+
+uniform mat4 uTransform;
+
+void main() {
+  gl_Position = uTransform * vec4(vPosition, 1);
+  color = vColor;
+}
\ No newline at end of file

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