1 /* Copyright (C) 2013 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Terrain rendering (everything related to patches and water) is
20  * encapsulated in TerrainRenderer
21  */
22 
23 #include "precompiled.h"
24 
25 #include "graphics/Camera.h"
26 #include "graphics/Decal.h"
27 #include "graphics/LightEnv.h"
28 #include "graphics/LOSTexture.h"
29 #include "graphics/Patch.h"
30 #include "graphics/GameView.h"
31 #include "graphics/Model.h"
32 #include "graphics/ShaderManager.h"
33 #include "renderer/ShadowMap.h"
34 #include "renderer/SkyManager.h"
35 #include "graphics/TerritoryTexture.h"
36 #include "graphics/TextRenderer.h"
37 
38 #include "maths/MathUtil.h"
39 
40 #include "ps/Filesystem.h"
41 #include "ps/CLogger.h"
42 #include "ps/Game.h"
43 #include "ps/Profile.h"
44 #include "ps/World.h"
45 
46 #include "renderer/DecalRData.h"
47 #include "renderer/PatchRData.h"
48 #include "renderer/Renderer.h"
49 #include "renderer/ShadowMap.h"
50 #include "renderer/TerrainRenderer.h"
51 #include "renderer/VertexArray.h"
52 #include "renderer/WaterManager.h"
53 
54 #include "tools/atlas/GameInterface/GameLoop.h"
55 
56 extern GameLoopState* g_AtlasGameLoop;
57 
58 ///////////////////////////////////////////////////////////////////////////////////////////////
59 // TerrainRenderer implementation
60 
61 
62 /**
63  * TerrainRenderer keeps track of which phase it is in, to detect
64  * when Submit, PrepareForRendering etc. are called in the wrong order.
65  */
66 enum Phase {
67 	Phase_Submit,
68 	Phase_Render
69 };
70 
71 
72 /**
73  * Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
74  */
75 struct TerrainRendererInternals
76 {
77 	/// Which phase (submitting or rendering patches) are we in right now?
78 	Phase phase;
79 
80 	/// Patches that were submitted for this frame
81 	std::vector<CPatchRData*> visiblePatches[CRenderer::CULL_MAX];
82 
83 	/// Decals that were submitted for this frame
84 	std::vector<CDecalRData*> visibleDecals[CRenderer::CULL_MAX];
85 
86 	/// Fancy water shader
87 	CShaderProgramPtr fancyWaterShader;
88 
89 	CSimulation2* simulation;
90 };
91 
92 
93 
94 ///////////////////////////////////////////////////////////////////
95 // Construction/Destruction
TerrainRenderer()96 TerrainRenderer::TerrainRenderer()
97 {
98 	m = new TerrainRendererInternals();
99 	m->phase = Phase_Submit;
100 }
101 
~TerrainRenderer()102 TerrainRenderer::~TerrainRenderer()
103 {
104 	delete m;
105 }
106 
SetSimulation(CSimulation2 * simulation)107 void TerrainRenderer::SetSimulation(CSimulation2* simulation)
108 {
109 	m->simulation = simulation;
110 }
111 
112 ///////////////////////////////////////////////////////////////////
113 // Submit a patch for rendering
Submit(int cullGroup,CPatch * patch)114 void TerrainRenderer::Submit(int cullGroup, CPatch* patch)
115 {
116 	ENSURE(m->phase == Phase_Submit);
117 
118 	CPatchRData* data = (CPatchRData*)patch->GetRenderData();
119 	if (data == 0)
120 	{
121 		// no renderdata for patch, create it now
122 		data = new CPatchRData(patch, m->simulation);
123 		patch->SetRenderData(data);
124 	}
125 	data->Update(m->simulation);
126 
127 	m->visiblePatches[cullGroup].push_back(data);
128 }
129 
130 ///////////////////////////////////////////////////////////////////
131 // Submit a decal for rendering
Submit(int cullGroup,CModelDecal * decal)132 void TerrainRenderer::Submit(int cullGroup, CModelDecal* decal)
133 {
134 	ENSURE(m->phase == Phase_Submit);
135 
136 	CDecalRData* data = (CDecalRData*)decal->GetRenderData();
137 	if (data == 0)
138 	{
139 		// no renderdata for decal, create it now
140 		data = new CDecalRData(decal, m->simulation);
141 		decal->SetRenderData(data);
142 	}
143 	data->Update(m->simulation);
144 
145 	m->visibleDecals[cullGroup].push_back(data);
146 }
147 
148 ///////////////////////////////////////////////////////////////////
149 // Prepare for rendering
PrepareForRendering()150 void TerrainRenderer::PrepareForRendering()
151 {
152 	ENSURE(m->phase == Phase_Submit);
153 
154 	m->phase = Phase_Render;
155 }
156 
157 ///////////////////////////////////////////////////////////////////
158 // Clear submissions lists
EndFrame()159 void TerrainRenderer::EndFrame()
160 {
161 	ENSURE(m->phase == Phase_Render || m->phase == Phase_Submit);
162 
163 	for (int i = 0; i < CRenderer::CULL_MAX; ++i)
164 	{
165 		m->visiblePatches[i].clear();
166 		m->visibleDecals[i].clear();
167 	}
168 
169 	m->phase = Phase_Submit;
170 }
171 
172 
173 ///////////////////////////////////////////////////////////////////
174 // Full-featured terrain rendering with blending and everything
RenderTerrain(int cullGroup)175 void TerrainRenderer::RenderTerrain(int cullGroup)
176 {
177 #if CONFIG2_GLES
178 	UNUSED2(cullGroup);
179 #else
180 	ENSURE(m->phase == Phase_Render);
181 
182 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
183 	std::vector<CDecalRData*>& visibleDecals = m->visibleDecals[cullGroup];
184 	if (visiblePatches.empty() && visibleDecals.empty())
185 		return;
186 
187 	CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
188 	dummyShader->Bind();
189 
190 	// render the solid black sides of the map first
191 	g_Renderer.BindTexture(0, 0);
192 	glEnableClientState(GL_VERTEX_ARRAY);
193 	glColor3f(0, 0, 0);
194 	PROFILE_START("render terrain sides");
195 	for (size_t i = 0; i < visiblePatches.size(); ++i)
196 		visiblePatches[i]->RenderSides(dummyShader);
197 	PROFILE_END("render terrain sides");
198 
199 	// switch on required client states
200 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
201 
202 	// render everything fullbright
203 	// set up texture environment for base pass
204 	pglActiveTextureARB(GL_TEXTURE0);
205 	pglClientActiveTextureARB(GL_TEXTURE0);
206 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
207 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
208 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
209 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
210 
211 	// Set alpha to 1.0
212 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
213 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT);
214 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
215 	static const float one[4] = { 1.f, 1.f, 1.f, 1.f };
216 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one);
217 
218 	PROFILE_START("render terrain base");
219 	CPatchRData::RenderBases(visiblePatches, CShaderDefines(), NULL, true, dummyShader);
220 	PROFILE_END("render terrain base");
221 
222 	// render blends
223 	// switch on the composite alpha map texture
224 	(void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
225 
226 	// switch on second uv set
227 	pglClientActiveTextureARB(GL_TEXTURE1);
228 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
229 
230 	// setup additional texenv required by blend pass
231 	pglActiveTextureARB(GL_TEXTURE1);
232 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
233 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
234 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
235 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
236 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
237 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
238 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
239 
240 	// switch on blending
241 	glEnable(GL_BLEND);
242 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
243 
244 	// no need to write to the depth buffer a second time
245 	glDepthMask(0);
246 
247 	// The decal color array contains lighting data, which we don't want in this non-shader mode
248 	glDisableClientState(GL_COLOR_ARRAY);
249 
250 	// render blend passes for each patch
251 	PROFILE_START("render terrain blends");
252 	CPatchRData::RenderBlends(visiblePatches, CShaderDefines(), NULL, true, dummyShader);
253 	PROFILE_END("render terrain blends");
254 
255 	// Disable second texcoord array
256 	pglClientActiveTextureARB(GL_TEXTURE1);
257 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
258 
259 
260 	// Render terrain decals
261 
262 	g_Renderer.BindTexture(1, 0);
263 	pglActiveTextureARB(GL_TEXTURE0);
264 	pglClientActiveTextureARB(GL_TEXTURE0);
265 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
266 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
267 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
268 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
269 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
270 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
271 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
272 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
273 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
274 
275 	PROFILE_START("render terrain decals");
276 	CDecalRData::RenderDecals(visibleDecals, CShaderDefines(), NULL, true, dummyShader);
277 	PROFILE_END("render terrain decals");
278 
279 
280 	// Now apply lighting
281 	const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
282 
283 	pglClientActiveTextureARB(GL_TEXTURE0);
284 	glEnableClientState(GL_COLOR_ARRAY); // diffuse lighting colors
285 
286 	// The vertex color is scaled by 0.5 to permit overbrightness without clamping.
287 	// We therefore need to draw clamp((texture*lighting)*2.0), where 'texture'
288 	// is what previous passes drew onto the framebuffer, and 'lighting' is the
289 	// color computed by this pass.
290 	// We can do that with blending by getting it to draw dst*src + src*dst:
291 	glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
292 
293 	// Scale the ambient color by 0.5 to match the vertex diffuse colors
294 	float terrainAmbientColor[4] = {
295 		lightEnv.m_TerrainAmbientColor.X * 0.5f,
296 		lightEnv.m_TerrainAmbientColor.Y * 0.5f,
297 		lightEnv.m_TerrainAmbientColor.Z * 0.5f,
298 		1.f
299 	};
300 
301 	CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();
302 
303 	int streamflags = STREAM_POS|STREAM_COLOR;
304 
305 	pglActiveTextureARB(GL_TEXTURE0);
306 	// We're not going to use a texture here, but we have to have a valid texture
307 	// bound else the texture unit will be disabled.
308 	// We should still have a bound splat texture from some earlier rendering,
309 	// so assume that's still valid to use.
310 	// (TODO: That's a bit of an ugly hack.)
311 
312 	// No shadows: (Ambient + Diffuse) * LOS
313 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
314 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
315 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
316 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
317 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
318 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
319 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
320 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
321 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
322 
323 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
324 
325 	losTexture.BindTexture(1);
326 	pglClientActiveTextureARB(GL_TEXTURE1);
327 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
328 	streamflags |= STREAM_POSTOUV1;
329 
330 	glMatrixMode(GL_TEXTURE);
331 	glLoadMatrixf(&losTexture.GetTextureMatrix()._11);
332 	glMatrixMode(GL_MODELVIEW);
333 
334 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
335 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
336 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
337 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
338 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
339 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
340 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
341 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
342 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
343 
344 	pglActiveTextureARB(GL_TEXTURE0);
345 	pglClientActiveTextureARB(GL_TEXTURE0);
346 
347 	PROFILE_START("render terrain streams");
348 	CPatchRData::RenderStreams(visiblePatches, dummyShader, streamflags);
349 	PROFILE_END("render terrain streams");
350 
351 	glMatrixMode(GL_TEXTURE);
352 	glLoadIdentity();
353 	glMatrixMode(GL_MODELVIEW);
354 
355 	// restore OpenGL state
356 	g_Renderer.BindTexture(1, 0);
357 
358 	pglClientActiveTextureARB(GL_TEXTURE1);
359 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
360 	glMatrixMode(GL_TEXTURE);
361 	glLoadIdentity();
362 	glMatrixMode(GL_MODELVIEW);
363 
364 	pglClientActiveTextureARB(GL_TEXTURE0);
365 	pglActiveTextureARB(GL_TEXTURE0);
366 
367 	glDepthMask(1);
368 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
369 	glDisable(GL_BLEND);
370 	glDisableClientState(GL_COLOR_ARRAY);
371 	glDisableClientState(GL_VERTEX_ARRAY);
372 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
373 
374 	dummyShader->Unbind();
375 #endif
376 }
377 
RenderTerrainOverlayTexture(int cullGroup,CMatrix3D & textureMatrix)378 void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup, CMatrix3D& textureMatrix)
379 {
380 #if CONFIG2_GLES
381 #warning TODO: implement TerrainRenderer::RenderTerrainOverlayTexture for GLES
382 	UNUSED2(cullGroup);
383 	UNUSED2(textureMatrix);
384 #else
385 	ENSURE(m->phase == Phase_Render);
386 
387 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
388 
389 	glEnableClientState(GL_VERTEX_ARRAY);
390 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
391 
392 	pglActiveTextureARB(GL_TEXTURE0);
393 	glEnable(GL_TEXTURE_2D);
394 	glEnable(GL_BLEND);
395 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
396 	glDepthMask(0);
397 	glDisable(GL_DEPTH_TEST);
398 
399 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
400 
401 	glMatrixMode(GL_TEXTURE);
402 	glLoadMatrixf(&textureMatrix._11);
403 	glMatrixMode(GL_MODELVIEW);
404 
405 	CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
406 	dummyShader->Bind();
407 	CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS|STREAM_POSTOUV0);
408 	dummyShader->Unbind();
409 
410 	// To make the overlay visible over water, render an additional map-sized
411 	// water-height patch
412 	CBoundingBoxAligned waterBounds;
413 	for (size_t i = 0; i < visiblePatches.size(); ++i)
414 	{
415 		CPatchRData* data = visiblePatches[i];
416 		waterBounds += data->GetWaterBounds();
417 	}
418 	if (!waterBounds.IsEmpty())
419 	{
420 		float h = g_Renderer.GetWaterManager()->m_WaterHeight + 0.05f; // add a delta to avoid z-fighting
421 		float waterPos[] = {
422 			waterBounds[0].X, h, waterBounds[0].Z,
423 			waterBounds[1].X, h, waterBounds[0].Z,
424 			waterBounds[0].X, h, waterBounds[1].Z,
425 			waterBounds[1].X, h, waterBounds[1].Z
426 		};
427 		glVertexPointer(3, GL_FLOAT, 3*sizeof(float), waterPos);
428 		glTexCoordPointer(3, GL_FLOAT, 3*sizeof(float), waterPos);
429 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
430 	}
431 
432 	glMatrixMode(GL_TEXTURE);
433 	glLoadIdentity();
434 	glMatrixMode(GL_MODELVIEW);
435 
436 	glDepthMask(1);
437 	glEnable(GL_DEPTH_TEST);
438 	glDisable(GL_BLEND);
439 	glDisableClientState(GL_COLOR_ARRAY);
440 	glDisableClientState(GL_VERTEX_ARRAY);
441 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
442 #endif
443 }
444 
445 
446 ///////////////////////////////////////////////////////////////////
447 
448 /**
449  * Set up all the uniforms for a shader pass.
450  */
PrepareShader(const CShaderProgramPtr & shader,ShadowMap * shadow)451 void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow)
452 {
453 	shader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
454 	shader->Uniform(str_cameraPos, g_Renderer.GetViewCamera().GetOrientation().GetTranslation());
455 
456 	const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
457 
458 	if (shadow)
459 	{
460 		shader->BindTexture(str_shadowTex, shadow->GetTexture());
461 		shader->Uniform(str_shadowTransform, shadow->GetTextureMatrix());
462 		int width = shadow->GetWidth();
463 		int height = shadow->GetHeight();
464 		shader->Uniform(str_shadowScale, width, height, 1.0f / width, 1.0f / height);
465 	}
466 
467 	CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
468 	shader->BindTexture(str_losTex, los.GetTextureSmooth());
469 	shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
470 
471 	shader->Uniform(str_ambient, lightEnv.m_TerrainAmbientColor);
472 	shader->Uniform(str_sunColor, lightEnv.m_SunColor);
473 	shader->Uniform(str_sunDir, lightEnv.GetSunDir());
474 
475 	shader->Uniform(str_fogColor, lightEnv.m_FogColor);
476 	shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f);
477 }
478 
RenderTerrainShader(const CShaderDefines & context,int cullGroup,ShadowMap * shadow)479 void TerrainRenderer::RenderTerrainShader(const CShaderDefines& context, int cullGroup, ShadowMap* shadow)
480 {
481 	ENSURE(m->phase == Phase_Render);
482 
483 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
484 	std::vector<CDecalRData*>& visibleDecals = m->visibleDecals[cullGroup];
485 	if (visiblePatches.empty() && visibleDecals.empty())
486 		return;
487 
488 	// render the solid black sides of the map first
489 	CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid);
490 	techSolid->BeginPass();
491 	CShaderProgramPtr shaderSolid = techSolid->GetShader();
492 	shaderSolid->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
493 	shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f);
494 
495 	PROFILE_START("render terrain sides");
496 	for (size_t i = 0; i < visiblePatches.size(); ++i)
497 		visiblePatches[i]->RenderSides(shaderSolid);
498 	PROFILE_END("render terrain sides");
499 
500 	techSolid->EndPass();
501 
502 	PROFILE_START("render terrain base");
503 	CPatchRData::RenderBases(visiblePatches, context, shadow);
504 	PROFILE_END("render terrain base");
505 
506 	// no need to write to the depth buffer a second time
507 	glDepthMask(0);
508 
509 	// render blend passes for each patch
510 	PROFILE_START("render terrain blends");
511 	CPatchRData::RenderBlends(visiblePatches, context, shadow, false);
512 	PROFILE_END("render terrain blends");
513 
514 	PROFILE_START("render terrain decals");
515 	CDecalRData::RenderDecals(visibleDecals, context, shadow, false);
516 	PROFILE_END("render terrain decals");
517 
518 	// restore OpenGL state
519 	g_Renderer.BindTexture(1, 0);
520 	g_Renderer.BindTexture(2, 0);
521 	g_Renderer.BindTexture(3, 0);
522 
523 	glDepthMask(1);
524 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
525 	glDisable(GL_BLEND);
526 }
527 
528 
529 ///////////////////////////////////////////////////////////////////
530 // Render un-textured patches as polygons
RenderPatches(int cullGroup)531 void TerrainRenderer::RenderPatches(int cullGroup)
532 {
533 	ENSURE(m->phase == Phase_Render);
534 
535 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
536 	if (visiblePatches.empty())
537 		return;
538 
539 #if CONFIG2_GLES
540 #warning TODO: implement TerrainRenderer::RenderPatches for GLES
541 #else
542 	CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
543 	dummyShader->Bind();
544 
545 	glEnableClientState(GL_VERTEX_ARRAY);
546 	CPatchRData::RenderStreams(visiblePatches, dummyShader, STREAM_POS);
547 	glDisableClientState(GL_VERTEX_ARRAY);
548 
549 	dummyShader->Unbind();
550 #endif
551 }
552 
553 
554 ///////////////////////////////////////////////////////////////////
555 // Render outlines of submitted patches as lines
RenderOutlines(int cullGroup)556 void TerrainRenderer::RenderOutlines(int cullGroup)
557 {
558 	ENSURE(m->phase == Phase_Render);
559 
560 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
561 	if (visiblePatches.empty())
562 		return;
563 
564 #if CONFIG2_GLES
565 #warning TODO: implement TerrainRenderer::RenderOutlines for GLES
566 #else
567 	glEnableClientState(GL_VERTEX_ARRAY);
568 	for (size_t i = 0; i < visiblePatches.size(); ++i)
569 		visiblePatches[i]->RenderOutline();
570 	glDisableClientState(GL_VERTEX_ARRAY);
571 #endif
572 }
573 
574 
575 ///////////////////////////////////////////////////////////////////
576 // Scissor rectangle of water patches
ScissorWater(int cullGroup,const CMatrix3D & viewproj)577 CBoundingBoxAligned TerrainRenderer::ScissorWater(int cullGroup, const CMatrix3D &viewproj)
578 {
579 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
580 
581 	CBoundingBoxAligned scissor;
582 	for (size_t i = 0; i < visiblePatches.size(); ++i)
583 	{
584 		CPatchRData* data = visiblePatches[i];
585 		const CBoundingBoxAligned& waterBounds = data->GetWaterBounds();
586 		if (waterBounds.IsEmpty())
587 			continue;
588 
589 		CVector4D v1 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f));
590 		CVector4D v2 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[0].Z, 1.0f));
591 		CVector4D v3 = viewproj.Transform(CVector4D(waterBounds[0].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f));
592 		CVector4D v4 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f));
593 		CBoundingBoxAligned screenBounds;
594 		#define ADDBOUND(v1, v2, v3, v4) \
595 			if (v1.Z >= -v1.W) \
596 				screenBounds += CVector3D(v1.X, v1.Y, v1.Z) * (1.0f / v1.W); \
597 			else \
598 			{ \
599 				float t = v1.Z + v1.W; \
600 				if (v2.Z > -v2.W) \
601 				{ \
602 					CVector4D c2 = v1 + (v2 - v1) * (t / (t - (v2.Z + v2.W))); \
603 					screenBounds += CVector3D(c2.X, c2.Y, c2.Z) * (1.0f / c2.W); \
604 				} \
605 				if (v3.Z > -v3.W) \
606 				{ \
607 					CVector4D c3 = v1 + (v3 - v1) * (t / (t - (v3.Z + v3.W))); \
608 					screenBounds += CVector3D(c3.X, c3.Y, c3.Z) * (1.0f / c3.W); \
609 				} \
610 				if (v4.Z > -v4.W) \
611 				{ \
612 					CVector4D c4 = v1 + (v4 - v1) * (t / (t - (v4.Z + v4.W))); \
613 					screenBounds += CVector3D(c4.X, c4.Y, c4.Z) * (1.0f / c4.W); \
614 				} \
615 			}
616 		ADDBOUND(v1, v2, v3, v4);
617 		ADDBOUND(v2, v1, v3, v4);
618 		ADDBOUND(v3, v1, v2, v4);
619 		ADDBOUND(v4, v1, v2, v3);
620 		#undef ADDBOUND
621 		if (screenBounds[0].X >= 1.0f || screenBounds[1].X <= -1.0f || screenBounds[0].Y >= 1.0f || screenBounds[1].Y <= -1.0f)
622 			continue;
623 		scissor += screenBounds;
624 	}
625 	return CBoundingBoxAligned(CVector3D(clamp(scissor[0].X, -1.0f, 1.0f), clamp(scissor[0].Y, -1.0f, 1.0f), -1.0f),
626 				  CVector3D(clamp(scissor[1].X, -1.0f, 1.0f), clamp(scissor[1].Y, -1.0f, 1.0f), 1.0f));
627 }
628 
629 // Render fancy water
RenderFancyWater(const CShaderDefines & context,int cullGroup,ShadowMap * shadow)630 bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow)
631 {
632 	PROFILE3_GPU("fancy water");
633 
634 	WaterManager* WaterMgr = g_Renderer.GetWaterManager();
635 	CShaderDefines defines = context;
636 
637 	// If we're using fancy water, make sure its shader is loaded
638 	if (!m->fancyWaterShader || WaterMgr->m_NeedsReloading)
639 	{
640 		if (WaterMgr->m_WaterRealDepth)
641 			defines.Add(str_USE_REAL_DEPTH, str_1);
642 		if (WaterMgr->m_WaterFancyEffects)
643 			defines.Add(str_USE_FANCY_EFFECTS, str_1);
644 		if (WaterMgr->m_WaterRefraction)
645 			defines.Add(str_USE_REFRACTION, str_1);
646 		if (WaterMgr->m_WaterReflection)
647 			defines.Add(str_USE_REFLECTION, str_1);
648 		if (shadow && WaterMgr->m_WaterShadows)
649 			defines.Add(str_USE_SHADOWS_ON_WATER, str_1);
650 
651 		// haven't updated the ARB shader yet so I'll always load the GLSL
652 		/*if (!g_Renderer.m_Options.m_PreferGLSL && !superFancy)
653 			m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("arb/water_high", defines);
654 		else*/
655 			m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("glsl/water_high", defines);
656 
657 		if (!m->fancyWaterShader)
658 		{
659 			LOGERROR("Failed to load water shader. Falling back to fixed pipeline water.\n");
660 			WaterMgr->m_RenderWater = false;
661 			return false;
662 		}
663 		WaterMgr->m_NeedsReloading = false;
664 	}
665 
666 	CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();
667 
668 	// creating the real depth texture using the depth buffer.
669 	if (WaterMgr->m_WaterRealDepth)
670 	{
671 		if (WaterMgr->m_depthTT == 0)
672 		{
673 			GLuint depthTex;
674 			glGenTextures(1, (GLuint*)&depthTex);
675 			WaterMgr->m_depthTT = depthTex;
676 			glBindTexture(GL_TEXTURE_2D, WaterMgr->m_depthTT);
677 			glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, g_Renderer.GetWidth(), g_Renderer.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL);
678 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
679 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
680 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
681 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
682 		}
683 		else
684 		{
685 			glBindTexture(GL_TEXTURE_2D, WaterMgr->m_depthTT);
686 			glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight(), 0);
687 		}
688 		glBindTexture(GL_TEXTURE_2D, 0);
689 	}
690 	// Calculating the advanced informations about Foam and all if the quality calls for it.
691 	/*if (WaterMgr->m_NeedInfoUpdate && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves))
692 	{
693 		WaterMgr->m_NeedInfoUpdate = false;
694 		WaterMgr->CreateSuperfancyInfo();
695 	}*/
696 
697 	double time = WaterMgr->m_WaterTexTimer;
698 	double period = 8;
699 	int curTex = (int)(time*60/period) % 60;
700 	int nexTex = (curTex + 1) % 60;
701 
702 	float repeatPeriod = WaterMgr->m_RepeatPeriod;
703 
704 	// Render normals and foam to a framebuffer if we're in fancy effects
705 	if (WaterMgr->m_WaterFancyEffects)
706 	{
707 		// Save the post-processing framebuffer.
708 		GLint fbo;
709 		glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo);
710 
711 		pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, WaterMgr->m_FancyEffectsFBO);
712 
713 		glDisable(GL_BLEND);
714 		glEnable(GL_DEPTH_TEST);
715 		glDepthFunc(GL_LEQUAL);
716 
717 		glDisable(GL_CULL_FACE);
718 		// Overwrite waves that would be behind the ground.
719 		CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("glsl/gui_solid", CShaderDefines());
720 		dummyShader->Bind();
721 
722 		dummyShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
723 		dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f);
724 		std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
725 		for (size_t i = 0; i < visiblePatches.size(); ++i)
726 		{
727 			CPatchRData* data = visiblePatches[i];
728 			data->RenderWater(dummyShader, true, true);
729 		}
730 		dummyShader->Unbind();
731 
732 		glEnable(GL_CULL_FACE);
733 		pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
734 	}
735 	glEnable(GL_BLEND);
736 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
737 	glEnable(GL_DEPTH_TEST);
738 	glDepthFunc(GL_LEQUAL);
739 
740 	m->fancyWaterShader->Bind();
741 
742 	const CCamera& camera = g_Renderer.GetViewCamera();
743 	CVector3D camPos = camera.m_Orientation.GetTranslation();
744 
745 	m->fancyWaterShader->BindTexture(str_normalMap, WaterMgr->m_NormalMap[curTex]);
746 	m->fancyWaterShader->BindTexture(str_normalMap2, WaterMgr->m_NormalMap[nexTex]);
747 
748 	if (WaterMgr->m_WaterFancyEffects)
749 	{
750 		m->fancyWaterShader->BindTexture(str_waterEffectsTexNorm, WaterMgr->m_FancyTextureNormal);
751 		m->fancyWaterShader->BindTexture(str_waterEffectsTexOther, WaterMgr->m_FancyTextureOther);
752 	}
753 
754 	if (WaterMgr->m_WaterRealDepth)
755 		m->fancyWaterShader->BindTexture(str_depthTex, WaterMgr->m_depthTT);
756 
757 	if (WaterMgr->m_WaterRefraction)
758 		m->fancyWaterShader->BindTexture(str_refractionMap, WaterMgr->m_RefractionTexture);
759 	if (WaterMgr->m_WaterReflection)
760 		m->fancyWaterShader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube());
761 
762 	m->fancyWaterShader->BindTexture(str_reflectionMap, WaterMgr->m_ReflectionTexture);
763 	m->fancyWaterShader->BindTexture(str_losMap, losTexture.GetTextureSmooth());
764 
765 	const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
766 
767 	m->fancyWaterShader->Uniform(str_transform, g_Renderer.GetViewCamera().GetViewProjection());
768 
769 	//TODO: bind only what's needed
770 	if (WaterMgr->m_WaterReflection)
771 	{
772 		// TODO: check that this rotates in the right direction.
773 		CMatrix3D skyBoxRotation;
774 		skyBoxRotation.SetIdentity();
775 		skyBoxRotation.RotateY(M_PI - 0.3f + lightEnv.GetRotation());
776 		m->fancyWaterShader->Uniform(str_skyBoxRot, skyBoxRotation);
777 	}
778 	m->fancyWaterShader->Uniform(str_sunDir, lightEnv.GetSunDir());
779 	m->fancyWaterShader->Uniform(str_sunColor, lightEnv.m_SunColor);
780 	m->fancyWaterShader->Uniform(str_color, WaterMgr->m_WaterColor);
781 	m->fancyWaterShader->Uniform(str_tint, WaterMgr->m_WaterTint);
782 	m->fancyWaterShader->Uniform(str_waviness, WaterMgr->m_Waviness);
783 	m->fancyWaterShader->Uniform(str_murkiness, WaterMgr->m_Murkiness);
784 	m->fancyWaterShader->Uniform(str_windAngle, WaterMgr->m_WindAngle);
785 	m->fancyWaterShader->Uniform(str_repeatScale, 1.0f / repeatPeriod);
786 	m->fancyWaterShader->Uniform(str_reflectionMatrix, WaterMgr->m_ReflectionMatrix);
787 	m->fancyWaterShader->Uniform(str_refractionMatrix, WaterMgr->m_RefractionMatrix);
788 	m->fancyWaterShader->Uniform(str_losMatrix, losTexture.GetTextureMatrix());
789 	m->fancyWaterShader->Uniform(str_cameraPos, camPos);
790 	m->fancyWaterShader->Uniform(str_fogColor, lightEnv.m_FogColor);
791 	m->fancyWaterShader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f);
792 	m->fancyWaterShader->Uniform(str_time, (float)time);
793 	m->fancyWaterShader->Uniform(str_screenSize, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0.0f, 0.0f);
794 
795 	if (WaterMgr->m_WaterType == L"clap")
796 	{
797 		m->fancyWaterShader->Uniform(str_waveParams1, 30.0f,1.5f,20.0f,0.03f);
798 		m->fancyWaterShader->Uniform(str_waveParams2, 0.5f,0.0f,0.0f,0.0f);
799 	}
800 	else if (WaterMgr->m_WaterType == L"lake")
801 	{
802 		m->fancyWaterShader->Uniform(str_waveParams1, 8.5f,1.5f,15.0f,0.03f);
803 		m->fancyWaterShader->Uniform(str_waveParams2, 0.2f,0.0f,0.0f,0.07f);
804 	}
805 	else
806 	{
807 		m->fancyWaterShader->Uniform(str_waveParams1, 15.0f,0.8f,10.0f,0.1f);
808 		m->fancyWaterShader->Uniform(str_waveParams2, 0.3f,0.0f,0.1f,0.3f);
809 	}
810 
811 	if (shadow && WaterMgr->m_WaterShadows)
812 	{
813 		m->fancyWaterShader->BindTexture(str_shadowTex, shadow->GetTexture());
814 		m->fancyWaterShader->Uniform(str_shadowTransform, shadow->GetTextureMatrix());
815 		int width = shadow->GetWidth();
816 		int height = shadow->GetHeight();
817 		m->fancyWaterShader->Uniform(str_shadowScale, width, height, 1.0f / width, 1.0f / height);
818 	}
819 
820 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
821 	for (size_t i = 0; i < visiblePatches.size(); ++i)
822 	{
823 		CPatchRData* data = visiblePatches[i];
824 		data->RenderWater(m->fancyWaterShader);
825 	}
826 	m->fancyWaterShader->Unbind();
827 
828 	glDepthFunc(GL_LEQUAL);
829 	glDisable(GL_BLEND);
830 
831 	return true;
832 }
833 
RenderSimpleWater(int cullGroup)834 void TerrainRenderer::RenderSimpleWater(int cullGroup)
835 {
836 #if CONFIG2_GLES
837 	UNUSED2(cullGroup);
838 #else
839 	PROFILE3_GPU("simple water");
840 
841 	WaterManager* WaterMgr = g_Renderer.GetWaterManager();
842 	CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture();
843 
844 	glEnable(GL_DEPTH_TEST);
845 	glDepthFunc(GL_LEQUAL);
846 
847 	double time = WaterMgr->m_WaterTexTimer;
848 	double period = 1.6f;
849 	int curTex = (int)(time*60/period) % 60;
850 
851 	WaterMgr->m_WaterTexture[curTex]->Bind();
852 
853 	// Shift the texture coordinates by these amounts to make the water "flow"
854 	float tx = -fmod(time, 81.0)/81.0;
855 	float ty = -fmod(time, 34.0)/34.0;
856 	float repeatPeriod = 16.0f;
857 
858 	// Perform the shifting by using texture coordinate generation
859 	GLfloat texgenS0[4] = { 1/repeatPeriod, 0, 0, tx };
860 	GLfloat texgenT0[4] = { 0, 0, 1/repeatPeriod, ty };
861 	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
862 	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
863 	glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS0);
864 	glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT0);
865 	glEnable(GL_TEXTURE_GEN_S);
866 	glEnable(GL_TEXTURE_GEN_T);
867 
868 	// Set up texture environment to multiply vertex RGB by texture RGB.
869 	GLfloat waterColor[4] = { WaterMgr->m_WaterColor.r, WaterMgr->m_WaterColor.g, WaterMgr->m_WaterColor.b, 1.0f };
870 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, waterColor);
871 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
872 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
873 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
874 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
875 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
876 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
877 
878 
879 	// Multiply by LOS texture
880 	losTexture.BindTexture(1);
881 	CMatrix3D losMatrix = losTexture.GetTextureMatrix();
882 	GLfloat texgenS1[4] = { losMatrix[0], losMatrix[4], losMatrix[8], losMatrix[12] };
883 	GLfloat texgenT1[4] = { losMatrix[1], losMatrix[5], losMatrix[9], losMatrix[13] };
884 	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
885 	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
886 	glTexGenfv(GL_S, GL_OBJECT_PLANE, texgenS1);
887 	glTexGenfv(GL_T, GL_OBJECT_PLANE, texgenT1);
888 	glEnable(GL_TEXTURE_GEN_S);
889 	glEnable(GL_TEXTURE_GEN_T);
890 
891 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
892 	glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
893 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
894 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
895 	glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
896 	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
897 
898 	CShaderProgramPtr dummyShader = g_Renderer.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
899 	dummyShader->Bind();
900 
901 	glEnableClientState(GL_VERTEX_ARRAY);
902 
903 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
904 	for (size_t i = 0; i < visiblePatches.size(); ++i)
905 	{
906 		CPatchRData* data = visiblePatches[i];
907 		data->RenderWater(dummyShader, false, true);
908 	}
909 
910 	glDisableClientState(GL_VERTEX_ARRAY);
911 
912 	dummyShader->Unbind();
913 
914 	g_Renderer.BindTexture(1, 0);
915 
916 	glDisable(GL_TEXTURE_GEN_S);
917 	glDisable(GL_TEXTURE_GEN_T);
918 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
919 
920 	pglActiveTextureARB(GL_TEXTURE0_ARB);
921 
922 	// Clean up the texture matrix and blend mode
923 	glDisable(GL_TEXTURE_GEN_S);
924 	glDisable(GL_TEXTURE_GEN_T);
925 	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
926 
927 	glDisable(GL_TEXTURE_2D);
928 #endif
929 }
930 
931 ///////////////////////////////////////////////////////////////////
932 // Render water that is part of the terrain
RenderWater(const CShaderDefines & context,int cullGroup,ShadowMap * shadow)933 void TerrainRenderer::RenderWater(const CShaderDefines& context, int cullGroup, ShadowMap* shadow)
934 {
935 	WaterManager* WaterMgr = g_Renderer.GetWaterManager();
936 
937 	WaterMgr->UpdateQuality();
938 
939 	if (!WaterMgr->WillRenderFancyWater())
940 		RenderSimpleWater(cullGroup);
941 	else
942 		RenderFancyWater(context, cullGroup, shadow);
943 }
944 
RenderPriorities(int cullGroup)945 void TerrainRenderer::RenderPriorities(int cullGroup)
946 {
947 	PROFILE("priorities");
948 
949 	ENSURE(m->phase == Phase_Render);
950 
951 	CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_text);
952 	tech->BeginPass();
953 	CTextRenderer textRenderer(tech->GetShader());
954 
955 	textRenderer.Font(CStrIntern("mono-stroke-10"));
956 	textRenderer.Color(1.0f, 1.0f, 0.0f);
957 
958 	std::vector<CPatchRData*>& visiblePatches = m->visiblePatches[cullGroup];
959 	for (size_t i = 0; i < visiblePatches.size(); ++i)
960 		visiblePatches[i]->RenderPriorities(textRenderer);
961 
962 	textRenderer.Render();
963 	tech->EndPass();
964 }
965