File size: 6,219 Bytes
b6a38d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
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