mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
285 lines
6.8 KiB
Lua
285 lines
6.8 KiB
Lua
|
|
--[[
|
||
|
|
| This file was obtained through the combined efforts
|
||
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
||
|
|
|
|
||
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
||
|
|
|
|
||
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||
|
|
--]]
|
||
|
|
|
||
|
|
-- Copyright © 2022-2072, Nak, https://steamcommunity.com/id/Nak2/
|
||
|
|
-- All Rights Reserved. Not allowed to be reuploaded.
|
||
|
|
-- License: https://github.com/Nak2/NikNaks/blob/main/LICENSE
|
||
|
|
|
||
|
|
local obj_tostring = "BSP %s"
|
||
|
|
local format = string.format
|
||
|
|
|
||
|
|
--- @class BSPObject
|
||
|
|
local meta = NikNaks.__metatables["BSP"]
|
||
|
|
local meta_leaf = NikNaks.__metatables["BSP Leaf"]
|
||
|
|
|
||
|
|
--[[The data is stored as an array of bit-vectors; for each cluster, a list of which other clusters are visible
|
||
|
|
from it are stored as individual bits (1 if visible, 0 if occluded) in an array, with the nth bit position
|
||
|
|
corresponding to the nth cluster. ]]
|
||
|
|
--- @param vis VisibilityInfo
|
||
|
|
--- @param offset number
|
||
|
|
local function getClusters( vis, offset, PVS )
|
||
|
|
local c = 0
|
||
|
|
local v = offset
|
||
|
|
local pvs_buffer = vis._bytebuff
|
||
|
|
local num_clusters = vis.num_clusters
|
||
|
|
|
||
|
|
while c <= num_clusters do
|
||
|
|
if pvs_buffer[v] == 0 then
|
||
|
|
v = v + 1
|
||
|
|
c = c + 8 * pvs_buffer[v]
|
||
|
|
else
|
||
|
|
local b = 1
|
||
|
|
|
||
|
|
while b ~= 0 do
|
||
|
|
if bit.band( pvs_buffer[v], b ) ~= 0 then
|
||
|
|
PVS[c] = true
|
||
|
|
end
|
||
|
|
|
||
|
|
b = bit.band( b * 2, 0xFF )
|
||
|
|
c = c + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
v = v + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--- PVS ( Potentially Visible Set )
|
||
|
|
do
|
||
|
|
--- @class PVSObject
|
||
|
|
--- @field __map BSPObject
|
||
|
|
local meta_pvs = {}
|
||
|
|
meta_pvs.__index = meta_pvs
|
||
|
|
meta_pvs.__tostring = "BSP PVS"
|
||
|
|
meta_pvs.MetaName = "BSP PVS"
|
||
|
|
NikNaks.__metatables["BSP PVS"] = meta_pvs
|
||
|
|
|
||
|
|
local DVIS_PVS = 1
|
||
|
|
|
||
|
|
--- Creates a new empty PVS-object.
|
||
|
|
--- @return PVSObject
|
||
|
|
function meta:CreatePVS()
|
||
|
|
local t = {}
|
||
|
|
t.__map = self
|
||
|
|
setmetatable( t, meta_pvs )
|
||
|
|
return t
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Uses the given ( or creates a new PVS-object ) and adds the position to it.
|
||
|
|
--- @param position Vector
|
||
|
|
--- @param PVS PVSObject?
|
||
|
|
--- @return PVSObject
|
||
|
|
function meta:PVSForOrigin( position, PVS )
|
||
|
|
PVS = PVS or self:CreatePVS()
|
||
|
|
|
||
|
|
PVS.__map = self
|
||
|
|
local cluster = self:ClusterFromPoint( position )
|
||
|
|
if cluster < 0 then return PVS end -- Empty cluster position.
|
||
|
|
|
||
|
|
local vis = self:GetVisibility()
|
||
|
|
local visofs = vis.VisData[cluster].PVS
|
||
|
|
|
||
|
|
getClusters( vis, visofs, PVS )
|
||
|
|
|
||
|
|
return PVS
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Returns true if the two positions are in same PVS.
|
||
|
|
--- @param position Vector
|
||
|
|
--- @param position2 Vector
|
||
|
|
--- @return boolean
|
||
|
|
function meta:PVSCheck( position, position2 )
|
||
|
|
local PVS = self:PVSForOrigin( position )
|
||
|
|
local cluster = self:ClusterFromPoint( position2 )
|
||
|
|
return PVS[cluster] or false
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
--- Adds the position to PVS
|
||
|
|
--- @param position Vector
|
||
|
|
--- @return self
|
||
|
|
function meta_pvs:AddPVS( position )
|
||
|
|
self.__map:PVSForOrigin( position, self )
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Removes the position from PVS
|
||
|
|
--- @param position Vector
|
||
|
|
--- @return self
|
||
|
|
function meta_pvs:RemovePVS( position )
|
||
|
|
for id in pairs( self.__map:PVSForOrigin( position ) ) do
|
||
|
|
if id ~= "__map" then self[id] = nil end
|
||
|
|
end
|
||
|
|
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Removes the leaf from PVS
|
||
|
|
--- @param leaf LeafObject
|
||
|
|
--- @return self PVSObject
|
||
|
|
function meta_pvs:RemoveLeaf( leaf )
|
||
|
|
self[leaf.cluster] = nil
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Returns true if the position is visible in the PVS
|
||
|
|
--- @param position Vector
|
||
|
|
--- @return boolean
|
||
|
|
function meta_pvs:TestPosition( position )
|
||
|
|
local cluster = self.__map:ClusterFromPoint( position )
|
||
|
|
return self[cluster] or false
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Create PVS from Leaf
|
||
|
|
--- @return PVSObject
|
||
|
|
function meta_leaf:CreatePVS()
|
||
|
|
local PVS = {}
|
||
|
|
PVS.__map = self.__map
|
||
|
|
setmetatable( PVS, meta_pvs )
|
||
|
|
if self.cluster < 0 then return PVS end -- Leaf invalid. Return empty PVS.
|
||
|
|
|
||
|
|
local vis = self.__map:GetVisibility()
|
||
|
|
local visofs = vis.VisData[self.cluster].PVS
|
||
|
|
|
||
|
|
getClusters( vis, visofs, PVS )
|
||
|
|
|
||
|
|
return PVS
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Returns a list of leafs within this PVS. Note: This is a bit slow.
|
||
|
|
function meta_pvs:GetLeafs()
|
||
|
|
local t = {}
|
||
|
|
local n = 1
|
||
|
|
local leafs = self.__map:GetLeafs()
|
||
|
|
|
||
|
|
for i = 1, #leafs do
|
||
|
|
local leaf = leafs[i]
|
||
|
|
local cluster = leaf.cluster
|
||
|
|
|
||
|
|
if cluster >= 0 and self[cluster] then
|
||
|
|
t[n] = leaf
|
||
|
|
n = n + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return t
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Returns true if the PVS has the given leaf
|
||
|
|
--- @param leaf LeafObject
|
||
|
|
--- @return boolean
|
||
|
|
function meta_pvs:HasLeaf( leaf )
|
||
|
|
if leaf.cluster < 0 then return false end
|
||
|
|
return self[leaf.cluster]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-- PAS
|
||
|
|
do
|
||
|
|
---@class PASObject
|
||
|
|
local meta_pas = {}
|
||
|
|
meta_pas.__index = meta_pas
|
||
|
|
meta_pas.__tostring = "BSP PAS"
|
||
|
|
meta_pas.MetaName = "BSP PAS"
|
||
|
|
NikNaks.__metatables["BSP PAS"] = meta_pas
|
||
|
|
local DVIS_PAS = 2
|
||
|
|
|
||
|
|
--- Creates a new empty PAS-object.
|
||
|
|
--- @return PASObject
|
||
|
|
function meta:CreatePAS()
|
||
|
|
return setmetatable( {}, meta_pas )
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Uses the given ( or creates a new PAS-object ) and adds the position to it.
|
||
|
|
--- @param position Vector
|
||
|
|
--- @param PAS PASObject?
|
||
|
|
--- @return PASObject?
|
||
|
|
function meta:PASForOrigin( position, PAS )
|
||
|
|
PAS = PAS or self:CreatePAS()
|
||
|
|
PAS.__map = self
|
||
|
|
|
||
|
|
local cluster = self:ClusterFromPoint( position )
|
||
|
|
local vis = self:GetVisibility()
|
||
|
|
if cluster < 0 then return end -- err
|
||
|
|
|
||
|
|
local visofs = vis.VisData[cluster].PAS
|
||
|
|
|
||
|
|
getClusters( vis, visofs, PAS )
|
||
|
|
|
||
|
|
return PAS
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Returns true if the two positions are in same PAS
|
||
|
|
--- @param position Vector
|
||
|
|
--- @param position2 Vector
|
||
|
|
--- @return boolean
|
||
|
|
function meta:PASCheck( position, position2 )
|
||
|
|
local PAS = self:PASForOrigin( position )
|
||
|
|
return PAS[self:ClusterFromPoint( position2 )] or false
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Adds the position to PAS
|
||
|
|
--- @param position Vector
|
||
|
|
--- @return PASObject self
|
||
|
|
function meta_pas:AddPAS( position )
|
||
|
|
self.__map:PASForOrigin( position, self )
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Removes the position from PAS
|
||
|
|
--- @param position Vector
|
||
|
|
--- @return PASObject self
|
||
|
|
function meta_pas:RemovePAS( position )
|
||
|
|
for id in pairs( self.__map:PASForOrigin( position ) ) do
|
||
|
|
if id ~= "__map" then self[id] = nil end
|
||
|
|
end
|
||
|
|
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Removes the leaf from PVS
|
||
|
|
--- @param leaf LeafObject
|
||
|
|
--- @return PASObject self
|
||
|
|
function meta_pas:RemoveLeaf( leaf )
|
||
|
|
self[leaf.cluster] = nil
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Returns true if the position is visible in the PAS
|
||
|
|
--- @param position Vector
|
||
|
|
--- @return boolean
|
||
|
|
function meta_pas:TestPosition( position )
|
||
|
|
local cluster = self.__map:ClusterFromPoint( position )
|
||
|
|
return self[cluster] or false
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Create PAS from Leaf
|
||
|
|
--- @return PASObject
|
||
|
|
function meta_leaf:CreatePAS()
|
||
|
|
local PAS = setmetatable( {}, meta_pas )
|
||
|
|
if self.cluster < 0 then return PAS end -- Leaf invalid. Return empty PVS.
|
||
|
|
|
||
|
|
local vis = self.__map:GetVisibility()
|
||
|
|
local visofs = vis[ self.cluster ][ DVIS_PAS ]
|
||
|
|
|
||
|
|
getClusters( vis, visofs, PAS )
|
||
|
|
|
||
|
|
return PAS
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Returns true if the PAS has the given leaf
|
||
|
|
--- @param leaf LeafObject
|
||
|
|
--- @return boolean
|
||
|
|
function meta_pas:HasLeaf( leaf )
|
||
|
|
if leaf.cluster < 0 then return false end
|
||
|
|
return self[leaf.cluster]
|
||
|
|
end
|
||
|
|
end
|