By Guest

Unnamed Paste

Auto Detect 10.11 KiB 15 14 days ago
local PIXELBOX = {} local OBJECT = {} local api = {} local graphic = {} local chars = "0123456789abcdef" graphic.to_blit = {} for i = 0, 15 do graphic.to_blit[2^i] = chars:sub(i + 1, i + 1) end local function build_graphode(terminal) local BOX = PIXELBOX.new(terminal) BOX:clear(colors.black) BOX:push_updates() local _MODE_ = 0 local _FROZEN_ = false local PALETTE = { [0]={}, [2]={} } PALETTE[1] = PALETTE[0] for i=0,15 do local c = {terminal.getPaletteColor(2^i)} PALETTE[0][2^i],PALETTE[2][i] = c,c end terminal.grapode = true local GETSIZE = terminal.getSize local SETPALETTE = terminal.setPaletteColor local CLEAR = terminal.clear if not terminal.graphode then terminal.graphode = true function terminal.setGraphicsMode(mode) if type(mode) == "boolean" then if _MODE_ == 0 and mode ~= _MODE_ then api.update(BOX) end _MODE_ = mode and 1 or 0 elseif type(mode) == "number" then if _MODE_ == 0 and mode ~= _MODE_ then api.update(BOX) end if mode >= 0 and mode <= 3 then _MODE_ = mode else error("Invalid mode: "..mode,2) end end end function terminal.getGraphicsMode() return not (_MODE_ == 0) and _MODE_ or false end function terminal.getSize(mode) local w,h = GETSIZE() if type(mode) == "number" and mode > 0 or mode == true then return w*2,h*3 else return w,h end end function terminal.setPaletteColor(color,r_hex,g,b) local rgb = {r_hex,g,b} if r_hex and not g and not b then rgb = {api.hex_to_palette(r_hex)} end if _MODE_ == 0 or _MODE_ == 1 then PALETTE[0][color] = rgb PALETTE[2][math.log(color,2)] = rgb elseif _MODE_ == 2 then if color >= 0 and color <= 255 then if color >= 0 and color <= 15 then PALETTE[0][2^color] = rgb end PALETTE[2][color] = rgb else error("Invalid color: "..color) end end api.update_palette(SETPALETTE, PALETTE[0]) end function terminal.getPaletteColor(color) return table.unpack(PALETTE[(_MODE_ == 0 or _MODE_ == 1) and 0 or 2][color]) end function terminal.setFrozen(frozen) if _FROZEN_ and frozen == false then api.update(BOX) end (type(frozen) == "boolean" and function() _FROZEN_ = not not frozen end or function() end)() end function terminal.clear() if _MODE_ == 0 then CLEAR() else BOX:clear(colors.black) end end function terminal.setPixel(x,y,color) if _MODE_ == 1 or _MODE_ == 0 then BOX:set_pixel(x,y,color) elseif _MODE_ == 2 then local rgb = PALETTE[2][color] _G.rgb = rgb local c = api.get_closest_color(PALETTE[1],rgb) BOX:set_pixel(x,y,c) else return end if not _FROZEN_ and _MODE_ > 0 then api.update(BOX) end end function terminal.getFrozen() return _FROZEN_ end end end function PIXELBOX.INDEX_SYMBOL_CORDINATION(tbl,x,y,val) tbl[x+y*2-2] = val return tbl end function OBJECT:within(x,y) return x > 0 and y > 0 and x <= self.width*2 and y <= self.height*3 end function PIXELBOX.RESTORE(BOX,color) BOX.CANVAS = api.createNDarray(1) BOX.UPDATES = api.createNDarray(1) BOX.CHARS = api.createNDarray(1) for y=1,BOX.height*3 do for x=1,BOX.width*2 do BOX.CANVAS[y][x] = color end end for y=1,BOX.height do for x=1,BOX.width do BOX.CHARS[y][x] = {symbol=" ",background=graphic.to_blit[color],fg="f"} end end getmetatable(BOX.CANVAS).__tostring = function() return "PixelBOX_SCREEN_BUFFER" end end function OBJECT:push_updates() self.symbols = api.createNDarray(2) self.lines = api.create_blit_array(self.height) local SYMBOL_COLORS = api.createNDarray(1) local SYMBOL_LUT = api.createNDarray(2) getmetatable(self.symbols).__tostring=function() return "PixelBOX.SYMBOL_BUFFER" end setmetatable(self.lines,{__tostring=function() return "PixelBOX.LINE_BUFFER" end}) for y,x_list in pairs(self.CANVAS) do for x,block_color in pairs(x_list) do local RELATIVE_X = math.ceil(x/2) local RELATIVE_Y = math.ceil(y/3) if self.UPDATES[RELATIVE_Y][RELATIVE_X] then local SYMBOL_POS_X = (x-1)%2+1 local SYMBOL_POS_Y = (y-1)%3+1 if not SYMBOL_LUT[RELATIVE_Y][RELATIVE_X][block_color] then if not SYMBOL_COLORS[RELATIVE_Y][RELATIVE_X] then SYMBOL_COLORS[RELATIVE_Y][RELATIVE_X] = 0 end SYMBOL_COLORS[RELATIVE_Y][RELATIVE_X] = SYMBOL_COLORS[RELATIVE_Y][RELATIVE_X] + 1 SYMBOL_LUT[RELATIVE_Y][RELATIVE_X][block_color] = true end self.symbols[RELATIVE_Y][RELATIVE_X] = PIXELBOX.INDEX_SYMBOL_CORDINATION( self.symbols[RELATIVE_Y][RELATIVE_X], SYMBOL_POS_X,SYMBOL_POS_Y, block_color ) end end end for y=1,self.height do for x=1,self.width do local color_block = self.symbols[y][x] if self.UPDATES[y][x] then local char,fg,bg = " ",colors.black,color_block[1] if SYMBOL_COLORS[y][x] > 1 then char,fg,bg = graphic.build_drawing_char(color_block) end self.CHARS[y][x] = {symbol=char, background=graphic.to_blit[bg], fg=graphic.to_blit[fg]} self.lines[y] = { self.lines[y][1]..char, self.lines[y][2]..graphic.to_blit[fg], self.lines[y][3]..graphic.to_blit[bg] } else local prev_data = self.CHARS[y][x] self.lines[y] = { self.lines[y][1]..prev_data.symbol, self.lines[y][2]..prev_data.fg, self.lines[y][3]..prev_data.background } end end end self.UPDATES = api.createNDarray(1) end function OBJECT:get_pixel(x,y) return self.CANVAS[y][x] end function OBJECT:clear(color) PIXELBOX.RESTORE(self,color) end function OBJECT:draw() for y,line in ipairs(self.lines) do self.term.setCursorPos(1,y) self.term.blit( table.unpack(line) ) end end function OBJECT:set_pixel(x,y,color) local RELATIVE_X = math.ceil((x+1)/2) local RELATIVE_Y = math.ceil((y+1)/3) self.CANVAS[y+1][x+1] = color self.UPDATES[RELATIVE_Y][RELATIVE_X] = true end function PIXELBOX.new(terminal,bg,existing) local bg = bg or terminal.getBackgroundColor() or colors.black local BOX = {} local w,h = terminal.getSize() BOX.term = terminal BOX.width = w BOX.height = h PIXELBOX.RESTORE(BOX,bg,existing) return setmetatable(BOX,{__index = OBJECT}) end function api.createNDarray(n, tbl) tbl = tbl or {} if n == 0 then return tbl end setmetatable(tbl, {__index = function(t, k) local new = api.createNDarray(n - 1) t[k] = new return new end}) return tbl end function api.create_blit_array(count) local out = {} for i=1,count do out[i] = {"","",""} end return out end function api.get_closest_color(palette,c) local result = {} for k,v in pairs(palette) do table.insert(result,{ dist=math.sqrt( (v[1]-c[1])^2 + (v[2]-c[2])^2 + (v[3]-c[3])^2 ), color=k }) end table.sort(result,function(a,b) return a.dist < b.dist end) return result[1].color end function api.convert_color_255(r,g,b) return r*255,g*255,b*255 end function api.hex_to_palette(hex) local r = (math.floor(hex/0x10000)%256)/255 local g = (math.floor(hex/0x100)%256)/255 local b = (hex%256)/255 return r,g,b end function api.update_palette(updater,palette) for k,v in pairs(palette) do updater(k,table.unpack(v)) end end function api.update(box) box:push_updates() box:draw() end function graphic.build_drawing_char(arr,mode) local cols,fin,char,visited = {},{},{},{} local entries = 0 for k,v in pairs(arr) do cols[v] = cols[v] ~= nil and {count=cols[v].count+1,c=cols[v].c} or (function() entries = entries + 1 return {count=1,c=v} end)() end for k,v in pairs(cols) do if not visited[v.c] then visited[v.c] = true if entries == 1 then table.insert(fin,v) end table.insert(fin,v) end end table.sort(fin,function(a,b) return a.count > b.count end) local swap = true for k=1,6 do if arr[k] == fin[1].c then char[k] = 1 elseif arr[k] == fin[2].c then char[k] = 0 else char[k] =(function() swap = not swap return swap and 1 or 0 end)() end end if char[6] == 1 then for i = 1, 5 do char[i] = 1-char[i] end end local n = 128 for i = 0, 4 do n = n + char[i+1]*2^i end return string.char(n),char[6] == 1 and fin[2].c or fin[1].c,char[6] == 1 and fin[1].c or fin[2].c end build_graphode(term)