Re: Textured Raycaster [Multiple Levels! Door Covers! Jumping!]
Posted: Thu Mar 30, 2017 5:10 am
Does the library use any canvas? Iirc they're cleared on setMode.
Code: Select all
--By xXxMoNkEyMaNxXx
--[[Complete API---- This was made to be a module, PLEASE USE IT AS A MODULE
.cw=false
-Counter clockwise vertex order starting at top left.
.cw=true
-Clockwise vertex order starting at top left.
.preload(loadup):
-loadup==true sets pixel effect to polygon texturer,
-loadup==false clears any pixel effect.
*NOTE: preload(false) must be done to draw blank polygons after textured ones.
.setRepeat(origin,size):
-Makes the image repeat every 'size' starting at 'origin'.
-The default is origin={0,0},size={1,1}.
.quad(image,v1,v2,v3,v4) - Draws a polygon.
-if 'image' is nil, the function will prepare to make it blank.
.quad(v1,v2,v3,v4) - draws a polygon with no image.
.fast(image,v1,v2,v3,v4) - draws a polygon with 'image' on it.
-slightly(!!!) faster than quad.
-Must include an image.
-Must call .preload(true) beforehand.
Info:
Vertices are in the form {x,y}.
Vertices go clockwise from the top left.
v1---v2
| img |
v4---v3
--]]
--Modified by RogueCarrot
local glsl=love.graphics.newShader[[
//Made by xXxMoNkEyMaNxXx
extern Image img;
extern Image img2;
extern vec2 v1;
extern vec2 v2;
extern vec2 v3;
extern vec2 v4;
extern vec2 p0;
extern vec2 rep;
//extern number SIZEY;//So annoying
extern number SIZEX;//So annoying
//extern number dim;
extern vec4 tint;
vec2 one=vec2(1.0,1.0);
number c(vec2 v1,vec2 v2)
{
return v1.x*v2.y-v2.x*v1.y;
}
number intersect(vec2 v1,vec2 d1,vec2 v2,vec2 d2)
{
//v1+d1*
return c(v2-v1,d2)/c(d1,d2);
}
vec4 mask(vec4 base,vec4 over)
{
return vec4(over.rgb*over.a+base.rgb*(1-over.a),over.a+base.a*(1-over.a));
}
vec4 effect(vec4 colour,Image UNUSED1,vec2 texture_coords,vec2 inverted)
{
vec2 p=vec2(inverted.x*SIZEX,inverted.y);//SO ANNOYING
vec2 A1=normalize(v2-v1);
vec2 A2=normalize(v3-v4);
vec2 B1=normalize(v2-v3);
vec2 B2=normalize(v1-v4);
number Adiv=c(A1,A2);
number Bdiv=c(B1,B2);
vec2 uv;
bvec2 eq0=bvec2(abs(Adiv)<=0.0001,abs(Bdiv)<=0.0001);
if(eq0.x && eq0.y){
//Both edges are parallel, therefore the shape is a parallelogram (Isometric)
number dis=dot(p-v1,A1);
//cos theta
number ct=dot(A1,B1);
//Closest point on v1->A1 to p
vec2 pA=v1+A1*dis;
//uv
number r=length(p-pA)/sqrt(1-ct*ct);
uv=vec2(1-r/length(v2-v3),(dis+r*ct)/length(v2-v1));
}else if(eq0.x){
//One Vanishing point occurs in numerically set scenarios in 3D, and is a feature of 2.5D
//Horizon is A1 (=A2) from B
vec2 Vp=v3+B1*c(v4-v3,B2)/Bdiv;
//Some point in the distance that diagonals go to
vec2 D=Vp+A1*intersect(Vp,A1,v4,normalize(v2-v4));
//uv
number u=intersect(v1,A1,Vp,normalize(p-Vp));
number v=intersect(v1,A1,D,normalize(p-D))-u;
number len=length(v2-v1);
uv=vec2(len-v,u)/len;//Reversed components to match up with other one
}else if(eq0.y){
//If the other edge is the parallel one
vec2 Vp=v1+A1*c(v4-v1,A2)/Adiv;
vec2 D=Vp+B1*intersect(Vp,B1,v4,normalize(v2-v4));
number u=intersect(v3,B1,Vp,normalize(p-Vp));
number len=length(v2-v3);
uv=vec2(u,len-intersect(v3,B1,D,normalize(p-D))+u)/len;
}else{
//Else, two vanishing points
//*intersect(v1,A1,v4,A2)
//*intersect(v3,B1,v4,B2)
//Vanishing points
vec2 A=v1+A1*c(v4-v1,A2)/Adiv;
vec2 B=v3+B1*c(v4-v3,B2)/Bdiv;
//Horizon
vec2 H=normalize(A-B);
//Pixel
uv=vec2(intersect(v4,-H,A,normalize(p-A))/intersect(v4,-H,v2,-A1),intersect(v4,H,B,normalize(p-B))/intersect(v4,H,v2,-B1));
}
vec4 tex2 = Texel(img,mod(uv*rep+vec2(p0.x-1,p0.y),one));
vec4 tex3 = Texel(img2,one);
vec4 tint2 = tint;
if (tex2.r * 255 == 911) {
tex2.r = 1;
tex2.g = 1;
tex2.b = 0;
} else {
vec4 diff;
diff[0] = (tint2[0] - tex2.r) * tex3.a;
diff[1] = (tint2[1] - tex2.g) * tex3.a;
diff[2] = (tint2[2] - tex2.b) * tex3.a;
tex2.r = tex2.r + diff[0] * tint2[3];
tex2.g = tex2.g + diff[1] * tint2[3];
tex2.b = tex2.b + diff[2] * tint2[3];
}
return mask(colour,tex2);
}
]]
local gl_send=glsl.send
local q=love.graphics.polygon
local win = love.window
local lgr = love.graphics
local tmr = love.timer
local setEffect=love.graphics.setShader
local print = print
gl_send(glsl,"SIZEX",1)--So annoying
-- gl_send(glsl,"SIZEY",love.graphics.getHeight())--So annoying
gl_send(glsl,"p0",{0,0})
gl_send(glsl,"rep",{1,1})
module(...)
local cw=true--clockwise
function preload(loadup)
if loadup then
setEffect(glsl)
else
setEffect()
end
end
function setRepeat(origin,size)
gl_send(glsl,"p0",origin)
gl_send(glsl,"rep",size)
end
-- function fast(img,v1,v2,v3,v4)
-- gl_send(glsl,"img",img)
-- gl_send(glsl,"v1",v2)
-- gl_send(glsl,"v2",v3)
-- gl_send(glsl,"v3",v4)
-- gl_send(glsl,"v4",v1)
-- q("fill",v1[1],v1[2],v2[1],v2[2],v3[1],v3[2],v4[1],v4[2])
-- end
function quad(img,v1,v2,v3,v4,w,h,tint,can)
local dim = dim or 1.0
local tint = tint or {1,1,1,0}
-- if h then gl_send(glsl,"SIZEY",h) end
if w then gl_send(glsl,"SIZEX",w/lgr.getWidth()) end
if img then
setEffect(glsl)
if can then gl_send(glsl,"img2", can) end
gl_send(glsl,"img", img)
gl_send(glsl,"tint", tint)
gl_send(glsl,"v1",v2)
gl_send(glsl,"v2",v3)
gl_send(glsl,"v3",v4)
gl_send(glsl,"v4",v1)
end
lgr.push()
-- lgr.translate(0, lgr.getHeight() / 2)
-- lgr.scale(1,-1)
-- lgr.translate(0, -(lgr.getHeight() / 2))
q("fill",v1[1],v1[2],v2[1],v2[2],v3[1],v3[2],v4[1],v4[2])
lgr.pop()
setEffect()
end
Code: Select all
--By xXxMoNkEyMaNxXx
--[[Complete API---- This was made to be a module, PLEASE USE IT AS A MODULE
.cw=false
-Counter clockwise vertex order starting at top left.
.cw=true
-Clockwise vertex order starting at top left.
.preload(loadup):
-loadup==true sets pixel effect to polygon texturer,
-loadup==false clears any pixel effect.
*NOTE: preload(false) must be done to draw blank polygons after textured ones.
.setRepeat(origin,size):
-Makes the image repeat every 'size' starting at 'origin'.
-The default is origin={0,0},size={1,1}.
.quad(image,v1,v2,v3,v4) - Draws a polygon.
-if 'image' is nil, the function will prepare to make it blank.
.quad(v1,v2,v3,v4) - draws a polygon with no image.
.fast(image,v1,v2,v3,v4) - draws a polygon with 'image' on it.
-slightly(!!!) faster than quad.
-Must include an image.
-Must call .preload(true) beforehand.
Info:
Vertices are in the form {x,y}.
Vertices go clockwise from the top left.
v1---v2
| img |
v4---v3
--]]
local glsl=love.graphics.newShader[[
//Made by xXxMoNkEyMaNxXx
extern Image img;
extern vec2 v1;
extern vec2 v2;
extern vec2 v3;
extern vec2 v4;
extern vec2 p0;
extern vec2 rep;
vec2 one=vec2(1.0,1.0);
number c(vec2 v1,vec2 v2)
{
return v1.x*v2.y-v2.x*v1.y;
}
number intersect(vec2 v1,vec2 d1,vec2 v2,vec2 d2)
{
//v1+d1*
return c(v2-v1,d2)/c(d1,d2);
}
vec4 mask(vec4 base,vec4 over)
{
return vec4(over.rgb*over.a+base.rgb*(1-over.a),over.a+base.a*(1-over.a));
}
vec4 effect(vec4 colour,Image UNUSED1,vec2 UNUSED2,vec2 inverted)
{
vec2 p=vec2(inverted.x,inverted.y);
vec2 A1=normalize(v2-v1);
vec2 A2=normalize(v3-v4);
vec2 B1=normalize(v2-v3);
vec2 B2=normalize(v1-v4);
number Adiv=c(A1,A2);
number Bdiv=c(B1,B2);
vec2 uv;
bvec2 eq0=bvec2(abs(Adiv)<=0.0001,abs(Bdiv)<=0.0001);
if(eq0.x && eq0.y){
//Both edges are parallel, therefore the shape is a parallelogram (Isometric)
number dis=dot(p-v1,A1);
//cos theta
number ct=dot(A1,B1);
//Closest point on v1->A1 to p
vec2 pA=v1+A1*dis;
//uv
number r=length(p-pA)/sqrt(1-ct*ct);
uv=vec2(1-r/length(v2-v3),(dis+r*ct)/length(v2-v1));
}else if(eq0.x){
//One Vanishing point occurs in numerically set scenarios in 3D, and is a feature of 2.5D
//Horizon is A1 (=A2) from B
vec2 Vp=v3+B1*c(v4-v3,B2)/Bdiv;
//Some point in the distance that diagonals go to
vec2 D=Vp+A1*intersect(Vp,A1,v4,normalize(v2-v4));
//uv
number u=intersect(v1,A1,Vp,normalize(p-Vp));
number v=intersect(v1,A1,D,normalize(p-D))-u;
number len=length(v2-v1);
uv=vec2(len-v,u)/len;//Reversed components to match up with other one
}else if(eq0.y){
//If the other edge is the parallel one
vec2 Vp=v1+A1*c(v4-v1,A2)/Adiv;
vec2 D=Vp+B1*intersect(Vp,B1,v4,normalize(v2-v4));
number u=intersect(v3,B1,Vp,normalize(p-Vp));
number len=length(v2-v3);
uv=vec2(u,len-intersect(v3,B1,D,normalize(p-D))+u)/len;
}else{
//Else, two vanishing points
//*intersect(v1,A1,v4,A2)
//*intersect(v3,B1,v4,B2)
//Vanishing points
vec2 A=v1+A1*c(v4-v1,A2)/Adiv;
vec2 B=v3+B1*c(v4-v3,B2)/Bdiv;
//Horizon
vec2 H=normalize(A-B);
//Pixel
uv=vec2(intersect(v4,-H,A,normalize(p-A))/intersect(v4,-H,v2,-A1),intersect(v4,H,B,normalize(p-B))/intersect(v4,H,v2,-B1));
}
return mask(colour,Texel(img,mod(uv*rep+vec2(p0.x-1,p0.y),one)));
}
]]
local gl_send=glsl.send
local q=love.graphics.polygon
-- local lgr = love.graphics
local setEffect=love.graphics.setShader
gl_send(glsl,"p0",{0,0})
gl_send(glsl,"rep",{1,1})
module(...)
cw=true--clockwise
function preload(loadup)
if loadup then
setEffect(glsl)
else
setEffect()
end
end
function setRepeat(origin,size)
gl_send(glsl,"p0",origin)
gl_send(glsl,"rep",size)
end
function fast(img,v1,v2,v3,v4)
gl_send(glsl,"img",img)
gl_send(glsl,"v1",v2)
gl_send(glsl,"v2",v3)
gl_send(glsl,"v3",v4)
gl_send(glsl,"v4",v1)
q("fill",v1[1],v1[2],v2[1],v2[2],v3[1],v3[2],v4[1],v4[2])
end
function quad(img,v1,v2,v3,v4,h)
if h then gl_send(glsl,"SIZEY",h) end
if img and v4 then
setEffect(glsl)
gl_send(glsl,"img",img)
if cw then
gl_send(glsl,"v1",v2)
gl_send(glsl,"v2",v3)
gl_send(glsl,"v3",v4)
gl_send(glsl,"v4",v1)
else
gl_send(glsl,"v1",v2)
gl_send(glsl,"v2",v1)
gl_send(glsl,"v3",v4)
gl_send(glsl,"v4",v3)
end
else
setEffect()
end
-- lgr.setBlendMode("premultiplied")
if v4 then
q("fill",v1[1],v1[2],v2[1],v2[2],v3[1],v3[2],v4[1],v4[2])
else--img acts as a vertex
q("fill",img[1],img[2],v1[1],v1[2],v2[1],v2[2],v3[1],v3[2])
end
-- lgr.setBlendMode("alpha")
setEffect()
end
The setMode bug is very annoying. Although, I do have a version of pers.lua that does begin working again after being re-required. It's not ideal, but it works. I'm currently on a cycling trip, so I'll manage to fish the code out in around 10 hours.Jasoco wrote: ↑Wed Mar 29, 2017 10:01 pmThe problem I'm talking about here is a completely unrelated one related to setMode. Really I should put this in a new thread. But I'll instead work on trying to rewrite the library and post a thread if I can't fix it. Maybe it's a bug. Since it doesn't seem to affect any other shaders, I don't know why it affects this one specifically.
Maybe David and I can look into it together. He seems really good at bettering me anyway. Haha.
Are you on Windows or Mac? How do you reload it to get it to work?Davidobot wrote: ↑Thu Mar 30, 2017 7:04 am The setMode bug is very annoying. Although, I do have a version of pers.lua that does begin working again after being re-required. It's not ideal, but it works. I'm currently on a cycling trip, so I'll manage to fish the code out in around 10 hours.
I am currently also looking into rewriting the library. Look forward to working with you.![]()
I'm on Windows. The problem with the thing not reloading has to do with the following part of the library:
Code: Select all
module(...)
Code: Select all
--By xXxMoNkEyMaNxXx
--[[Complete API---- This was made to be a module, PLEASE USE IT AS A MODULE
.cw=false
-Counter clockwise vertex order starting at top left.
.cw=true
-Clockwise vertex order starting at top left.
.preload(loadup):
-loadup==true sets pixel effect to polygon texturer,
-loadup==false clears any pixel effect.
*NOTE: preload(false) must be done to draw blank polygons after textured ones.
.setRepeat(origin,size):
-Makes the image repeat every 'size' starting at 'origin'.
-The default is origin={0,0},size={1,1}.
.quad(image,v1,v2,v3,v4) - Draws a polygon.
-if 'image' is nil, the function will prepare to make it blank.
.quad(v1,v2,v3,v4) - draws a polygon with no image.
.fast(image,v1,v2,v3,v4) - draws a polygon with 'image' on it.
-slightly(!!!) faster than quad.
-Must include an image.
-Must call .preload(true) beforehand.
Info:
Vertices are in the form {x,y}.
Vertices go clockwise from the top left.
v1---v2
| img |
v4---v3
--]]
local glsl=love.graphics.newShader[[
//Made by xXxMoNkEyMaNxXx
extern Image img;
extern vec2 v1;
extern vec2 v2;
extern vec2 v3;
extern vec2 v4;
extern vec2 p0;
extern vec2 rep;
vec2 one=vec2(1.0,1.0);
number c(vec2 v1,vec2 v2)
{
return v1.x*v2.y-v2.x*v1.y;
}
number intersect(vec2 v1,vec2 d1,vec2 v2,vec2 d2)
{
//v1+d1*
return c(v2-v1,d2)/c(d1,d2);
}
vec4 mask(vec4 base,vec4 over)
{
return base * over;
}
vec4 effect(vec4 colour,Image UNUSED1,vec2 UNUSED2,vec2 inverted)
{
vec2 p=vec2(inverted.x,inverted.y);
vec2 A1=normalize(v2-v1);
vec2 A2=normalize(v3-v4);
vec2 B1=normalize(v2-v3);
vec2 B2=normalize(v1-v4);
number Adiv=c(A1,A2);
number Bdiv=c(B1,B2);
vec2 uv;
bvec2 eq0=bvec2(abs(Adiv)<=0.0001,abs(Bdiv)<=0.0001);
if(eq0.x && eq0.y){
//Both edges are parallel, therefore the shape is a parallelogram (Isometric)
number dis=dot(p-v1,A1);
//cos theta
number ct=dot(A1,B1);
//Closest point on v1->A1 to p
vec2 pA=v1+A1*dis;
//uv
number r=length(p-pA)/sqrt(1-ct*ct);
uv=vec2(1-r/length(v2-v3),(dis+r*ct)/length(v2-v1));
}else if(eq0.x){
//One Vanishing point occurs in numerically set scenarios in 3D, and is a feature of 2.5D
//Horizon is A1 (=A2) from B
vec2 Vp=v3+B1*c(v4-v3,B2)/Bdiv;
//Some point in the distance that diagonals go to
vec2 D=Vp+A1*intersect(Vp,A1,v4,normalize(v2-v4));
//uv
number u=intersect(v1,A1,Vp,normalize(p-Vp));
number v=intersect(v1,A1,D,normalize(p-D))-u;
number len=length(v2-v1);
uv=vec2(len-v,u)/len;//Reversed components to match up with other one
}else if(eq0.y){
//If the other edge is the parallel one
vec2 Vp=v1+A1*c(v4-v1,A2)/Adiv;
vec2 D=Vp+B1*intersect(Vp,B1,v4,normalize(v2-v4));
number u=intersect(v3,B1,Vp,normalize(p-Vp));
number len=length(v2-v3);
uv=vec2(u,len-intersect(v3,B1,D,normalize(p-D))+u)/len;
}else{
//Else, two vanishing points
//*intersect(v1,A1,v4,A2)
//*intersect(v3,B1,v4,B2)
//Vanishing points
vec2 A=v1+A1*c(v4-v1,A2)/Adiv;
vec2 B=v3+B1*c(v4-v3,B2)/Bdiv;
//Horizon
vec2 H=normalize(A-B);
//Pixel
uv=vec2(intersect(v4,-H,A,normalize(p-A))/intersect(v4,-H,v2,-A1),intersect(v4,H,B,normalize(p-B))/intersect(v4,H,v2,-B1));
}
return mask(colour,Texel(img,mod(uv*rep+vec2(p0.x-1,p0.y),one)));
}
]]
pers = {}
local gl_send=glsl.send
local q=love.graphics.polygon
-- local lgr = love.graphics
local setEffect=love.graphics.setShader
gl_send(glsl,"p0",{1,1})
gl_send(glsl,"rep",{1,1})
pers.cw=true -- Clockwise
pers.flip=false -- Flip the image
function pers.preload(loadup)
if loadup then
setEffect(glsl)
else
setEffect()
end
end
function pers.setRepeat(origin,size)
gl_send(glsl,"p0",origin)
gl_send(glsl,"rep",size)
end
function pers.fast(img,v1,v2,v3,v4)
gl_send(glsl,"img",img)
gl_send(glsl,"v1",v2)
gl_send(glsl,"v2",v3)
gl_send(glsl,"v3",v4)
gl_send(glsl,"v4",v1)
q("fill",v1[1],v1[2],v2[1],v2[2],v3[1],v3[2],v4[1],v4[2])
end
function pers.quad(img,v1,v2,v3,v4,h)
if h then gl_send(glsl,"SIZEY",h) end
if img and v4 then
setEffect(glsl)
gl_send(glsl,"img",img)
if pers.cw and not pers.flip then
gl_send(glsl,"v1",v2)
gl_send(glsl,"v2",v3)
gl_send(glsl,"v3",v4)
gl_send(glsl,"v4",v1)
elseif pers.cw and pers.flip then
gl_send(glsl,"v1",v1)
gl_send(glsl,"v2",v4)
gl_send(glsl,"v3",v3)
gl_send(glsl,"v4",v2)
else
gl_send(glsl,"v1",v2)
gl_send(glsl,"v2",v1)
gl_send(glsl,"v3",v4)
gl_send(glsl,"v4",v3)
end
else
setEffect()
end
-- lgr.setBlendMode("premultiplied")
if v4 then
q("fill",v1[1],v1[2],v2[1],v2[2],v3[1],v3[2],v4[1],v4[2])
else--img acts as a vertex
q("fill",img[1],img[2],v1[1],v1[2],v2[1],v2[2],v3[1],v3[2])
end
-- lgr.setBlendMode("alpha")
setEffect()
end
Code: Select all
love.filesystem.load("pers.lua")()
Code: Select all
vec4 mask(vec4 base,vec4 over)
{
return base * over;
}
I knew it was that module() line. That's why it needs to be rewritten.Davidobot wrote: ↑Thu Mar 30, 2017 4:21 pmI'm on Windows. The problem with the thing not reloading has to do with the following part of the library:[/code]Code: Select all
module(...)
EDIT:
Started experimenting with the playmat library. So much tinkering around. I think I might be getting somewhere, but I'm not sure.
EDIT 2:
I remember running into very similar issues with projection when I was integrating your floor drawing quad library thing into mine. I should have a version of the my project with that code in there. I'll try to find it tomorrow and see if it helps.
Note to self: try drawing the floor canvas with the image size (32), not the expected size. Adjust player coordinates accordingly. Investigate exactly what "zoom" is in playmat. Could be that setting it to 32 and drawing image size as 32 will make things work.
I really don't want it to be meshes. They're too complicated. I'd much rather it be done in a simple extension of the polygon function. Something that accepts an image or an image/quad pair and a bunch of points and does what this does without the need for shaders.
So after experimenting with playmat for around 5 hours today, I came to the conclusion that using playmat is not going to work out for raycasting. I believe this has to do with the difference in the method of projection between raycasting and mode7. So as a conclusion - I'm not going down that rabbit hole. I will, however, attempt to rewrite the polygon library.
Code: Select all
return mask(colour,Texel(img,mod(uv*rep+vec2(p0.x-1,p0.y),one)));
Code: Select all
vec4 tex2 = Texel(img,mod(uv*rep+vec2(p0.x-1,p0.y),one));
vec4 tex3 = Texel(img2,one);
vec4 diff;
diff[0] = (tint[0] - tex2.r) * tex3.a;
diff[1] = (tint[1] - tex2.g) * tex3.a;
diff[2] = (tint[2] - tex2.b) * tex3.a;
tex2.r = tex2.r + diff[0] * tint[3];
tex2.g = tex2.g + diff[1] * tint[3];
tex2.b = tex2.b + diff[2] * tint[3];
return mask(colour,tex2);