const refAllDeclsRecursive = @import("std").testing.refAllDeclsRecursive;

const zgl = @import("zgl");
const zm = @import("zmath");

pub const Camera = @import("camera.zig");
pub const Color = @import("color.zig");
pub const Mesh = @import("mesh.zig");
pub const Model = @import("model.zig");
pub const Shader = @import("shader.zig");
pub const Texture = @import("texture.zig");

pub fn initEbo(T: type, indices: []const T) zgl.Buffer {
    var buffer = zgl.Buffer.create();
    buffer.storage(T, indices.len, indices.ptr, .{});
    return buffer;
}

pub fn initVbo(T: type, items: []const T, flags: zgl.BufferStorageFlags) zgl.Buffer {
    const buffer = zgl.Buffer.create();
    buffer.storage(T, items.len, items.ptr, flags);
    return buffer;
}

pub fn initUbo(T: type, shaders: []const Shader, name: [:0]const u8, binding: u32, size: u32) zgl.Buffer {
    for (shaders) |shader| {
        if (zgl.getUniformBlockIndex(shader.id, name)) |index| {
            zgl.uniformBlockBinding(shader.id, index, binding);
        }
    }
    var buffer = zgl.Buffer.create();
    buffer.storage(T, size, null, .{ .dynamic_storage = true });
    zgl.bindBufferRange(.uniform_buffer, binding, buffer, 0, size * @sizeOf(T));

    return buffer;
}

pub fn initSsbo(T: type, vertices: []const T, flags: zgl.BufferStorageFlags) zgl.Buffer {
    var buffer = zgl.Buffer.create();
    buffer.storage(T, vertices.len, vertices.ptr, flags);
    return buffer;
}

pub fn linkAttribute(vao: zgl.VertexArray, vbo: zgl.Buffer, location: u32, binding_index: u32, size: u32, attrib_type: zgl.Type, normalised: bool, offset: usize, stride: usize) void {
    vao.vertexBuffer(binding_index, vbo, offset, stride);
    vao.enableVertexAttribute(location);
    vao.attribFormat(location, size, attrib_type, normalised, offset);
    vao.attribBinding(location, binding_index);
}

comptime {
    refAllDeclsRecursive(@This());
}
