myspace / CommonLua /CameraMakeTransparent.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
13.4 kB
-- make objects that obstruct the view transparent (camera3p)
if FirstLoad then
g_CameraMakeTransparentEnabled = false
g_updateStepOpacityThread = false
g_CameraMakeTransparentThread = false
g_CMT_fade_out = false
g_CMT_fade_in = false
g_CMT_hidden = false
g_CMT_replaced = false
g_CMT_replaced_destroy = false
end
local CMT_fade_out = g_CMT_fade_out
local CMT_fade_in = g_CMT_fade_in
local CMT_hidden = g_CMT_hidden
local CMT_replaced = g_CMT_replaced
local CMT_replaced_destroy = g_CMT_replaced_destroy
local transparency_enum_flags = const.efCameraMakeTransparent
local transparency_surf_flags = EntitySurfaces.Walk + EntitySurfaces.Collision
local obstruct_view_refresh_time = const.ObstructViewRefreshTime
local fade_in_time = const.ObstructOpacityFadeInTime
local fade_out_time = const.ObstructOpacityFadeOutTime
local obstruct_opacity = const.ObstructOpacity
local obstruct_opacity_refresh_time = const.ObstructOpacityRefreshTime
local refresh_time = Max(obstruct_opacity_refresh_time, Max(fade_out_time, fade_in_time) / (100 - Clamp(obstruct_opacity, 0, 99)))
local opacity_change_fadein = fade_in_time <= 0 and 100 or (100 - obstruct_opacity) * refresh_time / fade_in_time
local opacity_change_fadeout = fade_out_time <= 0 and 100 or (100 - obstruct_opacity) * refresh_time / fade_out_time
local function ResetLists()
g_CMT_fade_out = {}
g_CMT_fade_in = {}
g_CMT_hidden = {}
g_CMT_replaced = {}
g_CMT_replaced_destroy = {}
CMT_fade_out = g_CMT_fade_out
CMT_fade_in = g_CMT_fade_in
CMT_hidden = g_CMT_hidden
CMT_replaced = g_CMT_replaced
CMT_replaced_destroy = g_CMT_replaced_destroy
end
if FirstLoad then
ResetLists()
end
function OnMsg.DoneMap()
g_updateStepOpacityThread = false
g_CameraMakeTransparentThread = false
ResetLists()
end
local function UpdateObstructors_StepOpacity(obstructors)
local view = 1
CMT_fade_in[view] = CMT_fade_in[view] or {}
CMT_fade_out[view] = CMT_fade_out[view] or {}
local vfade_in = CMT_fade_in[view]
local vfade_out = CMT_fade_out[view]
-- move fade_out objects to fade_in
for i = #vfade_out, 1, -1 do
local o = vfade_out[i]
if not (obstructors and obstructors[o]) then
assert(not vfade_in[o])
table.remove(vfade_out, i)
vfade_out[o] = nil
if o:GetOpacity() < 100 then
vfade_in[#vfade_in + 1] = o
vfade_in[o] = true
end
end
end
-- set the new fade_out
if obstructors then
for i = 1, #obstructors do
local o = obstructors[i]
if not vfade_out[o] then
vfade_out[#vfade_out + 1] = o
vfade_out[o] = true
end
if vfade_in[o] then
table.remove_entry(vfade_in, o)
vfade_in[o] = nil
end
end
end
end
local function UpdateObstructors_Hidden(view, obstructors)
-- logic for objects for which hide/show is immediate
local hidden_for_view = CMT_hidden[view]
CMT_hidden[view] = obstructors
if obstructors then
for i = 1, #obstructors do
local o = obstructors[i]
o:SetOpacity(0)
obstructors[o] = true
end
end
if hidden_for_view then
for i = 1, #hidden_for_view do
local o = hidden_for_view[i]
if IsValid(o) and not (obstructors and obstructors[o]) then
o:SetOpacity(100) -- show what was hidden in the previous tick
end
end
end
end
local function ClearObstructors()
for o in pairs(CMT_replaced) do
o:DestroyReplacement()
end
for view = 1, camera.GetViewCount() do
local vfade_out = CMT_fade_out[view]
if vfade_out then
for i = 1, #vfade_out do
local o = vfade_out[i]
if IsValid(o) then
o:SetOpacity(100)
end
end
end
local vfade_in = CMT_fade_in[view]
if vfade_in then
for i = 1, #vfade_in do
local o = vfade_in[i]
if IsValid(o) then
o:SetOpacity(100)
end
end
end
local hv = CMT_hidden[view]
if hv then
for i = 1, #hv do
local o = hv[i]
if IsValid(o) then
o:SetOpacity(100)
end
end
end
end
ResetLists()
end
local function UpdateObstructors(view, get_obstructors)
local success, obstructors, obstructors_immediate = procall(get_obstructors, view)
UpdateObstructors_StepOpacity(obstructors)
UpdateObstructors_Hidden(view, obstructors_immediate)
end
local function UpdateObstructorsRefresh(cam, get_obstructors)
local refresh_time = obstruct_view_refresh_time
while true do
while IsEditorActive() do
Sleep(2 * refresh_time)
end
-- restore opacity of fade_in/fade_out objects
if not g_CameraMakeTransparentEnabled or not cam.IsActive() then
ClearObstructors()
while not g_CameraMakeTransparentEnabled or not cam.IsActive() do
Sleep(refresh_time)
end
end
for view = 1, camera.GetViewCount() do
UpdateObstructors(view, get_obstructors)
end
Sleep(refresh_time)
end
end
local function UpdateStepOpacity(view)
local vfade_out = CMT_fade_out[view]
if vfade_out then
for i = #vfade_out, 1, -1 do
local o = vfade_out[i]
if not IsValid(o) then
vfade_out[o] = nil
table.remove(vfade_out, i)
else
local new_opacity = o:GetOpacity() - opacity_change_fadeout
if new_opacity < obstruct_opacity then
new_opacity = obstruct_opacity
end
o:SetOpacity(new_opacity)
end
end
end
local vfade_in = CMT_fade_in[view]
if vfade_in then
for i = #vfade_in, 1, -1 do
local o = vfade_in[i]
local keep
if IsValid(o) then
local new_opacity = Min(100, o:GetOpacity() + opacity_change_fadein)
o:SetOpacity(new_opacity)
keep = new_opacity < 100
end
if not keep then
vfade_in[o] = nil
table.remove(vfade_in, i)
end
end
end
end
local function UpdateStepOpacityRefresh()
local refresh_time = refresh_time
while true do
for view = 1, camera.GetViewCount() do
UpdateStepOpacity(view)
end
Sleep(refresh_time)
end
end
local DistSegmentToPt = DistSegmentToPt
local camera_clip_extend_radius = const.CameraClipExtendRadius
local offset_z_150cm = 150*guic
local cone_radius_max = config.CameraTransparencyConeRadiusMax
local cone_radius_min = config.CameraTransparencyConeRadiusMin
if FirstLoad then
draw_transparency_cone = false
end
function ToggleTransparencyCone()
DbgClearVectors()
draw_transparency_cone = not draw_transparency_cone
end
local hide_filter = function(u, eye)
local posx, posy, posz = u:GetVisualPosXYZ()
local scale = u:GetScale()
local dist_to_eye = DistSegmentToPt(posx, posy, posz, 0, 0, u.height * scale / 100, eye, true)
return dist_to_eye < u.camera_radius * scale / 100 + camera_clip_extend_radius
end
local col_exec = function(o, list)
if not list[o] then
list[#list + 1] = o
list[o] = true
end
end
local function GetViewObstructorsCamera3p(view)
local eye = camera.GetEye(view)
local lookat = camera3p.GetLookAt(view)
if not eye or not eye:IsValid() then
return
end
local to_fade, to_fade_count
local to_hide = MapGet(eye, 4*guim, "Unit", hide_filter, eye) or {}
for i = 1, #to_hide do
to_hide[ to_hide[i] ] = true
end
for loc_player = 1, LocalPlayersCount do
local obj = GetPlayerControlCameraAttachedObj(loc_player)
if obj and obj:IsValidPos() then
local posx, posy, posz = obj:GetVisualPosXYZ()
local err1, to_fade1 = AsyncIntersectConeWithObstacles(
eye, point(posx, posy, posz + offset_z_150cm),
cone_radius_max, cone_radius_min,
transparency_enum_flags,
transparency_surf_flags,
draw_transparency_cone)
assert(not err1, err1)
if to_fade1 then
if to_fade then
for i = 1, #to_fade1 do
local o = to_fade1[i]
if not to_fade[o] then
to_fade_count = to_fade_count + 1
to_fade[to_fade_count] = o
to_fade[o] = true
end
end
else
to_fade = to_fade1
to_fade_count = #to_fade
for i = 1, to_fade_count do
to_fade[ to_fade[i] ] = true
end
end
end
end
end
if to_fade then
for i = 1, to_fade_count do
local col = to_fade[i]:GetRootCollection()
if col and not to_fade[col] then
to_fade[col] = true
local col_areapoint1 = eye
local col_areapoint2 = lookat
MapForEach(
col_areapoint1, col_areapoint2, 50*guim,
"attached", false, "collection", col.Index, true,
const.efVisible, col_exec , to_fade)
end
end
end
return to_fade, to_hide
end
function RestartCameraMakeTransparent()
StopCameraMakeTransparent()
if g_CameraMakeTransparentEnabled then
g_CameraMakeTransparentThread = CreateMapRealTimeThread(UpdateObstructorsRefresh, camera3p, GetViewObstructorsCamera3p)
g_updateStepOpacityThread = CreateMapRealTimeThread(UpdateStepOpacityRefresh)
end
end
function StopCameraMakeTransparent()
ClearObstructors()
if g_updateStepOpacityThread then
DeleteThread(g_updateStepOpacityThread)
g_updateStepOpacityThread = false
end
if g_CameraMakeTransparentThread then
DeleteThread(g_CameraMakeTransparentThread)
g_CameraMakeTransparentThread = false
end
end
OnMsg.NewMapLoaded = RestartCameraMakeTransparent
OnMsg.LoadGame = RestartCameraMakeTransparent
OnMsg.GameEnterEditor = StopCameraMakeTransparent
DefineClass.CameraTransparentWallReplacement = {
__parents = { "CObject", "ComponentAttach" },
flags = { efCameraMakeTransparent = false, efCameraRepulse = true, efSelectable = false, efWalkable = false, efCollision = false, efApplyToGrids = false, efShadow = false },
properties =
{
{ id = "CastShadow", name = "Shadow from All", editor = "bool", default = false },
},
}
local function CameraSpecialWallReplaceObjects(o)
return { "(default)", "place_default", "" }
end
DefineClass.CameraSpecialWall = {
__parents = { "Object" },
flags = { efCameraMakeTransparent = true, efCameraRepulse = false },
properties = {
{ id = "TransparentReplace", editor = "combo", items = CameraSpecialWallReplaceObjects },
},
TransparentReplace = "(default)",
replace_default = "",
replace_height_min = -guim,
replace_height_max = guim,
}
function OnMsg.ClassesPostprocess()
-- create unique GetAction and GetActionEnd functions per class
local replace_default = {}
ClassDescendants("CameraSpecialWall", function(class_name, class, replace_default)
if class.replace_default == "" then
local classname = class:GetEntity() .. "_Base"
if g_Classes[classname] then
replace_default[class] = classname
end
end
local properties = class.properties
local idx = table.find(properties, "id", "OnCollisionWithCamera")
if idx then
local idx_old = table.find(properties, "id", "TransparentReplace")
local prop = properties[idx_old]
table.remove(properties, idx_old)
table.insert(properties, idx + (idx < idx_old and 1 or 0), prop)
end
end, replace_default)
for class, value in pairs(replace_default) do
class.replace_default = value
end
end
local default_color = RGBA(128, 128, 128, 0)
local default_roughness = 0
local default_metallic = 0
function CameraSpecialWall:PlaceReplacement()
local replacement = CMT_replaced[self]
if replacement then
CMT_replaced_destroy[self] = nil
return
end
local classname = self.TransparentReplace
if classname == "place_default" then
classname = self.replace_default
elseif classname == "(default)" then
classname = self.replace_default
local pos = self:GetPos()
local height = pos:z() and pos:z() - GetWalkableZ(pos) or 0
if height < self.replace_height_min or height > self.replace_height_max then
classname = ""
elseif self:RotateAxis(0,0,4096):z() < 2048 then
-- inclined more then 45 degrees
classname = ""
end
end
local replaced_base
if classname ~= "" then
local color1, roughness1, metallic1 = self:GetColorizationMaterial(1)
local color2, roughness2, metallic2 = self:GetColorizationMaterial(2)
local color3, roughness3, metallic3 = self:GetColorizationMaterial(3)
local components = 0
if (color1 ~= default_color or roughness1 ~= default_roughness or metallic1 ~= default_metallic) or
(color2 ~= default_color or roughness2 ~= default_roughness or metallic2 ~= default_metallic) or
(color3 ~= default_color or roughness3 ~= default_roughness or metallic3 ~= default_metallic) then
components = const.cofComponentColorizationMaterial
end
replaced_base = PlaceObject(classname, nil, components)
replaced_base:SetMirrored(self:GetMirrored())
replaced_base:SetAxis(self:GetAxis())
replaced_base:SetAngle(self:GetAngle())
replaced_base:SetScale(self:GetScale())
replaced_base:SetColorModifier(self:GetColorModifier())
if components == const.cofComponentColorizationMaterial then
replaced_base:SetColorizationMaterial(1, color1, roughness1, metallic1)
replaced_base:SetColorizationMaterial(2, color2, roughness2, metallic2)
replaced_base:SetColorizationMaterial(3, color3, roughness3, metallic3)
end
local anim = self:GetStateText()
if anim ~= "idle" and replaced_base:HasState(anim) and not replaced_base:IsErrorState(anim) then
replaced_base:SetState(anim)
end
replaced_base:SetPos(self:GetVisualPosXYZ())
end
CMT_replaced[self] = replaced_base or true
end
function CameraSpecialWall:DestroyReplacement(delay)
local obj = CMT_replaced[self]
if obj then
if obj == true then
CMT_replaced[self] = nil
return
end
if (delay or 0) == 0 then
CMT_replaced[self] = nil
CMT_replaced_destroy[self] = nil
DoneObject(obj)
elseif not CMT_replaced_destroy[self] then
CMT_replaced_destroy[self] = RealTime() + delay
end
end
end
function CameraSpecialWall:SetOpacity(opacity)
if opacity < 100 then
self:PlaceReplacement()
else
self:DestroyReplacement()
end
Object.SetOpacity(self, opacity)
end