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 writeFillInstruction(instructions, textdata, fills, x, y,
- bg, fg, char)
- if not instructions[bg] then
- instructions[bg] = {}
- textdata[bg] = {}
- end
- if not instructions[bg][fg] then
- instructions[bg][fg] = {}
- textdata[bg][fg] = {}
- end
- if not fills[bg] then
- fills[bg] = {}
- end
- if not fills[bg][fg] then
- fills[bg][fg] = {}
- end
- local i = #instructions[bg][fg] + 1
- instructions[bg][fg][i] = x * 0x100 + y
- textdata[bg][fg][i] = char
- fills[bg][fg][i] = true
- end
- local function writeLineInstruction(instructions, textdata, lines,
- x, y, bg, fg, line)
- if not instructions[bg] then
- instructions[bg] = {}
- textdata[bg] = {}
- end
- if not instructions[bg][fg] then
- instructions[bg][fg] = {}
- textdata[bg][fg] = {}
- end
- local pos = x * 0x100 + y
- local bgfg = bg * 0x100 + fg
- if lines[2 * pos] and lines[2 * pos] == bgfg then
- local i = lines[2 * pos + 1]
- textdata[bg][fg][i] = textdata[bg][fg][i] .. line
- lines[2 * pos] = nil
- lines[2 * pos + 1] = nil
- lines[2 * (pos + unicode.wlen(line))] = bgfg
- lines[2 * (pos + unicode.wlen(line)) + 1] = i
- else
- local i = #instructions[bg][fg] + 1
- instructions[bg][fg][i] = pos
- textdata[bg][fg][i] = line
- lines[2 * pos] = bgfg
- lines[2 * pos + 1] = i
- end
- end
- local function render()
- local instructions = {}
- local textdata = {}
- local fills = {}
- local lines = {}
- for block = 0, 16 * 5 - 1 do
- local sx = block % 16 * 10
- local sy = math.floor(block / 16) * 10
- if not isDirty(block) then
- goto continue
- end
- 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
- writeFillInstruction(instructions, textdata, fills, sx, sy, rbg, rfg, rc)
- goto continue
- end
- for y = sy, sy + 9 do
- local head = index(sx, y)
- local linex, linebg, linefg, line = 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 == linebg and (fg == linefg or c == " ") then
- table.insert(line, c)
- else
- writeLineInstruction(instructions, textdata, lines, linex, y,
- linebg, linefg, table.concat(line))
- linex, linebg, linefg, line = x, bg, fg, {c}
- end
- end
- if #line > 0 then
- writeLineInstruction(instructions, textdata, lines, linex, y,
- linebg, linefg, table.concat(line))
- end
- end
- ::continue::
- end
- for background, foregrounds in pairs(instructions) do
- setBg(util.palette.t3:inflate(background))
- for foreground, chain in pairs(foregrounds) do
- setFg(util.palette.t3:inflate(foreground))
- for i, pos in ipairs(chain) do
- local text = textdata[background][foreground][i]
- local x = bit32.rshift(pos, 8)
- local y = bit32.band(pos, 0xff)
- if fills[background] and fills[background][foreground]
- and fills[background][foreground][i] then
- gpu.fill(x, y, 10, 10, text)
- else
- gpu.set(x, y, text)
- end
- end
- 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