-- Leo's gemini proxy

-- Connecting to git.thebackupbox.net:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

repo: hackvr-turbo
action: commit
revision:
path_from:
revision_from: 5ce0050057def3e859d35a988be4ed51937ef258:
path_to:
revision_to:

git.thebackupbox.net

hackvr-turbo

git://git.thebackupbox.net/hackvr-turbo

commit 5ce0050057def3e859d35a988be4ed51937ef258
Author: Felix (xq) Queißner <git@mq32.de>
Date:   Sat Jul 4 16:50:17 2020 +0200

    Adds (badly working) picking and interaction output

diff --git a/SPEC.md b/SPEC.md

index 0c97b8d2602290523d71bd8b18a43172d08f6c7f..

index ..3bba50afd04a4bc5beea744cff0422f22538ecd6 100644

--- a/SPEC.md
+++ b/SPEC.md
@@ -107,7 +107,7 @@ Applies the current group transform to all contained vertices in the selected gr

 ## Output Commands

-### `name action targetgroup`
+### `[name] action [targetgroup]`

 when a group is clicked on using the name set from the command line. usually `$USER`

diff --git a/lib/hackvr/parser.zig b/lib/hackvr/parser.zig

index d7f6fe479ea8774e10adb25c3cb8f931404cf091..

index ..695e1de696589c4e56234171d5125a73a7f39dee 100644

