-- 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) table.insert(self.ClipStack, {self.XAbsClip, self.YAbsClip, self.W, self.H}) 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) table.insert(self.ClipStack, {self.XAbsClip, self.YAbsClip, self.W, self.H}) 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 -- -- 000:0222220021111110212121102122211021121110211111100111110000000000 -- 001:0bbbbb00b9999980b999b980b99bb980b9bbb980b99999800888880000000000 -- 002:0555550056666670565566705655567056655670566666700777770000000000 -- 003:0444440043333320433433204344432043434320433333200222220000000000 -- 004:0ddddd00deeeeef0dededef0deedeef0dededef0deeeeef00fffff0000000000 -- -- -- 000:00000000ffffffff00000000ffffffff -- 001:0123456789abcdeffedcba9876543210 -- 002:0123456789abcdef0123456789abcdef -- -- -- 000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000304000000000 -- -- -- 000:100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -- -- -- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f4be69ce61309940205d --