Files
wnsrc/lua/stormfox2/functions/sh_fog.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

288 lines
8.9 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/
--]]
--[[-------------------------------------------------------------------------
Use the map-data to set a minimum and maximum fogdistance
---------------------------------------------------------------------------]]
StormFox2.Setting.AddSV("enable_svfog",true,nil, "Effects")
if CLIENT then StormFox2.Setting.AddCL("enable_fog",true, "sf_enable_fog") end
StormFox2.Setting.AddSV("enable_fogz",false,nil, "Effects")
StormFox2.Setting.AddSV("overwrite_fogdistance",-1,nil, "Effects", -1, 800000)
StormFox2.Setting.SetType("overwrite_fogdistance","special_float")
StormFox2.Setting.AddSV("allow_fog_change",engine.ActiveGamemode() == "sandbox",nil, "Effects")
StormFox2.Fog = {}
-- Local functions
local function fogEnabledCheck()
if not StormFox2.Setting.SFEnabled() then return false end
if not StormFox2.Setting.GetCache("enable_svfog", true) then return false end
if not StormFox2.Setting.GetCache("allow_fog_change", false) then return true end
return StormFox2.Setting.GetCache("enable_fog", true)
end
local _fS, _fE, _fD = 0,400000,1
local function fogStart( f )
_fS = f
end
local function fogEnd( f )
_fE = f
end
local function fogDensity( f )
_fD = f
end
local function getFogFill()
if _fS >= 0 then return 0 end
return -_fS / (_fE - _fS) * _fD * 0.1
end
-- Makes it so fog isn't linear
local e = 2.71828
local function fogCalc(b, a, p)
if a == b then return a end
p = e^(-8.40871*p)
local d = b - a
return a + d * p
end
---Returns the start of the fog.
---@return number
---@shared
function StormFox2.Fog.GetStart()
return math.max(0, _fS)
end
---Returns the end of fog.
---@return number
---@shared
function StormFox2.Fog.GetEnd()
return _fE
end
-- Locate / Calculate the default fog-data
local map_distance, map_farZ = -1, -1
local tab = StormFox2.Map.FindClass("env_fog_controller")
if #tab < 1 then
map_distance = 400000
else
-- Set a minimum
map_distance = 6000
for _, data in ipairs(tab) do
map_farZ = math.max(map_farZ, data.farz)
-- Calculate fog-brightness. We can use this to scale the map-distance up to match the fog.
local col_brightness = 1
local density = (tonumber( data.fogmaxdensity or "" ) or 1)
if data.fogcolor then
local fcol = string.Explode(" ", data.fogcolor)
col_brightness = (0.2126 * fcol[1] + 0.7152 * fcol[2] + 0.0722 * fcol[3]) / 255
end
density = density * col_brightness
map_distance = math.max(((data.fogend or 6000) / density), map_distance)
end
-- It is important we don't overshoot farZ
if map_farZ > 0 then
map_distance = math.min(map_distance, map_farZ)
end
end
---Returns the fog-amount. 0 - 1
---@return number
---@shared
function StormFox2.Fog.GetAmount()
return 1 - _fE / map_distance
end
---Returns the fog-distance ( Same as StormFox2.Fog.GetEnd(), but uses the map as a fallback )
---@return number
---@shared
function StormFox2.Fog.GetDistance()
return _fE or map_distance
end
-- Returns the default fog-distance for clear weather.
local function getDefaultDistance()
local ov = StormFox2.Setting.GetCache("overwrite_fogdistance",-1)
if ov > -1 then
return ov
end
return map_distance
end
-- Returns the fog-distance.
local function getAimDistance(bFinal)
local cW = StormFox2.Weather.GetCurrent()
local ov = getDefaultDistance()
if cW.Name == "Clear" then return ov end
local perc = bFinal and StormFox2.Weather.GetFinishPercent() or StormFox2.Weather.GetPercent()
local a = math.min(cW:Get('fogDistance'), ov)
if a == ov then return ov end -- This weathertype doesn't change the fog .. or is higer than default
if not a or perc <= 0 then return ov end -- If weather percent is 0 or under. Return the "clear" distance.
if perc >= 1 then return a end -- If weather is higer or equal to 1, return the base value.
return fogCalc(ov, a, perc)
end
if SERVER then
local loaded, data, f_FogZ = true
---Sets the fogZ distance. Seems buggy atm, use at own rist.
---@param num number
---@param nTimer number
---@server
function StormFox2.Fog.SetZ(num, nTimer)
timer.Remove( "sf_fog_timer" )
if nTimer then
timer.Create("sf_fog_timer", nTimer, 1, function()
StormFox2.Fog.SetZ(num)
end)
return
end
f_FogZ = num
if not loaded then
data = num
return
end
if not num then num = map_farZ end
for k,v in ipairs( StormFox2.Ent.env_fog_controllers or {} ) do
if not IsValid(v) then continue end
v:SetKeyValue("farz", num)
end
end
---Returns the fogz distance.
---@return number
---@server
function StormFox2.Fog.GetZ()
if not StormFox2.Setting.Get("enable_fogz", false) then return map_farZ end
return f_FogZ or (StormFox2.Fog.GetDistance() + 100)
end
hook.Add("StormFox2.PostEntityScan", "StormFox2.Fog.Initz", function()
loaded = true
if data then
StormFox2.Fog.SetZ(data)
data = nil
end
end)
hook.Add("StormFox2.weather.postchange", "StormFox2.Fog.Updater", function( sName ,nPercentage, nDelta )
local old_fE = _fE or map_distance
_fE = getAimDistance(true)
if _fE > 3000 then
_fS = 0
else
_fS = _fE - 3000
end
-- Check fogZ distance
if not StormFox2.Setting.Get("enable_fogz", false) then return end
if old_fE > _fE then -- The fog shriks
StormFox2.Fog.SetZ(_fE * 2 + 100, nDelta)
elseif old_fE < _fE then -- The fog grows
StormFox2.Fog.SetZ(_fE * 2 + 100)
end
end)
timer.Create("StormFox2.Fog.SVUpdate", 2, 0, function()
local cWD = StormFox2.Weather.GetCurrent().Dynamic or {}
if cWD.fogDistance then return end
_fE = getAimDistance(true)
end)
---Returns the fog-color.
---@return Color
---@server
function StormFox2.Fog.GetColor()
return StormFox2.Mixer.Get("fogColor", StormFox2.Mixer.Get("bottomColor",color_white) ) or color_white
end
return
end
----- Fog render and clientside -----
-- Fog logic and default render
-- Returns the "distance" to outside
local f_outside = 0
local f_indoor = -1
local f_lastDist = map_distance
local function outSideVar()
local env = StormFox2.Environment.Get()
if env.outside then
return f_outside
end
if not env.nearest_outside then
return f_indoor
end
local dis = StormFox2.util.RenderPos():Distance(env.nearest_outside) / 300
if dis > 1 then
return f_indoor
end
return dis
end
hook.Add("Think", "StormFox2.Fog.Updater", function()
-- Figure out the fogdistance we should have
local f_envfar = outSideVar()
local fog_dis = getAimDistance()
local fog_indoor = StormFox2.Mixer.Get("fogIndoorDistance",3000)
if f_envfar == f_indoor then -- Indoors
fog_dis = math.max(fog_dis, fog_indoor)
elseif f_envfar ~= f_outside then
fog_dis = Lerp(f_envfar + 0.1, fog_dis, fog_indoor)
end
_fE = math.Approach(_fE, fog_dis, math.max(10, _fE) * FrameTime())
if _fE > 3000 then
_fS = 0
else
_fS = _fE - 3000
end
end)
local f_Col = color_white
local SkyFog = function(scale)
if _fD <= 0 then return end
if not scale then scale = 1 end
if not fogEnabledCheck() then return end
f_Col = StormFox2.Mixer.Get("fogColor", StormFox2.Mixer.Get("bottomColor") ) or color_white
-- Apply fog
local tD = StormFox2.Thunder.GetLight() / 2055
render.FogMode( 1 )
render.FogStart( StormFox2.Fog.GetStart() * scale )
render.FogEnd( StormFox2.Fog.GetEnd() * scale )
render.FogMaxDensity( (_fD - tD) * 0.999 )
render.FogColor( f_Col.r,f_Col.g,f_Col.b )
return true
end
hook.Add("SetupSkyboxFog","StormFox2.Sky.Fog",SkyFog)
hook.Add("SetupWorldFog","StormFox2.Sky.WorldFog",SkyFog)
-- Returns the fog-color.
function StormFox2.Fog.GetColor()
return f_Col or color_white
end
-- Additional Fog render
local m_fog = Material('stormfox2/effects/fog_sphere')
local l_fogz = 0
hook.Add("StormFox2.2DSkybox.FogLayer", "StormFox2.Fog.RSky", function( viewPos )
if not fogEnabledCheck() then return end
local v = Vector(math.cos( viewPos.y ), math.sin( viewPos.y ), 0)
m_fog:SetVector("$color", Vector(f_Col.r,f_Col.g,f_Col.b) / 255)
m_fog:SetFloat("$alpha", math.Clamp(5000 / _fE, 0, 1))
render.SetMaterial( m_fog )
local tH = math.min(StormFox2.Environment.GetZHeight(), 2100)
if tH ~= l_fogz then
local delta = math.abs(l_fogz, tH) / 2
l_fogz = math.Approach( l_fogz, tH, math.max(delta, 10) * 5 * FrameTime() )
end
local h = 2000 + 6000 * StormFox2.Fog.GetAmount()
render.DrawSphere( Vector(0,0,h - l_fogz * 4) , -30000, 30, 30, color_white)
end)
local mat = Material("color")
local v1 = Vector(1,1,1)
hook.Add("PostDrawOpaqueRenderables", "StormFox2.Sky.FogPDE", function()
if _fS >= 0 or _fD <= 0 then return end
if not fogEnabledCheck() then return end
local a = getFogFill()
mat:SetVector("$color",Vector(f_Col.r / 255,f_Col.g / 255,f_Col.b / 255))
mat:SetFloat("$alpha",a)
render.SetMaterial(mat)
render.DrawScreenQuad()
mat:SetVector("$color",v1)
mat:SetFloat("$alpha",1)
end)