2015-10-11 18:00:58 +13:00

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