Skip to content

Commit

Permalink
Merge pull request #56 from rotLua/collection-types
Browse files Browse the repository at this point in the history
add Grid and PointSet collection types
  • Loading branch information
paulofmandown authored Aug 7, 2017
2 parents 938dbce + 32cb1b5 commit 8a7fa1d
Show file tree
Hide file tree
Showing 20 changed files with 478 additions and 376 deletions.
10 changes: 9 additions & 1 deletion examples/brogue.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@ function love.load()
f =ROT.Display(80, 30)
brg=ROT.Map.Brogue(f:getWidth(), f:getHeight())
brg:create(calbak,true)
for _, room in ipairs(brg:getRooms()) do
room:getDoors(function(x, y) f:write('+', x, y) end)
end
end
function love.draw() f:draw() end
function calbak(x, y, val) f:write(val==3 and '*' or val==2 and '+' or val==1 and '#' or '.', x, y) end
function calbak(x, y, val)
f:write(val==1 and '#' or '.', x, y)
end
local update=false
function love.update()
if update then
update=false
brg:create(calbak)
for _, room in ipairs(brg:getRooms()) do
room:getDoors(function(x, y) f:write('+', x, y) end)
end
end
end
function love.keypressed(key) update=true end
6 changes: 4 additions & 2 deletions src/rot.lua
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ end

require (ROTLOVE_PATH .. 'newFuncs')

ROT.Type = {} -- collection types tuned for various use cases
ROT.Type.PointSet = require (ROTLOVE_PATH .. 'type.pointSet')
ROT.Type.Grid = require (ROTLOVE_PATH .. 'type.grid')

ROT.Dice = require (ROTLOVE_PATH .. 'dice')
ROT.Display = require (ROTLOVE_PATH .. 'display')
ROT.TextDisplay = require (ROTLOVE_PATH .. 'textDisplay')
Expand Down Expand Up @@ -88,8 +92,6 @@ ROT.Noise = require (ROTLOVE_PATH .. 'noise')
ROT.Noise.Simplex = require (ROTLOVE_PATH .. 'noise.simplex')
ROT.FOV = require (ROTLOVE_PATH .. 'fov')
ROT.FOV.Precise = require (ROTLOVE_PATH .. 'fov.precise')
ROT.Line = require (ROTLOVE_PATH .. 'line')
ROT.Point = require (ROTLOVE_PATH .. 'point')
ROT.FOV.Bresenham = require (ROTLOVE_PATH .. 'fov.bresenham')
ROT.FOV.Recursive = require (ROTLOVE_PATH .. 'fov.recursive')
ROT.Color = require (ROTLOVE_PATH .. 'color')
Expand Down
9 changes: 3 additions & 6 deletions src/rot/display.lua
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,9 @@ end
-- @tparam[opt] table fg The color used to write the provided character
-- @tparam[opt] table bg the color used to fill in the background of the cleared space
function Display:clear(c, x, y, w, h, fg, bg)
c =c and c or ' '
w =w and w or self.widthInChars
local s=''
for _=1,w do
s=s..c
end
c = c or ' '
w = w or self.widthInChars
local s = c:rep(self.widthInChars)
x =self:_validateX(x, s)
y =self:_validateY(y)
h =self:_validateHeight(y, h)
Expand Down
88 changes: 80 additions & 8 deletions src/rot/fov/bresenham.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,78 @@
-- @module ROT.FOV.Bresenham
local ROT = require((...):gsub(('.[^./\\]*'):rep(2) .. '$', ''))
local Bresenham=ROT.FOV:extend("Bresenham")

-- internal Point class

local Point = ROT.Class:extend("Point")

function Point:init(x, y)
self.isPoint = true
self.x=x
self.y=y
end

function Point:hashCode()
local prime =31
local result=1
result=prime*result+self.x
result=prime*result+self.y
return result
end

function Point:equals(other)
if self==other then return true end
if other==nil or
not other.isPoint or
(other.x and other.x ~= self.x) or
(other.y and other.y ~= self.y) then return false end
return true
end

function Point:adjacentPoints()
local points={}
local i =1
for ox=-1,1 do for oy=-1,1 do
points[i]=Point(self.x+ox,self.y+oy)
i=i+1
end end
return points
end

-- internal Line class

local Line = ROT.Class:extend("Line")

function Line:init(x1, y1, x2, y2)
self.x1=x1
self.y1=y1
self.x2=x2
self.y2=y2
self.points={}
end
function Line:getPoints()
local dx =math.abs(self.x2-self.x1)
local dy =math.abs(self.y2-self.y1)
local sx =self.x1<self.x2 and 1 or -1
local sy =self.y1<self.y2 and 1 or -1
local err=dx-dy

