-
Notifications
You must be signed in to change notification settings - Fork 2
/
gfx_volumetric_clouds.lua
362 lines (290 loc) · 10.8 KB
/
gfx_volumetric_clouds.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
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
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
function widget:GetInfo()
return {
name = "Volumetric Clouds",
version = 6,
desc = "Fog/Dust clouds that scroll with wind along the map's surface. Requires GLSL, expensive even with.",
author = "Anarchid, consulted and optimized by jK",
date = "november 2014",
license = "GNU GPL, v2 or later",
layer = -1000,
enabled = true
}
end
local enabled = true
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Config
local mapcfg = VFS.Include("mapinfo.lua");
if (not mapcfg)or(not mapcfg.custom)or(not mapcfg.custom.clouds) then
error("<Volumetric Clouds>: Can't find settings in mapinfo.lua!");
end
local CloudDefs = mapcfg.custom.clouds;
local gnd_min, gnd_max = Spring.GetGroundExtremes()
local function convertAltitude(input, default)
if (input == nil or input == "auto") then
return default
elseif type(input) == "number" then
return input
elseif (type(input) == "string" and input:match("(%d+)%%")) then
local percent = input:match("(%d+)%%")
return gnd_max * (percent / 100)
end
return input
end
CloudDefs.height = convertAltitude(CloudDefs.height, gnd_max*0.9)
CloudDefs.bottom = convertAltitude(CloudDefs.bottom, 0)
CloudDefs.fade_alt = convertAltitude(CloudDefs.fade_alt, gnd_max*0.8)
local cloudsHeight = CloudDefs.height
local cloudsBottom = CloudDefs.bottom or gnd_min
local cloudsColor = CloudDefs.color
local cloudsScale = CloudDefs.scale
local cloudsClamp = CloudDefs.clamp_to_map or false
local speed = CloudDefs.speed
local opacity = CloudDefs.opacity or 0.3
local sunPenetration = CloudDefs.sun_penetration or (-40.0)
local fade_alt = CloudDefs.fade_alt
local fr,fg,fb = unpack(cloudsColor)
local sunDir = {0,0,0}
local sunCol = {1,0,0}
assert(type(sunPenetration) == "number")
assert(type(cloudsClamp) == "boolean")
assert(type(cloudsHeight) == "number")
assert(type(cloudsBottom) == "number")
assert(type(fr) == "number")
assert(type(fg) == "number")
assert(type(fb) == "number")
assert(type(opacity) == "number")
assert(type(fade_alt) == "number")
assert(type(cloudsScale) == "number")
assert(type(speed) == "number")
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Automatically generated local definitions
local GL_MODELVIEW = GL.MODELVIEW
local GL_NEAREST = GL.NEAREST
local GL_ONE = GL.ONE
local GL_ONE_MINUS_SRC_ALPHA = GL.ONE_MINUS_SRC_ALPHA
local GL_PROJECTION = GL.PROJECTION
local GL_QUADS = GL.QUADS
local GL_SRC_ALPHA = GL.SRC_ALPHA
local glBeginEnd = gl.BeginEnd
local glBlending = gl.Blending
local glCallList = gl.CallList
local glColor = gl.Color
local glColorMask = gl.ColorMask
local glCopyToTexture = gl.CopyToTexture
local glCreateList = gl.CreateList
local glCreateShader = gl.CreateShader
local glCreateTexture = gl.CreateTexture
local glDeleteShader = gl.DeleteShader
local glDeleteTexture = gl.DeleteTexture
local glDepthMask = gl.DepthMask
local glDepthTest = gl.DepthTest
local glGetMatrixData = gl.GetMatrixData
local glGetShaderLog = gl.GetShaderLog
local glGetUniformLocation = gl.GetUniformLocation
local glGetViewSizes = gl.GetViewSizes
local glLoadIdentity = gl.LoadIdentity
local glLoadMatrix = gl.LoadMatrix
local glMatrixMode = gl.MatrixMode
local glMultiTexCoord = gl.MultiTexCoord
local glPopMatrix = gl.PopMatrix
local glPushMatrix = gl.PushMatrix
local glResetMatrices = gl.ResetMatrices
local glTexCoord = gl.TexCoord
local glTexture = gl.Texture
local glRect = gl.Rect
local glUniform = gl.Uniform
local glUniformMatrix = gl.UniformMatrix
local glUseShader = gl.UseShader
local glVertex = gl.Vertex
local glTranslate = gl.Translate
local spGetCameraPosition = Spring.GetCameraPosition
local spGetCameraVectors = Spring.GetCameraVectors
local spGetWind = Spring.GetWind
local time = Spring.GetGameSeconds
local spGetDrawFrame = Spring.GetDrawFrame
local function spEcho(words)
Spring.Echo('<Volumetric Clouds> '..words)
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- Extra GL constants
--
local GL_DEPTH_BITS = 0x0D56
local GL_DEPTH_COMPONENT = 0x1902
local GL_DEPTH_COMPONENT16 = 0x81A5
local GL_DEPTH_COMPONENT24 = 0x81A6
local GL_DEPTH_COMPONENT32 = 0x81A7
local GL_RGBA32F_ARB = 0x8814
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
if (gnd_min < 0) then gnd_min = 0 end
if (gnd_max < 0) then gnd_max = 0 end
local vsx, vsy
local depthShader
local depthTexture
local fogTexture
local uniformEyePos
local uniformViewPrjInv
local uniformOffset
local uniformSundir
local uniformSunColor
local uniformTime
local offsetX = 0;
local offsetY = 0;
local offsetZ = 0;
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:ViewResize()
vsx, vsy = gl.GetViewSizes()
if (Spring.GetMiniMapDualScreen()=='left') then
vsx=vsx/2;
end
if (Spring.GetMiniMapDualScreen()=='right') then
vsx=vsx/2
end
if (depthTexture) then
glDeleteTexture(depthTexture)
end
if (fogTexture) then
glDeleteTexture(fogTexture)
end
depthTexture = glCreateTexture(vsx, vsy, {
format = GL_DEPTH_COMPONENT24,
min_filter = GL_NEAREST,
mag_filter = GL_NEAREST,
});
fogTexture = glCreateTexture(vsx/3, vsy/3, {
min_filter = GL.LINEAR,
mag_filter = GL.LINEAR,
wrap_s = GL.CLAMP_TO_EDGE,
wrap_t = GL.CLAMP_TO_EDGE,
fbo = true,
});
if (depthTexture == nil) then
spEcho("Removing fog widget, bad depth texture")
widgetHandler:RemoveWidget();
end
end
widget:ViewResize()
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local vertSrc = [[
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_Vertex;
}
]]
local fragSrc = VFS.LoadFile("LuaUI/Widgets/Shaders/fog_frag.glsl");
fragSrc = fragSrc:format(
cloudsScale, cloudsHeight, cloudsBottom,
cloudsColor[1], cloudsColor[2], cloudsColor[3],
Game.mapSizeX, Game.mapSizeZ,
fade_alt, opacity, sunPenetration
);
if(cloudsClamp) then
fragSrc = '#define CLAMP_TO_MAP\n' .. fragSrc
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:Initialize()
if (Spring.GetMiniMapDualScreen() == 'left') then --FIXME dualscreen
enabled = false
end
if (not glCreateShader) then
enabled = false
end
if enabled then
depthShader = glCreateShader({
vertex = vertSrc,
fragment = fragSrc,
uniformInt = {
tex0 = 0,
tex1 = 1,
},
});
spEcho(glGetShaderLog())
if (not depthShader) then
spEcho("Bad shader, reverting to non-GLSL widget.")
enabled = false
else
uniformEyePos = glGetUniformLocation(depthShader, 'eyePos')
uniformViewPrjInv = glGetUniformLocation(depthShader, 'viewProjectionInv')
uniformOffset = glGetUniformLocation(depthShader, 'offset')
uniformSundir = glGetUniformLocation(depthShader, 'sundir')
uniformSunColor = glGetUniformLocation(depthShader, 'suncolor')
uniformTime = glGetUniformLocation(depthShader, 'time')
end
end
if not(enabled) then
widgetHandler:RemoveWidget();
return
end
end
function widget:Shutdown()
glDeleteTexture(depthTexture)
glDeleteTexture(fogTexture)
if (glDeleteShader) then
glDeleteShader(depthShader)
end
glDeleteTexture(":l:LuaUI/Widgets/Images/rgbnoise.png");
end
local function renderToTextureFunc()
-- render a full screen quad
glTexture(0, depthTexture)
glTexture(0, false)
glTexture(1,":l:LuaUI/Widgets/Images/rgbnoise.png");
glTexture(1, false)
gl.TexRect(-1, -1, 1, 1, 0, 0, 1, 1)
end
local function DrawFogNew()
--//FIXME handle dualscreen correctly!
-- copy the depth buffer
glCopyToTexture(depthTexture, 0, 0, 0, 0, vsx, vsy) --FIXME scale down?
-- setup the shader and its uniform values
glUseShader(depthShader)
-- set uniforms
glUniform(uniformEyePos, spGetCameraPosition())
glUniform(uniformOffset, offsetX, offsetY, offsetZ);
glUniform(uniformSundir, sunDir[1], sunDir[2], sunDir[3]);
glUniform(uniformSunColor, sunCol[1], sunCol[2], sunCol[3]);
glUniform(uniformTime, Spring.GetGameSeconds() * speed);
glUniformMatrix(uniformViewPrjInv, "viewprojectioninverse")
-- TODO: completely reset the texture before applying shader
-- TODO: figure out why it disappears in some places
-- maybe add a switch to make it high-res direct-render
gl.RenderToTexture(fogTexture, renderToTextureFunc);
glUseShader(0)
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:GameFrame()
local dx,dy,dz = spGetWind();
offsetX = offsetX-dx*speed;
offsetY = offsetY-0.25-dy*0.25*speed;
offsetZ = offsetZ-dz*speed;
sunDir = {gl.GetSun('pos')}
sunCol = {gl.GetSun('specular')}
end
widget:GameFrame()
function widget:DrawScreenEffects()
glBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) -- in theory not needed but sometimes evil widgets disable it w/o reenabling it
glTexture(fogTexture);
gl.TexRect(0,0,vsx,vsy,0,0,1,1);
glTexture(false);
end
function widget:DrawWorld()
glBlending(false)
DrawFogNew()
glBlending(true)
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------