Flickering lights
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--flickering lights | |
function setup() | |
--set up dark area covered by shader | |
SS_Dark.setup(WIDTH,600,true) | |
--add an unblinking light that can be moved | |
L1Pos=vec2(150,175) --initial pos of light1 | |
L1=SS_Dark.AddLight(L1Pos.x,L1Pos.y,150,0) | |
--add a flickering light (30% flicker) | |
L2=SS_Dark.AddLight(600,125,150,0.3) | |
--another light with a bigger flicker | |
L3=SS_Dark.AddLight(400,325,100,0.6) | |
print("Drag the first light round the screen with your finger") | |
end | |
function draw() | |
--give ourselves a background behind the dark | |
sprite("Cargo Bot:Starry Background",WIDTH/2,HEIGHT/2,WIDTH,HEIGHT) | |
SS_Dark.draw() --this draws the dark and the lights | |
end | |
--drag L1 light with finger | |
function touched(t) | |
if t.state==MOVING then | |
L1Pos=L1Pos + vec2(t.x-t.prevX,t.y-t.prevY) | |
SS_Dark.SetLight(L1,nil,L1Pos.x,L1Pos.y) --set new position | |
end | |
end | |
--Darkness and lighting code | |
--up to 3 lights can be controlled at once | |
SS_Dark={} | |
--w, h is width and height of rectangle containing lights | |
--everything except the lights will be black | |
--the darkness will fade towards the top if fade=true | |
function SS_Dark.setup(w,h,fade) | |
SS_Dark.width=w | |
SS_Dark.height=h | |
SS_Dark.Lights={} | |
SS_Dark.mesh=mesh() | |
SS_Dark.mesh:addRect(w/2,h/2,w,h) | |
SS_Dark.mesh.shader=shader(SS_Dark.shader.v,SS_Dark.shader.f) | |
if fade then SS_Dark.mesh.shader.topY=h else SS_Dark.mesh.shader.topY=0 end | |
SS_Dark.mesh.shader.lightRadius1=0 | |
SS_Dark.mesh.shader.lightRadius2=0 | |
SS_Dark.mesh.shader.lightRadius3=0 | |
SS_Dark.mesh.shader.lightPos1=vec4(0,0,0,0) | |
SS_Dark.mesh.shader.lightPos2=vec4(0,0,0,0) | |
SS_Dark.mesh.shader.lightPos3=vec4(0,0,0,0) | |
end | |
--shader lights can't be held in array, must be separate variables | |
--this next function allocates a new light to the next available shader variable | |
--making it easy to add and remove lights dynamically without having to worry about what the | |
--shader calls them | |
--x,y is position within the dark rectangle | |
--r is radius of the light | |
--f is the extent of the flicker (0-1, omit if no flicker) | |
--returns the id of the light | |
function SS_Dark.AddLight(x,y,r,f) | |
local id | |
for i=1,3 do | |
if SS_Dark.Lights[i]==nil then id=i break end | |
end | |
if not id then return end | |
if id==1 then | |
SS_Dark.mesh.shader.lightRadius1=r or 100 | |
SS_Dark.mesh.shader.lightFlicker1=f or 1 | |
SS_Dark.mesh.shader.lightPos1=vec4(x,y,0,1) | |
elseif id==2 then | |
SS_Dark.mesh.shader.lightRadius2=r or 100 | |
SS_Dark.mesh.shader.lightFlicker2=f or 1 | |
SS_Dark.mesh.shader.lightPos2=vec4(x,y,0,1) | |
elseif id==3 then | |
SS_Dark.mesh.shader.lightRadius3=r or 100 | |
SS_Dark.mesh.shader.lightFlicker3=f or 1 | |
SS_Dark.mesh.shader.lightPos3=vec4(x,y,0,1) | |
end | |
--the n variable is included to make the flicker different for each light | |
SS_Dark.Lights[id]={x=x,y=y,radius=r or 50,flicker=(f or 0),n=math.random()} | |
return id | |
end | |
--use this to change the current flicker or x,y, or radius | |
function SS_Dark.SetLight(id,f,x,y,r) | |
if id==1 then | |
if f then SS_Dark.mesh.shader.lightFlicker1=f end | |
if x and y then SS_Dark.mesh.shader.lightPos1=vec4(x,y,0,1) end | |
if r then SS_Dark.mesh.shader.lightRadius1=r end | |
elseif id==2 then | |
if f then SS_Dark.mesh.shader.lightFlicker2=f end | |
if x and y then SS_Dark.mesh.shader.lightPos2=vec4(x,y,0,1) end | |
if r then SS_Dark.mesh.shader.lightRadius2=r end | |
elseif id==3 then | |
if f then SS_Dark.mesh.shader.lightFlicker3=f end | |
if x and y then SS_Dark.mesh.shader.lightPos3=vec4(x,y,0,1) end | |
if r then SS_Dark.mesh.shader.lightRadius3=r end | |
end | |
end | |
function SS_Dark.RemoveLight(id) | |
SS_Dark.Lights[id]=nil | |
if id==1 then SS_Dark.mesh.shader.lightRadius1=vec2(0,0) | |
elseif id==2 then SS_Dark.mesh.shader.lightRadius2=vec2(0,0) | |
elseif id==3 then SS_Dark.mesh.shader.lightRadius3=vec2(0,0) | |
end | |
end | |
function SS_Dark.draw() | |
--set flicker for current lights | |
--use noise function to cause flicker | |
for id=1,3 do | |
if SS_Dark.Lights[id] ~=nil then | |
SS_Dark.SetLight(id,1+SS_Dark.Lights[id].flicker*noise(SS_Dark.Lights[id].n+ElapsedTime*2)) | |
end | |
end | |
SS_Dark.mesh:draw() | |
end | |
--shader | |
SS_Dark.shader={ | |
v=[[ | |
uniform mat4 modelViewProjection; | |
attribute vec4 position; | |
varying highp vec4 vPosition; | |
void main() | |
{ | |
vPosition = position; | |
gl_Position = modelViewProjection * position; | |
} | |
]] | |
, | |
f=[[ | |
precision highp float; | |
uniform vec4 lightPos1; //x,y position | |
uniform vec4 lightPos2; //x,y position | |
uniform vec4 lightPos3; //x,y position | |
uniform float lightRadius1; | |
uniform float lightRadius2; | |
uniform float lightRadius3; | |
uniform float lightFlicker1; | |
uniform float lightFlicker2; | |
uniform float lightFlicker3; | |
uniform float topY; | |
varying highp vec4 vPosition; | |
void main() | |
{ | |
highp float d=0.0; | |
//fade at top of darkness | |
if (topY>0.) d=clamp(1.0-distance(vPosition,vec4(vPosition.x,topY,0.0,1.0))/100.0,0.0,1.0); | |
if (lightRadius1>0.0) { | |
highp float f = lightRadius1 * lightFlicker1; | |
d=d+clamp(1.0-distance(vPosition,lightPos1)/f+0.1,0.0,1.0); | |
} | |
if (lightRadius2>0.0) { | |
highp float f = lightRadius2 * lightFlicker2; | |
d=d+clamp(1.0-distance(vPosition,lightPos2)/f+0.1,0.0,1.0); | |
} | |
if (lightRadius3>0.0) { | |
highp float f = lightRadius3 * lightFlicker3; | |
d=d+clamp(1.0-distance(vPosition,lightPos3)/f+0.1,0.0,1.0); | |
} | |
gl_FragColor = vec4(0.,0.,0.,1.0-d); | |
} | |
]] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment