| if FirstLoad then | |
| g_VSDbgVisModeThread = false | |
| restoreDbgValue = false | |
| g_VSDbgMode = false | |
| end | |
| function OnMsg.NewMapLoaded() | |
| g_VSDbgVisModeThread = false | |
| g_VSDbgMode = false | |
| end | |
| local dbgVectorsOffset = 200 | |
| local z_vector = point(0,0,3000) | |
| local vs_dbg_vis_voxel_range = 8 | |
| local last_cam, last_lookat, last_cursor_slab | |
| local function PlaceLitVector(pos) | |
| local v = GetVoxelStealthParams(pos) | |
| if band(v, const.vsFlagIlluminated) ~= 0 then | |
| DbgAddVector(pos:SetX(pos:x() - dbgVectorsOffset), z_vector, const.clrWhite) | |
| end | |
| if band(v, const.vsFlagTallGrass) ~= 0 then | |
| DbgAddVector(pos:SetX(pos:x() + dbgVectorsOffset), z_vector, const.clrGreen) | |
| end | |
| end | |
| local function PlaceCursorLitVectors(pos) | |
| if not pos then return end | |
| local _, overall_illum, lights, lights_illum = DebugGetVoxelStealthParams(pos) | |
| for idx, l in ipairs(lights) do | |
| if IsValid(l) then | |
| local l_pos = l:GetPos() | |
| DbgAddVector(l_pos, pos - l_pos, const.clrYellow) | |
| local text = string.format("%.2f / %.2f", lights_illum[idx], const.vsIlluminationThreshold) | |
| DbgAddText(text, (l_pos + pos) / 2, const.clrYellow, nil, const.clrBlack) | |
| end | |
| end | |
| local text = string.format("Overall: %.2f/%.2f", overall_illum, const.vsIlluminationThreshold) | |
| DbgAddText(text, pos, const.clrYellow, nil, const.clrBlack) | |
| end | |
| local function PlaceLitVectorsAround(pos_around) | |
| if not pos_around then return end | |
| DbgAddVector(pos_around, z_vector * 2, const.clrMagenta) | |
| local x, y, z = pos_around:xyz() | |
| local pt = point(x - vs_dbg_vis_voxel_range, y - vs_dbg_vis_voxel_range, z - vs_dbg_vis_voxel_range) | |
| for i = -vs_dbg_vis_voxel_range, vs_dbg_vis_voxel_range do | |
| for j = -vs_dbg_vis_voxel_range, vs_dbg_vis_voxel_range do | |
| for k = -2 * vs_dbg_vis_voxel_range, 2 * vs_dbg_vis_voxel_range do | |
| local pos = SnapToPassSlab(x + i * const.SlabSizeX, y + j * const.SlabSizeY, z + k * const.SlabSizeZ) | |
| if pos then | |
| PlaceLitVector(pos) | |
| end | |
| end | |
| end | |
| end | |
| end | |
| local function PlaceMapAreaLitVoxels() | |
| local sizex, sizey = terrain.GetMapSize() | |
| local bbox = box(0, 0, sizex, sizey) | |
| ForEachStealthParamVoxel(bbox, const.vsFlagIlluminated + const.vsFlagTallGrass, function(pos, stealth_mask) | |
| pos = pos:IsValidZ() and pos or pos:SetTerrainZ() | |
| if band(stealth_mask, const.vsFlagIlluminated) ~= 0 then | |
| DbgAddVector(pos:SetX(pos:x() - dbgVectorsOffset), z_vector, const.clrWhite) | |
| end | |
| if band(stealth_mask, const.vsFlagTallGrass) ~= 0 then | |
| DbgAddVector(pos:SetX(pos:x() + dbgVectorsOffset), z_vector, const.clrGreen) | |
| end | |
| end) | |
| end | |
| local function GetCursorSlabForLitCheck() | |
| local cursor_obj = GetPreciseCursorObj() | |
| local cursor_slab = cursor_obj and cursor_obj:GetPos() or GetCursorPos() | |
| local z = cursor_slab:z() | |
| local lit_check = point(VoxelToWorld(WorldToVoxel(cursor_slab))) | |
| return z and lit_check:SetZ(z) or lit_check | |
| end | |
| local function LightAroundCursor(cursor_slab) | |
| hr.VoxelStealthParamsDebugCacheCleared = false | |
| PlaceCursorLitVectors(cursor_slab) | |
| end | |
| local function IsLitChanged(cursor_slab) | |
| return last_cursor_slab ~= cursor_slab or hr.VoxelStealthParamsDebugCacheCleared | |
| end | |
| local function DrawCameraVectors(cursor_slab, cam, lookat) | |
| DbgClear() | |
| local box = GetVoxelBox(0, GetCameraLookatTerrainPos()) | |
| PlaceLitVectorsAround(box and box:Center() or GetCameraLookatTerrainPos()) | |
| LightAroundCursor(cursor_slab) | |
| last_cursor_slab = cursor_slab | |
| last_cam = cam | |
| last_lookat = lookat | |
| end | |
| local function DrawMapVectors(cursor_slab) | |
| DbgClear() | |
| LightAroundCursor(cursor_slab) | |
| PlaceMapAreaLitVoxels() | |
| last_cursor_slab = cursor_slab | |
| end | |
| function CycleVSDbgVisMode() | |
| g_VSDbgMode = (g_VSDbgMode or 0) + 1 | |
| if g_VSDbgMode == 3 then | |
| g_VSDbgMode = false | |
| end | |
| if g_VSDbgMode == 1 then | |
| print("Voxel Stealth Dbg Camera Look At is ON") | |
| ResetVoxelStealthParamsCache() | |
| ShowLightShadowsStats(1000) | |
| if g_VSDbgVisModeThread then return end | |
| if not hr.VoxelStealthParamsDebug then | |
| restoreDbgValue = true | |
| hr.VoxelStealthParamsDebug = true | |
| end | |
| g_VSDbgVisModeThread = CreateMapRealTimeThread(function() | |
| repeat | |
| local cam, lookat = GetCamera() | |
| local cursor_slab = GetCursorSlabForLitCheck() | |
| if IsLitChanged(cursor_slab) or cam ~= last_cam or lookat ~= last_lookat then | |
| DrawCameraVectors(cursor_slab, cam, lookat) | |
| end | |
| Sleep(500) | |
| until false | |
| end) | |
| elseif g_VSDbgMode == 2 then | |
| print("Voxel Stealth Dbg Whole Map ON") | |
| ResetVoxelStealthParamsCache() | |
| ShowLightShadowsStats(1000) | |
| DeleteThread(g_VSDbgVisModeThread) | |
| g_VSDbgVisModeThread = CreateMapRealTimeThread(function() | |
| repeat | |
| local cursor_slab = GetCursorSlabForLitCheck() | |
| if IsLitChanged(cursor_slab) then | |
| DrawMapVectors(cursor_slab) | |
| end | |
| Sleep(500) | |
| until false | |
| end) | |
| else | |
| print("Voxel Stealth Dbg OFF") | |
| DbgClear() | |
| if restoreDbgValue then | |
| restoreDbgValue = false | |
| hr.VoxelStealthParamsDebug = false | |
| end | |
| DeleteThread(g_VSDbgVisModeThread) | |
| HideLightShadowsStats() | |
| g_VSDbgVisModeThread = false | |
| end | |
| end | |
| local s_StealthCacheProperty = { | |
| ["DetailClass"] = true, | |
| ["Exterior"] = true, | |
| ["Interior"] = true, | |
| ["AttenuationRadius"] = true, | |
| ["InteriorAndExteriorWhenHasShadowmap"] = true, | |
| ["Intensity"] = true, | |
| ["ConstantIntensity"] = true, | |
| ["ConeInnerAngle"] = true, | |
| ["ConeOuterAngle"] = true, | |
| } | |
| function OnMsg.GedPropertyEdited(_, obj, prop_id, old_value) | |
| if s_StealthCacheProperty[prop_id] and IsKindOf(obj, "Light") then | |
| Msg("LightsStateUpdated") | |
| end | |
| end | |
| local function check_light_objects(objects) | |
| local function is_light_edited(obj) | |
| if obj:IsKindOf("Light") then return true end | |
| local light_edited | |
| obj:ForEachAttach(function(attach) | |
| if is_light_edited(attach) then | |
| light_edited = true | |
| return "break" | |
| end | |
| end) | |
| return light_edited | |
| end | |
| for _, obj in ipairs(table.validate(objects)) do | |
| if is_light_edited(obj) then | |
| Msg("LightsStateUpdated") | |
| break | |
| end | |
| end | |
| end | |
| function OnMsg.EditorCallback(id, objects, ...) | |
| if id == "EditorCallbackRotate" or id == "EditorCallbackPlace" or id == "EditorCallbackMove" or id == "EditorCallbackDelete" then | |
| check_light_objects(objects) | |
| end | |
| end | |
| function OnMsg.EditorResetZ() | |
| local sel = editor.GetSel() | |
| if #(sel or empty_table) > 0 then | |
| check_light_objects(sel) | |
| end | |
| end | |