demos are attached.
code:
Code: Select all
--local r=rectshadow.new([height],[posx],[posy],[sizex],[sizey])
--You can set r.h, r.px, r.py, r.sx, r.sy
--In order to delete a rectangle shadow, just do r:remove()
--What do you have to do to add this?
--For each button, make a new rectangle shadow with its pixel dimensions and height.
-- DO NOT MAKE A NEW ONE EACH FRAME, ONLY HAVE AS MAKE RECTANGLE OBJECTS AS YOU HAVE BUTTONS OR WHATEVER
--Each time you change the position of a rectangle button or frame or whatever, set r.px and r.py to change the position of the shadow thing.
--Draw all of your stuff to a canvas, for example lolcanvas, instead of the screen.
--Then when you want to finalize your UI (probably the last step in your render process)
-- call the rectshadow.draw(lolcanvas,outcanvas)
-- leave outcanvas to nil to have it draw directly to the screen
local rectshadow do
rectshadow={}
local setmt=setmetatable
local unpack=unpack
local getshader=love.graphics.getShader
local getcanvas=love.graphics.getCanvas
local setshader=love.graphics.setShader
local setcanvas=love.graphics.setCanvas
local draw=love.graphics.draw
local nrects=0
local rects={}
local htab={}
local ptab={}
function rectshadow.new(h,px,py,sx,sy)
local rect={
update=true;
i=0;
h=h or 0;
px=px or 0; py=py or 0;
sx=sx or 0; sy=sy or 0;
}
local meta={}
local funcs={}
function meta:__newindex(i,v)
rect[i]=v
rect.update=true
end
meta.__index=rect
local removed=false
function funcs:remove()
if not removed then
removed=true
local i=rect.i
rects[nrects].i=i
rects[i]=rects[nrects]
htab[i]=htab[nrects]
ptab[i]=ptab[nrects]
nrects=nrects-1
end
end
nrects=nrects+1
rects[nrects]=rect
htab[nrects]=h or 0
ptab[nrects]={
px or 0,py or 0,
(px or 0)+(sx or 0),
(py or 0)+(sy or 0)
}
rect.i=nrects
return setmt(funcs,meta)
end
local uniformshadowshader=love.graphics.newShader([[
extern number w;
extern number h;
//Must be sorted based on height from least to greatest
extern float height[64];
//Stores upper left corner in xy, lower right corner in zw
extern vec4 pos[64];
extern number n;
//idk lol.
float lightfromarea(in float x0,in float y0,in float x1,in float y1){
float sx0=inversesqrt(1+x0*x0);
float sy0=inversesqrt(1+y0*y0);
float sx1=inversesqrt(1+x1*x1);
float sy1=inversesqrt(1+y1*y1);
float atx0=atan(sx0*y0)-atan(sx0*y1);
float atx1=atan(sx1*y1)-atan(sx1*y0);
float aty0=atan(sy0*x0)-atan(sy0*x1);
float aty1=atan(sy1*x1)-atan(sy1*x0);
return 0.15915494*(sx0*x0*atx0+sx1*x1*atx1+sy0*y0*aty0+sy1*y1*aty1);
}
//As long as stuff doesn't overlap, it's exactly correct.
vec4 effect(vec4 colorin,Image texturein,vec2 posin, vec2 pixelin){
float px=w*posin.x;
float py=h*posin.y;
float besth=0;
for(int i=0;i<n;i++){
if(
besth<height[i]
&&pos[i].x<=px
&&pos[i].y<=py
&&px<=pos[i].z
&&py<=pos[i].w
){
besth=height[i];
}
}
float br=1;
for(int i=0;i<n;i++){
float dheight=height[i]-besth;
if(0<dheight){
br-=lightfromarea(
(pos[i].x-px)/dheight,
(pos[i].y-py)/dheight,
(pos[i].z-px)/dheight,
(pos[i].w-py)/dheight
);
}
}
return max(0,br)*Texel(texturein,posin);
}
]])
function rectshadow.draw(incanvas,outcanvas)
uniformshadowshader:send("n",nrects)
if 0<nrects then
for i=1,nrects do
local rect=rects[i]
if rect.update then
rect.update=false
htab[i]=rect.h
local p=ptab[i]
p[1]=rect.px
p[2]=rect.py
p[3]=rect.px+rect.sx
p[4]=rect.py+rect.sy
end
end
--Is there a less shitty way of doing this?
--I'd like to do :send("height[5]",x)
uniformshadowshader:send("height",unpack(htab))
uniformshadowshader:send("pos",unpack(ptab))
end
local w,h=incanvas:getDimensions()
uniformshadowshader:send("w",w)
uniformshadowshader:send("h",h)
local lastshader=getshader()
local lastcanvas=getcanvas()
setshader(uniformshadowshader)
setcanvas(outcanvas)
draw(incanvas)
setshader(lastshader)
setcanvas(lastcanvas)
end
end