Implement buffered windows to support transparancy

This commit is contained in:
Gabriel Tofvesson 2024-11-19 18:57:36 +01:00
parent 86c23b8433
commit b0e5877417
2 changed files with 232 additions and 0 deletions

232
gfx/render/buffer.lua Normal file
View File

@ -0,0 +1,232 @@
local Util = require("util")
local DEFAULT_C = " "
local DEFAULT_FG = colors.white
local DEFAULT_BG = colors.black
local function ensureC(cVal)
return (cVal ~= nil and #cVal == 1 and cVal) or DEFAULT_C
end
local WindowBuffer = {}
-- Create a shallow wrapper for window object
function WindowBuffer.wrapWindow(w, defaultC, defaultFg, defaultBg, clearColor)
defaultC = ensureC(defaultC)
defaultFg = defaultFg or DEFAULT_FG
defaultBg = defaultBg or DEFAULT_BG
clearColor = clearColor or DEFAULT_BG
local obj = {}
function obj.blit(text, fg, bg)
w.blit(text, fg, bg)
end
function obj.flush() end
function obj.getSize()
return w.getSize()
end
function obj._setPixel(x, y, c, fg, bg)
w.setCursorPos(x, y)
w.setFgColor(fg or defaultFg)
w.setBgColor(bg or defaultBg)
w.write(c or defaultC)
end
function obj.setPixel(x, y, c, fg, bg)
local width, height = obj.getSize()
Util.boundCheck(x, y, width, height)
obj._setPixel(x, y, c, fg, bg)
end
-- Partial writes are not possible for native window access
obj._writePixel = obj._setPixel
obj.writePixel = obj.setPixel
function obj.setCursorPos(x, y)
w.setCursorPos(x, y)
end
function obj.getCursorPos()
return w.getCursorPos()
end
function obj.clear()
w.setBgColor(clearColor)
--w.setFgColor(clearColor) -- Shouldn't matter for native clear
w.clear()
end
return obj
end
function WindowBuffer.new(width, height, clearC, clearFg, clearBg)
clearC = ensureC(clearC)
clearFg = clearFg or DEFAULT_FG
clearBg = clearBg or DEFAULT_BG
local obj = {}
local function setState(o, c, fg, bg)
o.c = c
o.bg = bg
o.fg = fg
return o
end
local function writeState(o, c, fg, bg)
o.c = c or o.c
o.bg = bg or o.bg
o.fg = fg or o.fg
return o
end
local buffer = {}
for i=1,height do
local line = {}
for j=1,width do
line[j] = setState({})
end
buffer[i] = line
end
local pX, pY = 1, 1
function obj.blit(text, fg, bg)
assert(#text == #fg, "Foreground color blit length must match text length")
assert(#text == #bg, "Background color blit length must match text length")
local line = buffer[pY]
local baseX = pX
for i=1,math.min(#text, width - baseX - 1) do
local blitChar = line[i]
blitChar.c = text:sub(i, i)
blitChar.fg = fg:sub(i, i)
blitChar.bg = bg:sub(i, i)
end
pX = pX + #text
end
function obj._setPixel(x, y, c, fg, bg)
setState(buffer[y][x], c, fg, bg)
end
function obj.setPixel(x, y, c, fg, bg)
Util.boundCheck(x, y, width, height)
obj._setPixel(x, y, c, fg, bg)
end
function obj._writePixel(x, y, c, fg, bg)
writeState(buffer[y][x], c, fg, bg)
end
function obj.writePixel(x, y, c, fg, bg)
Util.boundCheck(x, y, width, height)
obj._writePixel(x, y, c, fg, bg)
end
function obj.setCursorPos(x, y)
pX, pY = x, y
end
function obj.getCursorPos()
return pX, pY
end
function obj.clear()
for i=1,height do
local line = buffer[i]
for j=1,width do
setState(line[j], clearC, clearFg, clearBg)
end
end
end
-- TODO: Implement partial flush; obj.flush(win, offsetX, offsetY, width, height)
function obj.flush(win, offsetX, offsetY)
for i=1,height do
local line = buffer[i]
for j=1,width do
local entry = line[j]
win._writePixel(j + offsetX, i + offsetY, entry.c, entry.fg, entry.bg)
end
end
end
return obj
end
function WindowBuffer.shallowChild(windowBuffer, width, height, offsetX, offsetY, clearC, clearFg, clearBg)
-- Assume static for now
local parentWidth, parentHeight = windowBuffer.getSize()
Util.boundCheck(offsetX, offsetY, parentWidth, parentHeight)
Util.boundCheck(offsetX + width, offsetY + height, parentWidth, parentHeight)
clearC = ensureC(clearC)
clearFg = clearFg or DEFAULT_FG
clearBg = clearBg or DEFAULT_BG
local obj = {}
local pX, pY = 1, 1
local function setCursorPos()
windowBuffer.setCursorPos(pX + offsetX, pY + offsetY)
end
function obj.blit(text, fg, bg)
setCursorPos()
windowBuffer.blit(text, fg, bg)
pX = pX + #text
end
function obj._setPixel(c, fg, bg)
setCursorPos()
windowBuffer._setPixel(c, fg, bg)
end
function obj.setPixel(c, fg, bg)
setCursorPos()
windowBuffer.setPixel(c, fg, bg)
end
function obj._writePixel(c, fg, bg)
setCursorPos()
windowBuffer._writePixel(c, fg, bg)
end
function obj.writePixel(c, fg, bg)
setCursorPos()
windowBuffer.writePixel(c, fg, bg)
end
function obj.setCursorPos(x, y)
pX, pY = x, y
end
function obj.getCursorPos()
return pX, pY
end
function obj.getSize()
return width, height
end
function obj.clear()
for i=1,height do
for j=1,width do
windowBuffer._setPixel(clearC, clearFg, clearBg)
end
end
end
obj.flush = windowBuffer.flush()
return obj
end
return WindowBuffer

0
gfx/render/init.lua Normal file
View File