416 lines
10 KiB
Lua
416 lines
10 KiB
Lua
local rt_scale = 4
|
|
local rt_sweepdist = 10
|
|
local fbo_rt = client.fbo_create(screen_width/rt_scale, screen_height/rt_scale, true)
|
|
local shader_rt_map, result = shader_new{name="rt_map", vert=[=[
|
|
|
|
varying vec3 camh_in;
|
|
varying vec3 camv_in;
|
|
varying vec3 wpos_in;
|
|
varying vec3 wdir_in;
|
|
varying vec3 cdir_in;
|
|
varying vec3 dvec_in;
|
|
|
|
void main()
|
|
{
|
|
float vw = (gl_ProjectionMatrix*vec4(1.0, 0.0, 0.0, 0.0)).x;
|
|
float vh = (gl_ProjectionMatrix*vec4(0.0, 1.0, 0.0, 0.0)).y;
|
|
vec2 vmul = vec2(-1.0/vw, -1.0/vh);
|
|
wpos_in = (gl_ModelViewMatrixInverse * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
|
wdir_in = (gl_ModelViewMatrixInverse * vec4(-gl_Vertex.xy*vmul, 1.0, 0.0)).xyz;
|
|
dvec_in = gl_Vertex.xyz;
|
|
camh_in = normalize((gl_ModelViewMatrixInverse * vec4(1.0, 0.0, 0.0, 0.0)).xyz);
|
|
camv_in = normalize((gl_ModelViewMatrixInverse * vec4(0.0, 1.0, 0.0, 0.0)).xyz);
|
|
cdir_in = normalize((gl_ModelViewMatrixInverse * vec4(0.0, 0.0, 1.0, 0.0)).xyz);
|
|
gl_Position = vec4(gl_Vertex.x, gl_Vertex.y, -0.1, 1.0);
|
|
gl_FrontColor = gl_Color;
|
|
}
|
|
|
|
]=], frag=common.bin_load("pkg/gm/rt/shader_map.frag")}
|
|
|
|
assert(shader_rt_map, result)
|
|
|
|
local shader_rt_img, result = shader_new{name="rt_img", vert=[=[
|
|
|
|
varying vec2 tc_in;
|
|
|
|
void main()
|
|
{
|
|
tc_in = (gl_Vertex.xy+1.0)/2.0;
|
|
gl_Position = vec4(gl_Vertex.x, gl_Vertex.y, -0.1, 1.0);
|
|
gl_FrontColor = gl_Color;
|
|
}
|
|
|
|
]=], frag=[=[
|
|
|
|
uniform sampler2D tex0;
|
|
uniform float tex0_scale;
|
|
uniform vec2 screen_siz;
|
|
uniform vec2 screen_isiz;
|
|
varying vec2 tc_in;
|
|
|
|
void main()
|
|
{
|
|
//vec2 tc = floor(tc_in * screen_siz + 0.1);
|
|
vec2 tc = (floor(tc_in * screen_siz + 0.1) + 0.1) * screen_isiz;
|
|
/*
|
|
vec2 tcq = floor(tc/tex0_scale)*tex0_scale;
|
|
vec2 tcr = tc - tcq;
|
|
tcq += 0.5;
|
|
tc += 0.5;
|
|
*/
|
|
|
|
// Apply blur
|
|
// TODO: get a real kernel
|
|
vec4 cc = texture2D(tex0, tc);
|
|
/*
|
|
vec4 cb1 = (vec4(0.0)
|
|
+ texture2D(tex0, tc + vec2( 1.0, 0.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2( 0.0, 1.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2(-1.0, 0.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2( 0.0,-1.0)*tex0_scale*screen_isiz)
|
|
);
|
|
vec4 cb2 = (vec4(0.0)
|
|
+ texture2D(tex0, tc + vec2( 1.0, 1.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2( 1.0,-1.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2(-1.0, 1.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2(-1.0,-1.0)*tex0_scale*screen_isiz)
|
|
);
|
|
vec4 cb3 = (vec4(0.0)
|
|
+ texture2D(tex0, tc + vec2( 2.0, 0.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2( 0.0, 2.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2(-2.0, 0.0)*tex0_scale*screen_isiz)
|
|
+ texture2D(tex0, tc + vec2( 0.0,-2.0)*tex0_scale*screen_isiz)
|
|
);
|
|
*/
|
|
|
|
vec4 cfinal = cc;
|
|
|
|
/*
|
|
if(cc.a > 0.66)
|
|
{
|
|
cfinal = mix((cc + cb1)/5.0, cc, cc.a);
|
|
} else if(cc.a > 0.33) {
|
|
cfinal = mix(mix((cc + cb1)/5.0, cc, cc.a), (cc + cb1 + cb2)/9.0, cc.a/0.66);
|
|
} else {
|
|
cfinal = mix(
|
|
mix(mix((cc + cb1)/5.0, cc, cc.a), (cc + cb1 + cb2)/9.0, cc.a/0.66)
|
|
, (cc + cb1 + cb2 + cb3)/13.0, cc.a/0.33);
|
|
}
|
|
*/
|
|
|
|
gl_FragColor = vec4(cfinal.rgb, 1.0);
|
|
}
|
|
]=]}
|
|
assert(shader_rt_img, result)
|
|
|
|
client.map_set_render_format(map_loaded, "3v,3c")
|
|
local rt_force_update_full = true
|
|
local rt_tex = nil
|
|
local rt_hmap = {}
|
|
|
|
local function rt_update_map_height(pz)
|
|
local x
|
|
local xlen, ylen, zlen = common.map_get_dims()
|
|
|
|
rt_hmap[pz+1] = rt_hmap[pz+1] or {}
|
|
|
|
for x=0,xlen-1 do
|
|
rt_hmap[pz+1][x+1] = common.map_pillar_get(x, pz)[2]
|
|
end
|
|
end
|
|
|
|
local function rt_update_map_ring(px, pz)
|
|
local i, j
|
|
local rs = 0
|
|
|
|
px = px + 1
|
|
pz = pz + 1
|
|
local py = rt_hmap[pz][px]
|
|
|
|
for i=1,rt_sweepdist do
|
|
for j=-i,i do
|
|
local x0, z0 = px-i+j, pz-i
|
|
local x1, z1 = px+i, pz+i+j
|
|
local x2, z2 = px+i-j, pz+i
|
|
local x3, z3 = px-i, pz-i-j
|
|
|
|
local y0 = (rt_hmap[z0] and rt_hmap[z0][x0]) or py
|
|
local y1 = (rt_hmap[z1] and rt_hmap[z1][x1]) or py
|
|
local y2 = (rt_hmap[z2] and rt_hmap[z2][x2]) or py
|
|
local y3 = (rt_hmap[z3] and rt_hmap[z3][x3]) or py
|
|
|
|
if y0 < py then return rs end
|
|
if y1 < py then return rs end
|
|
if y2 < py then return rs end
|
|
if y3 < py then return rs end
|
|
end
|
|
|
|
rs = i
|
|
end
|
|
|
|
return rs
|
|
end
|
|
|
|
local function rt_gap_count(l)
|
|
local i = 1
|
|
local c = 1
|
|
|
|
while l[i] ~= 0 do
|
|
i = i + 4*l[i]
|
|
c = c + 1
|
|
end
|
|
|
|
return c + (#l)/4
|
|
end
|
|
|
|
local function rt_update_map_z(pz, do_sweep)
|
|
local xlen, ylen, zlen = common.map_get_dims()
|
|
local xoffs0 = xlen
|
|
local xoffs1 = xlen
|
|
local x, y, z
|
|
z = pz
|
|
|
|
local function skip_to_y(px, pz, ty)
|
|
if ty == 0 then return 0 end
|
|
if px < 0 or pz < 0 or px >= xlen or pz >= zlen then return 0 end
|
|
|
|
local l = common.map_pillar_get(px, pz)
|
|
local i = 0
|
|
local iadd = 0
|
|
|
|
while true do
|
|
if l[i+1] == 0 then break end
|
|
if ty <= l[i+3] then break end
|
|
i = i + l[i+1]*4
|
|
iadd = iadd + 1
|
|
end
|
|
|
|
return math.floor(i/4) + iadd
|
|
end
|
|
|
|
for x=0,xlen-1 do
|
|
local l = common.map_pillar_get(x, z)
|
|
local xoffs, zoffs
|
|
|
|
if xoffs0 <= xoffs1 then
|
|
xoffs = xoffs0
|
|
zoffs = 0
|
|
else
|
|
xoffs = xoffs1
|
|
zoffs = 1
|
|
end
|
|
|
|
do
|
|
local sx, sz
|
|
sx = x
|
|
sz = z
|
|
if sz >= 0 and sz < zlen then
|
|
local pdata = xoffs + 1 + (zoffs*0x010000)
|
|
common.img_pixel_set(rt_tex, sx, sz, pdata
|
|
+ ((do_sweep and 0x01000000*rt_update_map_ring(sx, sz)) or 0))
|
|
end
|
|
end
|
|
|
|
--common.img_pixel_set(rt_tex, xoffs, z*2 + zoffs, 0)
|
|
local time_to_gap = 0
|
|
for y=0,#l-1,4 do
|
|
assert(xoffs < rt_xsi)
|
|
local ninc = 0
|
|
if time_to_gap == 0 then
|
|
-- Calculate accel structure
|
|
local ty = (y == 0 and 0) or l[y+4]
|
|
common.img_pixel_set(rt_tex, xoffs, z*2 + zoffs,
|
|
0
|
|
+ skip_to_y(x-1, z, ty)*0x00010000
|
|
+ skip_to_y(x+1, z, ty)*0x00000100
|
|
+ skip_to_y(x, z-1, ty)*0x00000001
|
|
+ skip_to_y(x, z+1, ty)*0x01000000
|
|
)
|
|
|
|
-- Advance
|
|
time_to_gap = l[y+1]
|
|
xoffs = xoffs + 1
|
|
ninc = 1
|
|
end
|
|
|
|
time_to_gap = time_to_gap - 1
|
|
|
|
common.img_pixel_set(rt_tex, xoffs, z*2 + zoffs,
|
|
0
|
|
+ (l[y+1]+ninc)*0x00000001
|
|
+ (l[y+2])*0x00000100
|
|
+ (l[y+3])*0x00010000
|
|
+ (l[y+4])*0x01000000
|
|
)
|
|
xoffs = xoffs + 1
|
|
end
|
|
|
|
if zoffs == 0 then
|
|
xoffs0 = xoffs
|
|
else
|
|
xoffs1 = xoffs
|
|
end
|
|
end
|
|
end
|
|
|
|
local function rt_update_map_full()
|
|
-- Get map dims
|
|
local x, y, z
|
|
local _, xsi, zsi, xlen, zlen
|
|
local map = common.map_get()
|
|
xlen, _, zlen = common.map_get_dims()
|
|
rt_xsi, rt_zsi = xlen, xlen*2
|
|
|
|
-- Get map data size
|
|
local xmax = 0
|
|
for z=0,zlen-1 do
|
|
local xsum0 = 0
|
|
local xsum1 = 0
|
|
|
|
for x=0,xlen-1 do
|
|
if xsum0 <= xsum1 then
|
|
xsum0 = xsum0 + rt_gap_count(common.map_pillar_get(x, z))
|
|
else
|
|
xsum1 = xsum1 + rt_gap_count(common.map_pillar_get(x, z))
|
|
end
|
|
end
|
|
|
|
local xsum = math.max(xsum0, xsum1)
|
|
|
|
xmax = math.max(xmax, xsum)
|
|
end
|
|
|
|
while rt_xsi < xmax+xlen+256 do -- allow extra space
|
|
rt_xsi = rt_xsi * 2
|
|
end
|
|
print("xmax:", xmax, xmax+xlen, rt_xsi)
|
|
|
|
-- Create texture
|
|
rt_tex = common.img_new(rt_xsi, rt_zsi)
|
|
|
|
-- Copy data to GPU
|
|
for z=0,zlen-1 do
|
|
rt_update_map_height(z)
|
|
end
|
|
for z=0,zlen-1 do
|
|
rt_update_map_z(z, true)
|
|
print((z+1)*100/zlen)
|
|
end
|
|
|
|
-- Force image commit
|
|
--client.img_blit(rt_tex, 0, 0)
|
|
|
|
-- TODO: make this work
|
|
rt_force_update_full = false
|
|
end
|
|
|
|
local function rt_update_map_check(px, pz, ol, nl)
|
|
if rt_force_update_full then
|
|
return rt_update_map_full()
|
|
end
|
|
|
|
local i
|
|
local same = false and (#nl == #ol) -- TODO: use this optimisation
|
|
|
|
if same then
|
|
for i=1,#ol do
|
|
if ol[i] ~= nl[i] then
|
|
same = false
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if same then return end
|
|
|
|
local xlen, ylen, zlen = common.map_get_dims()
|
|
rt_update_map_height(pz)
|
|
|
|
if pz-1 >= 0 then rt_update_map_z(pz-1, false) end
|
|
rt_update_map_z(pz, false)
|
|
if pz+1 < zlen then rt_update_map_z(pz+1, false) end
|
|
|
|
local x,z
|
|
for z=pz-rt_sweepdist,pz+rt_sweepdist do
|
|
if z >= 0 and z < zlen then
|
|
for x=px-rt_sweepdist,px+rt_sweepdist do
|
|
if x >= 0 and x < xlen then
|
|
local pdata = common.img_pixel_get(rt_tex, x, z)
|
|
local old_dist = math.floor(pdata / 0x01000000)
|
|
if true or math.max(math.abs(x-px), math.abs(z-pz)) >= old_dist then
|
|
pdata = pdata % 0x01000000
|
|
common.img_pixel_set(rt_tex, x, z, pdata
|
|
+ 0x01000000*rt_update_map_ring(x, z))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
do
|
|
local va_map = common.va_make({
|
|
{-1,-1},
|
|
{ 1,-1},
|
|
{-1, 1},
|
|
{ 1, 1},
|
|
{-1, 1},
|
|
{ 1,-1},
|
|
}, nil, "2v")
|
|
local s_map_pillar_set = common.map_pillar_set
|
|
function common.map_pillar_set(px, py, pl, ...)
|
|
local ol = common.map_pillar_get(px, py)
|
|
local ret = {s_map_pillar_set(px, py, pl, ...)}
|
|
rt_update_map_check(px, py, ol, pl)
|
|
return unpack(ret)
|
|
end
|
|
|
|
local s_map_render = client.map_render
|
|
function client.map_render(map, px, py, pz, ...)
|
|
local xlen, ylen, zlen = common.map_get_dims()
|
|
shader_rt_map.set_uniform_i("tex0", 0)
|
|
shader_rt_map.set_uniform_f("map_siz", xlen, zlen)
|
|
shader_rt_map.set_uniform_f("tex0_siz", rt_xsi, rt_zsi)
|
|
shader_rt_map.set_uniform_f("tex0_isiz", 1.0/rt_xsi, 1.0/rt_zsi)
|
|
--shader_rt_map.set_uniform_f("light0_pos", -10.0, -math.max(xlen,zlen)/2, zlen/3+0.1)
|
|
--shader_rt_map.set_uniform_f("light0_diff", 1.0)
|
|
--shader_rt_map.set_uniform_f("light1_pos", xlen+10.0, -math.max(xlen,zlen)/2, zlen/4+0.1)
|
|
--shader_rt_map.set_uniform_f("light1_diff", 1.0)
|
|
|
|
local px, py, pz = client.camera_get_pos()
|
|
local vx, vy, vz = client.camera_get_forward()
|
|
local dist = trace_map_ray_dist(px, py, pz, vx, vy, vz, 50.0, false)
|
|
dist = dist - 2.5
|
|
shader_rt_map.set_uniform_f("light0_pos", px, py, pz)
|
|
shader_rt_map.set_uniform_f("light0_diff", 0.5)
|
|
--shader_rt_map.set_uniform_f("light0_diff", 1.0)
|
|
shader_rt_map.set_uniform_f("light1_pos", px + dist*vx, py + dist*vy, pz + dist*vz)
|
|
shader_rt_map.set_uniform_f("light1_diff", 1.1)
|
|
|
|
-- TODO: track old FBOs
|
|
client.gfx_depth_test(false);
|
|
client.fbo_use(fbo_rt)
|
|
client.gfx_viewport(0, 0, screen_width/rt_scale, screen_height/rt_scale)
|
|
shader_rt_map.push()
|
|
client.va_render_global(va_map, 0, 0, 0, 0, 0, 0, 1, {rt_tex})
|
|
shader_rt_map.pop()
|
|
|
|
client.fbo_use(nil)
|
|
client.gfx_viewport(0, 0, screen_width, screen_height)
|
|
shader_rt_img.set_uniform_i("tex0", 0)
|
|
shader_rt_img.set_uniform_f("screen_siz", screen_width, screen_height)
|
|
shader_rt_img.set_uniform_f("screen_isiz", 1.0/screen_width, 1.0/screen_height)
|
|
shader_rt_img.set_uniform_f("tex0_scale", rt_scale)
|
|
shader_rt_img.push()
|
|
client.va_render_global(va_map, 0, 0, 0, 0, 0, 0, 1, {fbo_rt})
|
|
shader_rt_img.pop()
|
|
client.gfx_depth_test(true);
|
|
|
|
--s_map_render(map, px, py, pz)--, ...)
|
|
end
|
|
rt_update_map_full()
|
|
end
|
|
|
|
fbo_world = nil
|
|
|