Files
warren/src/fov.lua
T

63 lines
1.8 KiB
Lua

-- Recursive shadowcasting over eight octants. Returns a set of visible map
-- indices for a given origin and radius.
local Fov = {}
local mult = {
{ 1, 0, 0, -1, -1, 0, 0, 1 },
{ 0, 1, -1, 0, 0, -1, 1, 0 },
{ 0, 1, 1, 0, 0, -1, -1, 0 },
{ 1, 0, 0, 1, -1, 0, 0, -1 },
}
local function castLight(map, cx, cy, row, start, finish, radius, xx, xy, yx, yy, visible)
if start < finish then return end
local radiusSq = radius * radius
local newStart = 0.0
for j = row, radius do
local dx, dy = -j - 1, -j
local blocked = false
while dx <= 0 do
dx = dx + 1
local mapX = cx + dx * xx + dy * xy
local mapY = cy + dx * yx + dy * yy
local leftSlope = (dx - 0.5) / (dy + 0.5)
local rightSlope = (dx + 0.5) / (dy - 0.5)
if start < rightSlope then
-- cell not yet inside the current view; keep scanning
elseif finish > leftSlope then
break
else
if dx * dx + dy * dy <= radiusSq and map:inBounds(mapX, mapY) then
visible[map:index(mapX, mapY)] = true
end
if blocked then
if map:blocksSight(mapX, mapY) then
newStart = rightSlope
else
blocked = false
start = newStart
end
elseif map:blocksSight(mapX, mapY) and j < radius then
blocked = true
castLight(map, cx, cy, j + 1, start, leftSlope, radius, xx, xy, yx, yy, visible)
newStart = rightSlope
end
end
end
if blocked then break end
end
end
function Fov.compute(map, originX, originY, radius)
local visible = {}
visible[map:index(originX, originY)] = true
for octant = 1, 8 do
castLight(map, originX, originY, 1, 1.0, 0.0, radius,
mult[1][octant], mult[2][octant], mult[3][octant], mult[4][octant], visible)
end
return visible
end
return Fov