2023-08-04 23:38:36 +00:00
|
|
|
-- title: kistaro-compositor
|
|
|
|
-- author: Kistaro Windrider (kistaro@gmail.com)
|
|
|
|
-- desc: Rendering compositor library. Includes Pico-8 camera features.
|
|
|
|
-- site: https://dragon.style/@kistaro
|
|
|
|
-- license: MIT License
|
|
|
|
-- version: 0.1
|
|
|
|
-- script: lua
|
|
|
|
|
|
|
|
|
|
|
|
function BOOT()
|
|
|
|
end
|
|
|
|
|
|
|
|
function TIC()
|
|
|
|
end
|
|
|
|
|
|
|
|
--stdlib--
|
|
|
|
|
|
|
|
-- generate standard "overlay"
|
|
|
|
-- constructor for type tt.
|
|
|
|
-- if more is defined, generated
|
|
|
|
-- new calls more(ret) after ret is
|
|
|
|
-- definitely not nil, before calling
|
|
|
|
-- setmetatable. Use to initialize
|
|
|
|
-- mutable items.
|
|
|
|
function MkNew(tt, more)
|
|
|
|
local mt = {__index=tt}
|
|
|
|
-- check "more" only once ever
|
|
|
|
if more then
|
|
|
|
tt.new = function(ret)
|
|
|
|
ret = ret or {}
|
|
|
|
more(ret)
|
|
|
|
setmetatable(ret, mt)
|
|
|
|
return ret
|
|
|
|
end
|
|
|
|
else
|
|
|
|
tt.new = function(ret)
|
|
|
|
ret = ret or {}
|
|
|
|
setmetatable(ret, mt)
|
|
|
|
return ret
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--Window compositor--
|
|
|
|
|
|
|
|
CamCtl = {
|
|
|
|
XOff = 0,
|
|
|
|
YOff = 0,
|
|
|
|
XAbsClip = 0,
|
|
|
|
YAbsClip = 0,
|
|
|
|
W = 240,
|
|
|
|
H = 136,
|
|
|
|
OriginStack = {},
|
|
|
|
ClipStack = {},
|
|
|
|
}
|
|
|
|
|
|
|
|
-- Overwrite current camera origin.
|
|
|
|
-- (0, 0) is now this pixel coordinate.
|
|
|
|
function CamCtl:SetAbsOrigin(x, y)
|
|
|
|
self.XOff, self.YOff = x, y
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Push current camera origin onto
|
|
|
|
-- the history stack and set the
|
|
|
|
-- new origin.
|
|
|
|
function CamCtl:PushAbsOrigin(x, y)
|
|
|
|
table.insert(self.OriginStack, {self.XOff, self.YOff})
|
|
|
|
self.XOff, self.YOff = x, y
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:SetRelOrigin(x, y)
|
|
|
|
self.XOff = self.XOff + x
|
|
|
|
self.YOff = self.Yoff + y
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:PushRelOrigin(x, y)
|
|
|
|
table.insert(self.OriginStack, {self.XOff, self.YOff})
|
|
|
|
self.XOff = self.XOff + x
|
|
|
|
self.YOff = self.YOff + Y
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:SetAbsCam(x, y)
|
|
|
|
self.XOff, self.YOff = -x, -y
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:PushAbsCam(x, y)
|
|
|
|
table.insert(self.OriginStack, {self.XOff, self.YOff})
|
|
|
|
self.XOff, self.YOff = -x, -y
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:SetRelCam(x, y)
|
|
|
|
self.XOff = self.XOff - x
|
|
|
|
self.YOff = self.YOff - y
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:PushRelCam(x, y)
|
|
|
|
table.insert(self.OriginStack, {self.XOff, self.YOff})
|
|
|
|
self.XOff = self.XOff - x
|
|
|
|
self.YOff = self.YOff - y
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:PopOrigin()
|
|
|
|
if #self.OriginStack == 0 then
|
|
|
|
self.XOff, self.YOff = 0, 0
|
|
|
|
return
|
|
|
|
end
|
|
|
|
self.XOff, self.YOff = unpack(table.Remove(self.OriginStack))
|
|
|
|
end
|
|
|
|
CamCtl.PopCam = CamCtl.PopOrigin
|
|
|
|
|
|
|
|
function CamCtl:SetNewClip(x, y, w, h)
|
|
|
|
if x then
|
|
|
|
self.XAbsClip = self.XOff + x
|
|
|
|
self.YAbsClip = self.YOff + y
|
|
|
|
self.W, self.H = w, h
|
|
|
|
clip(self.XAbsClip, self.YAbsClip, self.W, self.H)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
self.XAbsClip, self.YAbsClip, self.W, self.H = 0,0,240,136
|
|
|
|
clip()
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:PushNewClip(x, y, w, h)
|
2023-09-06 00:20:58 +00:00
|
|
|
table.insert(self.ClipStack, {self.XAbsClip, self.YAbsClip, self.W, self.H})
|
2023-08-04 23:38:36 +00:00
|
|
|
self:SetNewClip(x, y, w, h)
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:SetReClip(x,y,w,h)
|
|
|
|
if not x then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
x = x + self.XOff
|
|
|
|
local x2 = math.min(x + w, self.XAbsClip + self.W)
|
|
|
|
self.XAbsClip = math.max(x, self.XAbsClip)
|
|
|
|
self.W = max(0, x2 - self.XAbsClip)
|
|
|
|
|
|
|
|
y = y + self.YOff
|
|
|
|
local y2 = math.min(y+h, self.YAbsClip + self.H)
|
|
|
|
self.YAbsClip = math.max(y, self.YAbsClip)
|
|
|
|
self.H = max(0, y2 - self.YAbsClip)
|
|
|
|
|
|
|
|
clip(self.XAbsClip, self.YAbsClip, self.W, self.H)
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:PushReClip(x,y,w,h)
|
2023-09-06 00:20:58 +00:00
|
|
|
table.insert(self.ClipStack, {self.XAbsClip, self.YAbsClip, self.W, self.H})
|
2023-08-04 23:38:36 +00:00
|
|
|
self.SetReClip(x,y,w,h)
|
|
|
|
end
|
|
|
|
|
|
|
|
function CamCtl:PopClip()
|
|
|
|
if #self.ClipStack == 0 then
|
|
|
|
self.XAbsClip, self.YAbsClip, self.W, self.H = 0,0,240,136
|
|
|
|
clip()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local x,y,w,h = unpack(table.remove(self.ClipStack)))
|
|
|
|
self.XAbsClip, self.YAbsClip, self.W, self.H = x,y,w,h
|
|
|
|
clip(x,y,w,h)
|
|
|
|
end
|
|
|
|
-- Install
|
|
|
|
-- (swizzle all drawing functions!)
|
|
|
|
|
|
|
|
function CamCtl:Install()
|
|
|
|
local adjust_leading_2 = {
|
|
|
|
"circ", "circb",
|
|
|
|
"elli", "ellib",
|
|
|
|
"pix",
|
|
|
|
"rect", "rectb",
|
|
|
|
}
|
|
|
|
for _, fn in ipairs(adjust_leading_2) do
|
|
|
|
local f_orig = _G[fn]
|
|
|
|
_G[fn] = function(x, y, ...)
|
|
|
|
return f_orig(x + self.XOff, y + self.YOff, ...)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local keep_first_adjust_2_opt = {
|
|
|
|
"spr", "font", "print"
|
|
|
|
}
|
|
|
|
for _, fn in ipairs(keep_first_adjust_2_opt) do
|
|
|
|
local f_orig = _G[fn]
|
|
|
|
_G[fn] = function(v, x, y, ...)
|
|
|
|
if x then
|
|
|
|
x = x + self.XOff
|
|
|
|
end
|
|
|
|
if y then
|
|
|
|
y = y + self.YOff
|
|
|
|
end
|
|
|
|
return f_orig(v, x, y, ...)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local tri_family = {"tri", "trib", "textri"}
|
|
|
|
|
|
|
|
for _, fn in ipairs(tri_family) do
|
|
|
|
local f_orig = _G[fn]
|
|
|
|
_G[fn] = function(x1, y1, x2, y2, x3, y3, ...)
|
|
|
|
return f_orig(
|
|
|
|
x1 + self.XOff, y1 + self.YOff,
|
|
|
|
x2 + self.XOff, y2 + self.YOff,
|
|
|
|
x3 + self.XOff, y3 + self.YOff,
|
|
|
|
...
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local map_orig = map
|
|
|
|
map = function(mx, my, w, h, sx, sy, ...)
|
|
|
|
XXX(kistaro): implement!
|
|
|
|
-- if called with no args, calculate new map
|
|
|
|
-- coordinates, clipping at 0, to respect
|
|
|
|
-- camera movement! this will require full tile
|
|
|
|
-- movement to be reflected in mx/my, w and h to
|
|
|
|
-- stay 30 x 17 unless they go to 31 x 18 for
|
|
|
|
-- partial tiles at edges, and sx and sy to become
|
|
|
|
-- offsets. If sx and sy are provided, do the
|
|
|
|
-- obvious thing instead, which is much easier.
|
|
|
|
end
|
|
|
|
|
|
|
|
local line_orig = line
|
|
|
|
line = function(x0, y0, x1, y1, color)
|
|
|
|
return line_orig(
|
|
|
|
x0 + self.XOff, y0 + self.YOff,
|
|
|
|
x1 + self.XOff, y1 + self.YOff,
|
|
|
|
color
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
-- <SPRITES>
|
|
|
|
-- 000:0222220021111110212121102122211021121110211111100111110000000000
|
|
|
|
-- 001:0bbbbb00b9999980b999b980b99bb980b9bbb980b99999800888880000000000
|
|
|
|
-- 002:0555550056666670565566705655567056655670566666700777770000000000
|
|
|
|
-- 003:0444440043333320433433204344432043434320433333200222220000000000
|
|
|
|
-- 004:0ddddd00deeeeef0dededef0deedeef0dededef0deeeeef00fffff0000000000
|
|
|
|
-- </SPRITES>
|
|
|
|
|
|
|
|
-- <WAVES>
|
|
|
|
-- 000:00000000ffffffff00000000ffffffff
|
|
|
|
-- 001:0123456789abcdeffedcba9876543210
|
|
|
|
-- 002:0123456789abcdef0123456789abcdef
|
|
|
|
-- </WAVES>
|
|
|
|
|
|
|
|
-- <SFX>
|
|
|
|
-- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000
|
|
|
|
-- </SFX>
|
|
|
|
|
|
|
|
-- <TRACKS>
|
|
|
|
-- 000:100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
|
|
-- </TRACKS>
|
|
|
|
|
|
|
|
-- <PALETTE>
|
|
|
|
-- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f4be69ce61309940205d
|
|
|
|
-- </PALETTE>
|
|
|
|
|