while true do
table.insert(self.points, Point(self.x1, self.y1))
if self.x1==self.x2 and self.y1==self.y2 then break end
local e2=err*2
if e2>-dx then
err=err-dy
self.x1 =self.x1+sx
end
if e2<dx then
err=err+dx
self.y1 =self.y1+sy
end
end
return self
end

--- Constructor.
-- Called with ROT.FOV.Bresenham:new()
-- @tparam function lightPassesCallback A function with two parameters (x, y) that returns true if a map cell will allow light to pass through
Expand All @@ -30,17 +102,17 @@ function Bresenham:compute(cx, cy, r, callback)
local notvisited={}
for x=-r,r do
for y=-r,r do
notvisited[ROT.Point(cx+x, cy+y):hashCode()]={cx+x, cy+y}
notvisited[Point(cx+x, cy+y):hashCode()]={cx+x, cy+y}
end
end

callback(cx,cy,1,1)
notvisited[ROT.Point(cx, cy):hashCode()]=nil
notvisited[Point(cx, cy):hashCode()]=nil

local thePoints=self:_getCircle(cx, cy, r+3)
for _,p in pairs(thePoints) do
local x,y=p[1],p[2]
local line=ROT.Line(cx,cy,x, y):getPoints()
local line=Line(cx,cy,x, y):getPoints()
for i=2,#line.points do
local point=line.points[i]
if self:_oob(cx-point.x, cy-point.y, r) then break end
Expand All @@ -56,7 +128,7 @@ function Bresenham:compute(cx, cy, r, callback)

for _,v in pairs(notvisited) do
local x,y=v[1],v[2]
local line=ROT.Line(cx,cy,x, y):getPoints()
local line=Line(cx,cy,x, y):getPoints()
for i=2,#line.points do
local point=line.points[i]
if self:_oob(cx-point.x, cy-point.y, r) then break end
Expand Down Expand Up @@ -87,9 +159,9 @@ end
function Bresenham:computeThorough(cx, cy, r, callback)
local visited={}
callback(cx,cy,r)
visited[ROT.Point(cx, cy):hashCode()]=0
visited[Point(cx, cy):hashCode()]=0
for x=-r,r do for y=-r,r do
local line=ROT.Line(cx,cy,x+cx, y+cy):getPoints()
local line=Line(cx,cy,x+cx, y+cy):getPoints()
for i=2,#line.points do
local point=line.points[i]
if self:_oob(cx-point.x, cy-point.y, r) then break end
Expand Down Expand Up @@ -119,12 +191,12 @@ end
function Bresenham:computeQuick(cx, cy, r, callback)
local visited={}
callback(cx,cy,1, 1)
visited[ROT.Point(cx, cy):hashCode()]=0
visited[Point(cx, cy):hashCode()]=0

local thePoints=self:_getCircle(cx, cy, r+3)
for _,p in pairs(thePoints) do
local x,y=p[1],p[2]
local line=ROT.Line(cx,cy,x, y):getPoints()
local line=Line(cx,cy,x, y):getPoints()
for i=2,#line.points do
local point=line.points[i]
if self:_oob(cx-point.x, cy-point.y, r) then break end
Expand Down
115 changes: 49 additions & 66 deletions src/rot/lighting.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
local ROT = require((...):gsub(('.[^./\\]*'):rep(1) .. '$', ''))
local Lighting = ROT.Class:extend("Lighting")

local PointSet = ROT.Type.PointSet
local Grid = ROT.Type.Grid

--- Constructor.
-- @tparam function reflectivityCallback Callback to retrieve cell reflectivity must return float(0..1)
-- @tparam int reflectivityCallback.x x-position of cell
Expand All @@ -16,9 +19,9 @@ function Lighting:init(reflectivityCallback, options)
self._reflectivityCallback=reflectivityCallback
self._options={passes=1, emissionThreshold=100, range=10}
self._fov=nil
self._lights={}
self._reflectivityCache={}
self._fovCache={}
self._lights = Grid()
self._reflectivityCache = Grid()
self._fovCache = Grid()

if options then for k,_ in pairs(options) do self._options[k]=options[k] end end
end
Expand All @@ -31,7 +34,7 @@ end
-- @see ROT.FOV.Bresenham
function Lighting:setFOV(fov)
self._fov=fov
self._fovCache={}
self._fovCache = Grid()
return self
end

Expand All @@ -42,12 +45,8 @@ end
-- @treturn ROT.Lighting self
-- @see ROT.Color
function Lighting:setLight(x, y, color)
local key=x..','..y
if color then
self._lights[key]=type(color)=='string' and ROT.Color.fromString(color) or color
else
self._lights[key]=nil
end
self._lights:setCell(x, y,
type(color)=='string' and ROT.Color.fromString(color) or color or nil)
return self
end

Expand All @@ -56,14 +55,17 @@ end
-- @tparam function lightingCallback Will be called with (x, y, color) for every lit cell
-- @treturn ROT.Lighting self
function Lighting:compute(lightingCallback)
local doneCells={}
local emittingCells={}
local litCells={}

for k,_ in pairs(self._lights) do
local light=self._lights[k]
if not emittingCells[k] then emittingCells[k]={ 0, 0, 0 } end
ROT.Color.add_(emittingCells[k], light)
local doneCells = PointSet()
local emittingCells = Grid()
local litCells = Grid()

for _, x, y, light in self._lights:each() do
local emitted = emittingCells:getCell(x, y)
if not emitted then
emitted = { 0, 0, 0 }
emittingCells:setCell(x, y, emitted)
end
ROT.Color.add_(emitted, light)
end

for i=1,self._options.passes do
Expand All @@ -73,58 +75,46 @@ function Lighting:compute(lightingCallback)
end
end

for k,_ in pairs(litCells) do
local parts=k:split(',')
local x=tonumber(parts[1])
local y=tonumber(parts[2])
lightingCallback(x, y, litCells[k])
for _, x, y, value in litCells:each() do
lightingCallback(x, y, value)
end

return self

end

function Lighting:_emitLight(emittingCells, litCells, doneCells)
for k,_ in pairs(emittingCells) do
local parts=k:split(',')
local x=tonumber(parts[1])
local y=tonumber(parts[2])
self:_emitLightFromCell(x, y, emittingCells[k], litCells)
doneCells[k]=1
for _, x, y, v in emittingCells:each() do
self:_emitLightFromCell(x, y, v, litCells)
doneCells:push(x, y)
end
return self
end

function Lighting:_computeEmitters(litCells, doneCells)
local result={}
local result=Grid()
if not litCells then return nil end
for k,_ in pairs(litCells) do
if not doneCells[k] then
local color=litCells[k]

local reflectivity
if self._reflectivityCache and self._reflectivityCache[k] then
reflectivity=self._reflectivityCache[k]
else
local parts=k:split(',')
local x=tonumber(parts[1])
local y=tonumber(parts[2])
reflectivity=self:_reflectivityCallback(x, y)
self._reflectivityCache[k]=reflectivity
for _, x, y, color in litCells:each() do
if not doneCells:find(x, y) then

local reflectivity = self._reflectivityCache:getCell(x, y)
if not reflectivity then
reflectivity = self:_reflectivityCallback(x, y)
self._reflectivityCache:setCell(x, y, reflectivity)
end

if reflectivity>0 then
local emission ={}
local intensity=0
for l,_ in pairs(color) do
if l~='a' then
local part=math.floor(color[l]*reflectivity)
for l, c in ipairs(color) do
if l < 4 then
local part=math.floor(c*reflectivity)
emission[l]=part
intensity=intensity+part
end
end
if intensity>self._options.emissionThreshold then
result[k]=emission
result:setCell(x, y, emission)
end
end
end
Expand All @@ -134,40 +124,33 @@ function Lighting:_computeEmitters(litCells, doneCells)
end

function Lighting:_emitLightFromCell(x, y, color, litCells)
local key=x..','..y
local fov
if self._fovCache[key] then fov=self._fovCache[key]
else fov=self:_updateFOV(x, y)
end
local formFactor
for k,_ in pairs(fov) do
formFactor=fov[k]
if not litCells[k] then
litCells[k]={ 0, 0, 0 }
local fov = self._fovCache:getCell(x, y) or self:_updateFOV(x, y)
for _, x, y, formFactor in fov:each() do
local cellColor = litCells:getCell(x, y)
if not cellColor then
cellColor = { 0, 0, 0 }
litCells:setCell(x, y, cellColor)
end
for l, c in ipairs(color) do
if l < 4 then
litCells[k][l]=litCells[k][l]+math.floor(c*formFactor)
end
for l = 1, 3 do
cellColor[l] = cellColor[l] + math.floor(color[l]*formFactor)
end
end
return self
end

function Lighting:_updateFOV(x, y)
local key1=x..','..y
local cache={}
self._fovCache[key1]=cache
local cache = Grid()
self._fovCache:setCell(x, y, cache)
local range=self._options.range
local function cb(x, y, r, vis)
local key2=x..','..y
local formFactor=vis*(1-r/range)
if formFactor==0 then return end
cache[key2]=formFactor
cache:setCell(x, y, formFactor)
end
self._fov:compute(x, y, range, cb)

return cache
end

return Lighting

Loading

0 comments on commit 8a7fa1d

Please sign in to comment.