-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgui_unit_icon_view.lua
221 lines (195 loc) · 6.24 KB
/
gui_unit_icon_view.lua
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
function widget:GetInfo()
return {
name = "All Unit Icon Overview - View",
desc = "Replaces the default engine icon drawing. Conflicts with Icon Height.",
author = "esainane",
date = "2020-01-27",
license = "GNU GPL, v2 or later",
layer = 2000,
handler = true,
enabled = false -- loaded by default?
}
end
include("keysym.h.lua")
--
-- ICON DRAW SECTION
--
local spWorldToScreenCoords = Spring.WorldToScreenCoords
local glColor = gl.Color
local glTexture = gl.Texture
local glTexRect = gl.TexRect
local frame = 0
local shader
local tLoc
local isCloakyLoc
local constructionProgressLoc
local pulseRateLoc
local framesStaleLoc
local initialized = false
function widget:Initialize()
--[[
Shader:
glColor: team color (or white if selected)
cloaky_effect: truthy if cloaked
construction_effect: float of construction progress
--]]
shader = gl.CreateShader({
fragment=[[
#version 330
const float pi = 3.141592;
in vec4 gl_TexCoord[];
in vec4 gl_Color;
uniform sampler2D texture;
out vec4 diffuseColor;
uniform int t;
uniform int cloaky_effect;
uniform int frames_stale;
uniform float construction_effect;
uniform float pulse_rate;
void main(void) {
vec2 texCoord = vec2(gl_TexCoord[0]);
vec4 S0 = texture2D(texture, texCoord);
// As a base: Output is the input texture's color, tinted by the team color
diffuseColor = S0 * gl_Color;
if (bool(cloaky_effect)) {
// If a unit is cloaked, override the visible black parts of it with a
// shifting blue-green-purple effect
const float blackishThreshold = 0.4;
if (S0.r < blackishThreshold && S0.g < blackishThreshold && S0.b < blackishThreshold) {
// cloaky effect
diffuseColor.rgb += 3;
diffuseColor.rgb /= 4;
diffuseColor.rgb += vec3(
0.6+mod(texCoord.x*texCoord.x + texCoord.y / 3 + t / 50.0, 0.3),
0.7+mod(texCoord.y*texCoord.y + texCoord.x / 2 + t / 50.0, 0.3),
0.9
) * 3;
diffuseColor.rgb /= 4;
} else {
diffuseColor.rgb *= 1;
}
}
// Draw a completion progress circle for under-construction entities
if (construction_effect < 1.0f) {
// Work out how far along the circle we are
float dx = texCoord.x - .5;
float dy = texCoord.y - .5;
float angle;
// Avoid x == 0 divide-by-zero implementation-definedness
if (abs(dx) < 0.001) {
angle = dy > 0 ? 3.0 * pi / 2.0 : pi / 2.0;
} else {
angle = atan(dy, dx);
angle += pi;
}
// Change the boundary to be at the top of the icon
angle += 3 * pi / 2;
// convert to [0.0,1.0]
float equivProgress = mod(angle, 2 * pi) / (2 * pi);
// Ensure a minimal visible circle while under construction, of team color
// Used to work around icons that are off center or very uneven
// (Krow, Starlight)
if (abs(dx)*abs(dx)+abs(dy)*abs(dy) < 0.1) {
diffuseColor.rgb += (1 - diffuseColor.a) * gl_Color.rgb;
diffuseColor.a = max(0.9, diffuseColor.a);
}
// Under-construction entities pulse, and more insistently the closer they are to completion
// Now, actually darken the icon under-construction entities
float ft = float(t);
if (equivProgress > construction_effect) {
// Further along the circle than actual progress made, very dark
float mult = 0.50 + // Baseline
-(0.4 * construction_effect) + // Emphasize the smaller slice - darker slice is much darker when nearly done for visibility
0.16 * (mod(ft, pulse_rate) / pulse_rate); // Pulse
diffuseColor.rgb *= mult;
} else {
// We've built this far, still leave it darker than usual
float mult = 1 +
- (.1 + // Baseline
.36 * construction_effect // Emphasize the smaller slice - lighter slice is much ligher when barely started, for visibility
) * (1.0 - mod(ft, pulse_rate) / pulse_rate); // Pulse
diffuseColor.rgb *= mult;
}
}
// Is our information stale, by many frames?
// linear decay from 100% to 40% over 20 seconds
diffuseColor.a *= 1 - 0.6 * min(600, frames_stale) / 600.0;
}
]],
uniformInt = {cloaky_effect = 0, t=0, frames_stale = 0},
uniformFloat= {construction_effect = 1.0, pulse_rate = 20.0}
})
Spring.Echo(gl.GetShaderLog())
if not shader then
Spring.Echo("[gui_unit_icon::Initialize] no shader support")
Spring.Echo(gl.GetShaderLog())
widgetHandler:RemoveWidget(self)
return
end
tLoc = gl.GetUniformLocation(shader, "t")
isCloakyLoc = gl.GetUniformLocation(shader, "cloaky_effect")
pulseRateLoc = gl.GetUniformLocation(shader, "pulse_rate")
constructionProgressLoc = gl.GetUniformLocation(shader, "construction_effect")
framesStaleLoc = gl.GetUniformLocation(shader, "frames_stale")
initialized = true
end
function widget:Shutdown()
if initialized then
gl.DeleteShader(shader)
end
end
local function GetCameraHeight()
local cs = Spring.GetCameraState()
local gy = Spring.GetGroundHeight(cs.px, cs.pz)
local testHeight = cs.py - gy
if cs.name == "ov" then
testHeight = WG.AllUnitIcon.iconheight * 2
elseif cs.name == "ta" then
testHeight = cs.height - gy
end
return testHeight
end
local function GetIconScaleForHeight(h)
-- Want 10 for ~2600, 8 for 6000, 6 for 8334
return 11.5 - h * 2 / 3400
end
local function DrawOneUnit(u, iconScale)
local x,y,z = spWorldToScreenCoords(u.wx, u.wy, u.wz)
local tr,tg,tb = u.tr, u.tg, u.tb
local icon = u.icon
local size = iconScale * icon.size
glColor(tr,tg,tb,1)
local isCloakedInt
if u.isCloaked then
isCloakedInt = 1
else
isCloakedInt = 0
end
gl.UniformInt(isCloakyLoc, isCloakedInt)
gl.Uniform(constructionProgressLoc, u.buildProgress)
gl.Uniform(pulseRateLoc, u.pulseRate)
gl.UniformInt(framesStaleLoc, frame - u.lastUpdate)
--Spring.Echo(icon.bitmap)
glTexture(icon.bitmap)
glTexRect(x-size, y-size, x+size, y+size)
glTexture(false)
end
-- local lastHeight = 0
function widget:DrawScreen()
if not WG.AllUnitIcon.showing_icons then return end
local testHeight = GetCameraHeight()
local iconScale = GetIconScaleForHeight(testHeight)
--if lastHeight ~= testHeight then
-- Spring.Echo("New Height:", testHeight)
-- lastHeight = testHeight
--end
gl.UseShader(shader)
gl.UniformInt(tLoc, frame)
for i,u in pairs(WG.AllUnitIcon.all_units) do
DrawOneUnit(u, iconScale)
end
gl.UseShader(0)
end
function widget:GameFrame(n)
frame = n
end