local Tunnel={}
local texture,shader,mesh
local centerPixelX=1900
local centerPixelY=1060
local lastW,lastH
function Tunnel.setCenter(x,y)
centerPixelX=x
centerPixelY=y end
local function currentTargetSize()
local target=love.graphics.getCanvas()
if target then
return target:getWidth(),target:getHeight() end
return love.graphics.getWidth(),love.graphics.getHeight() end
local function buildResources(w,h)
if not texture then
texture=love.graphics.newImage("tunnel.png")
texture:setWrap("repeat","repeat") end
mesh=love.graphics.newMesh({{0,0,0,0},{w,0,1,0},{w,h,1,1},{0,h,0,1}},"fan","static")
mesh:setTexture(texture)
local aspect=w/h
local maxRadius=math.sqrt((0.5*aspect)^2+0.5^2)
shader=love.graphics.newShader([[
extern number speed = 0.3;
extern number aspect;
extern number maxRadius;
extern number centerX;
extern number centerY;
extern number time;
const number PI = 3.14159265359;
vec4 effect(vec4 color, Image tex, vec2 uv, vec2 screen_coords) {
vec2 centered = uv - vec2(centerX, centerY);
centered.x *= aspect;
float angle = atan(centered.y, centered.x) / (0.2 * PI) + 0.5;
float radius = length(centered);
float offset = 1.0 - radius / maxRadius;
float scroll = fract(time * speed + offset);
vec2 tc = vec2(angle, scroll);
return Texel(tex, tc) * color;
}
]])
shader:send("aspect",aspect)
shader:send("maxRadius",maxRadius)
lastW,lastH=w,h end
local function warmup(w,h)
local prevCanvas=love.graphics.getCanvas()
local prevShader=love.graphics.getShader()
local temp=love.graphics.newCanvas(w,h)
temp:renderTo(function()
love.graphics.clear(0,0,0,0)
local baseX=centerPixelX or (w*0.5)
local baseY=centerPixelY or (h*0.5)
shader:send("centerX",baseX/w)
shader:send("centerY",baseY/h)
shader:send("time",0.0)
love.graphics.setShader(shader)
love.graphics.draw(mesh,0,0)
love.graphics.setShader() end)
love.graphics.setShader(prevShader)
if prevCanvas then love.graphics.setCanvas(prevCanvas) else love.graphics.setCanvas() end
temp:release() end
function Tunnel.load()
if shader then return end
local w,h=currentTargetSize()
buildResources(w,h)
warmup(w,h) end
function Tunnel.draw()
if not shader then Tunnel.load() end
local w,h=currentTargetSize()
if w~=lastW or h~=lastH then
buildResources(w,h)
warmup(w,h) end
local baseX=centerPixelX or (w*0.5)
local baseY=centerPixelY or (h*0.5)
shader:send("centerX",baseX/w)
shader:send("centerY",baseY/h)
shader:send("time",love.timer.getTime())
love.graphics.setShader(shader)
love.graphics.draw(mesh,0,0)
love.graphics.setShader() end
return Tunnel
