Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local gpu = require("component").gpu
- local png = require("png")
- local unicode = require("unicode")
- local computer = require("computer")
- local bit32 = require("bit32")
- local util = {}
- function util.cached1arg(func, entries, pos)
- local cache = {}
- local count = 0
- return function(...)
- local arg = select(pos, ...)
- if cache[arg] then
- return cache[arg]
- else
- if count == entries then
- cache[next(cache)] = nil
- else
- count = count + 1
- end
- local out = func(...)
- cache[arg] = out
- return out
- end
- end
- end
- do
- util.palette = {}
- local extract = function(color)
- color = color % 0x1000000
- local r = math.floor(color / 0x10000)
- local g = math.floor((color - r * 0x10000) / 0x100)
- local b = color - r * 0x10000 - g * 0x100
- return r, g, b
- end
- util.palette.extract = extract
- local function delta(color1, color2)
- local r1, g1, b1 = extract(color1)
- local r2, g2, b2 = extract(color2)
- local dr = r1 - r2
- local dg = g1 - g2
- local db = b1 - b2
- return (0.2126 * dr^2 +
- 0.7152 * dg^2 +
- 0.0722 * db^2)
- end
- util.palette.delta = delta
- local function t1deflate(palette, color)
- for idx = 1, #palette, 1 do
- if palette[idx] == color then
- return idx - 1
- end
- end
- local idx, minDelta
- for i = 1, #palette, 1 do
- local d = delta(palette[i], color)
- if not minDelta or d < minDelta then
- idx, minDelta = i, d
- end
- end
- return idx - 1
- end
- local function t1inflate(palette, index)
- return palette[index + 1]
- end
- local function generateT1Palette(secondColor)
- local palette = {
- 0x000000,
- secondColor
- }
- palette.deflate = util.cached1arg(t1deflate, 128, 2)
- palette.inflate = t1inflate
- return palette
- end
- util.palette.t1 = generateT1Palette()
- local t2deflate = t1deflate
- local t2inflate = t1inflate
- local function generateT2Palette()
- local palette = {0xFFFFFF, 0xFFCC33, 0xCC66CC, 0x6699FF,
- 0xFFFF33, 0x33CC33, 0xFF6699, 0x333333,
- 0xCCCCCC, 0x336699, 0x9933CC, 0x333399,
- 0x663300, 0x336600, 0xFF3333, 0x000000}
- palette.deflate = util.cached1arg(t2deflate, 128, 2)
- palette.inflate = t2inflate
- return palette
- end
- util.palette.t2 = generateT2Palette()
- local t3inflate = t2inflate
- local RCOEF = (6 - 1) / 0xFF
- local GCOEF = (8 - 1) / 0xFF
- local BCOEF = (5 - 1) / 0xFF
- local t3deflate = function(palette, color)
- local paletteIndex = palette.t2deflate(palette, color)
- for i = 1, #palette, 1 do
- if palette[i] == color then
- return paletteIndex
- end
- end
- local r, g, b = extract(color)
- local idxR = math.floor(r * RCOEF + 0.5)
- local idxG = math.floor(g * RCOEF + 0.5)
- local idxB = math.floor(b * RCOEF + 0.5)
- local deflated = 16 + idxR * 40 + idxG * 5 + idxB
- if (delta(t3inflate(palette, deflated % 0x100), color) <
- delta(t3inflate(palette, paletteIndex % 0x100), color)) then
- return deflated
- else
- return paletteIndex
- end
- end
- local function generateT3Palette()
- local palette = {}
- for i = 1, 16, 1 do
- palette[i] = 0xFF * i / (16 + 1) * 0x10101
- end
- for idx = 16, 255, 1 do
- local i = idx - 16
- local iB = i % 5
- local iG = math.floor(i / 5) % 8
- local iR = math.floor(i / 5 / 8) % 6
- local r = math.floor(iR * 0xFF / (6 - 1) + 0.5)
- local g = math.floor(iG * 0xFF / (8 - 1) + 0.5)
- local b = math.floor(iB * 0xFF / (5 - 1) + 0.5)
- palette[idx + 1] = r * 0x10000 + g * 0x100 + b
- end
- palette.deflate = util.cached1arg(t3deflate, 128, 2)
- palette.t2deflate = util.cached1arg(t2deflate, 128, 2)
- palette.inflate = t3inflate
- return palette
- end
- util.palette.t3 = generateT3Palette()
- end
- local dirty = {}
- for i = 0, 16 * 5 - 1 do
- dirty[i] = true
- end
- local function isDirty(idx)
- return not not dirty[idx]
- end
- local function setDirty(idx)
- dirty[idx] = true
- end
- local function clearDirty(idx)
- dirty[idx] = nil
- end
- local function clearDirtyFull()
- dirty = {}
- end
- local buffer = {}
- for i = 1, 3 * 160 * 50, 3 do
- buffer[i] = util.palette.t3:deflate(0x000000)
- buffer[i + 1] = util.palette.t3:deflate(0xffffff)
- buffer[i + 2] = " "
- end
- local function index(x, y)
- return 3 * x + 480 * y + 1
- end
- local function set(x, y, bg, fg, char)
- local i = index(x, y)
- buffer[i] = util.palette.t3:deflate(bg)
- buffer[i + 1] = util.palette.t3:deflate(fg)
- buffer[i + 2] = char
- setDirty(math.floor(x / 10), math.floor(y / 10))
- end
- local cbg = gpu.getBackground()
- local cfg = gpu.getForeground()
- local function setBg(bg)
- if bg ~= cbg then
- gpu.setBackground(bg)
- cbg = bg
- end
- end
- local function setFg(fg)
- if fg ~= cfg then
- gpu.setForeground(fg)
- cfg = fg
- end
- end
- local function flushline(lops, ops, bg, fg, cs, x, y)
- if #cs > 0 then
- local sp = bit32.lshift(y, 8) + x
- local t = {bit32.lshift(bg, 8) + fg, cs, sp}
- lops[sp + unicode.wlen(cs)] = t
- table.insert(ops, t)
- end
- end
- local function flushrect(ops, bg, fg, c, x, y)
- table.insert(ops, {r = true, bit32.lshift(bg, 8) + fg, c, x, y})
- end
- local function render()
- local lops = {}
- local ops = {}
- for block = 0, 16 * 5 - 1 do
- local sx = block % 16 * 10
- local sy = math.floor(block / 16) * 10
- if isDirty(block) then
- local head = index(sx, sy)
- local rbg, rfg, rc = buffer[head], buffer[head + 1], buffer[head + 2]
- local rect = true
- for x = sx, sx + 9 do
- for y = sy, sy + 9 do
- local i = index(x, y)
- local bg = buffer[i]
- local fg = buffer[i + 1]
- local c = buffer[i + 2]
- if bg ~= rbg or fg ~= rfg or c ~= rc then
- rect = false
- break
- end
- end
- end
- if rect then
- flushrect(ops, rbg, rfg, rc, sx, sy)
- else
- for y = sy, sy + 9 do
- local head = index(sx, y)
- local lx, lbg, lfg, lcs = sx, buffer[head], buffer[head + 1], ""
- for x = sx, sx + 9 do
- local i = index(x, y)
- local bg = buffer[i]
- local fg = buffer[i + 1]
- local c = buffer[i + 2]
- if bg == lbg and fg == lfg then
- lcs = lcs .. c
- else
- flushline(lops, ops, lbg, lfg, lcs, lx, y)
- lx, lbg, lfg, lcs = x, bg, fg, c
- end
- end
- flushline(lops, ops, lbg, lfg, lcs, lx, y)
- end
- end
- end
- end
- local out = {}
- for i, op in ipairs(ops) do
- if not op.r then
- local prec = lops[op[3]]
- if prec and prec[1] == op[1] then
- local t = {op[1], prec[2] .. op[2], prec[3]}
- lops[op[3]] = nil
- lops[op[3] + unicode.wlen(op[2])] = t
- table.insert(out, t)
- else
- table.insert(out, op)
- end
- else
- table.insert(out, op)
- end
- end
- table.sort(out, function(rhs, lhs) return lhs[1] < rhs[1] end)
- for _, op in ipairs(out) do
- setBg(util.palette.t3:inflate(bit32.rshift(op[1], 8)))
- setFg(util.palette.t3:inflate(bit32.band(op[1], 0xff)))
- if op.r then
- gpu.fill(op[3] + 1, op[4] + 1, 10, 10, op[2])
- else
- gpu.set(bit32.band(op[3], 0xff) + 1, bit32.rshift(op[3], 8) + 1, op[2])
- end
- end
- end
- local lastYield = computer.uptime()
- local function tlwyGuard()
- if computer.uptime() - lastYield > 3 then
- os.sleep(0)
- end
- end
- local old, bg, fg = {}
- local image = png(select(1, ...), function(y, _, pixels)
- if y % 2 == 0 then
- for x, a in ipairs(old) do
- local b = pixels[x]
- bg = bit32.lshift(a.R, 16) + bit32.lshift(a.G, 8) + a.B
- fg = bit32.lshift(b.R, 16) + bit32.lshift(b.G, 8) + a.B
- set(x - 1, math.floor((y - 1) / 2), fg, bg, "▄")
- end
- else
- old = pixels
- end
- end)
- local start = computer.uptime()
- render()
- local elapsed = computer.uptime() - start
- require("event").pull("key_down")
- setBg(0x000000)
- setFg(0xffffff)
- require("term").clear()
- print("elapsed", elapsed)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement