local w, h = term.getSize()
local angle = 0

local points = {
    {-1,-1,-1}, {1,-1,-1}, {1,1,-1}, {-1,1,-1},
    {-1,-1, 1}, {1,-1, 1}, {1,1, 1}, {-1,1, 1}
}

local edges = {
    {1,2},{2,3},{3,4},{4,1},
    {5,6},{6,7},{7,8},{8,5},
    {1,5},{2,6},{3,7},{4,8}
}

local function rotate(p, ax, ay)
    local x,y,z = p[1],p[2],p[3]

    local cy, sy = math.cos(ay), math.sin(ay)
    x, z = x * cy - z * sy, x * sy + z * cy

    local cx, sx = math.cos(ax), math.sin(ax)
    y, z = y * cx - z * sx, y * sx + z * cx

    return {x,y,z}
end

local function project(p)
    local distance = 4
    local scale = 10
    local z = p[3] + distance

    local x2d = math.floor((p[1] / z) * scale + w / 2)
    local y2d = math.floor((p[2] / z) * scale + h / 2)

    return x2d, y2d
end

local function drawLine(x1, y1, x2, y2)
    local dx = math.abs(x2 - x1)
    local dy = math.abs(y2 - y1)
    local sx = x1 < x2 and 1 or -1
    local sy = y1 < y2 and 1 or -1
    local err = dx - dy

    while true do
        if x1 >= 1 and x1 <= w and y1 >= 1 and y1 <= h then
            term.setCursorPos(x1, y1)
            write("#")
        end

        if x1 == x2 and y1 == y2 then break end

        local e2 = err * 2
        if e2 > -dy then
            err = err - dy
            x1 = x1 + sx
        end
        if e2 < dx then
            err = err + dx
            y1 = y1 + sy
        end
    end
end

while true do
    term.setBackgroundColor(colors.black)
    term.setTextColor(colors.cyan)
    term.clear()

    local projected = {}

    for i, p in ipairs(points) do
        local rp = rotate(p, angle, angle * 0.7)
        local x, y = project(rp)
        projected[i] = {x, y}
    end

    for _, edge in ipairs(edges) do
        local a = projected[edge[1]]
        local b = projected[edge[2]]
        drawLine(a[1], a[2], b[1], b[2])
    end

    term.setCursorPos(2, 1)
    term.setTextColor(colors.white)
    write("3D Cube - Press Ctrl+T to stop")

    angle = angle + 0.08
    sleep(0.05)
end