const std = @import("std");
const ArrayList = std.ArrayList;

const zm = @import("zmath");

const Mesh = @import("mesh.zig");
const Shader = @import("shader.zig");
const Tree = @import("../tree.zig").Tree;

pub const JointData = struct {
    mesh: Mesh,
    translation: zm.Mat,
    rotation: zm.Quat,
};

data: Tree(JointData),

pub fn init(
    data: Tree(JointData),
) @This() {
    return .{ .data = data };
}

pub fn draw(self: *@This(), shader: Shader) void {
    var iter = self.data.depthFirstIterator();
    while (iter.next()) |node| {
        var rotation = node.val.rotation;
        var current = node;
        while (current.parent) |parent| {
            rotation = zm.qmul(rotation, parent.val.rotation);
            current = parent;
        }

        const model_matrix = zm.mul(zm.quatToMat(rotation), node.val.translation);
        const normal_matrix = zm.transpose(zm.inverse(model_matrix));
        shader.updateUniformMatrix("u_model_matrix", &.{model_matrix});
        shader.updateUniformMatrix("u_normal_matrix", &.{normal_matrix});
        node.val.mesh.draw(shader);
    }
}

pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
    self.data.deinit(allocator);
}
