diff --git a/include/luares.h b/include/luares.h index 33b8601..f754bac 100644 --- a/include/luares.h +++ b/include/luares.h @@ -13,7 +13,6 @@ extern char lua_init[]; extern char lua_internet[]; extern char lua_sandbox[]; extern char lua_textgpu[]; -extern char lua_textgpu_new[]; extern char lua_textgpu_old[]; extern char lua_util_buffer[]; extern char lua_util_color[]; diff --git a/src/lua/core/textgpu.lua b/src/lua/core/textgpu.lua index f33870b..9a0ec81 100644 --- a/src/lua/core/textgpu.lua +++ b/src/lua/core/textgpu.lua @@ -1,262 +1,283 @@ local textgpu = {} local mapping = {} +local palette = {} --- generate the mapping +-- generate color mapping -local i = 0 for g=0, 255, 0x24 do - for b=0, 255, 0x40 do + for b=0, 256, 0x40 do for r=0, 255, 0x33 do - mapping[tostring(i)] = (r * 0x10000) + (g * 0x100) + b - i = i + 1 + mapping[#mapping+1] = (math.min(r, 255) * 0x10000) + + (math.min(g, 255) * 0x100) + math.min(b, 255) end end end ---[[local nw = io.write -io.write = function(...) - nw(...) - io.flush() - native.sleep(20000) -end]]-- +for i=0, 15, 1 do + mapping[#mapping+1] = (i+1) * 0x0f0f0f + palette[i] = (i+1) * 0x0f0f0f +end local write = io.write local flush = io.flush -local background = "\0" -local foreground = "\255" +local background = 1 +local foreground = 256 local tbuffer = {} local bbuffer = {} local fbuffer = {} -local function prepareBuffers(w, h) - local tbline = (" "):rep(w) - local bbline = ("\0"):rep(w) - local fbline = ("\7"):rep(w) - for i=1, h do - tbuffer[i] = tbline - bbuffer[i] = bbline - fbuffer[i] = fbline +local function prep(w, h) + local tl = string.rep(" ", w) + local bb = string.rep("\0", w) + local fb = string.rep("\255", w) + + for i=1, h, 1 do + tbuffer[i] = tl + bbuffer[i] = bb + fbuffer[i] = fb end end -local usub -local function insertString(main, sub, at) - checkArg(1, main, "string") - checkArg(2, sub, "string") - checkArg(3, at, "number") +local fg = 256 +local bg = 1 +local w, h = 1, 1 - return usub(main, 1, at - 1) - .. sub .. usub(main, at + (utf8.len(sub) or 0)) +local unsub +local function set(x, y, text, f, b) + if x > w or x < 1 or y > h or y < 1 or not tbuffer[y] then + error("index out of bounds: " .. y, 3) + end + f = f or fg + b = b or bg + local len = utf8.len(text) + if x + len > w then + text = unsub(text, 1, -1 - ((x + len) - w)) + end + tbuffer[y] = tbuffer[y]:sub(1, x - 1) .. + text .. tbuffer[y]:sub(x + len) + if type(f) == "string" then + fbuffer[y] = fbuffer[y]:sub(1, x - 1) .. + f .. fbuffer[y]:sub(x + len) + else + fbuffer[y] = fbuffer[y]:sub(1, x - 1) .. + string.rep(string.char(f - 1), len) .. fbuffer[y]:sub(x + len) + end + if type(b) == "string" then + bbuffer[y] = bbuffer[y]:sub(1, x - 1) .. + b .. bbuffer[y]:sub(x + len) + else + bbuffer[y] = fbuffer[y]:sub(1, x - 1) .. + string.rep(string.char(b - 1), len) .. bbuffer[y]:sub(x + len) + end + local F, B = mapping[f], mapping[b] + write("\27[38;2;", F&0xFF0000, ";", F&0x00FF00, ";", F&0x0000FF, "m") + write("\27[48;2;", B&0xFF0000, ";", B&0x00FF00, ";", B&0x0000FF, "m") + write("\27[", x, ";", y, "H", text) +end + +local function fullRefresh() + for i=1, h, 1 do + local text = tbuffer[i] + local fgt = fbuffer[i] + local bgt = bbuffer[i] + local pb, pf + fgt = fgt:gsub("()(.)", function(n, fc) + local bc, tc = bgt:sub(n,n), text:sub(n,n) + local str = "" + if bc ~= pb then + pb = bc + local B = mapping[bc] + str = str .. string.format("\27[48;2;%d;%d;%dm", + B&0xFF0000, B&0x00FF00, B&0x0000FF) + end + if fc ~= pf then + pf = fc + local F = mapping[fc] + str = str .. string.format("\27[38;2;%d;%d;%dm", + F&0xFF0000, F&0x00FF00, F&0x0000FF) + end + str = str .. tc + return str + end) + write("\27[", h, ";1H", fgt) + flush() + end +end + +local function get(x, y, len) + if x < 1 or x > w or y < 1 or y > h then + error("index out of bounds: " .. y, 3) + end + len = (len or 1) - 1 + local txt = unsub(tbuffer[y], x, x + len) + if len == 0 then + return text, + mapping[fbuffer[y]:sub(x, x):byte() + 1], + mapping[bbuffer[y]:sub(x, x):byte() + 1] + else + return text, fbuffer[y]:sub(x, x + len), bbuffer[y]:sub(x, x + len) + end end function textgpu.start() - usub = modules.sandbox.unicode.sub - local _height = 0 + unsub = modules.sandbox.unicode.sub local gpu = {} - function gpu.bind() return false, "This is static bound gpu" end - function gpu.setBackground(color, isPaletteIndex) + + function gpu.setForeground(color, ispalette) checkArg(1, color, "number") - checkArg(2, isPaletteIndex, "boolean", "nil") - if isPaletteIndex then - return --TODO: Maybe? + checkArg(2, ispalette, "boolean", "nil") + if ispalette then + if not palette[color] then + error("invalid palette index", 2) + end + color = palette[color] end - local old = background - background = tostring(math.floor(modules.color.nearest(color, mapping))) - write("\x1b[48;5;" .. background:byte() .. "m") - flush() - return mapping[old] + local index = math.floor(modules.color.nearest(color, mapping)) + fg = index or fg + return true end - function gpu.setForeground(color, isPaletteIndex) + + function gpu.setBackground(color, ispalette) checkArg(1, color, "number") - checkArg(2, isPaletteIndex, "boolean", "nil") - if isPaletteIndex then - return --TODO: Maybe? + checkArg(2, ispalette, "boolean", "nil") + if ispalette then + if not palette[color] then + error("invalid palette index", 2) + end + color = palette[color] end - local old = foreground - foreground = tostring(math.floor(modules.color.nearest(color, mapping))) - write("\x1b[38;5;" .. foreground:byte() .. "m") - flush() - return mapping[old] + local index = math.floor(modules.color.nearest(color, mapping)) + bg = index or bg + return true end - function gpu.getBackground() - return mapping[background], false + + function gpu.setPaletteColor(c, v) + checkArg(1, c, "number") + checkArg(2, v, "number") + if not palette[c] then + error("invalid palette index", 2) + end + palette[c] = v end + + function gpu.getPaletteColor(c) + checkArg(1, c, "number") + if not palette[c] then + error("invalid palette index", 2) + end + return palette[c] + end + function gpu.getForeground() - return mapping[foreground], false + return mapping[fg] end - function gpu.getPaletteColor() - return nil - end - function gpu.setPaletteColor() - return nil - end - function gpu.maxDepth() - return 3 - end - function gpu.setDepth() - return false + + function gpu.getBackground() + return mapping[bg] end + function gpu.getDepth() - return 3 + return 4 end - function gpu.maxResolution() - return termutils.getSize() + + function gpu.maxDepth() + return 4 end + + function gpu.setDepth() + return true + end + function gpu.getResolution() return termutils.getSize() end - function gpu.getViewport() - return termutils.getSize() + + function gpu.setResolution() + return false end - function gpu.setViewport(w, h) - checkArg(1, w, "number") - checkArg(2, h, "number") - return false, "Viewport not supported for this gpu" - end - function gpu.setResolution(w, h) - checkArg(1, w, "number") - checkArg(2, h, "number") - return false, "Non resizeable gpu" + + gpu.maxResolution = gpu.getResolution + gpu.getViewport = gpu.getResolution + gpu.setViewport = gpu.setResolution + + function gpu.set(x, y, text, vert) + checkArg(1, x, "number") + checkArg(2, y, "number") + checkArg(3, text, "string") + checkArg(4, vert, "boolean", "nil") + if vert then + local i = 1 + local len = utf8.len(text) + while i <= len do + set(x, y + i - 1, unsub(text, i, i)) + i = i + 1 + end + return true + else + set(x, y, text) + end end + function gpu.get(x, y) checkArg(1, x, "number") checkArg(2, y, "number") - - return tbuffer[y]:sub(x,x), mapping[fbuffer[y]:sub(x,x)], mapping[bbuffer[y]:sub(x,x)] + return get(x, y) end - function gpu.set(x, y, value, vertical) - checkArg(1, x, "number") - checkArg(2, y, "number") - checkArg(3, value, "string") - checkArg(4, vertical, "boolean", "nil") - x = math.floor(x) - y = math.floor(y) - if not vertical then - if not tbuffer[y] then - native.log("GPU Set failed: under buffer") - return false - end - tbuffer[y] = insertString(tbuffer[y], value, x) - bbuffer[y] = insertString(bbuffer[y], background:rep(utf8.len(value)), x) - fbuffer[y] = insertString(fbuffer[y], foreground:rep(utf8.len(value)), x) - write("\x1b[" .. y .. ";" .. x .. "H" .. value) - else - --TODO: Buffers! - write("\x1b[" .. y .. ";" .. x .. "H") - value:gsub("([%z\1-\127\194-\244][\128-\191]*)", function(c) - write(c .. "\x1b[D\x1b[B") - end) - end - flush() - return true - end - function gpu.copy(x, y, w, h, tx, ty) --TODO: Check(check X multiple times) - checkArg(1, x, "number") - checkArg(2, y, "number") - checkArg(3, w, "number") - checkArg(4, h, "number") - checkArg(5, tx, "number") - checkArg(6, ty, "number") - local ttbuf = {} - local btbuf = {} - local ftbuf = {} - for i=1, h do - if i + y - 2 <= _height and i + y > 1 then - ttbuf[i] = tbuffer[y + i - 1] and usub(tbuffer[y + i - 1], x, x + w - 1) or (" "):rep(w) - btbuf[i] = bbuffer[y + i - 1] and bbuffer[y + i - 1]:sub(x, x + w - 1) or background:rep(w) - ftbuf[i] = fbuffer[y + i - 1] and fbuffer[y + i - 1]:sub(x, x + w - 1) or foreground:rep(w) - else - ttbuf[i] = (" "):rep(w) - btbuf[i] = background:rep(w) - ftbuf[i] = foreground:rep(w) - end - end - local bg = background - local fg = foreground - for i=1, h do - local line, linex - local lwrite = false - for j=1, w do - if btbuf[i]:sub(j,j) ~= bg then - lwrite = true - end - if ftbuf[i]:sub(j,j) ~= fg then - lwrite = true - end - if not line then linex = j end - line = (line or "") - if lwrite then - local wx = (tx + x + linex - 1)|0 - local wy = (ty + y + i - 1)|0 - if tbuffer[wy] then - write("\x1b[48;5;" .. bg:byte() .. "m\x1b[38;5;" .. fg:byte() .. "m\x1b[" .. wy - .. ";" .. wx .. "H" .. line) - tbuffer[wy] = insertString(tbuffer[wy], line, wx) - bbuffer[wy] = insertString(bbuffer[wy], bg:rep(utf8.len(line)), wx) - fbuffer[wy] = insertString(fbuffer[wy], fg:rep(utf8.len(line)), wx) - end - - bg = btbuf[i]:sub(j,j) - fg = ftbuf[i]:sub(j,j) - line = nil - linex = nil - lwrite = false - end - if not line then linex = j end - line = (line or "") .. usub(ttbuf[i], j,j) - end - if line then - local wx = (tx + x + linex - 1)|0 - local wy = (ty + y + i - 1)|0 - if tbuffer[wy] then - write("\x1b[48;5;" .. bg:byte() .. "m\x1b[38;5;" .. fg:byte() .. "m\x1b[" .. wy - .. ";" .. wx .. "H" .. line) - tbuffer[wy] = insertString(tbuffer[wy], line, wx) - bbuffer[wy] = insertString(bbuffer[wy], bg:rep(utf8.len(line)), wx) - fbuffer[wy] = insertString(fbuffer[wy], fg:rep(utf8.len(line)), wx) - end - line = nil - linex = nil - lwrite = false - end + function gpu.fill(x, y, W, H, c) + checkArg(1, x, "number") + checkArg(1, y, "number") + checkArg(1, W, "number") + checkArg(1, H, "number") + checkArg(1, c, "string") + c = unsub(c, 1, 1) + if #c == 0 then return true end + local str = c:rep(W) + for i=1, h, 1 do + set(x, y + i - 1, str) end - write("\x1b[48;5;" .. background:byte() .. "m") - write("\x1b[38;5;" .. foreground:byte() .. "m") - flush() return true end - function gpu.fill(x, y, w, h, ch) + + function gpu.copy(x, y, W, H, xd, yd) checkArg(1, x, "number") checkArg(2, y, "number") - checkArg(3, w, "number") - checkArg(4, h, "number") - checkArg(5, ch, "string") - ch = usub(ch, 1, 1):rep(math.floor(w)) - for i=1, h do - if i + y - 1 <= _height and i + y > 1 then - gpu.set(x, y + i - 1, ch) - end + checkArg(3, W, "number") + checkArg(4, H, "number") + checkArg(5, xd, "number") + checkArg(6, yd, "number") + local start, stop, step + if yd > 0 then -- moving up - copy from the top down + start, stop, step = y, y + H, 1 + else -- moving down - copy from the bottom up + start, stop, step = y + H, y, -1 end + for i=start, stop, step do + local str, fstr, bstr = get(x, i, W) + set(x + xd, i + yd, str, fstr, bstr) + end + fullRefresh() return true end local screenAddr - function gpu.getScreen() return screenAddr end + function gpu.bind() end + if not termutils.init() then return nil, "Cannot initialize terminal based gpu" end write("\x1b[?25l") --Disable cursor - local w, h = gpu.getResolution() - _height = h - prepareBuffers(w, h) + + w, h = gpu.getResolution() + prep(w, h) + gpu.setForeground(0xFFFFFF) gpu.setBackground(0x000000) diff --git a/src/lua/core/textgpu_new.lua b/src/lua/core/textgpu_new.lua deleted file mode 100644 index 810a4e6..0000000 --- a/src/lua/core/textgpu_new.lua +++ /dev/null @@ -1,319 +0,0 @@ -local textgpu = {} - -local write = io.write -local flush = io.flush - -local background = 0x000000 -- "0" -local foreground = 0xFFFFFF -- "0" - -local tbuffer = {} -local bbuffer = {} -local fbuffer = {} - -local palette = { - [0] = 0x0f0f0f, - 0x1e1e1e, - 0x2d2d2d, - 0x3c3c3c, - 0x4b4b4b, - 0x5a5a5a, - 0x696969, - 0x787878, - 0x878787, - 0x969696, - 0xa5a5a5, - 0xb4b4b4, - 0xc3c3c3, - 0xd2d2d2, - 0xe1e1e1, - 0xf0f0f0 -} - -local function prepareBuffers(w, h) - local tbline = (" "):rep(w) - local bbline = ("\0\0\0"):rep(w) -- ("0"):rep(w) - local fbline = ("\255\255\255"):rep(w) -- ("7"):rep(w) - for i=1, h do - tbuffer[i] = tbline - bbuffer[i] = bbline - fbuffer[i] = fbline - end -end - -local function setForeground(c) - local r = c & 0xFF0000 - local g = c & 0x00FF00 - local b = c & 0x0000FF - io.write("\27[38;2;", r, ";", g, ";", b, "m") -end - -local function setBackground(c) - local r = c & 0xFF0000 - local g = c & 0x00FF00 - local b = c & 0x0000FF - io.write("\27[48;2;", r, ";", g, ";", b, "m") -end - -local usub -local function insertString(main, sub, at) - checkArg(1, main, "string") - checkArg(2, sub, "string") - checkArg(3, at, "number") - - return (usub(main, 1, at - 1) or "") - .. sub .. (usub(main, at + (utf8.len(sub) or 0))) -end - -function textgpu.start() - usub = modules.sandbox.unicode.sub - local _height = 0 - local gpu = {} - function gpu.bind() return false, "This is static bound gpu" end - function gpu.setBackground(color, isPaletteIndex) - checkArg(1, color, "number") - checkArg(2, isPaletteIndex, "boolean", "nil") - if isPaletteIndex then - if color > 15 or color < 0 then - error("invalid palette index", 2) - end - return palette[color] - end - local old = background - background = color -- tostring(math.floor(modules.color.nearest(color, mapping))) - setBackground(background) - --write("\x1b[4" .. background .. "m") - flush() - return old -- mapping[old] - end - function gpu.setForeground(color, isPaletteIndex) - checkArg(1, color, "number") - checkArg(2, isPaletteIndex, "boolean", "nil") - if isPaletteIndex then - if color < 0 or color > 15 then - error("invalid palette index", 2) - end - return palette[color] - end - local old = foreground - foreground = color -- tostring(math.floor(modules.color.nearest(color, mapping))) - setForeground(foreground) - --write("\x1b[3" .. foreground .. "m") - flush() - return old -- mapping[old] - end - function gpu.getBackground() - return mapping[background], false - end - function gpu.getForeground() - return mapping[foreground], false - end - function gpu.getPaletteColor(index) - if index < 0 or index > 15 then - error("invalid palette index", 2) - end - return palette[index] - end - function gpu.setPaletteColor(index, value) - if index < 0 or index > 15 then - error("invalid palette index", 2) - end - palette[index] = value - return true - end - function gpu.maxDepth() - return 4 - end - function gpu.setDepth() - return true - end - function gpu.getDepth() - return 4 - end - function gpu.maxResolution() - return termutils.getSize() - end - function gpu.getResolution() - return termutils.getSize() - end - function gpu.getViewport() - return termutils.getSize() - end - function gpu.setViewport(w, h) - checkArg(1, w, "number") - checkArg(2, h, "number") - return false, "Viewport not supported for this gpu" - end - function gpu.setResolution(w, h) - checkArg(1, w, "number") - checkArg(2, h, "number") - return false, "Non resizeable gpu" - end - function gpu.get(x, y) - checkArg(1, x, "number") - checkArg(2, y, "number") - - return tbuffer[y]:sub(x,x), - fbuffer[y]:sub(x*3-2,x*3):unpack(">I3"), - bbuffer[y]:sub(x*3-2,x*3):unpack(">I3") - end - function gpu.set(x, y, value, vertical) - checkArg(1, x, "number") - checkArg(2, y, "number") - checkArg(3, value, "string") - checkArg(4, vertical, "boolean", "nil") - x = math.floor(x) - y = math.floor(y) - if not vertical then - if not tbuffer[y] then - native.log("GPU Set failed: under buffer") - return false - end - tbuffer[y] = insertString(tbuffer[y], value, x) - bbuffer[y] = insertString(bbuffer[y], - string.pack(">I3", background):rep(utf8.len(value)), x*3-2) - fbuffer[y] = insertString(fbuffer[y], - string.pack(">I3", foreground):rep(utf8.len(value)), x*3-2) - write("\x1b[" .. y .. ";" .. x .. "H" .. value) - else - --TODO: Buffers! - write("\x1b[" .. y .. ";" .. x .. "H") - value:gsub("([%z\1-\127\194-\244][\128-\191]*)", function(c) - write(c .. "\x1b[D\x1b[B") - end) - end - flush() - return true - end - function gpu.copy(x, y, w, h, tx, ty) --TODO: Check(check X multiple times) - checkArg(1, x, "number") - checkArg(2, y, "number") - checkArg(3, w, "number") - checkArg(4, h, "number") - checkArg(5, tx, "number") - checkArg(6, ty, "number") - local ttbuf = {} - local btbuf = {} - local ftbuf = {} - for i=1, h do - if i + y - 2 <= _height and i + y > 1 then - ttbuf[i] = tbuffer[y + i - 1] and usub(tbuffer[y + i - 1], x, x + w - 1) or (" "):rep(w) - btbuf[i] = bbuffer[y + i - 1] and - bbuffer[y + i - 1]:sub(x*3-2, (x + w - 1)*3) or string.pack(">I3", background):rep(w) - ftbuf[i] = fbuffer[y + i - 1] and - fbuffer[y + i - 1]:sub(x*3-2, (x + w - 1)*3) or string.pack(">I3", foreground):rep(w) - else - ttbuf[i] = (" "):rep(w) - btbuf[i] = string.pack(">I3", background):rep(w) - ftbuf[i] = string.pack(">I3", foreground):rep(w) - end - end - local bg = background - local fg = foreground - - for i=1, h do - local line, linex - local lwrite = false - for j=1, w do - if btbuf[i]:sub(j*3-2,j*3):unpack(">I3") ~= bg then - lwrite = true - end - if ftbuf[i]:sub(j*3-2,j*3):unpack(">I3") ~= fg then - lwrite = true - end - if not line then linex = j end - line = (line or "") - if lwrite then - local wx = (tx + x + linex - 1)|0 - local wy = (ty + y + i - 1)|0 - if tbuffer[wy] then - setBackground(bg) - setForeground(foreground) - --write("\x1b[4" .. bg .. "m\x1b[3" .. fg .. "m - write("\x1b[" .. wy .. ";" .. wx .. "H" .. line) - tbuffer[wy] = insertString(tbuffer[wy], line, wx) - bbuffer[wy] = insertString(bbuffer[wy], - string.pack(">I3", bg):rep(utf8.len(line)), wx*3-2) - fbuffer[wy] = insertString(fbuffer[wy], - string.pack(">I3", fg):rep(utf8.len(line)), wx*3-2) - end - - bg = btbuf[i]:sub(j*3-2,j*3):unpack(">I3") - fg = ftbuf[i]:sub(j*3-2,j*3):unpack(">I3") - line = nil - linex = nil - lwrite = false - end - if not line then linex = j end - line = (line or "") .. usub(ttbuf[i], j,j) - end - if line then - local wx = (tx + x + linex - 1)|0 - local wy = (ty + y + i - 1)|0 - if tbuffer[wy] then - setBackground(bg) - setForeground(fg) - --write("\x1b[4" .. bg .. "m\x1b[3" .. fg .. "m - write("\x1b[" .. wy .. ";" .. wx .. "H" .. line) - tbuffer[wy] = insertString(tbuffer[wy], line, wx) - bbuffer[wy] = insertString(bbuffer[wy], - string.pack(">I3", bg):rep(utf8.len(line)), wx*3-2) - fbuffer[wy] = insertString(fbuffer[wy], - string.pack(">I3", fg):rep(utf8.len(line)), wx*3-2) - end - line = nil - linex = nil - lwrite = false - end - end - setBackground(background) - setForeground(foreground) - --write("\x1b[4" .. background .. "m") - --write("\x1b[3" .. foreground .. "m") - flush() - return true - end - function gpu.fill(x, y, w, h, ch) - checkArg(1, x, "number") - checkArg(2, y, "number") - checkArg(3, w, "number") - checkArg(4, h, "number") - checkArg(5, ch, "string") - ch = usub(ch, 1, 1):rep(math.floor(w)) - for i=1, h do - if i + y - 1 <= _height and i + y > 1 then - gpu.set(x, y + i - 1, ch) - end - end - return true - end - - local screenAddr - - function gpu.getScreen() - return screenAddr - end - - if not termutils.init() then - return nil, "Cannot initialize terminal based gpu" - end - write("\x1b[?25l") --Disable cursor - local w, h = gpu.getResolution() - _height = h - prepareBuffers(w, h) - gpu.setForeground(0xFFFFFF) - gpu.setBackground(0x000000) - - local gpuaddr = modules.component.api.register(nil, "gpu", gpu) - screenAddr = modules.component.api.register(nil, "screen", {getKeyboards = function() return {"TODO:SetThisUuid"} end}) --verry dummy screen, TODO: make it better, kbd uuid also in epoll.c - modules.component.api.register("TODO:SetThisUuid", "keyboard", {}) - - deadhooks[#deadhooks + 1] = function() - write("\x1b[?25h\x1b[" .. ((h-1)|0) .. ";1H") --Enable cursor on quit - io.flush() - termutils.restore() - end - - return gpuaddr -end - -return textgpu