2016-01-07 02:58:05 +11:00
local textgpu = { }
2021-05-28 11:30:42 +10:00
local mapping = { }
2021-05-28 14:14:36 +10:00
local palette = { }
2021-05-28 11:30:42 +10:00
2021-05-28 14:14:36 +10:00
-- generate color mapping
2021-05-28 11:30:42 +10:00
for g = 0 , 255 , 0x24 do
2021-05-28 14:14:36 +10:00
for b = 0 , 256 , 0x40 do
2021-05-28 11:30:42 +10:00
for r = 0 , 255 , 0x33 do
2021-05-28 14:14:36 +10:00
mapping [ # mapping + 1 ] = ( math.min ( r , 255 ) * 0x10000 )
+ ( math.min ( g , 255 ) * 0x100 ) + math.min ( b , 255 )
2021-05-28 11:30:42 +10:00
end
end
end
2021-05-28 14:14:36 +10:00
for i = 0 , 15 , 1 do
mapping [ # mapping + 1 ] = ( i + 1 ) * 0x0f0f0f
palette [ i ] = ( i + 1 ) * 0x0f0f0f
end
2021-05-28 11:30:42 +10:00
2016-01-18 06:07:51 +11:00
local write = io.write
local flush = io.flush
2016-01-14 11:10:04 +11:00
2021-05-28 14:14:36 +10:00
local background = 1
local foreground = 256
2016-01-07 02:58:05 +11:00
2016-01-14 11:10:04 +11:00
local tbuffer = { }
local bbuffer = { }
local fbuffer = { }
2021-05-28 14:14:36 +10:00
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
2016-01-14 11:10:04 +11:00
end
end
2021-05-28 14:14:36 +10:00
local fg = 256
local bg = 1
local w , h = 1 , 1
2016-02-10 03:42:11 +11:00
2021-05-29 03:31:02 +10:00
local function rgb ( i )
return i >> 16 & 0xFF , i >> 8 & 0xFF , i & 0xFF
end
2021-05-29 03:10:05 +10:00
local unsub , fullRefresh
local function set ( x , y , text , f , b , safe )
2021-05-28 14:14:36 +10:00
if x > w or x < 1 or y > h or y < 1 or not tbuffer [ y ] then
2021-05-29 03:10:05 +10:00
if safe then
return
else
error ( " index out of bounds: " .. y , 3 )
end
2021-05-28 14:14:36 +10:00
end
2021-05-29 03:10:05 +10:00
if not text then return end
2021-05-28 14:14:36 +10:00
f = f or fg
b = b or bg
local len = utf8.len ( text )
if x + len > w then
2021-05-29 03:19:44 +10:00
--len = (x + len) - w
--text = unsub(text, 1, len)
2021-05-28 14:14:36 +10:00
end
2021-05-29 03:19:44 +10:00
tbuffer [ y ] = unsub ( tbuffer [ y ] , 1 , x - 1 ) ..
text .. unsub ( tbuffer [ y ] , x + len )
2021-05-28 14:14:36 +10:00
if type ( f ) == " string " then
fbuffer [ y ] = fbuffer [ y ] : sub ( 1 , x - 1 ) ..
f .. fbuffer [ y ] : sub ( x + len )
else
2021-05-29 03:10:05 +10:00
local F = mapping [ f ]
2021-05-29 03:31:02 +10:00
local r , g , _b = rgb ( F )
write ( " \27 [38;2; " , r , " ; " , g , " ; " , _b , " m " )
2021-05-28 14:14:36 +10:00
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
2021-05-29 03:10:05 +10:00
local B = mapping [ b ]
2021-05-29 03:31:02 +10:00
local r , g , _b = rgb ( B )
write ( " \27 [48;2; " , r , " ; " , g , " ; " , _b , " m " )
2021-05-29 03:10:05 +10:00
bbuffer [ y ] = bbuffer [ y ] : sub ( 1 , x - 1 ) ..
2021-05-28 14:14:36 +10:00
string.rep ( string.char ( b - 1 ) , len ) .. bbuffer [ y ] : sub ( x + len )
end
2021-05-29 03:19:44 +10:00
write ( " \27 [ " , y , " ; " , x , " H " , text )
2021-05-29 03:10:05 +10:00
flush ( )
2021-05-28 14:14:36 +10:00
end
2021-05-29 03:10:05 +10:00
fullRefresh = function ( )
2021-05-28 14:14:36 +10:00
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
2021-05-29 03:10:05 +10:00
local B = mapping [ bc : byte ( ) + 1 ]
2021-05-28 14:14:36 +10:00
str = str .. string.format ( " \27 [48;2;%d;%d;%dm " ,
2021-05-29 03:31:02 +10:00
rgb ( B ) )
2021-05-28 14:14:36 +10:00
end
if fc ~= pf then
pf = fc
2021-05-29 03:10:05 +10:00
local F = mapping [ fc : byte ( ) + 1 ]
2021-05-28 14:14:36 +10:00
str = str .. string.format ( " \27 [38;2;%d;%d;%dm " ,
2021-05-29 03:31:02 +10:00
rgb ( F ) )
2021-05-28 14:14:36 +10:00
end
str = str .. tc
return str
end )
2021-05-29 03:10:05 +10:00
write ( " \27 [ " , i , " ;1H " , fgt )
2021-05-28 14:14:36 +10:00
end
2021-05-29 03:10:05 +10:00
flush ( )
2021-05-28 14:14:36 +10:00
end
2021-05-29 03:10:05 +10:00
local function get ( x , y , len , safe )
2021-05-28 14:14:36 +10:00
if x < 1 or x > w or y < 1 or y > h then
2021-05-29 03:10:05 +10:00
if safe then
return
else
error ( " index out of bounds: " .. y , 3 )
end
2021-05-28 14:14:36 +10:00
end
len = ( len or 1 ) - 1
2021-05-29 03:10:05 +10:00
if x + len > w then
len = ( x + len ) - w
end
local text = unsub ( tbuffer [ y ] , x , x + len )
2021-05-28 14:14:36 +10:00
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
2016-01-14 11:10:04 +11:00
end
2016-01-07 02:58:05 +11:00
function textgpu . start ( )
2021-05-28 14:14:36 +10:00
unsub = modules.sandbox . unicode.sub
2016-01-07 02:58:05 +11:00
local gpu = { }
2021-05-28 14:14:36 +10:00
function gpu . setForeground ( color , ispalette )
2016-01-07 02:58:05 +11:00
checkArg ( 1 , color , " number " )
2021-05-28 14:14:36 +10:00
checkArg ( 2 , ispalette , " boolean " , " nil " )
if ispalette then
if not palette [ color ] then
error ( " invalid palette index " , 2 )
end
color = palette [ color ]
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
local index = math.floor ( modules.color . nearest ( color , mapping ) )
fg = index or fg
return true
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
function gpu . setBackground ( color , ispalette )
2016-01-07 02:58:05 +11:00
checkArg ( 1 , color , " number " )
2021-05-28 14:14:36 +10:00
checkArg ( 2 , ispalette , " boolean " , " nil " )
if ispalette then
if not palette [ color ] then
error ( " invalid palette index " , 2 )
end
color = palette [ color ]
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
local index = math.floor ( modules.color . nearest ( color , mapping ) )
bg = index or bg
return true
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
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 ]
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
2016-01-07 02:58:05 +11:00
function gpu . getForeground ( )
2021-05-28 14:14:36 +10:00
return mapping [ fg ]
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
function gpu . getBackground ( )
return mapping [ bg ]
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
function gpu . getDepth ( )
return 4
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
2016-01-07 02:58:05 +11:00
function gpu . maxDepth ( )
2021-05-28 14:14:36 +10:00
return 4
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
2016-01-07 02:58:05 +11:00
function gpu . setDepth ( )
2021-05-28 14:14:36 +10:00
return true
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
2016-01-07 02:58:05 +11:00
function gpu . getResolution ( )
return termutils.getSize ( )
end
2021-05-28 14:14:36 +10:00
function gpu . setResolution ( )
return false
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
gpu.maxResolution = gpu.getResolution
gpu.getViewport = gpu.getResolution
gpu.setViewport = gpu.setResolution
function gpu . set ( x , y , text , vert )
2016-01-07 02:58:05 +11:00
checkArg ( 1 , x , " number " )
checkArg ( 2 , y , " number " )
2021-05-28 14:14:36 +10:00
checkArg ( 3 , text , " string " )
checkArg ( 4 , vert , " boolean " , " nil " )
2021-05-29 03:19:44 +10:00
vert = false
2021-05-28 14:14:36 +10:00
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
2016-01-21 09:18:02 +11:00
end
2021-05-28 14:14:36 +10:00
return true
2016-01-07 02:58:05 +11:00
else
2021-05-28 14:14:36 +10:00
set ( x , y , text )
2021-05-29 03:10:05 +10:00
return true
2016-01-07 02:58:05 +11:00
end
end
2021-05-28 14:14:36 +10:00
function gpu . get ( x , y )
2016-01-07 02:58:05 +11:00
checkArg ( 1 , x , " number " )
checkArg ( 2 , y , " number " )
2021-05-28 14:14:36 +10:00
return get ( x , y )
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 )
2021-05-29 03:19:44 +10:00
for i = 1 , H , 1 do
2021-05-29 03:10:05 +10:00
set ( x , y + i - 1 , str , nil , nil , true )
2016-01-14 11:10:04 +11:00
end
return true
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
function gpu . copy ( x , y , W , H , xd , yd )
2016-01-07 02:58:05 +11:00
checkArg ( 1 , x , " number " )
checkArg ( 2 , y , " number " )
2021-05-28 14:14:36 +10:00
checkArg ( 3 , W , " number " )
checkArg ( 4 , H , " number " )
checkArg ( 5 , xd , " number " )
checkArg ( 6 , yd , " number " )
2021-05-29 03:10:05 +10:00
if xd == 0 and yd == 0 then return true end -- hah
2021-05-28 14:14:36 +10:00
local start , stop , step
2021-05-29 03:10:05 +10:00
if yd < 0 then -- moving up - copy from the top down
2021-05-28 14:14:36 +10:00
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
2021-05-29 03:10:05 +10:00
local str , fstr , bstr = get ( x , i , W , true )
if str and fstr and bstr then
set ( x + xd , i + yd , str , fstr , bstr , true )
end
2016-01-07 02:58:05 +11:00
end
2021-05-28 14:14:36 +10:00
fullRefresh ( )
2016-01-07 02:58:05 +11:00
return true
end
2016-01-20 04:25:09 +11:00
local screenAddr
function gpu . getScreen ( )
return screenAddr
end
2021-05-29 03:10:05 +10:00
function gpu . bind ( ) --[[STUB]] end
2021-05-28 14:14:36 +10:00
2016-02-28 01:30:34 +11:00
if not termutils.init ( ) then
return nil , " Cannot initialize terminal based gpu "
end
2016-01-18 06:07:51 +11:00
write ( " \x1b [?25l " ) --Disable cursor
2021-05-28 14:14:36 +10:00
w , h = gpu.getResolution ( )
prep ( w , h )
2021-05-29 03:10:05 +10:00
fullRefresh ( )
2021-05-28 14:14:36 +10:00
2016-01-07 02:58:05 +11:00
gpu.setForeground ( 0xFFFFFF )
gpu.setBackground ( 0x000000 )
2016-02-28 01:30:34 +11:00
local gpuaddr = modules.component . api.register ( nil , " gpu " , gpu )
2016-01-20 04:25:09 +11:00
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
2016-01-16 22:42:09 +11:00
modules.component . api.register ( " TODO:SetThisUuid " , " keyboard " , { } )
2016-01-10 05:39:48 +11:00
deadhooks [ # deadhooks + 1 ] = function ( )
2016-02-10 03:42:11 +11:00
write ( " \x1b [?25h \x1b [ " .. ( ( h - 1 ) | 0 ) .. " ;1H " ) --Enable cursor on quit
io.flush ( )
termutils.restore ( )
2016-01-10 05:39:48 +11:00
end
2016-02-28 01:30:34 +11:00
return gpuaddr
2016-01-07 02:58:05 +11:00
end
2016-01-20 05:46:40 +11:00
return textgpu