Skip to content

Instantly share code, notes, and snippets.

@MCJack123
Last active December 23, 2020 21:13
Show Gist options
  • Save MCJack123/f6819e41a60402b8a73403542bb23820 to your computer and use it in GitHub Desktop.
Save MCJack123/f6819e41a60402b8a73403542bb23820 to your computer and use it in GitHub Desktop.
CraftOS-PC Graphics Mode terminal (requires readBDFFont)
-- WARNING: Render crashes are lethal and will 100% kill the computer
local loadBDF = require "readBDFFont" -- get from https://gist.github.com/MCJack123/3cbce89640923b3c42d4d0a0b8eaa7b2
if term.setGraphicsMode == nil then error("This requires CraftOS-PC v1.2 or later.") end
local font, oldterm, gfxMode
local nativeTerm = term.native()
local oldSetGfx, oldGetGfx = term.setGraphicsMode, term.getGraphicsMode
local nativeWidth, nativeHeight = term.getSize()
nativeWidth = nativeWidth * 6
nativeHeight = nativeHeight * 9
local function log2(num) return math.floor(math.log10(num) / math.log10(2)) end
local function drawChar(x, y, ch, fg, bg, transparent)
x=x-1
y=y-1
if x * font.bounds.width > nativeWidth or y * font.bounds.height > nativeHeight or x < 0 or y < 0 then return end
local fch = font.chars[ch]
if fch == nil then fch = font.chars[' '] end
if transparent then
local heightDiff = (font.bounds.height + font.bounds.y) - fch.bounds.height + font.bounds.y - fch.bounds.y
for i,t in pairs(fch.bitmap) do if i <= font.bounds.height then for j,a in pairs(t) do if j <= font.bounds.width and a then
nativeTerm.setPixel(x*font.bounds.width+j-1, y*font.bounds.height+i+heightDiff-1, gfxMode == 2 and fg or log2(fg))
end end end end
else
local pixelTable = {}
for i = 1, font.bounds.height do pixelTable[i] = string.char(bg):rep(font.bounds.width) end
local starty = (font.bounds.height - fch.bounds.height) - fch.bounds.y + font.bounds.y
for i = 1, fch.bounds.height do
if fch.bitmap[i] then
pixelTable[i+starty] = string.char(bg):rep(fch.bounds.x)
for j = 1, font.bounds.width-fch.bounds.x do
pixelTable[i+starty] = pixelTable[i+starty] .. string.char(fch.bitmap[i][j] and fg or bg)
end
end
end
local ypos = y*font.bounds.height+font.bounds.y
while ypos < 0 do
table.remove(pixelTable, 1)
ypos=ypos+1
end
nativeTerm.drawPixels(x*font.bounds.width, ypos, pixelTable)
end
end
local file
if #({...}) > 0 then file = fs.open(shell.resolve(({...})[1]), "r")
else file = fs.open(shell.resolve("font.bdf"), "r") end
if file == nil then error("Could not find font!") end
font = loadBDF(file.readAll())
file.close()
local backgroundColor = 15
local textColor = 0
local cursorX = 1
local cursorY = 1
local cursorBlink = true -- soon(tm)
local cursorShouldBlink = true
local cursorTimer = os.startTimer(0.5)
local width = math.floor(nativeWidth / font.bounds.width)
local height = math.floor(nativeHeight / font.bounds.height)
gfxMode = 0
local termBuffer = {}
local colorBuffer = {}
for i = 1, height do
termBuffer[i] = {}
colorBuffer[i] = {}
for j = 1, width do
termBuffer[i][j] = " "
colorBuffer[i][j] = {textColor, backgroundColor}
end
end
local lastcx, lastcy = 1, 1
local function redrawCursor()
if lastcx <= width and lastcy <= height then drawChar(lastcx, lastcy, termBuffer[lastcy][lastcx], colorBuffer[lastcy][lastcx][1], colorBuffer[lastcy][lastcx][2], false) end
if cursorX <= width and cursorY <= height and cursorBlink and cursorShouldBlink then drawChar(cursorX, cursorY, '_', 0, 15, true) end
lastcx, lastcy = cursorX, cursorY
end
local termObject = {
write = function(text)
if cursorY > height or cursorX > width then return end
for c in text:gmatch(".") do
termBuffer[cursorY][cursorX] = c
colorBuffer[cursorY][cursorX] = {textColor, backgroundColor}
drawChar(cursorX, cursorY, c, textColor, backgroundColor, false)
cursorX = cursorX + 1
if cursorX > width then break end
end
redrawCursor()
end,
blit = function(text, fg, bg)
if #text ~= #fg or #fg ~= #bg then error("Arguments must be same length", 2) end
if cursorY > height or cursorX > width then return end
for i = 1, #text do
textColor = (("0123456789abcdef"):find(fg:sub(i, i)) or (textColor + 1)) - 1
backgroundColor = (("0123456789abcdef"):find(bg:sub(i, i)) or (backgroundColor + 1)) - 1
termBuffer[cursorY][cursorX] = text:sub(i, i)
colorBuffer[cursorY][cursorX] = {textColor, backgroundColor}
drawChar(cursorX, cursorY, text:sub(i, i), textColor, backgroundColor, false)
cursorX = cursorX + 1
if cursorX > width then break end
end
redrawCursor()
end,
clear = function()
for i = 1, height do
termBuffer[i] = {}
colorBuffer[i] = {}
for j = 1, width do
termBuffer[i][j] = " "
colorBuffer[i][j] = {textColor, backgroundColor}
drawChar(j, i, " ", textColor, backgroundColor, false)
end
end
redrawCursor()
end,
clearLine = function()
if cursorY > height then return end
for j = 1, width do
termBuffer[cursorY][j] = " "
colorBuffer[cursorY][j] = {textColor, backgroundColor}
drawChar(j, cursorY, " ", textColor, backgroundColor, false)
end
redrawCursor()
end,
getCursorPos = function() return cursorX, cursorY end,
setCursorPos = function(x, y) cursorX, cursorY = x, y end,
getCursorBlink = function() return cursorShouldBlink end,
setCursorBlink = function(b) cursorShouldBlink = b; redrawCursor() end,
isColor = function() return true end,
isColour = function() return true end,
getSize = function() return width, height end,
scroll = function(n)
for _ = 1, n do
table.remove(termBuffer, 1)
table.remove(colorBuffer, 1)
local tr, cr = {}, {}
for j = 1, width do
tr[j] = " "
cr[j] = {textColor, backgroundColor}
end
table.insert(termBuffer, tr)
table.insert(colorBuffer, cr)
end
for y = 1, height do for x = 1, width do drawChar(x, y, termBuffer[y][x], colorBuffer[y][x][1], colorBuffer[y][x][2], false) end end
redrawCursor()
end,
setTextColor = function(c) textColor = log2(c) end,
setTextColour = function(c) textColor = log2(c) end,
getTextColor = function() return bit.blshift(1, textColor) end,
getTextColour = function() return bit.blshift(1, textColor) end,
setBackgroundColor = function(c) backgroundColor = log2(c) end,
setBackgroundColour = function(c) backgroundColor = log2(c) end,
getBackgroundColor = function() return bit.blshift(1, backgroundColor) end,
getBackgroundColour = function() return bit.blshift(1, backgroundColor) end,
getPaletteColor = nativeTerm.getPaletteColor,
getPaletteColour = nativeTerm.getPaletteColour,
setPaletteColor = nativeTerm.setPaletteColor,
setPaletteColour = nativeTerm.setPaletteColour,
nativePaletteColor = nativeTerm.nativePaletteColor,
nativePaletteColour = nativeTerm.nativePaletteColour,
screenshot = nativeTerm.screenshot,
}
term.setGraphicsMode(1)
term.clear()
oldterm = term.redirect(termObject)
term.setGraphicsMode = function(mode)
gfxMode = mode
term.clear()
if gfxMode == 2 then oldSetGfx(2) else oldSetGfx(1) end
if gfxMode == 0 then for y = 1, height do for x = 1, width do drawChar(x, y, termBuffer[y][x], colorBuffer[y][x][1], colorBuffer[y][x][2], false) end end end
end
term.getGraphicsMode = function() return gfxMode end
parallel.waitForAny(function()
while true do
local ev = {os.pullEvent()}
if ev[1] == "term_resize" then
local oldw, oldh = width, height
nativeWidth, nativeHeight = nativeTerm.getSize()
nativeWidth = nativeWidth * 6
nativeHeight = nativeHeight * 9
width = math.floor(nativeWidth / font.bounds.width)
height = math.floor(nativeHeight / font.bounds.height)
if height > oldh then
for i = oldh+1, height do
termBuffer[i] = {}
colorBuffer[i] = {}
for j = 1, oldw do
termBuffer[i][j] = ' '
colorBuffer[i][j] = {textColor, backgroundColor}
end
end
elseif height < oldh then
for i = height+1, oldh do
termBuffer[i] = nil
colorBuffer[i] = nil
end
end
if width > oldw then
for i = 1, height do for j = oldw+1, width do
termBuffer[i][j] = ' '
colorBuffer[i][j] = {textColor, backgroundColor}
end end
elseif width < oldw then
for i = 1, height do for j = width+1, oldw do
termBuffer[i][j] = nil
colorBuffer[i][j] = nil
end end
end
elseif ev[1] == "timer" and ev[2] == cursorTimer then
cursorBlink = not cursorBlink
cursorTimer = os.startTimer(0.5)
redrawCursor()
end
end
end, function() shell.run("/rom/programs/shell.lua") end)
term.setGraphicsMode = oldSetGfx
term.getGraphicsMode = oldGetGfx
term.redirect(oldterm)
term.setGraphicsMode(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment