local args = {...}
local component = require("component")
local computer = require("computer")
local event = require("event")
local gpu = component.gpu
local unicode = require("unicode")
local keyboard = require("keyboard")
local text = require("text")
local os = require("os")
local pal = {}

function resetGPU(w, h)
	gpu.setResolution(w, h)
	gpu.setBackground(0, false)
	gpu.setForeground(16777215, false)
	gpu.fill(1, 1, w, h, " ")
end

local q = {}
for i=0,255 do
  local dat = (i & 0x01) << 7
  dat = dat | (i & 0x02) >> 1 << 6
  dat = dat | (i & 0x04) >> 2 << 5
  dat = dat | (i & 0x08) >> 3 << 2
  dat = dat | (i & 0x10) >> 4 << 4
  dat = dat | (i & 0x20) >> 5 << 1
  dat = dat | (i & 0x40) >> 6 << 3
  dat = dat | (i & 0x80) >> 7
  q[i + 1] = unicode.char(0x2800 | dat)
end

function error(str)
  print("ERROR: " .. str)
  os.exit()
end

function resetPalette(data)
 for i=0,255 do
  if (i < 16) then
    if data == nil then
      pal[i] = (i * 15) << 16 | (i * 15) << 8 | (i * 15)
    else
      pal[i] = data[3][i]
      gpu.setPaletteColor(i, data[3][i])
    end
  else
    local j = i - 16
    local b = math.floor((j % 5) * 255 / 4.0)
    local g = math.floor((math.floor(j / 5.0) % 8) * 255 / 7.0)
    local r = math.floor((math.floor(j / 40.0) % 6) * 255 / 5.0)
    pal[i] = r << 16 | g << 8 | b
  end
 end
end

resetPalette(nil)

function gpuBG()
  local a, al = gpu.getBackground()
  if al then
    return gpu.getPaletteColor(a)
  else
    return a
  end
end
function gpuFG()
  local a, al = gpu.getForeground()
  if al then
    return gpu.getPaletteColor(a)
  else
    return a
  end
end

active = 1
function onKeyDown(name, addr, char, key, player)
	active = 0
	return false
end
event.listen("key_down", onKeyDown)

resetGPU(160, 50)
local ticks = 0

local lastSleep = computer.uptime()
function sleep(time)
	local target = lastSleep + time
	while computer.uptime() < target do
		os.sleep(0.05)
	end
	lastSleep = target
end

function getPixel(x, y)
	local px = x << 1
	local py = y << 2
	return q[((calcPixel(px, py) << 7)
		| (calcPixel(px, py + 1) << 5)
		| (calcPixel(px, py + 2) << 3)
		| (calcPixel(px, py + 3) << 1)
		| (calcPixel(px + 1, py) << 6)
		| (calcPixel(px + 1, py + 1) << 4)
		| (calcPixel(px + 1, py + 2) << 2)
		| (calcPixel(px + 1, py + 3))
	) + 1]
end

local cubeData = {{138, 32}, {134, 32}, {154, 0}, {126, 32}, {150, 16},
{114, 32}, {100, 32}, {84, 32}, {66, 32}, {46, 32}, {24, 32}, {0, 32}, {124, 16}, {96, 16},
{66, 16}, {34, 16}, {0, 16}, {118, 0}, {80, 0}, {40, 0}}

function getColor(ticks, mul)
	local ctr = ((ticks & 31) / 32) * 6
	local x = math.floor(mul * (ctr % 1))
	local y = mul
	local z = math.floor(mul * (1 - (ctr % 1)))
	if ctr >= 5 then
		return (y << 16) | z
    end
	if ctr >= 4 then
		return (x << 16) | y
    end
	if ctr >= 3 then
		return (z << 8) | y
    end
	if ctr >= 2 then
		return (y << 8) | x
    end
	if ctr >= 1 then
		return (z << 16) | (y << 8)
    end
	return (y << 16) | (x << 8)
end

function drawLine(y, w, py)
	local t = ((y - 1) & 0xE) * 4
	gpu.set(1, y, ch)
	local sx = cubeData[w][1] + 1
	local sy = cubeData[w][2] + py
	local dx = 21 - w
	local dy = y
	gpu.copy(sx, sy, w * 2, 1, dx - sx, dy - sy)
end

local ticks = 0
gpu.setResolution(80, 25)
gpu.setBackground(0, false)

local t1 = 0
local t2 = 0

function calcPixel(x, y)
	local cx = x - 40 + t1
	local cy = y - 32 + (math.sin(ticks / 10 + (y * 2) / 30) * 16)
	local t = math.sin((cx * cx + cy * cy) / t2)
	if t > 0 then return 1 else return 0 end
end

while active == 1 do
 	t1 = math.cos(ticks / 20) * 20
	for iy=1,25 do
		t2 = 100 + math.sin((ticks + iy * 4) / 45) * 50
		local ch = ""
		for i=1,80,2 do
			ch = ch .. getPixel(i, iy) .. getPixel(i+1, iy)
		end
		gpu.setForeground(getColor(ticks + iy, 0xFF), false)
		gpu.set(1, iy, ch)
	end
	os.sleep(0.05)
	ticks = ticks + 1
end

resetGPU(80, 25)
