-- Assembled by the RiFT bundler

rift_statestreetsignalpanup=function()
R=R or {}
rift_syssys()(R) 
rift_syspalette()(R)
rift_3dgeom()(R)
rift_3dmodel()(R)
rift_3dactor()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

SCENE=nil
MODEL_GMAN=nil
MODEL_RMAN=nil
ACTOR_GMAN=nil
ACTOR_RMAN=nil

lampFilter=rift_screenfilterslamp()
local palYswitch=0

return {
    duration=5000,
    bdr=function(y,t,unitT)
        local rgb0=R.RGB:new(0,0,0)
        local blendTo=y<palYswitch and GLOBAL.rgbRMan or GLOBAL.rgbGMan
        for i=0,15 do
            local rgb=rgb0:getBlendTo(blendTo,i/15)
            R.setRGB(i,rgb)
        end
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())
            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)
            ACTOR_GMAN:setMat(R.M44:newTrans(0,0,3))
            SCENE:registerActor(ACTOR_GMAN)

            MODEL_RMAN=R.Model:new()
            MODEL_RMAN:load(rift_datamodelredman())
            ACTOR_RMAN=R.Actor:new(MODEL_RMAN)
            ACTOR_RMAN:setDrawFn(R.poly.Draw1Colour(1),0)
            ACTOR_RMAN:setMat(R.M44:newTrans(0,-2,3))
            SCENE:registerActor(ACTOR_RMAN)

            vbank(1)
            cls(0)  
        end

        vbank(0)
        cls()

        local camY=unitT*3
        local cam=SCENE:getCam()
        cam:setPos(R.V4:new({0,camY,0,1}))
        cam:setAim(R.V4:new({0,0,2,1}))
        palYswitch=camY*30+40

        SCENE:draw()
        lampFilter(120,68+camY*30,40)
        lampFilter(120,camY*30,40)
    end,
}

end

rift_statevehicleapproaches=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_VEHICLE=nil
local ACTOR_VEHICLE=nil

return {
    duration=4000,
    bdr=function(y,t,unitT)
        vbank(0)
        local bg=R.clamp(((unitT-.7)/.3)^1.4,0,1)
        R.setRGB(0,R.RGB:new(bg,bg,bg))
        R.setRGB(1,R.RGB:new(1,1,1))
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_VEHICLE=R.Model:new()
            MODEL_VEHICLE:load(rift_datamodelvehicle()())

            ACTOR_VEHICLE=R.Actor:new(MODEL_VEHICLE)
            ACTOR_VEHICLE:setDrawFn(R.poly.Draw1Colour(1),0)
            
            SCENE:registerActor(ACTOR_VEHICLE)
        end

        vbank(0)
        cls(0)

        local z=40-unitT*40
        local mat=R.M44:newTrans(.8,0,z)
        ACTOR_VEHICLE:setMat(mat)

        SCENE:draw()
    end,
}

end

rift_3dviewport=function()
return function(R)
	R.Viewport={}

	function R.Viewport:new(w,h)
		local o={
			xofs=w/2,
			yofs=h/2,
		}
		setmetatable(o,self)
		self.__index=self
		return o
	end

    function R.Viewport:transform(x,y)
        return self.xofs+x,self.yofs+y
    end
end

end

rift_sysrgb=function()
return function(R)
    R.RGB={}

    -- r,g,b are 0..1
    function R.RGB:new(r,g,b)
		local o={r=r,g=g,b=b}
		setmetatable(o,self)
		self.__index=self
		return o
	end

    -- Returns a new RGB
    -- t: 0 is all of self, 1 is all of toRgb
    function R.RGB:getBlendTo(toRgb,t)
		local tInv=1-t
        return R.RGB:new(
            self.r*tInv+toRgb.r*t,
            self.g*tInv+toRgb.g*t,
            self.b*tInv+toRgb.b*t
        )
	end

    -- index: 0..15
    R.setRGB=function(i,rgb)
        local a=0x3FC0+i*3
        poke(a,(rgb.r*255)//1)
        poke(a+1,(rgb.g*255)//1)
        poke(a+2,(rgb.b*255)//1)
    end

    -- For getting existing colours (to blend)
    R.getRGB=function(i)
        local a=0x3FC0+i*3
        return R.RGB:new(
            peek(a)/255,
            peek(a+1)/255,
            peek(a+2)/255
        )
    end
end

end

rift_stateoutrocard=function()
R=R or {}
rift_fontsysfont()(R)
rift_fontfont()(R)
rift_uiqrint()(R)
rift_syspalette()(R)
rift_sysmath()(R)

local GLOBAL=rift_global()

FONT=nil

function printBigCentre(text,y)
    local w=FONT:width(text,1)
    x=120-w/2
    FONT:print(text,x-1,y-1,1,1,3)
    FONT:print(text,x+1,y+1,1,1,2)
    FONT:print(text,x,y,1,1,1)
end

function printSmall(text,x,y)
    R.qrint(text,x,y,1,false,1,false,2,nil)
end

return {
    duration=12000,
    bdr=function(y,t,unitT)
        vbank(0)
        local pal0=R.Palette:new()
        pal0:setRGB(0,R.RGB:new(0,0,0))
        pal0:setRGB(1,R.RGB:new(0,0,0))
        pal0:setRGB(2,R.RGB:new(0,0,0))
        pal0:setRGB(3,R.RGB:new(0,0,0))

        local pal1=R.Palette:new()
        pal1:setRGB(0,GLOBAL.rgbGMan)
        pal1:setRGB(1,R.RGB:new(1,1,1))
        pal1:setRGB(2,R.RGB:new(.1,.5,.1))
        pal1:setRGB(3,R.RGB:new(.05,.4,.05))

        local inOut=.25
        local colT=1
        if unitT<inOut then
            colT=R.smoothStep(unitT/inOut,0,1)
        elseif unitT>(1-inOut) then
            colT=R.smoothStep((1-unitT)/inOut,0,1)
        end
        pal0:applyBlend(pal1,colT)
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls()
            
            vbank(0)

            local data=rift_datasysfontinformics7x7informics7x7()
            R.sysfontLoad(data)

            local fontdata=rift_datafontnucampi8x16nucampi8x16()
            FONT=R.Font:new()
            FONT:load(fontdata)        
        end
        cls(0)
        printBigCentre("Walk",2)
        printSmall("Thanks for watching!",64,50)
        if unitT<.2 then
        elseif unitT<.6 then
            printSmall("No polygons were harmed",52,79)
            printSmall("in the making of this production",35,89)
        else
            printSmall("Always look both ways when crossing a road",6,85)
        end
        printBigCentre("- RiFT -",24)
        printSmall("Bossman  -  Decca  -  jtruk",48,118)
        printSmall("Jynx - Mantratronic - T=Bach",44,128)
    end,
}

end

rift_3dscene=function()
return function(R)
--	rift_3dgeom()(R)
	rift_3dcam()(R)
	rift_3dproj()(R)
--	rift_3dmodel()(R)
	rift_3dviewport()(R)

	R.Scene={}

	function R.Scene:new()	
		local o={
			cam=R.Cam:new(R.V4:new({0,0,0,0}),R.V4:new({0,0,1,0}),R.V4:new({0,-1,0,1})),
			proj=R.Proj:new(R.Proj.PERSPECTIVE),
			viewport=R.Viewport:new(240,136),
			actors={},	-- Table of actors, entries may be nil if an actor was removed
		}
		setmetatable(o,self)
		self.__index=self
		return o
	end

	function R.Scene:getCam()
		return self.cam
	end

	function R.Scene:setCam(cam)
		self.cam=cam:clone()
	end

	function R.Scene:proj()
		return self.proj
	end

	function R.Scene:setProj(proj)
		self.proj=proj:clone()
	end

	--[[
	function R.Scene:addLight(light)
		local i=#self.lights+1
		self.lights[i]=light
		return i
	end
	--]]
	function R.Scene:clearActors()
		self.actors={}
	end

	-- mat is the World Transform - i.e. where the object is placed in the world
	function R.Scene:registerActor(actor)
		-- Slot this one into a gap if possible
		for i=1,#self.actors do
			local tryActor=self.actors
			if tryActor==nil then
				self.actors[i]=actor
				return
			end
		end

		self.actors[#self.actors+1]=actor
	end

	-- Removes the reference
	function R.Scene:unregisterActor(actor)
		for i=1,#self.actors do
			local tryActor=self.actors[i]
			if tryActor==actor then
				self.actors[i]=nil
			end
		end
	end

	function R.Scene:draw()
		viewMat=self.cam:getM44()
		projMat=self.proj:getM44()

		for i=1,#self.actors do
			local actor=self.actors[i]
			if actor~=nil then
				actor:draw(viewMat,projMat,self.viewport)
			end
		end
	end
end

end

rift_datamodelgreenman=function()
-- TrafficWalk2
return {
	flags=0,
	divide_by=100,
	scale=1,
	vertices={74,27,0,83,44,0,104,55,0,100,61,0,94,61,0,75,52,0,71,45,0,68,65,0,93,111,0,96,112,0,100,111,0,102,114,0,84,123,0,89,124,0,58,83,0,56,83,0,37,117,0,36,121,0,41,123,0,39,127,0,35,126,0,26,123,0,23,120,0,45,67,0,46,48,0,44,40,0,34,49,0,32,70,0,27,69,0,24,66,0,25,48,0,26,43,0,40,27,0,51,21,0,52,17,0,50,13,0,51,7,0,52,2,0,56,0,0,62,1,0,65,3,0,68,6,0,68,15,0,66,19,0,62,22,0,},
	triangles={1,7,2,7,6,2,2,5,6,5,3,4,3,2,5,1,25,8,8,15,9,15,13,9,9,13,14,9,10,14,10,12,11,12,10,14,15,16,8,16,25,8,25,24,16,24,17,16,24,23,17,23,22,17,22,17,18,22,21,18,21,19,18,19,21,20,25,45,1,45,34,25,25,26,34,33,34,26,27,26,33,33,32,27,27,32,31,27,30,31,30,27,29,29,28,27,34,35,45,45,44,35,35,36,44,43,44,36,36,42,43,42,36,37,42,41,37,37,38,41,41,40,38,38,39,40,},
	origin={0.6,0.6,0}
}

end

rift_datamodelrectangle=function()
return function(w,h)
    return {
        vertices={
            -w,-h,0,
            w,-h,0,
            w,h,0,
            -w,h,0,
        },
        -- These faces might have normals pointing the wrong way!
        triangles={
            1,2,3,
            3,4,1,
        },
        triangles_ex={{
            u1=0,v1=0,u2=1,v2=0,u3=1,v3=1,
        },{
            u1=1,v1=1,u2=0,v2=1,u3=0,v3=0,
        }},
        origin={0,0,0},
    }
end

end

rift_3dactor=function()
return function(R)
	rift_3dgeom()(R)
	rift_3dcam()(R)
	rift_3dproj()(R)
	rift_3dmodel()(R)
	rift_3dviewport()(R)

	R.Actor={}

    -- Attaches to a reference of the model
    -- So, copy that model if you want multiple, with deformations or whatever
	function R.Actor:new(model)
		local o={
			model=model,
			mat=R.M44:new(R.M44.ID),
            drawFn=nil,
            drawFlags=0,
			geomPrePassFn=nil,
			geomPostPassFn=nil,
			drawPassFns={},	-- {"pass1":fn,...}
            animCycle=nil,
            animTime=nil,
		}
		setmetatable(o,self)
		self.__index=self
		return o
    end

    function R.Actor:getMat()
        return self.mat
    end

    function R.Actor:setMat(mat)
        self.mat=mat:clone()
    end

    -- fn can be nil, but you won't get anything out!
	function R.Actor:setDrawFn(fn,flags)
		self.drawFn=fn
		self.drawFlags=flags
	end

	function R.Actor:setDrawPassFn(name,fn)
		self.drawPassFns[name]=fn
	end

	-- fn can be nil
	function R.Actor:setGeomPrePassFn(fn)
		self.geomPrePassFn=fn
	end

    -- fn can be nil
	function R.Actor:setGeomPostPassFn(fn)
		self.geomPostPassFn=fn
	end

	function R.Actor:setAnim(cycle,time)
        self.animCycle=cycle
        self.animTime=time
    end

	function R.Actor:clearAnim()
        self.animCycle=nil
    end

    function R.Actor:draw(viewMat,projMat,viewport)
        local draw={fn=self.drawFn,passFns=self.drawPassFns,flags=self.drawFlags}
        local anim=(self.animCycle) and {cycle=self.animCycle,time=self.animTime} or {}
        local cbFns={geomPrePassFn=self.geomPrePassFn,geomPostPassFn=self.geomPostPassFn}
		self.model:draw(self.mat,viewMat,projMat,viewport,draw,anim,cbFns)
    end
end

end

rift_statewalkprism=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

local function drawBuf(buf,w,h,dx0,dy0,dp,pixR)
    for oy=0,h do
        for ox=0,w do
            local dx,dy=dx0+ox,dy0+oy
--            local sp=pix(dx,dy)
            local bp=buf[oy*w+ox]
            if bp>0 then
                if math.random()<pixR then
                    pix(dx,dy,dp)
                end
--                pix(dx,dy,sp+1)
            end
        end    
    end
end

return {
    duration=7000,
    bdr=function(y,t,unitT)
        vbank(0)
        local rgbMen={GLOBAL.rgbGMan,R.RGB:new(.85,.85,0),R.RGB:new(0,.85,.85),R.RGB:new(1,.2,.2),R.RGB:new(.2,.2,1)}
        local tBlend=0.5+math.sin(unitT*math.pi)*.5
        for i=1,#rgbMen do
            R.setRGB(i,rgbMen[1]:getBlendTo(rgbMen[i],tBlend))
        end
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(10),0)
            MAT_GMAN=ACTOR_GMAN:getMat()
            MAT_GMAN:mulM44(R.M44:newTrans(0,0,1.5))
            
            SCENE:registerActor(ACTOR_GMAN)
        end

        local manX,manY,manW,manH=80,10,80,120

        vbank(1)
        cls(0)
        SCENE:draw()
        local buf={}
        for oy=0,manH do
            for ox=0,manW do
                local x,y=manX+ox,manY+oy
                buf[oy*manW+ox]=pix(x,y)
            end    
        end

        vbank(0)
        cls(0)
        local xc=manX
        local xd=math.sin(unitT*math.pi)*85
        local yd=math.sin(math.sin(unitT*math.pi)*4)*10
        local pixR=.6+(.5+math.cos(unitT*math.pi*2)*.5)*.4
        drawBuf(buf,manW,manH,xc-xd,manY-yd,4,pixR)
        drawBuf(buf,manW,manH,xc+xd,manY+yd,5,pixR)
        drawBuf(buf,manW,manH,xc-xd/2,manY-yd/2,2,pixR)
        drawBuf(buf,manW,manH,xc+xd/2,manY+yd/2,3,pixR)
        drawBuf(buf,manW,manH,xc,manY,1,pixR)

        vbank(1)
        cls(0)
    end,
}

end

rift_statewalkgalaxy=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

return {
    duration=4000,
    bdr=function(y,t,unitT)
        vbank(0)
        R.setRGB(1,GLOBAL.rgbGMan)
        R.setRGB(2,R.RGB:new(1,1,1))
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)
            MAT_GMAN=ACTOR_GMAN:getMat()
            MAT_GMAN:mulM44(R.M44:newTrans(0,0,1.5))
            
            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)
    
        local gx,gy=90,40
        for i=0,1000 do
            local arm,pos=math.modf(i/20)
            local d=pos
            local a=(arm/6)*math.pi*2+d+unitT
            local ox=math.sin(a)*d*100
            local x=gx+ox
            local y=gy+math.cos(a)*d*20-ox*.1
            pix(x,y,2)
        end

        SCENE:draw()
    end,
}

end

rift_statewalksplits=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

local function drawBuf(buf,w,sy0,sy1,dx0,dy0,dp,flipX)
    for oy=sy0//1,sy1//1 do
        for ox=0,w do
            local dx,dy=dx0+ox,dy0+oy
--            local sp=pix(dx,dy)
            local index=flipX and (oy*w+ox) or (oy*w+(w-ox))
            local bp=buf[index]
            if bp>0 then
                pix(dx,dy,dp)
            end
        end    
    end
end

return {
    duration=7000,
    bdr=function(y,t,unitT)
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(10),0)
            MAT_GMAN=ACTOR_GMAN:getMat()
            MAT_GMAN:mulM44(R.M44:newTrans(0,0,1.5))
            
            SCENE:registerActor(ACTOR_GMAN)
        end

        local manX,manY,manW,manH=80,10,80,120

        vbank(1)
        cls(0)
        SCENE:draw()
        local buf={}
        for oy=0,manH do
            for ox=0,manW do
                local x,y=manX+ox,manY+oy
                buf[oy*manW+ox]=pix(x,y)
            end    
        end

        vbank(0)
        cls(0)
        local xc=manW

        local sy0,sy1=manH*0,manH*.33
        local shift=(160+unitT*640)%320-160
        drawBuf(buf,manW,sy0,sy1,xc-shift,manY,4,true)

        local sy0,sy1=manH*.33,manH*.66
        drawBuf(buf,manW,sy0,sy1,xc,manY,1,true)

        sy0,sy1=manH*.66,manH*1
        drawBuf(buf,manW,sy0,sy1,xc+shift,manY,2,false)

        vbank(1)
        cls(0)
    end,
}

end

rift_global=function()
R=R or {}
rift_sysrgb()(R)

return {
    rgbGMan=R.RGB:new(.2,.9,.2),
    rgbRMan=R.RGB:new(1,0,0),
}

end

rift_syspalette=function()
return function(R)
    rift_sysrgb()(R)

    R.Palette={}

    function R.Palette:new()
		local o={rgbs={}}
		setmetatable(o,self)
		self.__index=self
		return o
	end

    function R.Palette:setRGB(i,rgb)
        self.rgbs[i]=rgb
    end

    -- can return rgb or nil
    function R.Palette:getRGB(i)
        -- #TODO: Check this returns nil if it doesn't exist
        return self.rgbs[i]
    end

    function R.Palette:setAllRGB(rgb)
        for i=0,15 do
            self:setRGB(i,rgb)
        end
    end

    function R.Palette:apply()
        for i,rgb in ipairs(self.rgbs) do
            R.setRGB(i,rgb)
        end
    end

    -- unitT: 0..1
    function R.Palette:applyBlend(toPalette,t)
        for i,rgb in pairs(self.rgbs) do
            local toRGB=toPalette:getRGB(i)
            local rgbBlend=toRGB and rgb:getBlendTo(toRGB,t) or rgb
            R.setRGB(i,rgbBlend)
        end
    end

    function R.Palette:readSys()
        for i=0,15 do
            self:setRGB(i,R.getRGB(i))
        end
    end
end

end

rift_statelogoopener=function()
R=R or {}
rift_syssys()(R)
rift_syspalette()(R)
local riftlogo=rift_datagfxriftlogo()

local SCENE=nil
local MODEL_RECT=nil
local ACTOR_RECT=nil
local PAL_LOGO=nil
local PAL0=nil

return {
    duration=10000,
    bdr=function(y,t,unitT)
        local cBlend1,cBlend2=1,1
        if unitT<.2 then
            cBlend1=unitT/.2
            cBlend2=unitT/.2
        elseif unitT>.7 then
            cBlend2=math.max(1-(unitT-.7)/.3,0)
        end

        vbank(0)
        local rgb0=R.RGB:new(0,0,0)
        R.setRGB(0,rgb0)
        local shiftLine1=(y>>1)%2==0 and .5 or 0
        for i=1,15 do
            local r=.5+.5*math.cos(i*.27+unitT*7+y*.027+shiftLine1)
            local g=.5+.5*math.cos(1+i*.032+unitT*6-y*.023-shiftLine1)
            local b=0
            local rgb=R.RGB:new(r,g,b)
            R.setRGB(i,rgb0:getBlendTo(rgb,cBlend2))
        end

        vbank(1)
        PAL0:applyBlend(PAL_LOGO,cBlend1)
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            PAL0=R.Palette:new()
            PAL0:setAllRGB(R.RGB:new(0,0,0))

            riftlogo.setup()
            PAL_LOGO=R.Palette:new()
            PAL_LOGO:readSys()

            SCENE=R.Scene:new()

            local w,h=riftlogo.getDims()
            MODEL_RECT=R.Model:new()
            MODEL_RECT:load(rift_datamodelrectangle()(1,h/w))

            ACTOR_RECT=R.Actor:new(MODEL_RECT)
            ACTOR_RECT:setDrawFn(function(tr)
                ttri(
                    tr.v[1].x,tr.v[1].y,
                    tr.v[2].x,tr.v[2].y,
                    tr.v[3].x,tr.v[3].y,
                    tr.ex.u1*w,tr.ex.v1*h,
                    tr.ex.u2*w,tr.ex.v2*h,
                    tr.ex.u3*w,tr.ex.v3*h,
                    2,
                    15,
                    -tr.v[1].z,-tr.v[2].z,-tr.v[3].z
                )
            end,0)
            
            SCENE:registerActor(ACTOR_RECT)
        end

        local inRot=1
        if unitT<.85 then
            inRot=unitT/.85
        end

        vbank(1)
        cls()
        riftlogo.draw(0,0)

        vbank(0)
        cls()
        local mat=R.M44:new(R.M44.ID)
        --mat:mulM44(R.M44:newTrans(0,0,4-inRot))
        mat:mulM44(R.M44:newTrans(math.sin(inRot*math.pi*4),math.sin(inRot*math.pi*5),4+math.cos(inRot*math.pi*3)*1.5)) 
        mat:mulM44(R.M44:newRotZ(inRot*4*math.pi))
        mat:mulM44(R.M44:newRotY(math.sin(inRot*math.pi*3)*math.pi))
--        mat:mulM44(R.M44:newRotX(inRot*.7*math.pi))
        ACTOR_RECT:setMat(mat)

        SCENE:draw()
        memcpy(0x8000,0,120*136)
        for y=0,136 do
            for x=0,240 do
                local ox,oy=x-120,y-68
                local a=math.atan2(oy,ox)
                local d=math.sqrt((ox)^2+(oy)^2)
                local c=d*.1+a+inRot*5
                pix(x,y,8+math.sin(c)*7)
            end
        end

        vbank(1)
        memcpy(0,0x8000,120*136)
    end,
}

end

rift_stategreenmanbreakout=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

lampFilter=rift_screenfilterslamp()

return {
    duration=15000,
    bdr=function(y,t,unitT)
        vbank(0)
        local pal0=R.Palette:new()
        local pal1=R.Palette:new()
        local rgbGMan=GLOBAL.rgbGMan
        pal0:setRGB(0,R.RGB:new(0,0,0))
        pal1:setRGB(0,R.RGB:new(0,0,0))
        for i=1,15 do
            local s1=i/15
            local s0=s1/4
            pal0:setRGB(i,R.RGB:new(rgbGMan.r*s0,rgbGMan.g*s0,rgbGMan.b*s0))
            pal1:setRGB(i,R.RGB:new(rgbGMan.r*s1,rgbGMan.g*s1,rgbGMan.b*s1))
        end
        local blend=1
        if unitT>.5 then
            local t=((unitT-.5)/.5)*math.pi*2*6
            blend=.5+math.cos(t)*.5
        end
        pal0:applyBlend(pal1,blend)

        vbank(1)
        R.setRGB(1,R.RGB:new(0,0,0))
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)

            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)  
        
        local mat=R.M44:new(R.M44.ID)
        local x,y,z,yr,zr=0,0,0,0,0
        local zBack=3
        if unitT < .4 then
            z=0
        elseif unitT <.7 then
            local inT=(unitT-.4)/.3
            local bounce=math.pi*10
            z=inT*zBack
            y=math.abs(math.sin(inT*bounce))
        elseif unitT <.9 then
            z=zBack
        else
            local inT=(unitT-.9)/.1
            local bounce=math.pi*10
            z=math.max(zBack-inT*(2+zBack),-1.5)
            x=math.sin(inT*bounce)*.5
            y=math.abs(math.sin(inT*bounce))
            zr=math.sin(inT*bounce)*.6
        end
        mat:mulM44(R.M44:newTrans(x*.2,y*-.2,1.5+z))
        mat:mulM44(R.M44:newRotZ(zr*.2))
        ACTOR_GMAN:setMat(mat)

        SCENE:draw()
        lampFilter(120,68,100)
    end,
}

end

rift_stategreenmangetup=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

return {
    duration=2000,
    bdr=function(y,t,unitT)
        vbank(0)
        R.setRGB(1,GLOBAL.rgbGMan)
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)
            
            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)
    
        local mat=R.M44:newTrans(0,0,1.5)
        mat:mulM44(R.M44:newRotX(-math.pi/2+unitT*math.pi/2))
        ACTOR_GMAN:setMat(mat)

        SCENE:draw()
    end,
}

end

rift_stateredmansaysstop=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

lampFilter=rift_screenfilterslamp()

return {
    duration=15000,
    bdr=function(y,t,unitT)
        vbank(0)
        local pal0=R.Palette:new()
        local pal1=R.Palette:new()
        local rgbRMan=GLOBAL.rgbRMan
        pal0:setRGB(0,R.RGB:new(0,0,0))
        pal1:setRGB(0,R.RGB:new(0,0,0))
        for i=1,15 do
            local s1=i/15
            local s0=s1/4
            pal0:setRGB(i,R.RGB:new(rgbRMan.r*s0,rgbRMan.g*s0,rgbRMan.b*s0))
            pal1:setRGB(i,R.RGB:new(rgbRMan.r*s1,rgbRMan.g*s1,rgbRMan.b*s1))
        end
        local blend=1
        if unitT>.5 then
            local t=((unitT-.5)/.5)*math.pi*2*6
            blend=.5+math.cos(t)*.5
        end
        pal0:applyBlend(pal1,blend)

        vbank(1)
        R.setRGB(1,R.RGB:new(0,0,0))
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelredman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)

            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)  
        
        local mat=R.M44:new(R.M44.ID)
        local x,y,z,yr,zr=0,0,0,0,0
        local zBack=3
        if unitT < .4 then
            z=0
        elseif unitT <.7 then
            local inT=(unitT-.4)/.3
            local bounce=math.pi*10
            z=inT*zBack
            y=math.abs(math.sin(inT*bounce))
        elseif unitT <.9 then
            z=zBack
        else
            local inT=(unitT-.9)/.1
            local bounce=math.pi*10
            z=math.max(zBack-inT*(2+zBack),-1.5)
            x=math.sin(inT*bounce)*.5
            y=math.abs(math.sin(inT*bounce))
            zr=math.sin(inT*bounce)*.6
        end
        mat:mulM44(R.M44:newTrans(x*.2,y*-.2,1.5+z))
        mat:mulM44(R.M44:newRotZ(zr*.2))
        ACTOR_GMAN:setMat(mat)

        SCENE:draw()
        lampFilter(120,68,100)
    end,
}

end

rift_3dproj=function()
return function(R)
	rift_3dgeom()(R)
    
    R.Proj={
		ORTHOGRAPHIC='o',
		PERSPECTIVE='p',
	}

	function R.Proj:new(type)
		local o={
			type=type,
		}
		setmetatable(o,self)
		self.__index=self
		return o
	end
    
    -- type is ORTHOGRAPHIC or PERSPECTIVE
    function R.Proj:setType(type)
        self.type=type
    end

    function R.Proj:getM44()
		local viewAngle=75
		local near=0.01
		local far=100

        if self.type==R.Proj.ORTHOGRAPHIC then
            -- width,height,near,far
            return R.NewM44OrthProj(1,1,near,far)
        else
            -- viewAngle,near,far
            return R.NewM44PersProj(viewAngle,near,far)
        end
    end
end


end

rift_3dgeom=function()
return function(R)
	rift_sysmath()(R)

	local S=math.sin
	local C=math.cos

	R.V4={
		EMPTY={0,0,0,0},
		ID={0,0,0,1},
	}
	
	R.M44={
		EMPTY={{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}},
		ID={{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}},
	}
	

	-- V4 --

	-- e:
	-- 	{1,2,3,4}
	-- 	V4.EMPTY
	-- 	V4.IDENTITY
	function R.V4:new(e)
		local o={e={}}
		for i=1,4 do
			o.e[i]=e[i]
		end
		setmetatable(o,self)
		self.__index=self
		return o
	end

	function R.V4:clone()
		return R.V4:new(self.e)
	end

	function R.V4:add(v4)
		for x=1,4 do
			self.e[x]=self.e[x]+v4.e[x]
		end
	end

	function R.V4:addC(v4)
		local o=self:clone()
		o:add(v4)
		return o
	end

	function R.V4:sub(v4)
		for x=1,4 do
			self.e[x]=self.e[x]-v4.e[x]
		end
	end

	function R.V4:subC(v4)
		local o=self:clone()
		o:sub(v4)
		return o
	end

	function R.V4:mul(s)
		for x=1,4 do
			self.e[x]=self.e[x]*s
		end
	end

	function R.V4:mulC(s)
		local o=self:clone()
		o:mul(s)
		return o
	end

	function R.V4:normal()
		local l=self:length()
		-- Catch l==0
		l=(l<.001) and .001 or l
		self.e[1]=self.e[1]/l
		self.e[2]=self.e[2]/l
		self.e[3]=self.e[3]/l
	end

	function R.V4:normalC()
		local o=self:clone()
		o:normal()
		return o
	end

	function R.V4:length()
		return math.sqrt(
			self.e[1]*self.e[1]
			+self.e[2]*self.e[2]
			+self.e[3]*self.e[3]
		)
	end

	function R.V4:dot(v4)
		return
			self.e[1]*v4.e[1]
			+self.e[2]*v4.e[2]
			+self.e[3]*v4.e[3]
	end

	function R.V4:cross(v4)
		return R.V4:new({
			self.e[2]*v4.e[3]-self.e[3]*v4.e[2],
			self.e[3]*v4.e[1]-self.e[1]*v4.e[3],
			self.e[1]*v4.e[2]-self.e[2]*v4.e[1],
			1
		})
	end

	function R.V4:lerp(v4,t)
		return R.V4:new({
			R.lerp(t,self.e[1],v4.e[1]),
			R.lerp(t,self.e[2],v4.e[2]),
			R.lerp(t,self.e[3],v4.e[3]),
			1
		})
	end

	function R.V4:mulM44E(m44,normalise)
		local out={}
		for y=1,4 do
			local acc=0
			for x=1,4 do
				acc=acc+self.e[x]*m44.e[y][x]
			end
			out[y]=acc
		end

		if normalise then
			if out[4]==0 then
				-- not sure if this is the right thing to do
				out[4]=0.00001
			end

			out[1]=out[1]/out[4]
			out[2]=out[2]/out[4]
			out[3]=out[3]/out[4]
		end

		return out
	end

	function R.V4:mulM44(m44,normalise)
		self.e=self:mulM44E(m44,normalise)
	end

	function R.V4:mulM44C(m44,normalise)
		return R.V4:new(self:mulM44E(m44,normalise))
	end

	function R.V4Normal(v1,v2,v3)
		local u=v2:subC(v1)
		local v=v3:subC(v1)
		local cross=u:cross(v)
		local l=cross:length()
		l=(l<.001) and .001 or l -- Catch l==0
		return R.V4:new({cross.e[1]/l,cross.e[2]/l,cross.e[3]/l,1})
	end

	-- M44 --

	function R.M44:new(e)
		local o={e={{},{},{},{}}}
		for y=1,4 do
			for x=1,4 do
				o.e[y][x]=e[y][x]
			end
		end
		setmetatable(o,self)
		self.__index=self
		return o
	end

	function R.M44:clone()
		return R.M44:new(self.e)
	end

	function R.M44:newRotX(a)
		local s,c=S(a),C(a)
		return R.M44:new({{1,0,0,0},{0,c,-s,0},{0,s,c,0},{0,0,0,1}})
	end

	function R.M44:newRotY(a)
		local s,c=S(a),C(a)
		return R.M44:new({
		{c,0,-s,0},
		{0,1,0,0},
		{s,0,c,0},
		{0,0,0,1}})
	end

	function R.M44:newRotZ(a)
		local s,c=S(a),C(a)
		return R.M44:new({{c,-s,0,0},{s,c,0,0},{0,0,1,0},{0,0,0,1}})
	end

	function R.M44:newScale(x,y,z)
		return R.M44:new({{x,0,0,0},{0,y,0,0},{0,0,z,0},{0,0,0,1}})
	end

	function R.M44:newTrans(x,y,z)
		return R.M44:new({{1,0,0,x},{0,1,0,y},{0,0,1,z},{0,0,0,1}})
	end

	-- Returns e[][]
	function R.M44:mulM44E(m44)
	local out={{},{},{},{}}
		for y=1,4 do
			for x=1,4 do
				local acc=0
				for i=1,4 do
					acc=acc+self.e[y][i]*m44.e[i][x]
				end
				out[y][x]=acc
			end
		end
		return out
	end

	function R.M44:mulM44(m44)
		self.e=self:mulM44E(m44)
	end

	function R.M44:mulM44C(m44)
		return R.M44:new(self:mulM44E(m44))
	end

	function R.NewM44LookAt(from,to,up)
		--[[
		-- https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/lookat-function/framing-lookat-function.html
		local forward=from:subC(to)
		forward:normal()
		local right=up:cross(forward)
		right:normal()
		local newUp=forward:cross(right)
		return R.M44:new({
			{right.e[1],newUp.e[1],forward.e[1],from.e[1]},
			{right.e[2],newUp.e[2],forward.e[2],from.e[2]},
			{right.e[3],newUp.e[3],forward.e[3],from.e[3]},
			{0,0,0,1}
		})
		--]]

		local z=(to:subC(from)):normalC()
		local x=up:cross(z):normalC()
		local y=z:cross(x):normalC()
		return R.M44:new({
			{x.e[1],x.e[2],x.e[3],-x:dot(from)},
			{y.e[1],y.e[2],y.e[3],-y:dot(from)},
			{z.e[1],z.e[2],z.e[3],-z:dot(from)},
			{0,0,0,1},
		})
	end

	function R.NewM44OrthProj(width,height,near,far)
		return R.M44:new({
			{1/width,0,0,0},
			{0,1/height,0,0},
			{0,0,-(2/(far-near)),-((far+near)/(far-near))},
			{0,0,0,1},
		})
	end

	-- viewAngle: 90
	-- near: .1
	-- far: 100
	-- https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/building-basic-perspective-projection-matrix.html
	function R.NewM44PersProj(viewAngle,near,far)
		local scale=1/math.tan(viewAngle * 0.5 * math.pi / 180);
		local p1=-(far/(near-far))
		local p2=-((far*near)/(far-near))

		return R.M44:new({
			{scale,0,0,0},
			{0,scale,0,0},
			{0,0,p1,-1},
			{0,0,p2,0},
		})
	end

	function R.M44:trace(name)
		if name==null then name="" end
		trace(string.format(name.."\n|%.2f, %.2f, %.2f, %.2f|\n|%.2f, %.2f, %.2f, %.2f|\n|%.2f, %.2f, %.2f, %.2f|\n|%.2f, %.2f, %.2f, %.2f|\n",
			self.e[1][1], self.e[1][2], self.e[1][3], self.e[1][4],
			self.e[2][1], self.e[2][2], self.e[2][3], self.e[2][4],
			self.e[3][1], self.e[3][2], self.e[3][3], self.e[3][4],
			self.e[4][1], self.e[4][2], self.e[4][3], self.e[4][4]))
	end
end

end

rift_datamodelvehicle=function()
return function()
    local lampsW=.4
    local lampsH=.3
    local lampsY=0.3
    
    return {
        vertices={
            -1,-lampsY,0,
            -1+lampsW,-lampsY,0,
            -1+lampsW,-lampsY+lampsH,0,
            -1,-lampsY+lampsH,0,

            1-lampsW,-lampsY,0,
            1,-lampsY,0,
            1,-lampsY+lampsH,0,
            1-lampsW,-lampsY+lampsH,0,
        },
        triangles={
            1,2,3,
            3,4,1,

            5,6,7,
            7,8,5,
        },
        origin={0,0,0},
    }
end

end

rift_sysobject=function()
return function(R)
    -- http://lua-users.org/wiki/CopyTable
    R.shallowCopy=function(src)
        local dst
        if type(src)=='table' then
            dst = {}
            for k,v in pairs(src) do
                dst[k]=v
            end
        else -- number, string, boolean, etc
            dst=src
        end
        return dst
    end

    -- http://lua-users.org/wiki/CopyTable
    -- Not sure if this works- seems to recursive loop on my test
    R.deepCopy=function(src)
        local dst
        if type(src)=='table' then
            dst={}
            for k,v in next,src,nil do
                trace(k)
                dst[R.deepCopy(k)]=R.deepCopy(v)
            end
            setmetatable(dst,R.deepCopy(getmetatable(src)))
        else -- number, string, boolean, etc
            dst=src
        end
        return dst
    end
end

end

rift_stategreenmanlying=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

return {
    duration=10000,
    bdr=function(y,t,unitT)
        vbank(0)
        R.setRGB(0,R.RGB:new(0,0,0))
        R.setRGB(1,GLOBAL.rgbGMan)
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(function(tr)
                local cx,cy=120,68
                -- Get the offset of each point from the centre
                local d1x,d1y=tr.v[1].x-cx,tr.v[1].y-cy
                local d2x,d2y=tr.v[2].x-cx,tr.v[2].y-cy
                local d3x,d3y=tr.v[3].x-cx,tr.v[3].y-cy
                -- Get the centre of this triangle
                local dcx,dcy=(d1x+d2x+d3x)/3,(d1y+d2y+d3y)/3
                local dox,doy=dcx,dcy
                tri(
                    cx+d1x+dox,cy+d1y+doy,
                    cx+d2x+dox,cy+d2y+doy,
                    cx+d3x+dox,cy+d3y+doy,
                    1
                )
            end,0)

            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)
    
        local mat=R.M44:new(R.M44.ID)
        mat:mulM44(R.M44:newTrans(0,0,unitT*3))
        mat:mulM44(R.M44:newRotZ(-math.pi/4+unitT*math.pi/2))
        ACTOR_GMAN:setMat(mat)

        SCENE:draw()
    end,
}

end

rift_fontsysfont=function()
return function(R)
    function R.sysfontLoad(font)
        if font.rle then
            R.sysfontLoadRLE(font)
        else
            R.sysfontLoadRAW(font)
        end
    end

    function R.sysfontLoadRLE(font)
        local str=font.rle
        local o=tonumber(str:sub(1,5),16) -- get (o)ffset
        local w=tonumber(str:sub(6,7),16)*8-1 -- get (w)idth
        local e=str:sub(8,str:len()) -- remove header to get (e)ncoded data
        local d = "" -- (d)ecoded data
        for m, c in e:gmatch("(%u+)([^%u]+)") do -- decode rle, (m)atch & (c)ounter
            d = d .. m .. (m:sub(-1):rep(c))  
        end
        local y=0
        for x = 1,#d,1 do -- write to mem
            local c=string.byte(d:sub(x,x))-65 -- get (c)olor value
            poke4(o+y,c) y=y+1
            if y>w then y=0 o=o+1024 end
        end
    end

    function R.sysfontLoadRAW(font)
        local str=font.raw
        local tnb=tonumber
        local o=tnb(str:sub(1,5),16) -- get (o)ffset
        local w=tnb(str:sub(6,7),16)*8-1 -- get (w)idth
        local d=str:sub(8,str:len()) -- remove header to get (d)ata
        local y=0
        for x = 1,#d,1 do -- write to mem
        local c=tnb(d:sub(x,x),16) -- get (c)olor value
        poke4(o+y,c) y=y+1
            if y>w then y=0 o=o+1024 end
        end
    end
end
  

end

rift_datasysfontinformics7x7informics7x7=function()
-- title:  INFORMICS 7x7 ng2
-- artist: Decca / RiFT

return {
    name="INFORMICS 7x7 ng2",
    rle="28E0880A15DADADADA2DA4LBLBJA10KAPBKAKAPBKA4EAOBHAMBPAEA4NAMAGAGADALA4MAGBODLBLBOCA3DADABA10GADADADADAGA4DAGAGAGAGADA6OAPBPBPBOA8CAHACA12DADABA10HA16DADA4MAMAGAGADADA4OALBLBLBLBOA4GAHAGAGAGAGA4HAMAGADADAPA4HAMAGAMAMAHA4BANANAOBMAMA4PABAHAMAMAHA4OADAPALBLBOA4PBIBMAGAGAGA4OALBOALBLBOA4OALBLBOBIBOA6DADA2DADA6DA2DADABA6EAOBPBOBEA8HA2HA8EAPAPBPAEA4PAIBOAGA2GA4OABBFBNABAOA4OALBLBPBLBLBA3PALBPALBLBPA4OBDADADADAOBA3PALBLBLBLBPA4PBDAHADADAPBA3OBDAHADADADA4OBDADALBDBOBA3LBLBPBLBLBLBA3DADADADADADA4MAMAMAMAMAHA4LBLBPALBLBLBA3DADADADADAOA4PBLCLCLCLCLCA3DBHBPBLBDBDBA3OALBLBLBLBOA4PALBLBPADADA4OALBLBLBLAOBA3PALBLBPALBLBA3OBDAOAIBIBPA4PAGAGAGAGAGA4LBLBLBLBLBOA4LBLBLBLBLAGA4FDFDFDFDFDOBA3LBLBOALBLBLBA3LBLBLBOAGAGA4PBIBOADADAPBA3HADADADADAHA4DADAGAGAMAMA4HAGAGAGAGAHA4EAKABBOALBOA14HA4DADACA12PAIBOBLBOBA3DAPALBLBLBPA6OBDADADAOBA3IBOBLBLBLBOBA5OALBPBDAOBA3MBGAPAGAGAGA6OBLBLBOBIBPA2DAPALBLBLBLBA3DA2DADADADA4GA2GAGAGAGADA2DALBLBPALBLBA3DADADADADADA6PBLCLCLCLCA5PALBLBLBLBA5OALBLBLBOA6OALBLBLBPADA4OALBLBLBOBIBA3OADADADADA6OBDAOAIBPA4GAPAGAGAGAMA6LBLBLBLBOBA5LBLBLBLAGA6FDFDFDFDOBA5LBLBOALBLBA5LBLBLBOBIBPA4PBIBOADAPBA0",

}

end

rift_datafontnucampi8x16nucampi8x16=function()
-- title:  Nucampi 8x16
-- artist: Decca / RiFT

return {
	name="Nucampi 8x16",
	rle="0800020OHPHOHPHP7HOHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOPPHAHOP2HHAHOPPOPOHHOP5HOHAHAHOHOHAHAHOHOHAHAHOHOHAHAHOHOPDPDHAP2DPDHP2HAMBHOHAHAMBHOHAHAMBHOHAHAMBHOHAHAMBHOHAHAMBHOHAHAMBPHHAHAMBPDHAP2AHOOHP2BHOPPHOMBHOHOHOMBPOHOHOMBPOHOHOMBPPHOHOMBPPHOHOMBPPHOPPHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOHOP5HOPHOHPHA7HAHAHPHOHAHAHOHOHAHAHOHOHAHAHOHOHAHAHOHOPPHAPPHOPPHAOPHOA7HAMBPHHAHAMBHOHAHAMBHOHAHAMBHOHAHAMBHOHAHAPBHOPHHAPAHOOHA7HOMBHPHOHOMBHPHOHOMBHOHOHOMBHOHOHOMBHOHOHOMBHOPPHOMBHOOHA7PHOHPHOHP7HOHOHOHOHOHOHOHOHOHOHOHAHOHOHOPAHOHOHOODPPHOPHMHPPBAHOHOPPBAHOHOIDAAHOHOIDAAHOHOIDAAHOHOIDAAHOHOIDAAHOHOIDAAHOHOHOMBHOH2OMBHOH2OMBHOH2OMBHOH2OMBHOH2OMBHOH2OMBOHPHHOMBMDODPPAAHA2PPAAHA3OAAHA3OOHPHOHAOP5APHOHOHOMHHOHOHOODHOHOHAPHHOPPAPHAHOHOAOHAHOHOHOHAHOHOHOHAHGHOHOHAPPHOPPHAOPHOOHA7IDAAHOHOIDAAHOHOIDAAHOHOIDAAHOHOIDAAHOHHIDAAP2DIDAAOHOBA7HOMBOHMBHOMBHOMBHOMBHOMBHOMBHOMBHOMBHOMBP2BHOMBOPPAHOMBA7PAIPHOHAHAOPHOHAHAHOHOHOHAHOHOHOHAHOHOHOP9OPPHOHA8OAAMDA2OAAODA2OAAOA2OPOHPDOP5DPPHOHOOAHOHOHOOAHOHOPPOAHOHAHAOAHAHAHAOAHAHA4HAPHHAOAHOPPHAOAHOHOHAOAHOHOHAOAHOHOHAOAPHHA6HA6HA6HAP2APHHAP2BPPHAHOMBHOHAHOMBHOHAHOMBHOA23OHPHOPPDP6HHOHOHOH2OHOHOH2OHOHOHAHOPPOAHOHOHAOAHOHOHOOAHOHOHOOAHOHOHOOAHOP3OAPPOPOHOAOPA6OHOHAOAPDHOHAOAPHHOHAOAHOHOHAOAHOHOHAOAHOHOHAOAHOHOHAOAHOA3OA2HAHOMBHOHAHOMBHOHAHOMBHOHAHOMBHOHAHOMBHOHAHOMBHOHAHOMBHOA7HOHOHOHAHOHOHOHAHOHOHOHAHOHOHOHAHOHOHOHAP5HAOHPHOPHA2HAAOA7HOA5PPA5OHA43PA6PA6HA108HAAOA3HAAOA3HAAOA43OA6OA6OA4OHPDHOHOP2DHOHOHOOAHOHOHAOAHOHOPAOAHOHOA23HOMBHOHOHOMBHOHOHOMBHOHOHOMBHOHOHOMBHOHOAAHAOA4HAOA4HAHA2PPHA4PPHA2MAAOHA2MAAOHA2PDAPHA2PDA5OHA5PPA5HOA5HOA6OA6PAAPDAAIHAAPDAAMDODOAHOHOMHOAHOHOAPOAHOHOAOOAHOHOHOOAHOHGPPOBP2HOHMBOPODA7HOMBOHHOHOMBMDHOHOMBOHHOHOMBHOHOHOMBHOP4BHOOPOPPAHOAOA6OMHHA2MAODHA2MAPAHA4HAHA4HA6PPHA4PPHA18OBA5OA6OA8OA2HAOAOA2HAOAHA2HAOA78HOA5PPA5OHA167OHIHOHOHPPMHP3HOOHHOHOHOPHHOHOHOHHAOAOHOAHAPAOHOAHMHIHHOAHODIPHA2PPOHHA2P3HA2HOHOHOAAHOHOHOAAHAHAHOAAHAHAHOAAPHPDPPBAP2HPPOHOHAAP5AAHOHOHOAAHOHOHOA2OHOHOA2PHOHOAAIHOHHOHAMDP3HAIBMPDAAOMDOPHAAOGGHAOAAPAADAMAAHOHDLNAAHPPLPNAIHHOLJNAIDHOLJNAMDHOAHPAAOHOAHHAAOHOAHHAHOHOAHHAHOHOAHHAHOPPAHP3OHAHPPOHA7OPBAAOHOAOA2OHOAOAAHOHOAOAAHOHOAOAAHOHOAOAAP3AOAAOHOHA7OBHOOPHAOAHOAOAAOAHOAOAAOAHOHOAAOAHOHOHAOAP3HAOAOHOHHA8HOLJNAMBHOLPNAMBHODLPAOAHODAHAOAHOHA2PAPPOPBAHAOHMPBAHA1032",
	chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!'+,-.?0123456789:=@/ ",
	-- font data {"A", sprite number, page?, num sprites x, y, width (px), height}
	layout={
		{0,0,1,2,8,16},{1,0,1,2,8,16},{2,0,1,2,8,16},{3,0,1,2,8,16},{4,0,1,2,8,16},{5,0,1,2,8,16},{6,0,1,2,8,16},{7,0,1,2,8,16},{8,0,1,2,3,16},{9,0,1,2,5,16},{10,0,1,2,8,16},{11,0,1,2,7,16},{12,0,2,2,13,16},{14,0,1,2,8,16},{15,0,1,2,8,16},
		{128,0,1,2,8,16},{129,0,1,2,8,16},{130,0,1,2,8,16},{131,0,1,2,8,16},{132,0,2,2,9,16},{134,0,1,2,8,16},{135,0,1,2,8,16},{136,0,2,2,13,16},{138,0,1,2,8,16},{139,0,1,2,7,16},{140,0,1,2,8,16},{141,0,1,2,8,16},{142,0,1,2,8,16},{143,0,1,2,8,16},
		{256,0,1,2,8,16},{257,0,1,2,8,16},{258,0,1,2,6,19},{259,0,1,3,8,16},{260,0,1,2,8,16},{261,0,1,2,3,19},{262,0,1,3,4,16},{263,0,1,2,8,16},{264,0,1,2,3,16},{265,0,2,2,13,16},{267,0,1,2,8,16},{268,0,1,3,8,19},{269,0,1,3,8,19},{270,0,1,3,8,16},{271,0,1,2,7,16},
		{448,0,1,2,8,16},{449,0,1,2,6,16},{450,0,1,2,8,16},{451,0,1,2,8,16},{452,0,2,2,13,16},{454,0,1,2,8,19},{455,0,1,3,8,16},{456,0,1,2,8,16},{457,0,1,2,3,16},{458,0,1,2,4,16},{459,0,1,2,6,16},{460,0,1,2,4,16},{461,0,1,2,6,16},{462,0,1,2,3,16},{463,0,1,2,8,16},
		{640,0,1,2,8,16},{641,0,1,2,7,16},{642,0,1,2,8,16},{643,0,1,2,8,16},{644,0,2,2,9,16},{646,0,1,2,8,16},{647,0,1,2,8,16},{648,0,1,2,8,16},{649,0,1,2,8,16},{650,0,1,2,8,16},{651,0,1,2,3,16},{652,0,1,2,8,16},{653,0,2,2,12,16},{655,0,1,2,8,16},
		{768,0,1,2,8,16}
	}
}

end

rift_datagfxriftlogo=function()
-- title:  rift-logo-16.png
-- author: TicMcTile
-- script: lua

-- set the palette
function tovram(str)
  local o=0
  for c=1,#str,2 do -- walk colors
    local v=tonumber(str:sub(c,c+1),16) -- get color (v)alue
    poke(0x3fc0+o,v) o=o+1 -- set color
  end
end

-- the rle-decoder
function tomem(str)
  local o=tonumber(str:sub(1,2),16)*256 -- get (o)ffset
  local w=tonumber(str:sub(3,4),16)*8-1 -- get (w)idth
  local e=str:sub(5,str:len()) -- remove header to get (e)ncoded data
  local d = "" -- (d)ecoded data
  for m, c in e:gmatch("(%u+)([^%u]+)") do -- decode rle, (m)atch & (c)ounter
    d = d .. m .. (m:sub(-1):rep(c))  
  end
  local y=0
  for x = 1,#d,1 do -- write to mem
    local c=string.byte(d:sub(x,x))-65 -- get (c)olor value
    poke4(o+y,c) y=y+1
    if y>w then y=0 o=o+1024 end
  end
end

return {
  getDims=function()
    return 128,85
  end,
  setup=function()
    local pal = "9c5f62000000af34c369285bde30ee8eafa499905bc632d6100b0c76a0b1ab5e2255333d9d3a44a643a22a161cc94526"
    local gfx = " "
    tovram(pal)
    tomem(gfx)
  end,
  draw=function(xofs,yofs)
    m=2 -- mode
    t=0 -- tiles/sprites
    r=0 -- range
    if m==2 and r>0 then r=0 end
    if m==4 and r>16 then r=16 end
    if t==0 then s=r else s=r+(128*m) end
    poke4(2*0x03ffc,m)
    for y = 0,128-8,8 do
      for x = 0,(m*64)-8,8 do
        spr(s,xofs+x,yofs+y) s=s+1
      end
    end
  end
}

end

rift_3danim=function()
return function(R)
    R.Anim={}
    R.AnimFrame={}

    function R.Anim:new(name)
		local o={
            name=name,
            frames={},
        }
		setmetatable(o,self)
		self.__index=self
		return o
	end

    function R.Anim:addFrame(f)
        self.frames[#self.frames+1]=f
	end

    function R.AnimFrame:new()
		local o={
            vtxs={}
        }
		setmetatable(o,self)
		self.__index=self
		return o
	end

    function R.AnimFrame:addVtx(v)
        self.vtxs[#self.vtxs+1]=v
	end
end

end

rift_3dcam=function()
return function(R)
	rift_3dgeom()(R)

	R.Cam={}

	function R.Cam:new(pos,aim,up)
		local o={
			pos=pos,
			aim=aim,
			up=up,
		}
		setmetatable(o,self)
		self.__index=self
		return o
	end

    -- pos is a V4
    function R.Cam:setPos(pos)
        self.pos=pos
    end
    
    -- aim is a V4
    function R.Cam:setAim(aim)
        self.aim=aim
    end

    -- up is a V4
    function R.Cam:setUp(up)
        self.up=up
    end

	function R.Cam:getM44()
		return R.NewM44LookAt(self.pos,self.aim,self.up)
    end
end

end

rift_stategreenmanrecaptured=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

lampFilter=rift_screenfilterslamp()

return {
    duration=6000,
    bdr=function(y,t,unitT)
        vbank(0)
        local pal0=R.Palette:new()
        local pal1=R.Palette:new()
        local rgbGMan=GLOBAL.rgbGMan
        pal0:setRGB(0,R.RGB:new(0,0,0))
        pal1:setRGB(0,R.RGB:new(0,0,0))
        for i=1,15 do
            local s1=i/15
            local s0=s1/4
            pal0:setRGB(i,R.RGB:new(rgbGMan.r*s0,rgbGMan.g*s0,rgbGMan.b*s0))
            pal1:setRGB(i,R.RGB:new(rgbGMan.r*s1,rgbGMan.g*s1,rgbGMan.b*s1))
        end
        local blend=1
        if unitT>.5 then
            local t=((unitT-.5)/.5)*math.pi*2*6
            blend=.5+math.cos(t)*.5
        end
        pal0:applyBlend(pal1,blend)

        vbank(1)
        R.setRGB(1,R.RGB:new(0,0,0))
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)

            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)  
        
        local mat=R.M44:new(R.M44.ID)
        local x,y,z,yr,zr=0,0,0,0,0
        local zBack=3
        if unitT < .4 then
            z=0
        elseif unitT <.7 then
        elseif unitT <.9 then
        else
        end
        mat:mulM44(R.M44:newTrans(x*.2,y*-.2,1.5+z))
        mat:mulM44(R.M44:newRotZ(zr*.2))
        ACTOR_GMAN:setMat(mat)

        SCENE:draw()
        lampFilter(120,68,100)

        vbank(1)
        tri(0,30,240,100,120,60,12)
        tri(240,30,0,100,120,60,12)
    end,
}

end

rift_3dmodel=function()
return function(R)
	rift_3dgeom()(R)
	rift_3danim()(R)
	rift_sysobject()(R)
	
	R.poly={}
	R.Tri={}
	R.Model={
		Z_SORT=1,	-- Sort faces by average Z
		CALC_NORMAL=2,	-- Calculate face normals
	}

	-- point index: p1,p2,p3
	-- ex: extra data
	function R.Tri:new(p1,p2,p3,ex,normal)
		local o={
			vx={p1,p2,p3},
			ex=ex,
			normal=normal,
		}
		setmetatable(o,self)
		self.__index=self
		return o
	end

	-- vtxs: V4
	-- tris: tri
	--  p[1]-p[3]
	function R.Model:new()
		local o={
			vtxs={},
			anim={},
			tris={},
			passes={},
		}
		setmetatable(o,self)
		self.__index=self
		return o
	end

	-- v=V4
	-- Returns the index
	function R.Model:addVtx(v)
		local i=#self.vtxs+1
		self.vtxs[i]=v
		return i
	end

	-- tri is a Tri
	-- normal can be unset/nil
	function R.Model:addTri(tri)
		local i=#self.tris+1
		self.tris[i]=tri
		return i
	end

	function R.Model:AddDrawPass(name,tris,priority)
		self.passes[#self.passes+1]={name=name,tris=tris,priority=priority}
		table.sort(self.passes,function(a,b) return a.priority<b.priority end)
	end

	-- Transform the geometry:
	-- (local) >entityMat> (world) >viewMat> (view) >projMat> (screen)
	--	(#TODO: collapse that to viewMat -> projMat coming in to this function?)
	-- Transform the normals by entityMat
	-- anim: nil or {cycle=,time=}
	function R.Model:draw(entityMat,viewMat,projMat,viewport,draw,anim,cbFns)
		cbFns={
			geomPrePassFn=cbFns and cbFns.geomPrePassFn or nil,
			geomPostPassFn=cbFns and cbFns.geomPostPassFn or nil,
		}
--		local geomMat=R.M44:new(R.M44.ID)
		local geomMat=viewMat:mulM44C(projMat)
--		geomMat:mulM44(projMat)
		geomMat:mulM44(entityMat)

		local vtxs={} -- put the model vtxs in a fresh table so that deformations don't alter source data
		local vtxFrame=nil
		if anim==nil or anim.cycle==nil then
			vtxFrame=self.vtxs
		else
			local animDef=self.anim[anim.cycle]
			local unitTime=math.fmod(anim.time,1)	-- Get the fractional part, 0-1
			local iFrame1,interp=math.modf(unitTime*#animDef.frames)
			local iFrame2=1+(iFrame1+1)%#animDef.frames
			iFrame1=iFrame1+1

			-- Blend frames:
			local frame1vtxs=animDef.frames[iFrame1].vtxs
			local frame2vtxs=animDef.frames[iFrame2].vtxs
			for i=1,#animDef.frames[iFrame1].vtxs do
				vtxs[i]=frame1vtxs[i]:lerp(frame2vtxs[i],interp)
			end
			vtxFrame=vtxs
		end

		if cbFns.geomPrePassFn then
			for i=1,#self.vtxs do
				vtxs[i]=cbFns.geomPrePassFn(i,vtxFrame[i]:clone())
			end
		else
			for i=1,#self.vtxs do
				vtxs[i]=vtxFrame[i]:clone()
			end
		end

		local geom={}
		for i=1,#vtxs do
			local p=vtxs[i]:mulM44C(geomMat,true)

			if cbFns.geomPostPassFn then
				p=cbFns.geomPostPassFn(i,p)
			end

			local x,y=viewport:transform(p.e[1],p.e[2])
			geom[i]={x=x,y=y,z=p.e[3]}
		end

		if draw then
			if #self.passes>0 then
				for i=1,#self.passes do
					local pass=self.passes[i]
					local drawFn=draw.passFns[pass.name]
					drawFn=drawFn or R.poly.Draw1Colour(math.random(1,15))
					local draw={
						fn=drawFn,
						flags=0,
					}
					self:drawTris(draw,geom,pass.tris,nil)
				end
			elseif draw.fn then
				self:drawTris(draw,geom,self.tris,entityMat)
			end
		end
	end

	function R.Model:drawTris(draw,geom,tris,entityMat)
		local rTris={}
		for i=1,#tris do
			local t=tris[i]

			-- If this triangle doesn't have a normal then create one...
			-- Should only happen on the first run
			if not t.normal then
				t.normal=R.V4Normal(
					self.vtxs[t.vx[1]],
					self.vtxs[t.vx[2]],
					self.vtxs[t.vx[3]]
				)
			end

			local vScr1=geom[t.vx[1]]
			local vScr2=geom[t.vx[2]]
			local vScr3=geom[t.vx[3]]

			local normal=t.normal
			if draw.flags and draw.flags&R.Model.CALC_NORMAL>0 then
				normal=normal:mulM44C(entityMat,true)
			else
				-- Return a dummy normal pointing towards the viewer
				normal=R.V4:new({0,0,1,0})
			end
			
			rTris[#rTris+1]={
				i=i,
				v={vScr1,vScr2,vScr3},
				normal=normal,
				ex=t.ex,
			}
		end

		if draw.flags and draw.flags&R.Model.Z_SORT>0 then
			-- Should this instead sort by closest Z, rather than average?
			table.sort(rTris,
				function(a,b)
					local az=a.v[1].z+a.v[2].z+a.v[3].z
					local bz=b.v[1].z+b.v[2].z+b.v[3].z
					return az>bz
				end
			)
		end
		
		for i=1,#rTris do
			local t=rTris[i]
			local az=t.v[1].z+t.v[2].z+t.v[3].z
	-- This is broke
	--			if az > 0.0 then
				draw.fn(t)
	--			end
		end
	end

	-- Load
	--	vertices: table (one dimension: x,y,z fixed point values)
	--	triangles: table (one dimension: index of p[1]-p[3])
	function R.Model:load(data)
		local scale=data.scale or 1
		local origin=data.origin or {0,0,0}
		local divide_by=data.divide_by or nil

		if divide_by==nil then
			divide_by=0
			-- Get the largest extent of the model. This will be our bound
			for i=1,#data.vertices do
				local extent=math.max(math.abs(data.vertices[i]))
				divide_by=math.max(divide_by,extent)
			end
		end

		self.vtxs={}
		for i=1,#data.vertices//3 do
			local startindex = (i-1)*3+1
			local x=(data.vertices[startindex])/divide_by-origin[1]
			local y=(data.vertices[startindex+1])/divide_by-origin[2]
			local z=(data.vertices[startindex+2])/divide_by-origin[3]
			local v=R.V4:new({x*scale,y*scale,z*scale,1})
			self:addVtx(v)
		end

		self.anim={}
		if data.vanim then
			for name,frames in pairs(data.vanim) do
				local anim=R.Anim:new(name)
				for i,vertices in ipairs(frames) do
					local frame=R.AnimFrame:new()
					for i=1,#vertices//3 do
						local startindex = (i-1)*3+1
						local x=(vertices[startindex])/divide_by-origin[1]
						local y=(vertices[startindex+1])/divide_by-origin[2]
						local z=(vertices[startindex+2])/divide_by-origin[3]
						local v=R.V4:new({x*scale,y*scale,z*scale,1})
						frame:addVtx(v)
					end
					anim:addFrame(frame)
				end
				self.anim[name]=anim
			end
		end

		self.tris={}
		if data.triangles then
			for i=1,#data.triangles//3 do
				local startindex = (i-1)*3+1
				local p1 = data.triangles[startindex]
				local p2 = data.triangles[startindex+1]
				local p3 = data.triangles[startindex+2]
				local ex={}
				if data.triangles_ex then
					ex=data.triangles_ex[i]
				end
				self:addTri(R.Tri:new(p1,p2,p3,ex,nil))
			end
		end

		if data.drawpasses then
			for name,dp in pairs(data.drawpasses) do
				local tris={}
				for i=1,#dp.triangles//3 do
					local startindex = (i-1)*3+1
					local p1 = dp.triangles[startindex]
					local p2 = dp.triangles[startindex+1]
					local p3 = dp.triangles[startindex+2]
--[[					local ex={}
					if data.triangles_ex then
						ex=data.triangles_ex[i]
					end
--]]
					tris[#tris+1]=R.Tri:new(p1,p2,p3,{},nil)
				end
				self:AddDrawPass(name,tris,dp.priority)
			end
		end
	end

	function R.poly.Draw1Colour(colour)
		return function(tr)
			tri(
				tr.v[1].x,tr.v[1].y,
				tr.v[2].x,tr.v[2].y,
				tr.v[3].x,tr.v[3].y,
				colour
			)
		end
	end

	function R.poly.DrawDebug(tr)
		tri(
			tr.v[1].x,tr.v[1].y,
			tr.v[2].x,tr.v[2].y,
			tr.v[3].x,tr.v[3].y,
			1+(tr.i)%15
		)
	end

	function R.poly.DrawFlat(tr)
		tri(
			tr.v[1].x,tr.v[1].y,
			tr.v[2].x,tr.v[2].y,
			tr.v[3].x,tr.v[3].y,
			tr.ex.c
		)
	end

	--[[
	-- Render example
	-- Lit normals
	-- (NB normalising light in the 
	--  function each time is inefficient
	--  obvs!)
	local DrawLit=function(t)
		local light=V4:new({0,0,-1,1})
		light:normal()

		local l=1+(7.5+t.normal:dot(light)*7.5)//1
		tri(
			t.v[1].x,t.v[1].y,
			t.v[2].x,t.v[2].y,
			t.v[3].x,t.v[3].y,
			l
		)
	end
	--]]

	function R.poly.DrawLit(tr)
		-- #TODO: Move light and screen out of this function
		local light=R.V4:new({
			math.sin(time()*0.0002*math.pi),0,math.cos(time()*0.0002*math.pi),1
		})
		light:normal()
		local screen=R.V4:new({0,0,-1,1})
		screen:normal()

		local l=tr.normal:dot(light)*14
		l=math.min(14,math.max(0,l))
		l=l+1
		local facing=tr.normal:dot(screen)
		
		if facing > 0 then
		tri(
			tr.v[1].x,tr.v[1].y,
			tr.v[2].x,tr.v[2].y,
			tr.v[3].x,tr.v[3].y,
			l
		)
		end
	end

	-- ex: {u1,v1,u2,v2,u3,v3}
	function R.poly.DrawTex(tr)
		if tr.ex.u1 then
			ttri(
				tr.v[1].x,tr.v[1].y,
				tr.v[2].x,tr.v[2].y,
				tr.v[3].x,tr.v[3].y,
				tr.ex.u1,tr.ex.v1,
				tr.ex.u2,tr.ex.v2,
				tr.ex.u3,tr.ex.v3,
				2
			)
		end
	end
end

end

rift_datamodelredman=function()
-- TrafficStop2
return {
	flags=0,
	divide_by=100,
	scale=1,
	vertices={68,19,0,81,22,0,87,25,0,93,44,0,92,62,0,91,66,0,85,72,0,89,70,0,83,68,0,83,43,0,80,38,0,78,57,0,78,75,0,83,120,0,87,122,0,89,126,0,73,127,0,71,123,0,64,82,0,58,122,0,56,127,0,41,127,0,42,124,0,47,120,0,49,75,0,48,57,0,46,39,0,44,46,0,45,67,0,45,73,0,38,70,0,36,64,0,34,46,0,40,26,0,44,22,0,58,20,0,57,16,0,55,12,0,56,7,0,58,2,0,62,1,0,65,1,0,69,3,0,70,8,0,70,12,0,69,15,0,},
	triangles={7,9,8,8,6,9,9,6,5,5,10,9,10,4,5,10,11,4,4,3,11,11,3,2,2,1,11,1,36,12,12,11,1,12,19,36,12,19,13,13,19,18,18,13,14,18,17,14,17,14,15,17,14,15,16,17,15,36,26,19,26,25,19,26,36,27,27,35,36,35,34,27,34,33,28,28,34,27,33,32,28,28,32,29,29,32,31,31,29,30,25,19,24,24,19,20,20,21,24,21,24,22,22,23,24,36,1,46,46,37,36,37,38,46,46,45,38,38,44,45,44,39,38,39,40,44,44,43,40,40,41,43,43,42,41,},
	origin={0.6,0.6,0}
}

end

rift_fontfont=function()
return function(R)
    R.Font={}

	function R.Font:new()
        local o={
            -- this could be useful for compression later
            font={},
        }
        setmetatable(o,self)
        self.__index=self
        return o
	end

    function R.Font:load(font)
        if(font.rle) then
            self:_loadRLE(font) 
        else
            self:_loadRAW(font)
        end
    end

    function R.Font:_loadRLE(font)
        local str=font.rle
        local o=tonumber(str:sub(1,5),16) -- get (o)ffset
        local w=tonumber(str:sub(6,7),16)*8-1 -- get (w)idth
        local e=str:sub(8,str:len()) -- remove header to get (e)ncoded data
        local d = "" -- (d)ecoded data
        for m, c in e:gmatch("(%u+)([^%u]+)") do -- decode rle, (m)atch & (c)ounter
          d = d .. m .. (m:sub(-1):rep(c))  
        end
        local y=0
        for x = 1,#d,1 do -- write to mem
          local c=string.byte(d:sub(x,x))-65 -- get (c)olor value
          poke4(o+y,c) y=y+1
          if y>w then y=0 o=o+1024 end
        end
        self:_init(font)
    end

    function R.Font:_loadRAW(font)
        local str=font.raw
        local tnb=tonumber
        local o=tnb(str:sub(1,5),16) -- get (o)ffset
        local w=tnb(str:sub(6,7),16)*8-1 -- get (w)idth
        local d=str:sub(8,str:len()) -- remove header to get (d)ata
        local y=0
        for x = 1,#d,1 do -- write to mem
          local c=tnb(d:sub(x,x),16) -- get (c)olor value
          poke4(o+y,c) y=y+1
          if y>w then y=0 o=o+1024 end
        end
        self:_init(font)
    end

    function R.Font:_init(font)
        for i=1,#font.layout do
            self.font[string.sub(font.chars,i,i)]=font.layout[i]
        end
    end

    -- kx kerning (optional): integer
    function R.Font:width(str,kx)
        kx = kx or 1
        local pcx = 0
        for i=1,string.len(str) do
            local letter = self.font[string.sub(str,i,i)]
            -- update kerning
            pcx = pcx + letter[5] + kx
        end
        return pcx
    end

    -- fprint ("text", x, y, [x kerning = 1],[y kerning = 1], [colour = 15])
    function R.Font:print(str,tx,ty,kx,ky,tc)
        kx = kx or 1
        ky = ky or 1
        tc = tc or 10
        local pcx = 0
        local pcy = 0
        -- set to blit segment (8 = BG-1)
        poke4(2*0x03ffc,8)
        -- set colour
        poke4(2*0x03FF0 + 1, tc)
        -- print each letter
        for i=1,string.len(str) do
            local letter = self.font[string.sub(str,i,i)]
            spr(letter[1],tx+pcx,ty+pcy,0,1,0,0,letter[3],letter[4])

            -- update kerning
            pcx = pcx + letter[5] + kx
        end
    end
end
  

end

rift_sysmath=function()
return function(R)
    R.clamp=function(v,min,max)
        return math.min(math.max(v,min),max)
    end

    R.lerp=function(t,v0,v1)
        return (1-t)*v0+t*v1
    end

    -- quadratic Bézier
    R.qBezier=function(t,v0,v1,v2)
        local tInv=1-t
        return (tInv*tInv*v0)+(tInv*t*v1)+(t*t*v2)
    end

    -- cubic Bézier
    R.cBezier=function(t,v0,v1,v2,v3)
        local tInv=1-t
        return (tInv*tInv*tInv*v0)+(3*tInv*tInv*t*v1)+(3*tInv*t*t*v2)+(t*t*t*v3)
    end

    -- smoothstep Easing function
    R.smoothStep=function(t,e0,e1)
        local s = (t-e0)/(e1-e0)
        local x = R.clamp(s,0,1)
        return e0 + (x * x * (3.0 - 2.0 * x))*(e1-e0)
    end

    -- smootherstep Easing function
    R.smootherStep=function(t,e0,e1)
        local s = (t-e0)/(e1-e0)
        local x = R.clamp(s,0,1)
        return e0 + (x * x * x * (3.0 * x * (2.0 * x - 5.0) + 10.0))*(e1-e0)
    end
end

end

rift_syssys=function()
return function(R)
    rift_uimouse()(R)

    local mouse=R.Mouse:new()
    local mouseState=nil

    R.tryBreak=function(key)
        key=key or 51
        if keyp(key) then
            exit()
        end
    end

    R.hideMouse=function()
        poke(0x3FFB,0)
    end

    R.ticWrap=function(tic)
        return function()
            mouseState=mouse:update()
            tic()
        end
    end

    function R.getMouse()
        return mouseState
    end
end

end

rift_statewalkwind=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

local m=math
local s=m.sin
local c=m.cos
local r=m.random
local tau=m.pi*2
local t=0

-- three flow field angles
-- small leaves/squares moving through fields, 2 background behind greenman, 1 in front
-- added move from left to right for main wind direction

-- 2d array of angles
local field1 = {} -- foreground
local field2 = {} 
local field3 = {} -- background

-- array of 2d points
local leaves1 = {}
local leaves2 = {}
local leaves3 = {}

function setupWindEffect()
    for i=1,5 do
        leaves1[i]={x=r(240)-1,y=r(136)-1}
    end
    for i=1,10 do
        leaves2[i]={x=r(240)-1,y=r(136)-1}
    end
    for i=1,20 do
        leaves3[i]={x=r(240)-1,y=r(136)-1}
    end

    field1 = makeFlowField(0.1,0.05,10,.8)
    field1.scale = 10
    field1.speed = 3
    field2 = makeFlowField(0.3,0.15,5,0.9)
    field2.scale = 5
    field2.speed = 1.75
    field3 = makeFlowField(0.4,0.2,3,1.0)
    field3.scale = 3
    field3.speed = 1.25
end

function makeFlowField(xZoom,yZoom,scale,curve)
  local ff={}
  for x=0,240/scale+1 do
    ff[x]={}
    for y=0,136/scale+1 do
     ff[x][y]=(s(x*xZoom)+c(y*yZoom))*curve
    end
   end
  return ff
end

function windFlow(field, leaves, scale)
    for i=1,#leaves do
      local fx=leaves[i].x//field.scale
      local fy=leaves[i].y//field.scale
    
      if fx < 0 or fx > #field-2 or fy < 0 or fy > #field[fx] then
        local r = r(376)
        local x = 0
        local y = 0
        if r < 136 then
          y = r
        else
          x = r-136
        end
        fx=x//field.scale
        fy=y//field.scale
        leaves[i].x = x
        leaves[i].y = y
      end
      local fa = field[fx][fy]
    
      leaves[i].x = leaves[i].x+field.speed*s(fa+t/1000)+field.speed
      leaves[i].y = leaves[i].y+field.speed*c(fa)
    
      --pix(leaves[i].x,leaves[i].y,2+scale)
      --rect(leaves[i].x,leaves[i].y,scale,scale,2+scale)
      -- Forgive me, mantratronic, for hacking these to go R-to-L!
      local xleaf=240-(leaves[i].x-4*scale)
      spr(0,xleaf,leaves[i].y-4*scale,0,scale)
    end
  end
  
  
  return {
    duration=8000,
    bdr=function(y,t,unitT)
        vbank(1)
        R.setRGB(1,GLOBAL.rgbGMan)
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            setupWindEffect()

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)
            MAT_GMAN=ACTOR_GMAN:getMat()
            MAT_GMAN:mulM44(R.M44:newTrans(0,0,1.5))
            
            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)
    
        windFlow(field3, leaves3,1)
        windFlow(field2, leaves2,2)

        vbank(1)
        cls()
        SCENE:draw()

        -- Windy pixels
        -- Feel free to make better / replace!
        for y=0,136 do
            for x=220,80,-1 do
                local p=pix(x+1,y)
                if p > 0 then
                    if math.random()<.6 then
                        pix(x,y,1)
                    end
                end
            end
        end
        windFlow(field1, leaves1,3)
    end,
}

end

rift_screenfilterslamp=function()
return function(cx,cy,r)
    rSnap=r//1
    for dx=-rSnap,rSnap do
        for dy=-rSnap,rSnap do
            local x,y=cx+dx,cy+dy
            local p=pix(x,y)
            local d=1-(((dx)^2+(dy)^2)^.5)/r
            local d=d-.2+math.abs(math.sin(d*20))*.4 -- some rings
            if d>0 then
                d=d^.6  -- Taper
                local xDot=dx/(r*.2)
                local yDot=dy/(r*.2)
                local s=.7+((math.sin(xDot*math.pi*2)+math.sin(yDot*math.pi*2))/2)*.3 -- Led stippling
                local pBlend=(1+p)/2
                local c=(s*d*pBlend)*15 -- Scale colour
                c=R.clamp(c,0,15)
                c=c-(math.random()>(c-c//1) and 1 or 0) -- Blended fuzz
                pix(x,y,c)
            end
        end
    end
end

end

rift_uiqrint=function()
--   name: qrint - the quilled print-function
-- author: Decca / RiFT
-- script: lua
--   info: adds centering (x or y or both), outline and shadows (left or right) to the build-in print-function of the TIC-80
-- syntax: qrint(text, [x=0 to 240/false], [y=0 to 136/false], [color=0 to 15], [fixed=true/false], [scale=1 to x], [smallfont=true/false], [outline=0 to 15], [shadow=0 to 15], [shadowdirection=true/false])
return function(R)
    R.qrint=function(txt,x,y,col,fix,scl,sml,otl,sdw,sdr)
        ht=7 -- height (default: 6)
        wd=6 -- width (default: 6)
        rows = select(2,txt:gsub("\n","\n"))+1
        if not y then ypos = 60-(rows/2*((ht+2)*scl)) else ypos = y end
        if not scl then scl=1 end
        if not fix then mgx=2.25 else mgx=2.075 end
        if sml then mgx=(mgx*1.55) end
        if scl > 1 then mgx=(mgx/scl) end
        for row in string.gmatch(txt,"([^".."\n".."]+)") do
            if not x then xpos=119-(#row*6)/mgx else xpos=x end
            if sdw then -- shadow
                if sdr then -- left
                    print(row,xpos-1,ypos+1,sdw,fix,scl,sml)
                    print(row,xpos-2,ypos+1,sdw,fix,scl,sml)
                    print(row,xpos-1,ypos+2,sdw,fix,scl,sml)
                    print(row,xpos-2,ypos+2,sdw,fix,scl,sml) 
                else --right
                    print(row,xpos+1,ypos+1,sdw,fix,scl,sml)
                    print(row,xpos+2,ypos+1,sdw,fix,scl,sml)
                    print(row,xpos+1,ypos+2,sdw,fix,scl,sml)
                    print(row,xpos+2,ypos+2,sdw,fix,scl,sml)  
                end
            end
            if otl then -- outline
                print(row,xpos-1,ypos,otl,fix,scl,sml)
                print(row,xpos+1,ypos,otl,fix,scl,sml)
                print(row,xpos,ypos-1,otl,fix,scl,sml)
                print(row,xpos,ypos+1,otl,fix,scl,sml)
            end
            print(row,xpos,ypos,col,fix,scl,sml)
            ypos=ypos+(ht+1)*scl
            if otl then ypos=ypos+2 end
            if sdw then ypos=ypos+1 end
        end
    end
end

end

rift_datamodelstreetlight=function()
return {
	flags=0,
	divide_by=645,
	scale=4,
	vertices={19,-594,19,26,-594,0,19,-594,-20,0,-594,-27,-20,-594,-20,-27,-594,0,-20,-594,19,0,-594,26,9,603,9,13,603,-0,9,603,-10,0,603,-14,-10,603,-10,-14,603,-0,-10,603,9,0,603,13,-10,-345,9,-14,-345,0,-10,-345,-10,0,-345,-14,9,-345,-10,13,-345,0,9,-345,9,0,-345,13,-20,-352,19,-27,-352,0,-20,-352,-20,0,-352,-27,19,-352,-20,26,-352,0,19,-352,19,0,-352,26,12,603,12,18,603,-0,12,603,-13,0,603,-19,-13,603,-13,-19,603,-0,-13,603,12,0,603,18,12,608,12,18,608,-0,12,608,-13,0,608,-19,-13,608,-13,-19,608,-0,-13,608,12,0,608,18,-11,552,-14,-11,572,-14,10,572,-14,10,552,-14,3,625,182,-4,625,182,3,633,181,-4,633,181,3,626,276,-4,626,276,3,633,276,-4,633,276,10,552,-19,-11,552,-19,-11,572,-19,10,572,-19,-8,571,-11,7,571,-11,7,553,-11,-8,553,-11,-4,615,137,-4,624,135,3,624,135,3,615,137,-11,617,273,-11,637,273,-11,637,294,10,637,273,10,637,294,10,617,273,10,617,294,19,617,354,22,617,373,-23,617,373,22,637,373,-23,637,373,18,617,406,-19,617,406,18,637,406,-19,637,406,10,617,421,-11,617,421,10,637,421,-11,637,421,-7,645,285,-7,645,302,6,645,302,6,645,285,-15,645,369,14,645,369,-12,645,396,11,645,396,-7,645,409,6,645,409,12,617,363,-13,617,363,14,617,373,-15,617,373,10,617,403,-11,617,403,5,617,412,-6,617,412,9,609,368,-10,609,368,10,609,376,-11,609,376,7,609,400,-8,609,400,4,609,407,-5,609,407,0,617,414,0,609,408,0,606,400,0,606,376,0,609,364,0,617,358,},
	triangles={2,31,1,3,30,2,4,29,3,5,28,4,6,27,5,6,25,26,8,25,7,1,32,8,17,14,18,18,13,19,19,12,20,20,11,21,21,10,22,22,9,23,23,16,24,24,15,17,26,17,18,26,19,27,27,20,28,29,20,21,29,22,30,31,22,23,31,24,32,32,17,25,9,34,33,34,41,33,35,42,34,36,43,35,37,44,36,38,45,37,39,46,38,40,47,39,33,48,40,89,92,90,43,45,47,91,101,92,7,5,3,14,38,37,74,96,76,68,50,49,50,66,51,51,67,52,70,66,65,62,64,61,67,68,52,57,54,53,84,94,75,60,55,56,49,61,52,50,62,49,51,63,50,52,64,51,55,72,67,69,54,70,70,55,71,72,54,69,83,79,76,94,102,95,111,122,123,122,115,121,83,85,81,82,88,84,121,117,120,87,89,85,86,92,88,75,93,74,77,96,95,83,95,98,82,75,74,84,99,97,83,100,87,88,101,99,87,102,91,81,103,80,73,76,78,103,123,124,105,111,103,106,112,114,107,113,105,108,114,116,107,117,115,109,120,117,108,118,110,90,106,108,120,110,118,121,118,116,122,116,114,112,122,114,104,123,112,2,30,31,3,29,30,4,28,29,5,27,28,6,26,27,6,7,25,8,32,25,1,31,32,17,15,14,18,14,13,19,13,12,20,12,11,21,11,10,22,10,9,23,9,16,24,16,15,26,25,17,26,18,19,27,19,20,29,28,20,29,21,22,31,30,22,31,23,24,32,24,17,9,10,34,34,42,41,35,43,42,36,44,43,37,45,44,38,46,45,39,47,46,40,48,47,33,41,48,89,91,92,47,48,41,41,42,43,43,44,45,45,46,47,47,41,43,91,102,101,3,2,1,1,8,7,7,6,5,5,4,3,3,1,7,16,9,33,35,34,10,35,10,11,16,33,40,15,16,40,36,35,11,36,11,12,15,40,39,14,15,39,37,36,12,37,12,13,14,39,38,37,13,14,74,93,96,68,65,50,50,65,66,51,66,67,70,71,66,62,63,64,67,72,69,68,49,52,67,69,68,57,58,54,84,97,94,60,59,55,49,62,61,50,63,62,51,64,63,52,61,64,66,71,55,55,59,57,55,57,53,67,66,55,55,53,72,54,58,60,60,56,70,70,65,68,70,68,69,54,60,70,70,56,55,72,53,54,76,77,83,83,81,80,79,78,76,83,80,79,96,93,94,94,97,99,99,101,102,102,100,98,95,96,94,102,98,95,94,99,102,111,113,122,122,113,115,83,87,85,82,86,88,121,115,117,87,91,89,86,90,92,75,94,93,77,76,96,83,77,95,74,73,82,82,84,75,84,88,99,83,98,100,88,92,101,87,100,102,81,105,103,73,74,76,103,111,123,105,113,111,106,104,112,107,115,113,108,106,114,107,109,117,109,119,120,108,116,118,90,86,82,82,73,78,79,80,103,82,78,79,81,85,89,107,105,81,107,81,89,79,103,124,79,124,104,109,107,89,119,109,89,82,79,104,82,104,106,119,89,90,110,119,90,90,82,106,108,110,90,120,119,110,121,120,118,122,121,116,112,123,122,104,124,123,},
	origin={0,-1,0},
}

end

rift_stateintrocard=function()
R=R or {}
rift_fontsysfont()(R)
rift_fontfont()(R)
rift_uiqrint()(R)
rift_syspalette()(R)
rift_sysmath()(R)

local GLOBAL=rift_global()

FONT=nil

return {
    duration=4000,
    bdr=function(y,t,unitT)
        vbank(0)
        local pal0=R.Palette:new()
        pal0:setRGB(0,R.RGB:new(0,0,0))
        pal0:setRGB(1,R.RGB:new(0,0,0))
        pal0:setRGB(2,R.RGB:new(0,0,0))
        pal0:setRGB(3,R.RGB:new(0,0,0))

        local pal1=R.Palette:new()
        pal1:setRGB(0,GLOBAL.rgbGMan)
        pal1:setRGB(1,R.RGB:new(1,1,1))
        pal1:setRGB(2,R.RGB:new(.1,.5,.1))
        pal1:setRGB(3,R.RGB:new(.05,.4,.05))

        local inOut=.25
        local colT=1
        if unitT<inOut then
            colT=R.smoothStep(unitT/inOut,0,1)
        elseif unitT>(1-inOut) then
            colT=R.smoothStep((1-unitT)/inOut,0,1)
        end
        pal0:applyBlend(pal1,colT)
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            local data=rift_datasysfontinformics7x7informics7x7()
            R.sysfontLoad(data)

            local fontdata=rift_datafontnucampi8x16nucampi8x16()
            FONT=R.Font:new()
            FONT:load(fontdata)        
        end
        cls(0)
        FONT:print("Walk / RiFT",73,59,1,1,3)
        FONT:print("Walk / RiFT",75,61,1,1,2)
        FONT:print("Walk / RiFT",74,60,1,1,1)
        R.qrint("TIC-80 / Nova 23 (wild)",127,128,1,false,1,false,2,nil)
    end,
}

end

rift_statestreetopening=function()
R=R or {}
rift_syssys()(R)
rift_syspalette()(R)
rift_3dgeom()(R)
rift_3dmodel()(R)
rift_3dactor()(R)
rift_3dscene()(R)
local riftlogo=rift_datagfxriftlogo()

local SCENE0=nil
local SCENE1=nil
local MODEL_LOGO=nil
local MODEL_WALL=nil
local MODEL_LAMP=nil
local ACTOR_LOGO=nil
local ACTOR_WALL=nil
local ACTOR_LAMP=nil

local PAL0=nil
local PAL_LOGO=nil


--[[
function drawWallTexture()
    for y=0,96 do
        for x=0,192 do
            local p=((x%32==0) or (y%10==0)) and 14 or 15
            pix(x,y,p)
        end
    end
end
--]]

return {
    duration=8000,
    bdr=function(y,t,unitT)
        vbank(0)
        local pal=R.Palette:new()
        for i=0,15 do
            local s=i/15
            pal:setRGB(i,R.RGB:new(s,s,s))
        end
        PAL0:applyBlend(pal,math.min(1,unitT*3))

        vbank(1)
        PAL_LOGO:apply()
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            PAL0=R.Palette:new()
            PAL0:setAllRGB(R.RGB:new(0,0,0))

            riftlogo.setup()
            PAL_LOGO=R.Palette:new()
            PAL_LOGO:readSys() -- steal the palette

            local w,h=riftlogo.getDims()
            local modelRect=rift_datamodelrectangle()(1,h/w)

            SCENE0=R.Scene:new()
            SCENE1=R.Scene:new()

            -- LOGO
            MODEL_LOGO=R.Model:new()
            MODEL_LOGO:load(modelRect)
            
            ACTOR_LOGO=R.Actor:new(MODEL_LOGO)
            ACTOR_LOGO:setDrawFn(function(tr)
                ttri(
                    tr.v[1].x,tr.v[1].y,
                    tr.v[2].x,tr.v[2].y,
                    tr.v[3].x,tr.v[3].y,
                    tr.ex.u1*w,tr.ex.v1*h,
                    tr.ex.u2*w,tr.ex.v2*h,
                    tr.ex.u3*w,tr.ex.v3*h,
                    2,
                    15
--                    -tr.v[1].z,-tr.v[2].z,-tr.v[3].z
                )
            end,0)

            -- WALL
            MODEL_WALL=R.Model:new()
            MODEL_WALL:load(modelRect)
--            MODEL_WALL.origin={0,2,0}

            ACTOR_WALL=R.Actor:new(MODEL_WALL)
            ACTOR_WALL:setDrawFn(R.poly.Draw1Colour(3),0)

            -- LAMP
            MODEL_LAMP=R.Model:new()
            MODEL_LAMP:load(rift_datamodelstreetlight())

            ACTOR_LAMP=R.Actor:new(MODEL_LAMP)
            ACTOR_LAMP:setDrawFn(R.poly.Draw1Colour(3),0)

            SCENE0:registerActor(ACTOR_WALL)
            SCENE0:registerActor(ACTOR_LAMP)
            SCENE1:registerActor(ACTOR_LOGO)
        end

        vbank(1)
        cls()
        riftlogo.draw(0,0)

        vbank(0)
        cls()

        local camPos=R.V4:new({unitT*2,0,-2,1})
        local camAim=R.V4:new({0,0,0,1})
        SCENE0:getCam():setPos(camPos)
        SCENE0:getCam():setAim(camAim)
        SCENE1:getCam():setPos(camPos)
        SCENE1:getCam():setAim(camAim)

        local mat=R.M44:newTrans(0,0,2.5)
        ACTOR_WALL:setMat(mat)
        ACTOR_LOGO:setMat(mat)

        mat=R.M44:newTrans(-8,3,12)
        mat:mulM44(R.M44:newRotX(math.pi))
        ACTOR_LAMP:setMat(mat)

        SCENE1:draw()
        memcpy(0x8000,0,120*136)
        cls()

        SCENE0:draw()

        vbank(1)
        cls()
        memcpy(0,0x8000,120*136)
    end,
}

end

rift_statefall=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

return {
    duration=5000,
    bdr=function(y,t,unitT)
        vbank(0)
        R.setRGB(1,GLOBAL.rgbGMan)
        R.setRGB(2,R.RGB:new(.4,.2,.1))
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)
            
            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)
    
        local mat=R.M44:newTrans(0,-1.75+unitT*3.5,1.5)
        mat.mulM44(mat,R.M44:newRotZ(math.pi+math.sin(unitT*math.pi*3)*.8))
        mat.mulM44(mat,R.M44:newRotY(unitT*5*math.pi))
        ACTOR_GMAN:setMat(mat)

        for i=0,100 do
            local x=(i^7)%240
            local y=(i^3-(unitT*(500+i*26)))%136
            line(x,y-4*(i/20),x,y,2)

            if i==50 then
                SCENE:draw()
            end
        end
    end,
}

end

rift_statewalkgarden=function()
R=R or {}
rift_3dmodel()(R)
rift_3dscene()(R)

local GLOBAL=rift_global()

local SCENE=nil
local MODEL_GMAN=nil
local ACTOR_GMAN=nil
local MAT_GMAN=nil

return {
    duration=6000,
    bdr=function(y,t,unitT)
        vbank(0)
        R.setRGB(1,GLOBAL.rgbGMan)
        R.setRGB(2,R.RGB:new(1,1,.3))
    end,
    tic=function(isFirstRun,t,unitT)
        if isFirstRun then
            vbank(1)
            cls(0)

            SCENE=R.Scene:new()

            MODEL_GMAN=R.Model:new()
            MODEL_GMAN:load(rift_datamodelgreenman())

            ACTOR_GMAN=R.Actor:new(MODEL_GMAN)
            ACTOR_GMAN:setDrawFn(R.poly.Draw1Colour(1),0)
            MAT_GMAN=ACTOR_GMAN:getMat()
            MAT_GMAN:mulM44(R.M44:newTrans(0,0,1.5))
            
            SCENE:registerActor(ACTOR_GMAN)
        end

        vbank(0)
        cls(0)

        local xwalk=unitT*200
        for i=0,240,4 do
            local x=(i-xwalk)%240
            line(x,110,x,136,1)

            if i%80==0 then
                circ(x,100,4,2)
            end
        end

        SCENE:draw()
    end,
}

end

rift_uimouse=function()
return function(R)
    R.Mouse={}

	function R.Mouse:new()
		local o={
			last=nil,
            now=nil,
		}
		setmetatable(o,self)
		self.__index=self
		return o
	end

    function R.Mouse:update()
        self.last=self.now
        local x,y,lb,mb,rb,sx,sy=mouse()
        self.now={
            x=x,y=y,
            lb=lb,mb=mb,rb=rb,
            sx=sx,sy=sy,
        }
        local lastLb,lastMb,lastRb=false,false,false
        if self.last~=nil then
            lastLb,lastMb,lastRb=self.last.lb,self.last.mb,self.last.rb
        end

        self.now.lbp=self.now.lb and not lastLb
        self.now.mbp=self.now.mb and not lastMb
        self.now.rbp=self.now.rb and not lastRb
        return self.now
    end
end

end


IS_DEBUG_MODE=false

-- If IS_DEBUG_MODE
-- nil or index of state
DEBUG_SET_STATE=6
DEBUG_SHOW_TIME=false

R=R or {}
rift_syssys()(R)

STATES={
    rift_stateintrocard(),
    -- Jazzy logo, some colour shifting?
    rift_statelogoopener(),
--    rift_statelogoopener(),
    -- Logo transforms onto a wall. Pans around to street signal
    rift_statestreetopening(),
    -- Pans up the street signal, showing green and red man
    rift_statestreetsignalpanup(),
    -- Green man breaks out
    rift_stategreenmanbreakout(),
    -- Green man falls
    rift_statefall(),
    -- Green man gets up
    rift_stategreenmangetup(),
    -- A number of walk cycles
    rift_statewalkgarden(),
    rift_statewalkwind(),
    rift_statewalkprism(),
    rift_statewalkgalaxy(),
    rift_statewalksplits(),
    -- ...
    -- ...
    -- Redman gets angry
    rift_stateredmansaysstop(),
    rift_statevehicleapproaches(),
    -- A shattered Greenman
    rift_stategreenmanlying(),
    -- Greenman is back, broken in his prison
    rift_stategreenmanrecaptured(),
    rift_stateoutrocard(),
}

I_STATE=0
STATE_START_TIME=0
DO_NEXT_STATE=true

function BOOT()
    setStateNext()
    if IS_DEBUG_MODE and DEBUG_SET_STATE ~= nil then
        I_STATE=DEBUG_SET_STATE-1
    end
end

BDR=function(y)
	state=STATES[I_STATE]
    if state.bdr then
        local t=time()-STATE_START_TIME
        local unitT=state.duration and t/state.duration or nil
        state.bdr(y,t,unitT)        
    end
end

TIC=R.ticWrap(function()
	R.tryBreak()
	R.hideMouse()

    local isFirstRun=false
    if DO_NEXT_STATE then
        I_STATE=I_STATE+1
        STATE_START_TIME=time()
        isFirstRun=true
        DO_NEXT_STATE=false
    end

	local state=STATES[I_STATE]
    local t=time()-STATE_START_TIME
    local unitT=state.duration and t/state.duration or nil
    local endThisState=state.tic(isFirstRun,t,unitT)
    
    if IS_DEBUG_MODE and keyp(48) then
        setStateNext()
    elseif endThisState or (unitT~=nil and unitT >= 1) then
        setStateNext()
    end

    if IS_DEBUG_MODE then
        if DEBUG_SHOW_TIME then
            vbank(1)
            rect(4,127,111,7,15)
            print(string.format("S: %s T: %.2d UT: %.2f", I_STATE, t, (unitT) and unitT or 0),6,128,14)
        end
    end
end)

function setStateNext()
    if I_STATE>=#STATES then
        trace("- Natural Exit :)",12)
        exit()
    end
    DO_NEXT_STATE=true
end

-- <TILES>
-- 000:0000000000000220000223320322232002322320222332200032220000000000
-- </TILES>

-- <PALETTE>
-- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
-- 001:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
-- </PALETTE>

