Last active
July 11, 2022 20:11
-
-
Save SammyForReal/3dfb65e46a9949ae9201343eb014c398 to your computer and use it in GitHub Desktop.
Small lua pixel render API, written for ComputerCraft.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Coater | Pixel render API | v.1.0 | |
================================= | |
Available under the MIT Licence | |
Copyright (c) 2022 Sammy L. Koch | |
]] | |
local ccExpect = require("cc.expect") | |
local expect,field,range = ccExpect.expect,ccExpect.field,ccExpect.range | |
local tCToB = {[1]='0',[2]='1',[4]='2',[8]='3',[16]='4',[32]='5',[64]='6',[128]='7',[256]='8',[512]='9',[1024]='a',[2048]='b',[4096]='c',[8192]='d',[16384]='e',[32768]='f' } | |
local tBToC = {['0']=1,['1']=2,['2']=4,['3']=8,['4']=16,['5']=32,['7']=128,['8']=256,['9']=512,['a']=1024,['b']=2048,['c']=4096,['d']=8192,['e']=16384,['f']=32768 } | |
---Converts a given table to a blit char. | |
---@param str string Something like: "100110" for \153 | |
---@return string sChar Matching counter part | |
---@return boolean bReversed Swaped text & background color? | |
local function toBlit(str) | |
if type(str) ~= "string" or #str < 6 then | |
str = "000000" | |
elseif str:sub(1,1) == '#' then | |
return str:sub(2,2), false | |
end | |
local t = {} | |
for i=1,6 do | |
t[#t+1] = tonumber(str:sub(i,i)) or 0 | |
end | |
if t[6]==1 then | |
for i=1,5 do | |
t[i] = 1-t[i] | |
end end | |
local n = 128 | |
for i=0,4 do | |
n = n+t[i+1]*2^i | |
end | |
return string.char(n), (t[6] == 1) | |
end | |
---Sets the text & background color or swaps them, if no colors are given. | |
---@param self table | |
---@param cBG? number Background color | |
---@param cFG? number Foreground color (Textcolor) | |
local function setColor(self, cBG,cFG) | |
expect(1, self, "table") | |
expect(2, cBG, "number", "nil") | |
expect(3, cFG, "number", "nil") | |
if not (cBG and cFG) then | |
cBG = term.getBackgroundColor() | |
self.termCBG = term.getTextColor() | |
self.termCFG = cBG | |
return cFG, cBG | |
else | |
if cBG then self.termCBG = tCToB[cBG] end | |
if cFG then self.termCFG = tCToB[cFG] end | |
end | |
return cBG,cFG | |
end | |
---Sets one (or multible) pixel in the buffer at a given position. | |
---@param self table | |
---@param nX number | |
---@param nY number | |
---@param pixel any The pixels. Can be a single one (number), a row (string) or a whole 'sprite' (table) | |
local function setPixel(self, nX,nY, pixel) | |
expect(0, self, "table") | |
expect(1, nX, "number") | |
expect(2, nY, "number") | |
expect(3, pixel,"number", "string", "table") | |
if type(pixel) ~= "table" then | |
pixel = { tostring(pixel) } | |
end | |
for i,line in pairs(pixel) do | |
line = tostring(line) | |
local nCurLine = self[nY+i-1] | |
if nY+i-1 > 0 and nY+i-1 < #self then | |
if #line >= #self[nY+i-1]-nX then | |
line = line:sub(0,#self[nY+i-1]-nX-2) | |
end | |
self[nY+i-1] = nCurLine:sub(1,nX-1)..line..nCurLine:sub(nX+#line) | |
end | |
end | |
end | |
---Clears the whole screen. | |
---@param self table | |
local function clear(self) | |
local line = ('0'):rep(#self[1]) | |
for i=1,#self do | |
self[i] = line | |
end | |
end | |
---Writes a message at a given position. | |
---@param self table | |
---@param nX number | |
---@param nY number | |
---@param sLabel string | |
local function setLabel(self, nX,nY, sLabel) | |
expect(0, self, "table") | |
expect(1, nX, "number") | |
expect(2, nY, "number") | |
expect(4, sLabel,"string") | |
local sNew = "" | |
for i=1,#sLabel do | |
sNew = sNew..'#'..sLabel:sub(i,i) | |
end | |
self:setPixel((nX-1)*2+1,(nY-1)*3+1, { sNew }) | |
end | |
---Renders a given map at a given position. | |
---@param self table | |
---@param nOffsetX? number | |
---@param nOffsetY? number | |
local function render(self, nOffsetX,nOffsetY) | |
expect(1, self, "table") | |
expect(2, nOffsetX, "number", "nil") | |
expect(3, nOffsetY, "number", "nil") | |
field(self, "cBG", "table") | |
field(self, "cFG", "table") | |
for y=1,#self,3 do | |
for x=1,#self[1],2 do | |
local bit,reverse = toBlit( | |
self[y]:sub(x,x+1).. | |
self[y+1]:sub(x,x+1).. | |
self[y+2]:sub(x,x+1) | |
) | |
local nX,nY = math.floor(x/2)+1,math.floor(y/3)+1 | |
local cBG,cFG = colors.black,colors.white | |
if nX > 0 and nX < #self.cBG[1] | |
and nY > 0 and nY < #self.cBG then | |
cBG,cFG = tBToC[self.cBG[nY]:sub(nX,nX):lower()],tBToC[self.cFG[nY]:sub(nX,nX):lower()] | |
end | |
if reverse then cFG,cBG = cBG,cFG end | |
term.setBackgroundColor(cBG) | |
term.setTextColor(cFG) | |
term.setCursorPos(nX+(nOffsetX or 0), nY+(nOffsetY or 0)) | |
term.write(bit) | |
end end end | |
---Generates an empty map with given sizes. | |
---@param nW? number Width | |
---@param nH? number Height | |
---@return table tNewMap | |
local function createMap(nW,nH) | |
expect(1,nW, "number") | |
expect(2,nH, "number") | |
nW = nW*2 | |
nH = nH*3 | |
local tNewMap = { cFG={}, cBG={} } | |
local sPixelRow = ('0'):rep(nW) | |
local sColorRow = ('f'):rep(nW/2) | |
for i=1,nH do | |
tNewMap[i] = sPixelRow | |
if i<nH/3 then | |
tNewMap.cFG[i] = sPixelRow:sub(1,nW/2) | |
tNewMap.cBG[i] = sColorRow | |
end | |
end | |
tNewMap.render = render | |
tNewMap.setColor = setColor | |
tNewMap.setPixel = setPixel | |
tNewMap.setLabel = setLabel | |
tNewMap.clear = clear | |
return tNewMap | |
end | |
return { | |
createMap = createMap | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment