File size: 11,638 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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
 -- offset against voxel border
const.ContoursOffset = -80
const.ContoursOffset_Merc = -85
const.ContoursOffset_BorderlineAttack = const.ContoursOffset -90
const.ContoursOffset_BorderlineTurn = const.ContoursOffset
-- z offset
const.ContoursOffsetZ = 15*guic
const.ContoursOffsetZ_Merc = const.ContoursOffsetZ +30
const.ContoursOffsetZ_BorderlineAttack = const.ContoursOffsetZ 
const.ContoursOffsetZ_BorderlineTurn = const.ContoursOffsetZ 
-- width
const.ContoursWidth = 480 / 5
const.ContoursWidth_Merc = const.ContoursWidth
const.ContoursWidth_BorderlineAttack = const.ContoursWidth
const.ContoursWidth_BorderlineTurn = const.ContoursWidth
-- turn radius
const.ContoursRadius2D = 180
const.ContoursRadius2D_Merc = 180
const.ContoursRadius2D_Merc_Exploration = 500
const.ContoursRadiusVertical = 80
const.ContoursRadiusSteps = 8
-- voxel connectivity
const.ContoursPassConnection = false
const.ContoursTunnelMask =
	const.TunnelMaskWalk
	| const.TunnelMaskClimbDrop
	| const.TunnelTypeLadder
	| const.TunnelTypeJumpOver1
	| const.TunnelTypeDoor
	| const.TunnelTypeWindow


function GetRangeContour(voxels, contour_width, radius2D, offset, offsetz, voxel_pass_connection, tunnels_mask, exclude_voxels)
	if not voxels or #voxels == 0 then
		return
	end
	contour_width = contour_width or const.ContoursWidth
	radius2D = radius2D or const.ContoursRadius2D
	local radius_vertical = const.ContoursRadiusVertical
	offset = offset or const.ContoursOffset
	offsetz = offsetz or const.ContoursOffsetZ
	voxel_pass_connection = voxel_pass_connection or const.ContoursPassConnection
	tunnels_mask = tunnels_mask or const.ContoursTunnelMask
	local contours = GetContoursPStr(voxels, voxel_pass_connection, tunnels_mask, contour_width, radius2D, radius_vertical, offset, offsetz)
	return contours
end


local function RGBToModifier(r, g, b)
	local r = MulDivRound(r, 100, 255)
	local g = MulDivRound(g, 100, 255)
	local b = MulDivRound(b, 100, 255)
	return RGB(r, g, b)
end
function PlaceContourPolyline(contour, color, shader)
	local meshes = {
		SetVisible = function(self, value)
			for _, m in ipairs(self) do
				m:SetVisible(value)
			end
		end
	}
	shader = shader or "range_contour"
	if type(color) == "string" then
		color = Mesh.ColorFromTextStyle(color)
	else
		local r, g, b, opacity = GetRGBA(color)
		color = RGBToModifier(r, g, b)
	end
	for _, v_pstr in ipairs(contour) do
		local mesh = PlaceObject("Mesh")
		mesh:SetColorModifier(color)
		mesh:SetMesh(v_pstr)
		if not ProceduralMeshShaders[shader] then
			mesh:SetCRMaterial(shader)
		else
			mesh:SetShader(ProceduralMeshShaders[shader])
		end
		mesh:SetPos(0, 0, 0)
		table.insert(meshes, mesh)
	end
	return meshes
end

function PlaceSingleTileStaticContourMesh(color_textstyle_id, pos, exploration)
	local r = const.SlabSizeX / 2 + const.ContoursOffset_Merc
	local z = const.ContoursOffsetZ_Merc
	local contour = GetRectContourPStr(box(-r, -r, z, r, r, z), const.ContoursWidth_Merc, exploration and const.ContoursRadius2D_Merc_Exploration or const.ContoursRadius2D_Merc)
	local polyline = PlaceContourPolyline({contour}, color_textstyle_id)
	if pos then
		polyline[1]:SetPos(pos)
	end
	return polyline[1]
end

function DestroyMesh(mesh)
	if IsValid(mesh) then
		mesh:delete()
	end
end

function DestroyContourPolyline(meshes)
	if not meshes then return end
	for _, mesh in ipairs(meshes) do
		DestroyMesh(mesh)
	end
	table.iclear(meshes)
end

function ContourPolylineSetVisible(meshes, visible)
	for _, mesh in ipairs(meshes) do
		if IsValid(mesh) then
			if visible then
				mesh:SetEnumFlags(const.efVisible)
			else
				mesh:ClearEnumFlags(const.efVisible)
			end
		end
	end
end

function ContourPolylineSetColor(meshes, color_textstyle_id)
	for _, mesh in ipairs(meshes) do
		mesh:SetColorFromTextStyle(color_textstyle_id)
	end
end

function ContourPolylineSetShader(meshes, shader)
	shader = ProceduralMeshShaders[shader]
	for _, mesh in ipairs(meshes) do
		if mesh.shader ~= shader then
			mesh:SetShader(shader)
		end
	end
end

function PlaceGroundRectMesh(v_pstr, color_textstyle_id, shader)
	shader = shader or "ground_strokes"
	local mesh = PlaceObject("Mesh")
	if color_textstyle_id then
		mesh:SetColorFromTextStyle(color_textstyle_id)
	end
	mesh:SetMesh(v_pstr)
	mesh:SetPos(0, 0, 0)
	if IsKindOf(shader, "CRMaterial") then
		mesh:SetCRMaterial(shader)
	else
		mesh:SetShader(ProceduralMeshShaders[shader])
	end
	mesh:SetDepthTest(true)
	return mesh
end

local reload_prop_ids = {TextColor = true, ShadowColor = true, ShadowSize = true, }
function TextStyle:OnEditorSetProperty(prop_id, old_value, ged)
	if self.group == "Zulu Ingame" and reload_prop_ids[prop_id] then
		DelayedCall(300, MapForEach, "map", "Mesh", function(mesh)
			if mesh.textstyle_id == self.id then
				mesh:SetColorFromTextStyle(self.id)
			end
		end)
	end
end

DefineClass.CRM_RangeContourPreset = {
	__parents = { "CRMaterial" },
	group = "RangeContourPreset",
	properties = {
		{ uniform = true, id = "depth_softness", editor = "number", default = 0, scale = 1000, min = -2000, max = 2000, slider = true, },
		{ uniform = true, id = "fill_color", editor = "color", default = RGB(0, 255, 0) },
		{ uniform = true, id = "border_color", editor = "color", default = RGB(255, 255, 255) },
		{ uniform = true, id = "dash_color", editor = "color", default = RGB(255, 255, 255) },

		{ uniform = true, id = "fill_width", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, slider = true, },
		{ uniform = true, id = "border_width", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, slider = true, },
		{ uniform = true, id = "border_softness", editor = "number", default = 200, scale = 1000, min = 0, max = 1000, slider = true, },

		{ uniform = true, id = "dash_density", editor = "number", scale = 1000, default = 1000, slider = true, min = 0, max = 1000},
		{ uniform = true, id = "dash_segment", editor = "number", scale = 1000, default = 1000, slider = true, min = 0, max = 100000},

		{ uniform = true, id = "anim_speed", editor = "number", scale = 1000, default = 1000, slider = true, min = 0, max = 10000},
		{ uniform = true, id = "grain_strength", editor = "number", scale = 1000, default = 200, slider = true, min = 0, max = 1000},
		{ uniform = true, id = "interlacing_strength", editor = "number", scale = 1000, default = 200, slider = true, min = 0, max = 1000},
	},

	shader_id = "range_contour_default",
}

DefineClass.CRM_RangeContourControllerPreset = {
	__parents = { "CRMaterial" },
	group = "RangeContourControllerPreset",

	shader_id = "combat_border",
	properties = {
		{ id = "contour_base_inside", editor = "preset_id", preset_class = "CRM_RangeContourPreset", default = false, },
		{ id = "contour_base_outside", editor = "preset_id", preset_class = "CRM_RangeContourPreset", default = false, },
		{ id = "contour_fx_inside", editor = "preset_id", preset_class = "CRM_RangeContourPreset", default = false, },
		{ id = "contour_fx_outside", editor = "preset_id", preset_class = "CRM_RangeContourPreset", default = false, },

		{ uniform = "integer", id = "fade_inout_start", editor = "number", scale = 1, default = 0, no_edit = true, dont_save = true, },
		{ uniform = true, id = "fade_in", editor = "number", scale = 1000, default = 200, min = 0, max = 2000, slider = true, },
		{ uniform = true, id = "cursor_alpha_distance", editor = "number", scale = 1000, default = 1000, min = 0, max = 3000, slider = true, },
		{ uniform = true, id = "cursor_alpha_falloff", editor = "number", scale = 1000, default = 1000, min = 0, max = 25000, slider = true, },
		
		{ uniform = "integer", id = "pop_in_start", editor = "number", scale = 1, default = 0, no_edit = true, dont_save = true,  },
		{ id = "pop_delay", editor = "number", scale = 1, default = 0, },
		{ uniform = true, id = "pop_in_time", editor = "number", scale = 1000, default = 500, slider = true, min = 0, max = 1200, },
		{ uniform = true, id = "pop_in_freq", editor = "number", scale = 1000, default = 200, slider = true, min = 0, max = 1200, },

		{ id = "is_inside", editor = "bool", default = false, no_edit = true, dont_save = true,  },

		{ uniform = true, id = "ZOffset", editor = "number", default = false, scale = 1000, no_edit = true, default = 0, }
	},
}

function CRM_RangeContourControllerPreset:Recreate()
	self.dirty = false

	local pstr_buffer = self.pstr_buffer

	local preset = CRM_RangeContourPreset:GetById(self.is_inside and self.contour_base_inside or self.contour_base_outside)
	pstr_buffer = preset:WriteBuffer(pstr_buffer)

	local preset2 = CRM_RangeContourPreset:GetById(self.is_inside and self.contour_fx_inside or self.contour_fx_outside)
	pstr_buffer = preset2:WriteBuffer(pstr_buffer, 4 * 12)

	self:WriteBuffer(pstr_buffer, 4 * 12 * 2 )
	self.pstr_buffer = pstr_buffer
end

function CRM_RangeContourControllerPreset:SetIsInside(value, notimereset)
	value = value and true or false
	if self.is_inside ~= value then
		self.is_inside = value
		if not notimereset then
			self.fade_inout_start =  RealTime()
		end
		self.dirty = true
	end
end


DefineClass.RangeContourMesh = {
	__parents = {"Mesh"},

	preset_id = false,

	polyline = false,
	exclude_polyline = false,
	use_exclude_polyline = true,

	meshes = false,
	dirty_geometry = false,
}

function RangeContourMesh:SetPolyline(polyline, exclude_polyline)
	self.polyline = polyline
	self.exclude_polyline = exclude_polyline
end

function RangeContourMesh:SetPreset(preset)
	if type(preset) == "string" then
		preset = CRM_RangeContourControllerPreset:GetById(preset)
	end
	if self.CRMaterial and preset.id == self.CRMaterial.id  then
		return
	end
	self:SetCRMaterial(preset:Clone())
end

function RangeContourMesh:SetVisible(value)
	if not g_PhotoMode then
		for _, mesh in ipairs(self.meshes or empty_table) do
			mesh:SetVisible(value)
		end
		if self.visible ~= value then
			self.CRMaterial.pop_in_start = RealTime() + self.CRMaterial.pop_delay
			self.visible = value
			self.CRMaterial.dirty = true
		end
	end
end

function RangeContourMesh:SetIsInside(value)
	self.CRMaterial:SetIsInside(value)
end

function RangeContourMesh:SetUseExcludePolyline(value)
	if self.use_exclude_polyline ~= value then
		self.use_exclude_polyline = value
		self.dirty_geometry = true
	end
end

function RangeContourMesh:Recreate(force_geometry)
	if #(self.meshes or empty_table) == 0 then
		force_geometry = true
	end
	if force_geometry or self.dirty_geometry then
		self.dirty_geometry = false
		for _, mesh in ipairs(self.meshes) do
			mesh:delete()
		end
		--self.polyline.side_len = 200
		self.meshes = PlaceContourPolyline(self.polyline, RGB(255, 255, 255), self.CRMaterial, self.use_exclude_polyline and self.exclude_polyline)
	else
		for _, mesh in ipairs(self.meshes) do
			mesh:SetCRMaterial(self.CRMaterial)
		end
	end
end

function RangeContourMesh:delete()
	for _, mesh in ipairs(self.meshes or empty_table) do
		mesh:delete()
	end
	self.meshes = false
	Mesh.delete(self)
end

function CRM_RangeContourPreset:Apply()
	CRMaterial.Apply(self)
	self.cached_uniform_buf = self:GetDataPstr()
	if CurrentMap ~= "" then
		MapGet("map", "RangeContourMesh", function(o)
			if o.preset_id == self.id then
				o:Recreate()
			end
		end)
	end
end

RegisterSceneParam({
	id = "CursorPos", type = "float", elements = 3, default = { 0, 0, 0 }, scale = 1000, prop_id = false,
})
local cursor_pos_table = {0,0,0}
MapRealTimeRepeat("RangeContourSceneParam", 33, function()
	local pos = GetCursorPos()
	if pos then
		cursor_pos_table[1], cursor_pos_table[2], cursor_pos_table[3] = pos:xyz()
		local interp_time = next(PauseReasons) and 0 or 33
		SetSceneParamEx(1, "CursorPos", cursor_pos_table, interp_time)
	end
end)