1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 /**
4 * @brief extended bump-mapping water shader
5 */
6
7
8 #include "BumpWater.h"
9
10 #include <boost/format.hpp>
11
12 #include "ISky.h"
13 #include "Game/Game.h"
14 #include "Game/Camera.h"
15 #include "Game/GlobalUnsynced.h"
16 #include "Map/MapInfo.h"
17 #include "Map/ReadMap.h"
18 #include "Map/BaseGroundDrawer.h"
19 #include "Rendering/GlobalRendering.h"
20 #include "Rendering/FeatureDrawer.h"
21 #include "Rendering/ProjectileDrawer.h"
22 #include "Rendering/ShadowHandler.h"
23 #include "Rendering/UnitDrawer.h"
24 #include "Rendering/GL/VertexArray.h"
25 #include "Rendering/Shaders/ShaderHandler.h"
26 #include "Rendering/Shaders/Shader.h"
27 #include "Rendering/Textures/Bitmap.h"
28 #include "Rendering/Textures/TextureAtlas.h"
29 #include "Sim/Misc/Wind.h"
30 #include "System/bitops.h"
31 #include "System/FileSystem/FileHandler.h"
32 #include "System/FastMath.h"
33 #include "System/myMath.h"
34 #include "System/EventHandler.h"
35 #include "System/Config/ConfigHandler.h"
36 #include "System/TimeProfiler.h"
37 #include "System/Log/ILog.h"
38 #include "System/Exceptions.h"
39 #include "System/Util.h"
40
41 using std::string;
42 using std::vector;
43 using std::min;
44 using std::max;
45
46 CONFIG(int, BumpWaterTexSizeReflection).defaultValue(512).minimumValue(32).description("Sets the size of the framebuffer texture used to store the reflection in Bumpmapped water.");
47 CONFIG(int, BumpWaterReflection).defaultValue(1).minimumValue(0).maximumValue(2).description("Determines the amount of objects reflected in Bumpmapped water.\n0:=off, 1:=fast (skip terrain), 2:=full");
48 CONFIG(int, BumpWaterRefraction).defaultValue(1).minimumValue(0).maximumValue(2).description("Determines the method of refraction with Bumpmapped water.\n0:=off, 1:=screencopy, 2:=own rendering cycle");
49 CONFIG(float, BumpWaterAnisotropy).defaultValue(0.0f).minimumValue(0.0f);
50 CONFIG(bool, BumpWaterUseDepthTexture).defaultValue(true);
51 CONFIG(int, BumpWaterDepthBits).defaultValue(24).minimumValue(16).maximumValue(32);
52 CONFIG(bool, BumpWaterBlurReflection).defaultValue(false);
53 CONFIG(bool, BumpWaterShoreWaves).defaultValue(true).safemodeValue(false).description("Enables rendering of shorewaves.");
54 CONFIG(bool, BumpWaterEndlessOcean).defaultValue(true).description("Sets whether Bumpmapped water will be drawn beyond the map edge.");
55 CONFIG(bool, BumpWaterDynamicWaves).defaultValue(true);
56 CONFIG(bool, BumpWaterUseUniforms).defaultValue(false);
57 CONFIG(bool, BumpWaterOcclusionQuery).defaultValue(false); //FIXME doesn't work as expected (it's slower than w/o), needs fixing
58
59
60 #define LOG_SECTION_BUMP_WATER "BumpWater"
LOG_REGISTER_SECTION_GLOBAL(LOG_SECTION_BUMP_WATER)61 LOG_REGISTER_SECTION_GLOBAL(LOG_SECTION_BUMP_WATER)
62
63 // use the specific section for all LOG*() calls in this source file
64 #ifdef LOG_SECTION_CURRENT
65 #undef LOG_SECTION_CURRENT
66 #endif
67 #define LOG_SECTION_CURRENT LOG_SECTION_BUMP_WATER
68
69 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
70 /// HELPER FUNCTIONS
71 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
72
73 static void GLSLDefineConst4f(string& str, const string& name, const float x, const float y, const float z, const float w)
74 {
75 str += boost::str(boost::format(string("#define ")+name+" vec4(%1$.12f,%2$.12f,%3$.12f,%4$.12f)\n") % (x) % (y) % (z) % (w));
76 }
77
GLSLDefineConstf4(string & str,const string & name,const float3 & v,const float & alpha)78 static void GLSLDefineConstf4(string& str, const string& name, const float3& v, const float& alpha)
79 {
80 str += boost::str(boost::format(string("#define ")+name+" vec4(%1$.12f,%2$.12f,%3$.12f,%4$.12f)\n") % (v.x) % (v.y) % (v.z) % (alpha));
81 }
82
83
GLSLDefineConstf3(string & str,const string & name,const float3 & v)84 static void GLSLDefineConstf3(string& str, const string& name, const float3& v)
85 {
86 str += boost::str(boost::format(string("#define ")+name+" vec3(%1$.12f,%2$.12f,%3$.12f)\n") % (v.x) % (v.y) % (v.z));
87 }
88
89
GLSLDefineConstf2(string & str,const string & name,const float & x,const float & y)90 static void GLSLDefineConstf2(string& str, const string& name, const float& x, const float& y)
91 {
92 str += boost::str(boost::format(string("#define ")+name+" vec2(%1$.12f,%2$.12f)\n") % x % y);
93 }
94
95
GLSLDefineConstf1(string & str,const string & name,const float & x)96 static void GLSLDefineConstf1(string& str, const string& name, const float& x)
97 {
98 str += boost::str(boost::format(string("#define ")+name+" %1$.12f\n") % x);
99 }
100
101
LoadTexture(const string & filename,const float anisotropy=0.0f,int * sizeX=NULL,int * sizeY=NULL)102 static GLuint LoadTexture(const string& filename, const float anisotropy = 0.0f, int* sizeX = NULL, int* sizeY = NULL)
103 {
104 GLuint texID;
105 CBitmap bm;
106 if (!bm.Load(filename)) {
107 throw content_error("[" LOG_SECTION_BUMP_WATER "] Could not load texture from file " + filename);
108 }
109
110 glGenTextures(1, &texID);
111 glBindTexture(GL_TEXTURE_2D, texID);
112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
116 if (anisotropy > 0.0f) {
117 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
118 }
119 glBuildMipmaps(GL_TEXTURE_2D, GL_RGBA8, bm.xsize, bm.ysize, GL_RGBA, GL_UNSIGNED_BYTE, bm.mem);
120
121 if (sizeY != NULL) {
122 *sizeX = bm.xsize;
123 *sizeY = bm.ysize;
124 }
125
126 return texID;
127 }
128
129
DrawRadialDisc(CVertexArray * va)130 static void DrawRadialDisc(CVertexArray* va)
131 {
132 //! SAME ALGORITHM AS FOR WATER-PLANE IN BFGroundDrawer.cpp!
133 const float xsize = (gs->mapx * SQUARE_SIZE) >> 2;
134 const float ysize = (gs->mapy * SQUARE_SIZE) >> 2;
135
136 float3 p;
137
138 const float alphainc = fastmath::PI2 / 32;
139 const float size = std::min(xsize, ysize);
140
141 for (int n = 0; n < 4 ; ++n) {
142 const float r1 = n*n * size;
143 float r2 = (n + 1) * (n + 1) * size;
144 if (n == 3) {
145 r2 = (n + 0.5) * (n + 0.5) * size;
146 }
147 for (float alpha = 0.0f; (alpha - fastmath::PI2) < alphainc; alpha += alphainc) {
148 p.x = r1 * fastmath::sin(alpha) + 2 * xsize;
149 p.z = r1 * fastmath::cos(alpha) + 2 * ysize;
150 va->AddVertex0(p);
151 p.x = r2 * fastmath::sin(alpha) + 2 * xsize;
152 p.z = r2 * fastmath::cos(alpha) + 2 * ysize;
153 va->AddVertex0(p);
154 }
155 }
156
157 va->DrawArray0(GL_TRIANGLE_STRIP);
158 }
159
160
161 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
162 /// (DE-)CONSTRUCTOR
163 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
164
CBumpWater()165 CBumpWater::CBumpWater()
166 : CEventClient("[CBumpWater]", 271923, false)
167 , target(GL_TEXTURE_2D)
168 , screenTextureX(globalRendering->viewSizeX)
169 , screenTextureY(globalRendering->viewSizeY)
170 , displayList(0)
171 , refractTexture(0)
172 , reflectTexture(0)
173 , depthTexture(0)
174 , waveRandTexture(0)
175 , foamTexture(0)
176 , normalTexture(0)
177 , normalTexture2(0)
178 , coastTexture(0)
179 , coastUpdateTexture(0)
180 , wasVisibleLastFrame(false)
181 {
182 eventHandler.AddClient(this);
183
184 // LOAD USER CONFIGS
185 reflTexSize = next_power_of_2(configHandler->GetInt("BumpWaterTexSizeReflection"));
186 reflection = configHandler->GetInt("BumpWaterReflection");
187 refraction = configHandler->GetInt("BumpWaterRefraction");
188 anisotropy = configHandler->GetFloat("BumpWaterAnisotropy");
189 depthCopy = configHandler->GetBool("BumpWaterUseDepthTexture");
190 depthBits = configHandler->GetInt("BumpWaterDepthBits");
191 if ((depthBits == 24) && !globalRendering->support24bitDepthBuffers)
192 depthBits = 16;
193 blurRefl = configHandler->GetBool("BumpWaterBlurReflection");
194 shoreWaves = (configHandler->GetBool("BumpWaterShoreWaves")) && mapInfo->water.shoreWaves;
195 endlessOcean = (configHandler->GetBool("BumpWaterEndlessOcean")) && mapInfo->water.hasWaterPlane
196 && ((readMap->HasVisibleWater()) || (mapInfo->water.forceRendering));
197 dynWaves = (configHandler->GetBool("BumpWaterDynamicWaves")) && (mapInfo->water.numTiles > 1);
198 useUniforms = (configHandler->GetBool("BumpWaterUseUniforms"));
199
200 // CHECK HARDWARE
201 if (!globalRendering->haveGLSL) {
202 throw content_error("[" LOG_SECTION_BUMP_WATER "] your hardware/driver setup does not support GLSL");
203 }
204
205 shoreWaves = shoreWaves && (GLEW_EXT_framebuffer_object);
206 dynWaves = dynWaves && (GLEW_EXT_framebuffer_object && GLEW_ARB_imaging);
207
208
209 // LOAD TEXTURES
210 foamTexture = LoadTexture(mapInfo->water.foamTexture);
211 normalTexture = LoadTexture(mapInfo->water.normalTexture , anisotropy , &normalTextureX, &normalTextureY);
212
213 //! caustic textures
214 const vector<string>& causticNames = mapInfo->water.causticTextures;
215 if (causticNames.empty()) {
216 throw content_error("[" LOG_SECTION_BUMP_WATER "] no caustic textures");
217 }
218 for (int i = 0; i < (int)causticNames.size(); ++i) {
219 caustTextures.push_back(LoadTexture(causticNames[i]));
220 }
221
222 // CHECK SHOREWAVES TEXTURE SIZE
223 if (shoreWaves) {
224 GLint maxw, maxh;
225 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA16F_ARB, 4096, 4096, 0, GL_RGBA, GL_FLOAT, NULL);
226 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &maxw);
227 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &maxh);
228 if (gs->mapx>maxw || gs->mapy>maxh) {
229 shoreWaves = false;
230 LOG_L(L_WARNING, "Can not display shorewaves (map too large)!");
231 }
232 }
233
234
235 // SHOREWAVES
236 if (shoreWaves) {
237 waveRandTexture = LoadTexture( "bitmaps/shorewaverand.png" );
238
239 glGenTextures(1, &coastTexture);
240 glBindTexture(GL_TEXTURE_2D, coastTexture);
241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
243 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
244 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
245 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
246 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
247 //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, gs->mapx, gs->mapy, 0, GL_RGBA, GL_FLOAT, NULL);
248 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, gs->mapx, gs->mapy, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
249 //glGenerateMipmapEXT(GL_TEXTURE_2D);
250
251
252 {
253 blurShader = shaderHandler->CreateProgramObject("[BumpWater]", "CoastBlurShader", false);
254 blurShader->AttachShaderObject(shaderHandler->CreateShaderObject("GLSL/bumpWaterCoastBlurFS.glsl", "", GL_FRAGMENT_SHADER));
255 blurShader->Link();
256
257 if (!blurShader->IsValid()) {
258 const char* fmt = "shorewaves-shader compilation error: %s";
259 const char* log = (blurShader->GetLog()).c_str();
260
261 LOG_L(L_ERROR, fmt, log);
262
263 //! string size is limited with content_error()
264 throw content_error(string("[" LOG_SECTION_BUMP_WATER "] shorewaves-shader compilation error!"));
265 }
266
267 blurShader->SetUniformLocation("tex0"); // idx 0
268 blurShader->SetUniformLocation("tex1"); // idx 1
269 blurShader->Enable();
270 blurShader->SetUniform1i(0, 0);
271 blurShader->SetUniform1i(1, 1);
272 blurShader->Disable();
273 blurShader->Validate();
274
275 if (!blurShader->IsValid()) {
276 const char* fmt = "shorewaves-shader validation error: %s";
277 const char* log = (blurShader->GetLog()).c_str();
278
279 LOG_L(L_ERROR, fmt, log);
280 throw content_error(string("[" LOG_SECTION_BUMP_WATER "] shorewaves-shader validation error!"));
281 }
282 }
283
284
285 coastFBO.reloadOnAltTab = true;
286 coastFBO.Bind();
287 coastFBO.AttachTexture(coastTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT);
288
289 if (coastFBO.CheckStatus("BUMPWATER(Coastmap)")) {
290 //! initialize texture
291 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
292 glClear(GL_COLOR_BUFFER_BIT);
293
294 //! fill with current heightmap/coastmap
295 UnsyncedHeightMapUpdate(SRectangle(0, 0, gs->mapx, gs->mapy));
296 UploadCoastline(true);
297 UpdateCoastmap();
298 } else
299 shoreWaves = false;
300
301 if (shoreWaves)
302 eventHandler.InsertEvent(this, "UnsyncedHeightMapUpdate");
303
304 //coastFBO.Unbind(); // gets done below
305 }
306
307
308 // CREATE TEXTURES
309 if ((refraction > 0) || depthCopy) {
310 //! ATIs do not have GLSL support for texrects
311 if (GLEW_ARB_texture_rectangle && !globalRendering->atiHacks) {
312 target = GL_TEXTURE_RECTANGLE_ARB;
313 } else if (!globalRendering->supportNPOTs) {
314 screenTextureX = next_power_of_2(screenTextureX);
315 screenTextureY = next_power_of_2(screenTextureY);
316 }
317 }
318
319 if (refraction > 0) {
320 //! CREATE REFRACTION TEXTURE
321 glGenTextures(1, &refractTexture);
322 glBindTexture(target, refractTexture);
323 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
324 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
325 if (GLEW_EXT_texture_edge_clamp) {
326 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
327 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
328 } else {
329 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP);
330 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP);
331 }
332 glTexImage2D(target, 0, GL_RGBA8, screenTextureX, screenTextureY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
333 }
334
335 if (reflection > 0) {
336 //! CREATE REFLECTION TEXTURE
337 glGenTextures(1, &reflectTexture);
338 glBindTexture(GL_TEXTURE_2D, reflectTexture);
339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
340 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
341 if (GLEW_EXT_texture_edge_clamp) {
342 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
343 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
344 } else {
345 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
346 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
347 }
348 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
349 }
350
351 if (depthCopy) {
352 //! CREATE DEPTH TEXTURE
353 glGenTextures(1, &depthTexture);
354 glBindTexture(target, depthTexture);
355 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
356 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
357 GLuint depthFormat = GL_DEPTH_COMPONENT32;
358 if (!globalRendering->atiHacks) { depthFormat = GL_DEPTH_COMPONENT24; }
359 glTexImage2D(target, 0, depthFormat, screenTextureX, screenTextureY, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
360 }
361
362 if (dynWaves) {
363 //! SETUP DYNAMIC WAVES
364 tileOffsets = new unsigned char[mapInfo->water.numTiles * mapInfo->water.numTiles];
365
366 normalTexture2 = normalTexture;
367 glBindTexture(GL_TEXTURE_2D, normalTexture2);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
370
371 glGenTextures(1, &normalTexture);
372 glBindTexture(GL_TEXTURE_2D, normalTexture);
373 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
374 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
375 if (anisotropy > 0.0f) {
376 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
377 }
378 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, normalTextureX, normalTextureY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
379 glGenerateMipmapEXT(GL_TEXTURE_2D);
380 }
381
382 // CREATE FBOs
383 if (GLEW_EXT_framebuffer_object) {
384 GLuint depthRBOFormat = GL_DEPTH_COMPONENT;
385 switch (depthBits) {
386 case 16: depthRBOFormat = GL_DEPTH_COMPONENT16; break;
387 case 24: depthRBOFormat = GL_DEPTH_COMPONENT24; break;
388 case 32: depthRBOFormat = GL_DEPTH_COMPONENT32; break;
389 }
390
391 if (reflection>0) {
392 reflectFBO.Bind();
393 reflectFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, depthRBOFormat, reflTexSize, reflTexSize);
394 reflectFBO.AttachTexture(reflectTexture);
395 if (!reflectFBO.CheckStatus("BUMPWATER(reflection)")) {
396 reflection = 0;
397 }
398 }
399
400 if (refraction>0) {
401 refractFBO.Bind();
402 refractFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, depthRBOFormat, screenTextureX, screenTextureY);
403 refractFBO.AttachTexture(refractTexture,target);
404 if (!refractFBO.CheckStatus("BUMPWATER(refraction)")) {
405 refraction = 0;
406 }
407 }
408
409 if (dynWaves) {
410 dynWavesFBO.reloadOnAltTab = true;
411 dynWavesFBO.Bind();
412 dynWavesFBO.AttachTexture(normalTexture);
413 if (dynWavesFBO.CheckStatus("BUMPWATER(DynWaves)")) {
414 UpdateDynWaves(true); //! initialize
415 }
416 }
417 FBO::Unbind();
418 }
419
420
421 /*
422 * DEFINE SOME SHADER RUNTIME CONSTANTS
423 * (I do not use Uniforms for that, because the GLSL compiler can not
424 * optimize those!)
425 */
426 string definitions;
427 if (reflection>0) definitions += "#define opt_reflection\n";
428 if (refraction>0) definitions += "#define opt_refraction\n";
429 if (shoreWaves) definitions += "#define opt_shorewaves\n";
430 if (depthCopy) definitions += "#define opt_depth\n";
431 if (blurRefl) definitions += "#define opt_blurreflection\n";
432 if (endlessOcean) definitions += "#define opt_endlessocean\n";
433 if (target == GL_TEXTURE_RECTANGLE_ARB) definitions += "#define opt_texrect\n";
434
435 GLSLDefineConstf3(definitions, "MapMid", float3(gs->mapx * SQUARE_SIZE * 0.5f, 0.0f, gs->mapy * SQUARE_SIZE * 0.5f));
436 GLSLDefineConstf2(definitions, "ScreenInverse", 1.0f / globalRendering->viewSizeX, 1.0f / globalRendering->viewSizeY);
437 GLSLDefineConstf2(definitions, "ScreenTextureSizeInverse", 1.0f / screenTextureX, 1.0f / screenTextureY);
438 GLSLDefineConstf2(definitions, "ViewPos", globalRendering->viewPosX, globalRendering->viewPosY);
439
440 if (useUniforms) {
441 SetupUniforms(definitions);
442 } else {
443 GLSLDefineConstf4(definitions, "SurfaceColor", mapInfo->water.surfaceColor*0.4, mapInfo->water.surfaceAlpha );
444 GLSLDefineConstf4(definitions, "PlaneColor", mapInfo->water.planeColor*0.4, mapInfo->water.surfaceAlpha );
445 GLSLDefineConstf3(definitions, "DiffuseColor", mapInfo->water.diffuseColor);
446 GLSLDefineConstf3(definitions, "SpecularColor", mapInfo->water.specularColor);
447 GLSLDefineConstf1(definitions, "SpecularPower", mapInfo->water.specularPower);
448 GLSLDefineConstf1(definitions, "SpecularFactor", mapInfo->water.specularFactor);
449 GLSLDefineConstf1(definitions, "AmbientFactor", mapInfo->water.ambientFactor);
450 GLSLDefineConstf1(definitions, "DiffuseFactor", mapInfo->water.diffuseFactor * 15.0f);
451 GLSLDefineConstf3(definitions, "SunDir", sky->GetLight()->GetLightDir()); // FIXME: not a constant
452 GLSLDefineConstf1(definitions, "FresnelMin", mapInfo->water.fresnelMin);
453 GLSLDefineConstf1(definitions, "FresnelMax", mapInfo->water.fresnelMax);
454 GLSLDefineConstf1(definitions, "FresnelPower", mapInfo->water.fresnelPower);
455 GLSLDefineConstf1(definitions, "ReflDistortion", mapInfo->water.reflDistortion);
456 GLSLDefineConstf2(definitions, "BlurBase", 0.0f, mapInfo->water.blurBase / globalRendering->viewSizeY);
457 GLSLDefineConstf1(definitions, "BlurExponent", mapInfo->water.blurExponent);
458 GLSLDefineConstf1(definitions, "PerlinStartFreq", mapInfo->water.perlinStartFreq);
459 GLSLDefineConstf1(definitions, "PerlinLacunarity", mapInfo->water.perlinLacunarity);
460 GLSLDefineConstf1(definitions, "PerlinAmp", mapInfo->water.perlinAmplitude);
461 GLSLDefineConstf1(definitions, "WindSpeed", mapInfo->water.windSpeed);
462 GLSLDefineConstf1(definitions, "shadowDensity", sky->GetLight()->GetGroundShadowDensity());
463 }
464
465 {
466 const int mapX = gs->mapx * SQUARE_SIZE;
467 const int mapZ = gs->mapy * SQUARE_SIZE;
468 const float shadingX = (float)gs->mapx / gs->pwr2mapx;
469 const float shadingZ = (float)gs->mapy / gs->pwr2mapy;
470 const float scaleX = (mapX > mapZ) ? (gs->mapy/64)/16.0f * (float)mapX/mapZ : (gs->mapx/64)/16.0f;
471 const float scaleZ = (mapX > mapZ) ? (gs->mapy/64)/16.0f : (gs->mapx/64)/16.0f * (float)mapZ/mapX;
472 GLSLDefineConst4f(definitions, "TexGenPlane", 1.0f/mapX, 1.0f/mapZ, scaleX/mapX, scaleZ/mapZ);
473 GLSLDefineConst4f(definitions, "ShadingPlane", shadingX/mapX, shadingZ/mapZ, shadingX, shadingZ);
474 }
475
476
477
478 // LOAD SHADERS
479 {
480 waterShader = shaderHandler->CreateProgramObject("[BumpWater]", "WaterShader", false);
481 waterShader->AttachShaderObject(shaderHandler->CreateShaderObject("GLSL/bumpWaterVS.glsl", definitions, GL_VERTEX_SHADER));
482 waterShader->AttachShaderObject(shaderHandler->CreateShaderObject("GLSL/bumpWaterFS.glsl", definitions, GL_FRAGMENT_SHADER));
483 waterShader->Link();
484 waterShader->SetUniformLocation("eyePos"); // idx 0
485 waterShader->SetUniformLocation("frame"); // idx 1
486 waterShader->SetUniformLocation("normalmap"); // idx 2, texunit 0
487 waterShader->SetUniformLocation("heightmap"); // idx 3, texunit 1
488 waterShader->SetUniformLocation("caustic"); // idx 4, texunit 2
489 waterShader->SetUniformLocation("foam"); // idx 5, texunit 3
490 waterShader->SetUniformLocation("reflection"); // idx 6, texunit 4
491 waterShader->SetUniformLocation("refraction"); // idx 7, texunit 5
492 waterShader->SetUniformLocation("depthmap"); // idx 8, texunit 7
493 waterShader->SetUniformLocation("coastmap"); // idx 9, texunit 6
494 waterShader->SetUniformLocation("waverand"); // idx 10, texunit 8
495 waterShader->SetUniformLocation("infotex"); // idx 11, texunit 10
496 waterShader->SetUniformLocation("shadowmap"); // idx 12, texunit 9
497 waterShader->SetUniformLocation("shadowMatrix"); // idx 13
498
499 if (!waterShader->IsValid()) {
500 const char* fmt = "water-shader compilation error: %s";
501 const char* log = (waterShader->GetLog()).c_str();
502 LOG_L(L_ERROR, fmt, log);
503 throw content_error(string("[" LOG_SECTION_BUMP_WATER "] water-shader compilation error!"));
504 }
505
506 if (useUniforms) {
507 GetUniformLocations(waterShader);
508 }
509
510 // BIND TEXTURE UNIFORMS
511 // NOTE: ATI shader validation code is stricter wrt. state,
512 // so postpone the call until all texture uniforms are set
513 waterShader->Enable();
514 waterShader->SetUniform1i( 2, 0);
515 waterShader->SetUniform1i( 3, 1);
516 waterShader->SetUniform1i( 4, 2);
517 waterShader->SetUniform1i( 5, 3);
518 waterShader->SetUniform1i( 6, 4);
519 waterShader->SetUniform1i( 7, 5);
520 waterShader->SetUniform1i( 8, 7);
521 waterShader->SetUniform1i( 9, 6);
522 waterShader->SetUniform1i(10, 8);
523 waterShader->SetUniform1i(11, 10);
524 waterShader->SetUniform1i(12, 9);
525 waterShader->Disable();
526 waterShader->Validate();
527
528 if (!waterShader->IsValid()) {
529 const char* fmt = "water-shader validation error: %s";
530 const char* log = (waterShader->GetLog()).c_str();
531
532 LOG_L(L_ERROR, fmt, log);
533 throw content_error(string("[" LOG_SECTION_BUMP_WATER "] water-shader validation error!"));
534 }
535 }
536
537
538 // CREATE DISPLAYLIST
539 displayList = glGenLists(1);
540 CVertexArray* va = GetVertexArray();
541 va->Initialize();
542 va->CheckInitSize(4 * 33 * 2); // endless
543 glNewList(displayList, GL_COMPILE);
544 if (endlessOcean) {
545 DrawRadialDisc(va);
546 } else {
547 const int mapX = gs->mapx * SQUARE_SIZE;
548 const int mapZ = gs->mapy * SQUARE_SIZE;
549 for (int z = 0; z < 9; z++) {
550 for (int x = 0; x < 10; x++) {
551 va->AddVertex0(float3(x*(mapX/9.0f), 0.0f, (z + 0)*(mapZ/9.0f)));
552 va->AddVertex0(float3(x*(mapX/9.0f), 0.0f, (z + 1)*(mapZ/9.0f)));
553 }
554 va->EndStrip();
555 }
556 va->DrawArray0(GL_TRIANGLE_STRIP);
557 }
558 glEndList();
559
560 /*
561 windndir = wind.GetCurrentDirection();
562 windStrength = (smoothstep(0.0f, 12.0f, wind.GetCurrentStrength()) * 0.5f + 4.0f);
563 windVec = windndir * windStrength;
564 */
565 windVec = float3(20.0, 0.0, 20.0);
566
567 occlusionQuery = 0;
568 occlusionQueryResult = GL_TRUE;
569 wasVisibleLastFrame = true;
570 #ifdef GLEW_ARB_occlusion_query2
571 bool useOcclQuery = (configHandler->GetBool("BumpWaterOcclusionQuery"));
572 if (useOcclQuery && GLEW_ARB_occlusion_query2 && (refraction < 2)) { //! in the case of a separate refraction pass, there isn't enough time for a occlusion query
573 GLint bitsSupported;
574 glGetQueryiv(GL_ANY_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &bitsSupported);
575 if (bitsSupported > 0) {
576 glGenQueries(1, &occlusionQuery);
577 }
578 }
579 #endif
580
581 if (refraction > 1) {
582 drawSolid = true;
583 }
584 }
585
586
~CBumpWater()587 CBumpWater::~CBumpWater()
588 {
589 if (reflectTexture) {
590 glDeleteTextures(1, &reflectTexture);
591 }
592 if (refractTexture) {
593 glDeleteTextures(1, &refractTexture);
594 }
595 if (depthCopy) {
596 glDeleteTextures(1, &depthTexture);
597 }
598
599 glDeleteTextures(1, &foamTexture);
600 glDeleteTextures(1, &normalTexture);
601 for (int i = 0; i < (int)caustTextures.size(); ++i) {
602 glDeleteTextures(1, &caustTextures[i]);
603 }
604
605 glDeleteLists(displayList, 1);
606
607 if (shoreWaves) {
608 glDeleteTextures(1, &coastTexture);
609 glDeleteTextures(1, &waveRandTexture);
610 }
611
612 if (dynWaves) {
613 glDeleteTextures(1, &normalTexture2);
614 delete[] tileOffsets;
615 }
616
617 #ifdef GLEW_ARB_occlusion_query2
618 if (occlusionQuery) {
619 glDeleteQueries(1, &occlusionQuery);
620 }
621 #endif
622
623 shaderHandler->ReleaseProgramObjects("[BumpWater]");
624 }
625
626
SetupUniforms(string & definitions)627 void CBumpWater::SetupUniforms(string& definitions)
628 {
629 definitions += "uniform vec4 SurfaceColor;\n";
630 definitions += "uniform vec4 PlaneColor;\n";
631 definitions += "uniform vec3 DiffuseColor;\n";
632 definitions += "uniform vec3 SpecularColor;\n";
633 definitions += "uniform float SpecularPower;\n";
634 definitions += "uniform float SpecularFactor;\n";
635 definitions += "uniform float AmbientFactor;\n";
636 definitions += "uniform float DiffuseFactor;\n";
637 definitions += "uniform vec3 SunDir;\n";
638 definitions += "uniform float FresnelMin;\n";
639 definitions += "uniform float FresnelMax;\n";
640 definitions += "uniform float FresnelPower;\n";
641 definitions += "uniform float ReflDistortion;\n";
642 definitions += "uniform vec2 BlurBase;\n";
643 definitions += "uniform float BlurExponent;\n";
644 definitions += "uniform float PerlinStartFreq;\n";
645 definitions += "uniform float PerlinLacunarity;\n";
646 definitions += "uniform float PerlinAmp;\n";
647 definitions += "uniform float WindSpeed;\n";
648 definitions += "uniform float shadowDensity;\n";
649 }
650
GetUniformLocations(const Shader::IProgramObject * shader)651 void CBumpWater::GetUniformLocations(const Shader::IProgramObject* shader)
652 {
653 uniforms[ 0] = glGetUniformLocation( shader->GetObjID(), "SurfaceColor" );
654 uniforms[ 1] = glGetUniformLocation( shader->GetObjID(), "PlaneColor" );
655 uniforms[ 2] = glGetUniformLocation( shader->GetObjID(), "DiffuseColor" );
656 uniforms[ 3] = glGetUniformLocation( shader->GetObjID(), "SpecularColor" );
657 uniforms[ 4] = glGetUniformLocation( shader->GetObjID(), "SpecularPower" );
658 uniforms[ 5] = glGetUniformLocation( shader->GetObjID(), "SpecularFactor" );
659 uniforms[ 6] = glGetUniformLocation( shader->GetObjID(), "AmbientFactor" );
660 uniforms[ 7] = glGetUniformLocation( shader->GetObjID(), "DiffuseFactor" );
661 uniforms[ 8] = glGetUniformLocation( shader->GetObjID(), "SunDir" );
662 uniforms[ 9] = glGetUniformLocation( shader->GetObjID(), "FresnelMin" );
663 uniforms[10] = glGetUniformLocation( shader->GetObjID(), "FresnelMax" );
664 uniforms[11] = glGetUniformLocation( shader->GetObjID(), "FresnelPower" );
665 uniforms[12] = glGetUniformLocation( shader->GetObjID(), "ReflDistortion" );
666 uniforms[13] = glGetUniformLocation( shader->GetObjID(), "BlurBase" );
667 uniforms[14] = glGetUniformLocation( shader->GetObjID(), "BlurExponent" );
668 uniforms[15] = glGetUniformLocation( shader->GetObjID(), "PerlinStartFreq" );
669 uniforms[16] = glGetUniformLocation( shader->GetObjID(), "PerlinLacunarity" );
670 uniforms[17] = glGetUniformLocation( shader->GetObjID(), "PerlinAmp" );
671 uniforms[18] = glGetUniformLocation( shader->GetObjID(), "WindSpeed" );
672 uniforms[19] = glGetUniformLocation( shader->GetObjID(), "shadowDensity" );
673 }
674
675
676 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
677 /// UPDATE
678 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
679
Update()680 void CBumpWater::Update()
681 {
682 if (!mapInfo->water.forceRendering && !readMap->HasVisibleWater())
683 return;
684 if (!wasVisibleLastFrame)
685 return;
686
687 /*
688 windndir *= 0.995f;
689 windndir -= wind.GetCurrentDirection() * 0.005f;
690 windStrength *= 0.9999f;
691 windStrength += (smoothstep(0.0f, 12.0f, wind.GetCurrentStrength()) * 0.5f + 4.0f) * 0.0001f;
692 windVec = windndir * windStrength;
693 */
694
695 if (dynWaves) {
696 UpdateDynWaves();
697 }
698
699 if (!shoreWaves) {
700 return;
701 }
702
703 SCOPED_TIMER("BumpWater::Update (Coastmap)");
704
705 if ((gs->frameNum % 10) == 0 && !heightmapUpdates.empty()) {
706 UploadCoastline();
707 }
708
709 if ((gs->frameNum % 10) == 5 && !coastmapAtlasRects.empty()) {
710 UpdateCoastmap();
711 }
712 }
713
714
UpdateWater(CGame * game)715 void CBumpWater::UpdateWater(CGame* game)
716 {
717 if (!mapInfo->water.forceRendering && !readMap->HasVisibleWater())
718 return;
719
720 #ifdef GLEW_ARB_occlusion_query2
721 if (occlusionQuery && !wasVisibleLastFrame) {
722 SCOPED_TIMER("BumpWater::UpdateWater (Occlcheck)");
723
724 glGetQueryObjectuiv(occlusionQuery, GL_QUERY_RESULT_AVAILABLE, &occlusionQueryResult);
725 if (occlusionQueryResult) {
726 glGetQueryObjectuiv(occlusionQuery, GL_QUERY_RESULT, &occlusionQueryResult);
727
728 wasVisibleLastFrame = !!occlusionQueryResult;
729
730 if (!occlusionQueryResult) {
731 return;
732 }
733 }
734
735 wasVisibleLastFrame = true;
736 }
737 #endif
738
739 glPushAttrib(GL_FOG_BIT);
740 if (refraction > 1) DrawRefraction(game);
741 if (reflection > 0) DrawReflection(game);
742 if (reflection || refraction) {
743 FBO::Unbind();
744 glViewport(globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY);
745 }
746 glPopAttrib();
747 }
748
749
750 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
751 /// SHOREWAVES/COASTMAP
752 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
753
CoastAtlasRect(const SRectangle & rect)754 CBumpWater::CoastAtlasRect::CoastAtlasRect(const SRectangle& rect)
755 {
756 ix1 = std::max(rect.x1 - 15, 0);
757 ix2 = std::min(rect.x2 + 15, gs->mapx);
758 iy1 = std::max(rect.y1 - 15, 0);
759 iy2 = std::min(rect.y2 + 15, gs->mapy);
760
761 xsize = ix2 - ix1;
762 ysize = iy2 - iy1;
763
764 x1 = (ix1 + 0.5f) / (float)gs->mapx;
765 x2 = (ix2 + 0.5f) / (float)gs->mapx;
766 y1 = (iy1 + 0.5f) / (float)gs->mapy;
767 y2 = (iy2 + 0.5f) / (float)gs->mapy;
768 tx1 = tx2 = ty1 = ty2 = 0.f;
769 isCoastline = true;
770 }
771
UnsyncedHeightMapUpdate(const SRectangle & rect)772 void CBumpWater::UnsyncedHeightMapUpdate(const SRectangle& rect)
773 {
774 if (!shoreWaves || !readMap->HasVisibleWater())
775 return;
776
777 heightmapUpdates.push_back(rect);
778 }
779
780
UploadCoastline(const bool forceFull)781 void CBumpWater::UploadCoastline(const bool forceFull)
782 {
783 //! optimize update area (merge overlapping areas etc.)
784 heightmapUpdates.Optimize();
785
786 //! limit the to be updated areas
787 unsigned int currentPixels = 0;
788
789 //! select the to be updated areas
790 while (!heightmapUpdates.empty()) {
791 SRectangle& cuRect1 = heightmapUpdates.front();
792
793 if ((currentPixels + cuRect1.GetArea() <= 512 * 512) || forceFull) {
794 currentPixels += cuRect1.GetArea();
795 coastmapAtlasRects.push_back(cuRect1);
796 heightmapUpdates.pop_front();
797 } else {
798 break;
799 }
800 }
801
802
803 //! create a texture atlas for the to-be-updated areas
804 CTextureAtlas atlas;
805 atlas.SetFreeTexture(false);
806
807 const float* heightMap = (gs->frameNum > 0) ? readMap->GetCornerHeightMapUnsynced() : readMap->GetCornerHeightMapSynced();
808
809 for (size_t i = 0; i < coastmapAtlasRects.size(); i++) {
810 CoastAtlasRect& caRect = coastmapAtlasRects[i];
811
812 unsigned int a = 0;
813 unsigned char* texpixels = (unsigned char*) atlas.AddTex(IntToString(i), caRect.xsize, caRect.ysize);
814
815 for (int y = 0; y < caRect.ysize; ++y) {
816 const int yindex = (y + caRect.iy1) * (gs->mapx+1) + caRect.ix1;
817 const int yindex2 = y * caRect.xsize;
818
819 for (int x = 0; x < caRect.xsize; ++x) {
820 const int index = yindex + x;
821 const int index2 = (yindex2 + x) << 2;
822 const float& height = heightMap[index];
823
824 texpixels[index2 ] = (height > 10.0f)? 255 : 0; //! isground
825 texpixels[index2 + 1] = (height > 0.0f)? 255 : 0; //! coastdist
826 texpixels[index2 + 2] = (height < 0.0f)? CReadMap::EncodeHeight(height) : 255; //! waterdepth
827 texpixels[index2 + 3] = 0;
828 a += (height > 0.0f)? 1: 0;
829 }
830 }
831
832 if (a == 0 || a == caRect.ysize * caRect.xsize) {
833 caRect.isCoastline = false;
834 }
835 }
836
837 //! create the texture atlas
838 if (!atlas.Finalize()) {
839 coastmapAtlasRects.clear();
840 return;
841 }
842
843 coastUpdateTexture = atlas.GetTexID();
844 atlasX = (atlas.GetSize()).x;
845 atlasY = (atlas.GetSize()).y;
846
847 //! save the area positions in the texture atlas
848 for (size_t i = 0; i < coastmapAtlasRects.size(); i++) {
849 CoastAtlasRect& r = coastmapAtlasRects[i];
850 const AtlasedTexture& tex = atlas.GetTexture(IntToString(i));
851 r.tx1 = tex.xstart;
852 r.tx2 = tex.xend;
853 r.ty1 = tex.ystart;
854 r.ty2 = tex.yend;
855 }
856 }
857
858
UpdateCoastmap()859 void CBumpWater::UpdateCoastmap()
860 {
861 coastFBO.Bind();
862 blurShader->Enable();
863
864 glDisable(GL_BLEND);
865 glDepthMask(GL_FALSE);
866 glDisable(GL_DEPTH_TEST);
867
868 glActiveTexture(GL_TEXTURE1);
869 glBindTexture(GL_TEXTURE_2D, coastUpdateTexture);
870 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
871 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
872 glActiveTexture(GL_TEXTURE0);
873 glBindTexture(GL_TEXTURE_2D, coastTexture);
874 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
875 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
876
877 glMatrixMode(GL_MODELVIEW);
878 glPushMatrix();
879 glLoadIdentity();
880 glMatrixMode(GL_PROJECTION);
881 glPushMatrix();
882 glLoadIdentity();
883 glOrtho(0, 1, 0, 1, -1, 1);
884
885 glViewport(0, 0, gs->mapx, gs->mapy);
886 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
887 coastFBO.AttachTexture(coastTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT);
888 glMultiTexCoord2i(GL_TEXTURE2, 0, 0);
889
890 glBegin(GL_QUADS);
891 for (size_t i = 0; i < coastmapAtlasRects.size(); i++) {
892 const CoastAtlasRect& r = coastmapAtlasRects[i];
893 glTexCoord4f(r.tx1, r.ty1, 0.0f, 0.0f); glVertex2f(r.x1, r.y1);
894 glTexCoord4f(r.tx1, r.ty2, 0.0f, 1.0f); glVertex2f(r.x1, r.y2);
895 glTexCoord4f(r.tx2, r.ty2, 1.0f, 1.0f); glVertex2f(r.x2, r.y2);
896 glTexCoord4f(r.tx2, r.ty1, 1.0f, 0.0f); glVertex2f(r.x2, r.y1);
897 }
898 glEnd();
899
900 if (atlasX > 0 && atlasY > 0) {
901 int n = 0;
902 for (int i = 0; i < 5; ++i) {
903 coastFBO.AttachTexture(coastUpdateTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT);
904 glViewport(0, 0, atlasX, atlasY);
905 glMultiTexCoord2i(GL_TEXTURE2, 1, ++n);
906
907 glBegin(GL_QUADS);
908 for (size_t j = 0; j < coastmapAtlasRects.size(); j++) {
909 const CoastAtlasRect& r = coastmapAtlasRects[j];
910 if (!r.isCoastline) continue;
911 glTexCoord4f(r.x1, r.y1, 0.0f, 0.0f); glVertex2f(r.tx1, r.ty1);
912 glTexCoord4f(r.x1, r.y2, 0.0f, 1.0f); glVertex2f(r.tx1, r.ty2);
913 glTexCoord4f(r.x2, r.y2, 1.0f, 1.0f); glVertex2f(r.tx2, r.ty2);
914 glTexCoord4f(r.x2, r.y1, 1.0f, 0.0f); glVertex2f(r.tx2, r.ty1);
915 }
916 glEnd();
917
918 coastFBO.AttachTexture(coastTexture, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT);
919 glViewport(0, 0, gs->mapx, gs->mapy);
920 glMultiTexCoord2i(GL_TEXTURE2, 0, ++n);
921
922 glBegin(GL_QUADS);
923 for (size_t j = 0; j < coastmapAtlasRects.size(); j++) {
924 const CoastAtlasRect& r = coastmapAtlasRects[j];
925 if (!r.isCoastline) continue;
926 glTexCoord4f(r.tx1, r.ty1, 0.0f, 0.0f); glVertex2f(r.x1, r.y1);
927 glTexCoord4f(r.tx1, r.ty2, 0.0f, 1.0f); glVertex2f(r.x1, r.y2);
928 glTexCoord4f(r.tx2, r.ty2, 1.0f, 1.0f); glVertex2f(r.x2, r.y2);
929 glTexCoord4f(r.tx2, r.ty1, 1.0f, 0.0f); glVertex2f(r.x2, r.y1);
930 }
931 glEnd();
932 }
933 }
934
935 //glMatrixMode(GL_PROJECTION);
936 glPopMatrix();
937 glMatrixMode(GL_MODELVIEW);
938 glPopMatrix();
939
940 blurShader->Disable();
941 coastFBO.Detach(GL_COLOR_ATTACHMENT1_EXT);
942 //coastFBO.Unbind();
943
944 //! generate mipmaps
945 //glActiveTexture(GL_TEXTURE0);
946 //glBindTexture(GL_TEXTURE_2D, coastTexture);
947 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
948 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
949 glGenerateMipmapEXT(GL_TEXTURE_2D);
950
951 //! delete UpdateAtlas
952 glActiveTexture(GL_TEXTURE1);
953 glBindTexture(GL_TEXTURE_2D, 0);
954 glDeleteTextures(1, &coastUpdateTexture);
955 coastmapAtlasRects.clear();
956
957 //glViewport(globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY);
958 glActiveTexture(GL_TEXTURE0);
959 }
960
961
962 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
963 /// DYNAMIC WAVES
964 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
965
UpdateDynWaves(const bool initialize)966 void CBumpWater::UpdateDynWaves(const bool initialize)
967 {
968 if (!dynWaves || !dynWavesFBO.IsValid()) {
969 return;
970 }
971
972 static const unsigned char tiles = mapInfo->water.numTiles; //! (numTiles <= 16)
973 static const unsigned char ntiles = mapInfo->water.numTiles * mapInfo->water.numTiles;
974 static const float tilesize = 1.0f/mapInfo->water.numTiles;
975
976 const int f = (gs->frameNum+1) % 60;
977
978 if (f == 0) {
979 for (unsigned char i = 0; i < ntiles; ++i) {
980 do {
981 tileOffsets[i] = (unsigned char)(gu->RandFloat()*ntiles);
982 } while (tileOffsets[i] == i);
983 }
984 }
985
986 dynWavesFBO.Bind();
987 glEnable(GL_TEXTURE_2D);
988 glBindTexture(GL_TEXTURE_2D, normalTexture2);
989 glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
990 glBlendColor(1.0f, 1.0f, 1.0f, (initialize) ? 1.0f : (f + 1)/600.0f );
991 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
992 glEnable(GL_BLEND);
993 glDepthMask(GL_FALSE);
994 glDisable(GL_DEPTH_TEST);
995
996 glViewport(0, 0, normalTextureX, normalTextureY);
997 glMatrixMode(GL_MODELVIEW);
998 glPushMatrix();
999 glLoadIdentity();
1000 glMatrixMode(GL_PROJECTION);
1001 glPushMatrix();
1002 glLoadIdentity();
1003 glOrtho(0, 1, 0, 1, -1, 1);
1004 glMatrixMode(GL_TEXTURE);
1005 glPushMatrix();
1006 glLoadIdentity();
1007
1008 glBegin(GL_QUADS);
1009 unsigned char offset, tx, ty;
1010 for (unsigned char y = 0; y < tiles; ++y) {
1011 for (unsigned char x = 0; x < tiles; ++x) {
1012 offset = tileOffsets[y * tiles + x];
1013 tx = offset % tiles;
1014 ty = (offset - tx)/tiles;
1015 glTexCoord2f( tx * tilesize, ty * tilesize ); glVertex2f( x * tilesize, y * tilesize );
1016 glTexCoord2f( tx * tilesize, (ty+1) * tilesize ); glVertex2f( x * tilesize, (y+1) * tilesize );
1017 glTexCoord2f( (tx+1) * tilesize, (ty+1) * tilesize ); glVertex2f( (x+1) * tilesize, (y+1) * tilesize );
1018 glTexCoord2f( (tx+1) * tilesize, ty * tilesize ); glVertex2f( (x+1) * tilesize, y * tilesize );
1019 }
1020 }
1021 glEnd();
1022
1023 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1024
1025 glPopMatrix();
1026 glMatrixMode(GL_PROJECTION);
1027 glPopMatrix();
1028 glMatrixMode(GL_MODELVIEW);
1029 glPopMatrix();
1030 glViewport(globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY);
1031
1032 dynWavesFBO.Unbind();
1033
1034 glBindTexture(GL_TEXTURE_2D, normalTexture);
1035 glGenerateMipmapEXT(GL_TEXTURE_2D);
1036 }
1037
1038
1039 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1040 /// DRAW FUNCTIONS
1041 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1042
SetUniforms()1043 void CBumpWater::SetUniforms()
1044 {
1045 glUniform4f( uniforms[ 0], mapInfo->water.surfaceColor.x*0.4, mapInfo->water.surfaceColor.y*0.4, mapInfo->water.surfaceColor.z*0.4, mapInfo->water.surfaceAlpha);
1046 glUniform4f( uniforms[ 1], mapInfo->water.planeColor.x*0.4, mapInfo->water.planeColor.y*0.4, mapInfo->water.planeColor.z*0.4, mapInfo->water.surfaceAlpha);
1047 glUniform3f( uniforms[ 2], mapInfo->water.diffuseColor.x, mapInfo->water.diffuseColor.y, mapInfo->water.diffuseColor.z);
1048 glUniform3f( uniforms[ 3], mapInfo->water.specularColor.x, mapInfo->water.specularColor.y, mapInfo->water.specularColor.z);
1049 glUniform1f( uniforms[ 4], mapInfo->water.specularPower);
1050 glUniform1f( uniforms[ 5], mapInfo->water.specularFactor);
1051 glUniform1f( uniforms[ 6], mapInfo->water.ambientFactor);
1052 glUniform1f( uniforms[ 7], mapInfo->water.diffuseFactor * 15.0f);
1053 glUniform3fv(uniforms[ 8], 1, &sky->GetLight()->GetLightDir().x);
1054 glUniform1f( uniforms[ 9], mapInfo->water.fresnelMin);
1055 glUniform1f( uniforms[10], mapInfo->water.fresnelMax);
1056 glUniform1f( uniforms[11], mapInfo->water.fresnelPower);
1057 glUniform1f( uniforms[12], mapInfo->water.reflDistortion);
1058 glUniform2f( uniforms[13], 0.0f, mapInfo->water.blurBase / globalRendering->viewSizeY);
1059 glUniform1f( uniforms[14], mapInfo->water.blurExponent);
1060 glUniform1f( uniforms[15], mapInfo->water.perlinStartFreq);
1061 glUniform1f( uniforms[16], mapInfo->water.perlinLacunarity);
1062 glUniform1f( uniforms[17], mapInfo->water.perlinAmplitude);
1063 glUniform1f( uniforms[18], mapInfo->water.windSpeed);
1064 glUniform1f( uniforms[19], sky->GetLight()->GetGroundShadowDensity());
1065 }
1066
1067
Draw()1068 void CBumpWater::Draw()
1069 {
1070 if (!occlusionQueryResult || (!mapInfo->water.forceRendering && !readMap->HasVisibleWater()))
1071 return;
1072
1073 #ifdef GLEW_ARB_occlusion_query2
1074 if (occlusionQuery) {
1075 glBeginConditionalRenderNV(occlusionQuery, GL_QUERY_BY_REGION_WAIT_NV);
1076 glBeginQuery(GL_ANY_SAMPLES_PASSED,occlusionQuery);
1077 }
1078 #endif
1079
1080 if (refraction == 1) {
1081 //! _SCREENCOPY_ REFRACT TEXTURE
1082 glBindTexture(target, refractTexture);
1083 glCopyTexSubImage2D(target, 0, 0, 0, globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY);
1084 }
1085
1086 if (depthCopy) {
1087 //! _SCREENCOPY_ DEPTH TEXTURE
1088 glBindTexture(target, depthTexture);
1089 glCopyTexSubImage2D(target, 0, 0, 0, globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY);
1090 }
1091
1092 glDisable(GL_ALPHA_TEST);
1093 if (refraction < 2) {
1094 glDepthMask(GL_FALSE);
1095 }
1096 if (refraction > 0) {
1097 glDisable(GL_BLEND);
1098 }
1099
1100 const CBaseGroundDrawer* gd = readMap->GetGroundDrawer();
1101
1102 waterShader->SetFlag("opt_shadows", (shadowHandler && shadowHandler->shadowsLoaded));
1103 waterShader->SetFlag("opt_infotex", gd->DrawExtraTex());
1104
1105 waterShader->Enable();
1106 waterShader->SetUniform3fv(0, &camera->GetPos()[0]);
1107 waterShader->SetUniform1f(1, (gs->frameNum + globalRendering->timeOffset) / 15000.0f);
1108
1109 if (shadowHandler && shadowHandler->shadowsLoaded) {
1110 waterShader->SetUniformMatrix4fv(13, false, &shadowHandler->shadowMatrix.m[0]);
1111
1112 glActiveTexture(GL_TEXTURE9);
1113 glBindTexture(GL_TEXTURE_2D, (shadowHandler && shadowHandler->shadowsLoaded) ? shadowHandler->shadowTexture : 0);
1114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
1115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
1116 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
1117 }
1118
1119 const int causticTexNum = (gs->frameNum % caustTextures.size());
1120 glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, readMap->GetShadingTexture());
1121 glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, caustTextures[causticTexNum]);
1122 glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, foamTexture);
1123 glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, reflectTexture);
1124 glActiveTexture(GL_TEXTURE5); glBindTexture(target, refractTexture);
1125 glActiveTexture(GL_TEXTURE6); glBindTexture(GL_TEXTURE_2D, coastTexture);
1126 glActiveTexture(GL_TEXTURE7); glBindTexture(target, depthTexture);
1127 glActiveTexture(GL_TEXTURE8); glBindTexture(GL_TEXTURE_2D, waveRandTexture);
1128 //glActiveTexture(GL_TEXTURE9); see above
1129 glActiveTexture(GL_TEXTURE10); glBindTexture(GL_TEXTURE_2D, gd->GetActiveInfoTexture());
1130 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, normalTexture);
1131
1132 if (useUniforms) {
1133 SetUniforms();
1134 }
1135
1136 glMultiTexCoord2f(GL_TEXTURE1, windVec.x, windVec.z);
1137 glCallList(displayList);
1138
1139 waterShader->Disable();
1140
1141 if (shadowHandler && shadowHandler->shadowsLoaded) {
1142 glActiveTexture(GL_TEXTURE9); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
1143 glActiveTexture(GL_TEXTURE0);
1144 }
1145 if (refraction < 2) {
1146 glDepthMask(GL_TRUE);
1147 }
1148 if (refraction > 0) {
1149 glEnable(GL_BLEND);
1150 }
1151
1152 #ifdef GLEW_ARB_occlusion_query2
1153 if (occlusionQuery) {
1154 glEndQuery(GL_ANY_SAMPLES_PASSED);
1155 glEndConditionalRenderNV();
1156 }
1157 #endif
1158 }
1159
1160
DrawRefraction(CGame * game)1161 void CBumpWater::DrawRefraction(CGame* game)
1162 {
1163 //! _RENDER_ REFRACTION TEXTURE
1164 refractFBO.Bind();
1165
1166 camera->Update();
1167
1168 game->SetDrawMode(CGame::gameRefractionDraw);
1169 glViewport(0, 0, globalRendering->viewSizeX, globalRendering->viewSizeY);
1170 glClearColor(mapInfo->atmosphere.fogColor[0], mapInfo->atmosphere.fogColor[1], mapInfo->atmosphere.fogColor[2], 0);
1171 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1172 //sky->Draw();
1173 glDisable(GL_FOG); // fog has overground settings, if at all we should add special underwater settings
1174
1175 const float3 oldsun = unitDrawer->unitSunColor;
1176 const float3 oldambient = unitDrawer->unitAmbientColor;
1177
1178 unitDrawer->unitSunColor *= float3(0.5f, 0.7f, 0.9f);
1179 unitDrawer->unitAmbientColor *= float3(0.6f, 0.8f, 1.0f);
1180
1181 drawRefraction = true;
1182
1183 glEnable(GL_CLIP_PLANE2);
1184 const double plane[4] = {0, -1, 0, 5};
1185 glClipPlane(GL_CLIP_PLANE2, plane);
1186
1187 // opaque
1188 readMap->GetGroundDrawer()->Draw(DrawPass::WaterRefraction);
1189 unitDrawer->Draw(false, true);
1190 featureDrawer->Draw();
1191
1192 // transparent stuff
1193 unitDrawer->DrawCloakedUnits();
1194 featureDrawer->DrawFadeFeatures();
1195 projectileDrawer->Draw(false, true);
1196 eventHandler.DrawWorldRefraction();
1197
1198 glDisable(GL_CLIP_PLANE2);
1199 game->SetDrawMode(CGame::gameNormalDraw);
1200 drawRefraction = false;
1201
1202 glEnable(GL_FOG);
1203
1204 unitDrawer->unitSunColor=oldsun;
1205 unitDrawer->unitAmbientColor=oldambient;
1206 }
1207
1208
DrawReflection(CGame * game)1209 void CBumpWater::DrawReflection(CGame* game)
1210 {
1211 //! CREATE REFLECTION TEXTURE
1212 reflectFBO.Bind();
1213
1214 // CCamera* realCam = camera;
1215 // camera = new CCamera(*realCam);
1216 char realCam[sizeof(CCamera)];
1217 new (realCam) CCamera(*camera); // anti-crash workaround for multithreading
1218
1219 camera->forward.y *= -1.0f;
1220 camera->SetPos(camera->GetPos() * float3(1.0f, -1.0f, 1.0f));
1221 camera->Update();
1222
1223 game->SetDrawMode(CGame::gameReflectionDraw);
1224 glViewport(0, 0, reflTexSize, reflTexSize);
1225 glClearColor(mapInfo->atmosphere.fogColor[0], mapInfo->atmosphere.fogColor[1], mapInfo->atmosphere.fogColor[2], 0);
1226 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1227 sky->Draw();
1228
1229 glEnable(GL_CLIP_PLANE2);
1230 const double plane[4] = {0, 1, 0, 1};
1231 glClipPlane(GL_CLIP_PLANE2, plane);
1232 drawReflection = true;
1233
1234 // opaque
1235 if (reflection > 1) {
1236 readMap->GetGroundDrawer()->Draw(DrawPass::WaterReflection);
1237 }
1238 unitDrawer->Draw(true);
1239 featureDrawer->Draw();
1240
1241 // transparent
1242 unitDrawer->DrawCloakedUnits(true);
1243 featureDrawer->DrawFadeFeatures(true);
1244 projectileDrawer->Draw(true);
1245 eventHandler.DrawWorldReflection();
1246
1247 game->SetDrawMode(CGame::gameNormalDraw);
1248 drawReflection = false;
1249 glDisable(GL_CLIP_PLANE2);
1250
1251 // delete camera;
1252 // camera = realCam;
1253 camera->~CCamera();
1254 new (camera) CCamera(*(reinterpret_cast<CCamera*>(realCam)));
1255 reinterpret_cast<CCamera*>(realCam)->~CCamera();
1256 camera->Update();
1257 }
1258
1259
OcclusionQuery()1260 void CBumpWater::OcclusionQuery()
1261 {
1262 if (!occlusionQuery || (!mapInfo->water.forceRendering && !readMap->HasVisibleWater()))
1263 return;
1264
1265 #ifdef GLEW_ARB_occlusion_query2
1266 glGetQueryObjectuiv(occlusionQuery, GL_QUERY_RESULT_AVAILABLE, &occlusionQueryResult);
1267
1268 if (occlusionQueryResult || !wasVisibleLastFrame) {
1269 glGetQueryObjectuiv(occlusionQuery,GL_QUERY_RESULT, &occlusionQueryResult);
1270 wasVisibleLastFrame = !!occlusionQueryResult;
1271 } else {
1272 occlusionQueryResult = true;
1273 wasVisibleLastFrame = true;
1274 }
1275
1276 if (!wasVisibleLastFrame) {
1277 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1278 glDepthMask(GL_FALSE);
1279 glEnable(GL_DEPTH_TEST);
1280
1281 glPushMatrix();
1282 glTranslatef(0.0, 10.0, 0.0);
1283 glBeginQuery(GL_ANY_SAMPLES_PASSED, occlusionQuery);
1284 glCallList(displayList);
1285 glEndQuery(GL_ANY_SAMPLES_PASSED);
1286 glPopMatrix();
1287
1288 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1289 glDepthMask(GL_TRUE);
1290 }
1291 #endif
1292 }
1293