--- a/lib/hackvr/parser.zig
+++ b/lib/hackvr/parser.zig
@@ -266,10 +266,18 @@ pub const Parser = struct {
                     const event = self.parseLine(line) catch |err| switch (err) {
                         error.UnknownCommand => return PushResult{
                             .parse_error = .{
+                                .source = line,
                                 .rest = rest,
                                 .error_type = .unknown_command,
                             },
                         },
+                        error.ArgumentMismatch => return PushResult{
+                            .parse_error = .{
+                                .source = line,
+                                .rest = rest,
+                                .error_type = .argument_mismatch,
+                            },
+                        },
                         else => return err,
                     };

@@ -319,8 +327,12 @@ pub const PushResult = union(enum) {
             syntax_error,
             invalid_format,
             unknown_command,
+            argument_mismatch,
         };

+        /// The portion that triggered the error.
+        source: []const u8,
+
         /// The portion of the input data that was not parsed
         /// while encountering this event.
         /// Feed it into `push` again until .needs_data happens.
diff --git a/lib/zgl b/lib/zgl

index 239e268a0215776a8e8afd9cd5930544d37fcf25..

index ..a62c9b91efc0853afc7c47a57cfb1b641952acee 160000

--- a/lib/zgl
+++ b/lib/zgl
@@ -1 +1 @@
-Subproject commit 239e268a0215776a8e8afd9cd5930544d37fcf25
+Subproject commit a62c9b91efc0853afc7c47a57cfb1b641952acee
diff --git a/src/main.zig b/src/main.zig

index 01434f07b8ab5c6214622575378581ac03910b38..

index ..5ac706a36c354a4002e2e936b329aed7df367330 100644

--- a/src/main.zig
+++ b/src/main.zig
@@ -135,6 +135,7 @@ pub fn main() anyerror!void {
     defer lines_vertex_buffer.delete();

     const PolygonGroup = struct {
+        group_index: usize,
         transform: zlm.Mat4,
         begin_tris: usize,
         count_tris: usize,
@@ -208,6 +209,11 @@ pub fn main() anyerror!void {
         return;
     };

+    const highlighted_loc = (try shader_program.uniformLocation("uHighlighting")) orelse {
+        std.log.crit(.Exe, "Failed to query uniform uHighlighting!\n", .{});
+        return;
+    };
+
     try gl.enable(.depth_test);
     try gl.depthFunc(.less_or_equal);
     try gl.enable(.polygon_offset_line);
@@ -220,6 +226,7 @@ pub fn main() anyerror!void {
     var parser = hackvr.parsing.Parser.init();

     const stdin = std.io.getStdIn().reader();
+    const stderr = std.io.getStdErr().writer();
     const stdout = std.io.getStdOut().writer();

     _ = try std.os.fcntl(
@@ -268,8 +275,13 @@ pub fn main() anyerror!void {

                         // should never be reached as the test.hackvr file is correct
                         .parse_error => |err| {
-                            try stdout.print("# Error while parsing line: {}\n", .{
+                            try stdout.print("# Error while parsing line: {}\n# '{}'\n", .{
+                                err.error_type,
+                                err.source,
+                            });
+                            try stderr.print("# Error while parsing line: {}\n# '{}'\n", .{
                                 err.error_type,
+                                err.source,
                             });
                             slice = err.rest;
                         },
@@ -284,12 +296,19 @@ pub fn main() anyerror!void {
             }
         }

+        var signal_picked_shape = false;
+
         // process SDL events
         {
             var event: c.SDL_Event = undefined;
             while (c.SDL_PollEvent(&event) != 0) {
                 switch (event.type) {
                     c.SDL_QUIT => break :mainLoop,
+                    c.SDL_MOUSEBUTTONDOWN => {
+                        if (event.button.button == c.SDL_BUTTON_LEFT) {
+                            signal_picked_shape = true;
+                        }
+                    },
                     c.SDL_MOUSEMOTION => {
                         const motion = &event.motion;

@@ -375,9 +394,11 @@ pub fn main() anyerror!void {
             vertex_list.shrink(0);
             poly_groups.shrink(0);

+            var group_index: usize = 0;
             var groups = state.iterator();
-            while (groups.next()) |group| {
+            while (groups.next()) |group| : (group_index += 1) {
                 var poly_grp = PolygonGroup{
+                    .group_index = group_index,
                     .begin_tris = vertex_list.items.len,
                     .count_tris = undefined,
                     .begin_lines = outline_list.items.len,
@@ -439,9 +460,6 @@ pub fn main() anyerror!void {

                 try poly_groups.append(poly_grp);
             }
-
-            try gl.namedBufferData(tris_vertex_buffer, Vertex, vertex_list.items, .dynamic_draw);
-            try gl.namedBufferData(lines_vertex_buffer, Vertex, outline_list.items, .dynamic_draw);
         }

         const mat_proj = zlm.Mat4.createPerspective(1.0, 16.0 / 9.0, 0.1, 10000.0);
@@ -457,6 +475,117 @@ pub fn main() anyerror!void {

         const mat_view_proj = mat_view.mul(mat_proj);

+        const mat_view_proj_inv = invertMatrix(mat_view_proj) orelse unreachable;
+
+        // std.debug.warn("normal: {}\n", .{mat_view_proj});
+        // std.debug.warn("invert: {}\n", .{mat_view_proj_inv});
+
+        const PickedShape = struct {
+            group_index: usize,
+            shape_index: usize,
+            group: *hackvr.Group,
+            shape: *hackvr.Shape3D,
+        };
+
+        var picked_shape: ?PickedShape = blk: {
+            var mouse_x: c_int = undefined;
+            var mouse_y: c_int = undefined;
+            _ = c.SDL_GetMouseState(&mouse_x, &mouse_y);
+
+            var mouse_pos_near_ss = zlm.Vec4{
+                .x = 2.0 * @intToFloat(f32, mouse_x) / 1279.0 - 1.0,
+                .y = 1.0 - 2.0 * @intToFloat(f32, mouse_y) / 719.0,
+                .z = 0.0,
+                .w = 1.0,
+            };
+            var mouse_pos_far_ss = zlm.Vec4{
+                .x = mouse_pos_near_ss.x,
+                .y = mouse_pos_near_ss.y,
+                .z = 1.0,
+                .w = 1.0,
+            };
+
+            // std.debug.print("ss {} {}\n", .{ mouse_pos_near_ss, mouse_pos_far_ss });
+
+            var mouse_pos_near_ws = mouse_pos_near_ss.transform(mat_view_proj_inv);
+            mouse_pos_near_ws = mouse_pos_near_ws.scale(1.0 / mouse_pos_near_ws.w);
+
+            var mouse_pos_far_ws = mouse_pos_far_ss.transform(mat_view_proj_inv);
+            mouse_pos_far_ws = mouse_pos_far_ws.scale(1.0 / mouse_pos_far_ws.w);
+
+            // std.debug.print("ws {} {}\n", .{ mouse_pos_near_ws, mouse_pos_far_ws });
+
+            var ray_origin = mouse_pos_near_ws.swizzle("xyz");
+
+            var ray_direction = mouse_pos_far_ws.swizzle("xyz").sub(ray_origin).normalize();
+
+            try outline_list.append(Vertex{
+                .position = ray_origin,
+                .color = parseColor("#FF00FF"),
+            });
+            try outline_list.append(Vertex{
+                .position = ray_origin.add(ray_direction.scale(100)),
+                .color = parseColor("#FF00FF"),
+            });
+
+            var distance = std.math.inf(f32);
+
+            var result: ?PickedShape = null;
+
+            var group_index: usize = 0;
+            var groups = state.iterator();
+            while (groups.next()) |group| : (group_index += 1) {
+                const transform = zlm.Mat4.mul(
+                    zlm.Mat4.createAngleAxis(zlm.Vec3.unitY, zlm.toRadians(group.rotation.y)),
+                    zlm.Mat4.createTranslation(group.translation),
+                );
+
+                for (group.shapes.items) |*shape, shape_index| {
+                    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) {
+                            if (rayTriangleIntersect(
+                                ray_origin,
+                                ray_direction,
+                                shape.points[0].transformPosition(transform),
+                                shape.points[i - 1].transformPosition(transform),
+                                shape.points[i].transformPosition(transform),
+                            )) |dist| {
+                                if (dist < distance) {
+                                    distance = dist;
+                                    result = PickedShape{
+                                        .group_index = group_index,
+                                        .shape_index = shape_index,
+                                        .shape = shape,
+                                        .group = group,
+                                    };
+                                }
+                            }
+
+                            i += 1;
+                        }
+                    }
+                }
+            }
+            break :blk result;
+        };
+
+        if (signal_picked_shape) {
+            if (picked_shape) |indices| {
+                try stdout.print("{} action {}\n", .{
+                    "USER",
+                    indices.group.name,
+                });
+            }
+        }
+
+        try gl.namedBufferData(tris_vertex_buffer, Vertex, vertex_list.items, .dynamic_draw);
+        try gl.namedBufferData(lines_vertex_buffer, Vertex, outline_list.items, .dynamic_draw);
+
         // render graphics
         {
             try gl.clearColor(0.0, 0.0, 0.3, 1.0);
@@ -469,6 +598,12 @@ pub fn main() anyerror!void {
             try vao.bind();
             try shader_program.use();

+            try gl.programUniform1f(
+                shader_program,
+                highlighted_loc,
+                0.0,
+            );
+
             try vao.vertexBuffer(0, tris_vertex_buffer, 0, @sizeOf(Vertex));
             for (poly_groups.items) |poly_grp| {
                 const transform = zlm.Mat4.mul(poly_grp.transform, mat_view_proj);
@@ -487,6 +622,17 @@ pub fn main() anyerror!void {
             for (poly_groups.items) |poly_grp| {
                 const transform = zlm.Mat4.mul(poly_grp.transform, mat_view_proj);

+                const picked = if (picked_shape) |indices|
+                    indices.group_index == poly_grp.group_index
+                else
+                    false;
+
+                try gl.programUniform1f(
+                    shader_program,
+                    highlighted_loc,
+                    if (picked) @as(f32, 1.0) else @as(f32, 0.0),
+                );
+
                 try gl.programUniformMatrix4(
                     shader_program,
                     transform_loc,
@@ -496,6 +642,15 @@ pub fn main() anyerror!void {
                 try gl.drawArrays(.lines, poly_grp.begin_lines, poly_grp.count_lines);
             }

+            var transform = mat_view_proj;
+            try gl.programUniformMatrix4(
+                shader_program,
+                transform_loc,
+                false,
+                @ptrCast([*]const [4][4]f32, &transform.fields)[0..1],
+            );
+            try gl.drawArrays(.lines, outline_list.items.len - 2, 2);
+
             c.SDL_GL_SwapWindow(window);
             c.SDL_Delay(10);
         }
@@ -545,3 +700,195 @@ fn isDataOnStdInAvailable() !bool {
     }
     return false;
 }
+
+fn rayTriangleIntersect(orig: zlm.Vec3, dir: zlm.Vec3, v0: zlm.Vec3, v1: zlm.Vec3, v2: zlm.Vec3) ?f32 {
+    const kEpsilon = 0.0001;
+
+    // compute plane's normal
+    const v0v1 = v1.sub(v0);
+    const v0v2 = v2.sub(v0);
+    // no need to normalize
+    const N = v0v1.cross(v0v2); // N
+    const area2 = N.length();
+
+    // Step 1: finding P
+
+    // check if ray and plane are parallel ?
+    const NdotRayDirection = N.dot(dir);
+    if (std.math.absFloat(NdotRayDirection) < kEpsilon) { // almost 0
+        return null; // they are parallel so they don't intersect !
+    }
+
+    // compute d parameter using equation 2
+    const d = N.dot(v0);
+
+    // compute t (equation 3)
+    const t = (N.dot(orig) + d) / NdotRayDirection;
+    // check if the triangle is in behind the ray
+    if (t < 0) {
+        return null; // the triangle is behind
+    }
+
+    // compute the intersection point using equation 1
+    const P = orig.add(dir.scale(t));
+
+    // Step 2: inside-outside test
+
+    // edge 0
+    const edge0 = v1.sub(v0);
+    const vp0 = P.sub(v0);
+    const C0 = edge0.cross(vp0); // vector perpendicular to triangle's plane
+    if (N.dot(C0) < 0) {
+        return null; // P is on the right side
+    }
+
+    // edge 1
+    const edge1 = v2.sub(v1);
+    const vp1 = P.sub(v1);
+    const C1 = edge1.cross(vp1);
+    if (N.dot(C1) < 0) {
+        return null; // P is on the right side
+    }
+
+    // edge 2
+    const edge2 = v0.sub(v2);
+    const vp2 = P.sub(v2);
+    const C2 = edge2.cross(vp2);
+    if (N.dot(C2) < 0) {
+        return null; // P is on the right side;
+    }
+
+    return t; // this ray hits the triangle
+}
+
+fn invertMatrix(mat: zlm.Mat4) ?zlm.Mat4 {
+    const m = @bitCast([16]f32, mat.fields);
+    var inv: [16]f32 = undefined;
+
+    inv[0] = m[5] * m[10] * m[15] -
+        m[5] * m[11] * m[14] -
+        m[9] * m[6] * m[15] +
+        m[9] * m[7] * m[14] +
+        m[13] * m[6] * m[11] -
+        m[13] * m[7] * m[10];
+
+    inv[4] = -m[4] * m[10] * m[15] +
+        m[4] * m[11] * m[14] +
+        m[8] * m[6] * m[15] -
+        m[8] * m[7] * m[14] -
+        m[12] * m[6] * m[11] +
+        m[12] * m[7] * m[10];
+
+    inv[8] = m[4] * m[9] * m[15] -
+        m[4] * m[11] * m[13] -
+        m[8] * m[5] * m[15] +
+        m[8] * m[7] * m[13] +
+        m[12] * m[5] * m[11] -
+        m[12] * m[7] * m[9];
+
+    inv[12] = -m[4] * m[9] * m[14] +
+        m[4] * m[10] * m[13] +
+        m[8] * m[5] * m[14] -
+        m[8] * m[6] * m[13] -
+        m[12] * m[5] * m[10] +
+        m[12] * m[6] * m[9];
+
+    inv[1] = -m[1] * m[10] * m[15] +
+        m[1] * m[11] * m[14] +
+        m[9] * m[2] * m[15] -
+        m[9] * m[3] * m[14] -
+        m[13] * m[2] * m[11] +
+        m[13] * m[3] * m[10];
+
+    inv[5] = m[0] * m[10] * m[15] -
+        m[0] * m[11] * m[14] -
+        m[8] * m[2] * m[15] +
+        m[8] * m[3] * m[14] +
+        m[12] * m[2] * m[11] -
+        m[12] * m[3] * m[10];
+
+    inv[9] = -m[0] * m[9] * m[15] +
+        m[0] * m[11] * m[13] +
+        m[8] * m[1] * m[15] -
+        m[8] * m[3] * m[13] -
+        m[12] * m[1] * m[11] +
+        m[12] * m[3] * m[9];
+
+    inv[13] = m[0] * m[9] * m[14] -
+        m[0] * m[10] * m[13] -
+        m[8] * m[1] * m[14] +
+        m[8] * m[2] * m[13] +
+        m[12] * m[1] * m[10] -
+        m[12] * m[2] * m[9];
+
+    inv[2] = m[1] * m[6] * m[15] -
+        m[1] * m[7] * m[14] -
+        m[5] * m[2] * m[15] +
+        m[5] * m[3] * m[14] +
+        m[13] * m[2] * m[7] -
+        m[13] * m[3] * m[6];
+
+    inv[6] = -m[0] * m[6] * m[15] +
+        m[0] * m[7] * m[14] +
+        m[4] * m[2] * m[15] -
+        m[4] * m[3] * m[14] -
+        m[12] * m[2] * m[7] +
+        m[12] * m[3] * m[6];
+
+    inv[10] = m[0] * m[5] * m[15] -
+        m[0] * m[7] * m[13] -
+        m[4] * m[1] * m[15] +
+        m[4] * m[3] * m[13] +
+        m[12] * m[1] * m[7] -
+        m[12] * m[3] * m[5];
+
+    inv[14] = -m[0] * m[5] * m[14] +
+        m[0] * m[6] * m[13] +
+        m[4] * m[1] * m[14] -
+        m[4] * m[2] * m[13] -
+        m[12] * m[1] * m[6] +
+        m[12] * m[2] * m[5];
+
+    inv[3] = -m[1] * m[6] * m[11] +
+        m[1] * m[7] * m[10] +
+        m[5] * m[2] * m[11] -
+        m[5] * m[3] * m[10] -
+        m[9] * m[2] * m[7] +
+        m[9] * m[3] * m[6];
+
+    inv[7] = m[0] * m[6] * m[11] -
+        m[0] * m[7] * m[10] -
+        m[4] * m[2] * m[11] +
+        m[4] * m[3] * m[10] +
+        m[8] * m[2] * m[7] -
+        m[8] * m[3] * m[6];
+
+    inv[11] = -m[0] * m[5] * m[11] +
+        m[0] * m[7] * m[9] +
+        m[4] * m[1] * m[11] -
+        m[4] * m[3] * m[9] -
+        m[8] * m[1] * m[7] +
+        m[8] * m[3] * m[5];
+
+    inv[15] = m[0] * m[5] * m[10] -
+        m[0] * m[6] * m[9] -
+        m[4] * m[1] * m[10] +
+        m[4] * m[2] * m[9] +
+        m[8] * m[1] * m[6] -
+        m[8] * m[2] * m[5];
+
+    const det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
+
+    if (det == 0)
+        return null;
+
+    const inv_det = 1.0 / det;
+
+    for (inv) |*val| {
+        val.* *= inv_det;
+    }
+
+    return zlm.Mat4{
+        .fields = @bitCast([4][4]f32, inv),
+    };
+}
diff --git a/src/shader/flat.frag b/src/shader/flat.frag

index 5c6ddd46d636e44dba774d3b8da825221017db28..

index ..dbcf1ff73e3299f902359e2075ff928e3457d6ec 100644

--- a/src/shader/flat.frag
+++ b/src/shader/flat.frag
@@ -4,4 +4,9 @@ layout(location = 0) out vec4 fColor;

 in vec3 color;

-void main() { fColor = vec4(color, 1.0); }
\ No newline at end of file
+uniform float uHighlighting;
+
+void main() {
+  // comment
+  fColor = mix(vec4(color, 1.0), vec4(1, 0, 0, 1), uHighlighting);
+}
\ No newline at end of file

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

-- Response ended

-- Page fetched on Sun Jun 2 16:07:46 2024