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