1 /* Copyright (C) 2013 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
19 * Terrain rendering (everything related to patches and water) is
20 * encapsulated in TerrainRenderer
23 #include "precompiled.h"
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"
38 #include "maths/MathUtil.h"
40 #include "ps/Filesystem.h"
41 #include "ps/CLogger.h"
43 #include "ps/Profile.h"
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"
54 #include "tools/atlas/GameInterface/GameLoop.h"
56 extern GameLoopState
* g_AtlasGameLoop
;
58 ///////////////////////////////////////////////////////////////////////////////////////////////
59 // TerrainRenderer implementation
63 * TerrainRenderer keeps track of which phase it is in, to detect
64 * when Submit, PrepareForRendering etc. are called in the wrong order.
73 * Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
75 struct TerrainRendererInternals
77 /// Which phase (submitting or rendering patches) are we in right now?
80 /// Patches that were submitted for this frame
81 std::vector
<CPatchRData
*> visiblePatches
[CRenderer::CULL_MAX
];
83 /// Decals that were submitted for this frame
84 std::vector
<CDecalRData
*> visibleDecals
[CRenderer::CULL_MAX
];
86 /// Fancy water shader
87 CShaderProgramPtr fancyWaterShader
;
89 CSimulation2
* simulation
;
94 ///////////////////////////////////////////////////////////////////
95 // Construction/Destruction
96 TerrainRenderer::TerrainRenderer()
98 m
= new TerrainRendererInternals();
99 m
->phase
= Phase_Submit
;
102 TerrainRenderer::~TerrainRenderer()
107 void TerrainRenderer::SetSimulation(CSimulation2
* simulation
)
109 m
->simulation
= simulation
;
112 ///////////////////////////////////////////////////////////////////
113 // Submit a patch for rendering
114 void TerrainRenderer::Submit(int cullGroup
, CPatch
* patch
)
116 ENSURE(m
->phase
== Phase_Submit
);
118 CPatchRData
* data
= (CPatchRData
*)patch
->GetRenderData();
121 // no renderdata for patch, create it now
122 data
= new CPatchRData(patch
, m
->simulation
);
123 patch
->SetRenderData(data
);
125 data
->Update(m
->simulation
);
127 m
->visiblePatches
[cullGroup
].push_back(data
);
130 ///////////////////////////////////////////////////////////////////
131 // Submit a decal for rendering
132 void TerrainRenderer::Submit(int cullGroup
, CModelDecal
* decal
)
134 ENSURE(m
->phase
== Phase_Submit
);
136 CDecalRData
* data
= (CDecalRData
*)decal
->GetRenderData();
139 // no renderdata for decal, create it now
140 data
= new CDecalRData(decal
, m
->simulation
);
141 decal
->SetRenderData(data
);
143 data
->Update(m
->simulation
);
145 m
->visibleDecals
[cullGroup
].push_back(data
);
148 ///////////////////////////////////////////////////////////////////
149 // Prepare for rendering
150 void TerrainRenderer::PrepareForRendering()
152 ENSURE(m
->phase
== Phase_Submit
);
154 m
->phase
= Phase_Render
;
157 ///////////////////////////////////////////////////////////////////
158 // Clear submissions lists
159 void TerrainRenderer::EndFrame()
161 ENSURE(m
->phase
== Phase_Render
|| m
->phase
== Phase_Submit
);
163 for (int i
= 0; i
< CRenderer::CULL_MAX
; ++i
)
165 m
->visiblePatches
[i
].clear();
166 m
->visibleDecals
[i
].clear();
169 m
->phase
= Phase_Submit
;
173 ///////////////////////////////////////////////////////////////////
174 // Full-featured terrain rendering with blending and everything
175 void TerrainRenderer::RenderTerrain(int cullGroup
)
180 ENSURE(m
->phase
== Phase_Render
);
182 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
183 std::vector
<CDecalRData
*>& visibleDecals
= m
->visibleDecals
[cullGroup
];
184 if (visiblePatches
.empty() && visibleDecals
.empty())
187 CShaderProgramPtr dummyShader
= g_Renderer
.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
190 // render the solid black sides of the map first
191 g_Renderer
.BindTexture(0, 0);
192 glEnableClientState(GL_VERTEX_ARRAY
);
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");
199 // switch on required client states
200 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
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
);
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
);
218 PROFILE_START("render terrain base");
219 CPatchRData::RenderBases(visiblePatches
, CShaderDefines(), NULL
, true, dummyShader
);
220 PROFILE_END("render terrain base");
223 // switch on the composite alpha map texture
224 (void)ogl_tex_bind(g_Renderer
.m_hCompositeAlphaMap
, 1);
226 // switch on second uv set
227 pglClientActiveTextureARB(GL_TEXTURE1
);
228 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
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
);
240 // switch on blending
242 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
244 // no need to write to the depth buffer a second time
247 // The decal color array contains lighting data, which we don't want in this non-shader mode
248 glDisableClientState(GL_COLOR_ARRAY
);
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");
255 // Disable second texcoord array
256 pglClientActiveTextureARB(GL_TEXTURE1
);
257 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
260 // Render terrain decals
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
);
275 PROFILE_START("render terrain decals");
276 CDecalRData::RenderDecals(visibleDecals
, CShaderDefines(), NULL
, true, dummyShader
);
277 PROFILE_END("render terrain decals");
280 // Now apply lighting
281 const CLightEnv
& lightEnv
= g_Renderer
.GetLightEnv();
283 pglClientActiveTextureARB(GL_TEXTURE0
);
284 glEnableClientState(GL_COLOR_ARRAY
); // diffuse lighting colors
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
);
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
,
301 CLOSTexture
& losTexture
= g_Renderer
.GetScene().GetLOSTexture();
303 int streamflags
= STREAM_POS
|STREAM_COLOR
;
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.)
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
);
323 glTexEnvfv(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_COLOR
, terrainAmbientColor
);
325 losTexture
.BindTexture(1);
326 pglClientActiveTextureARB(GL_TEXTURE1
);
327 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
328 streamflags
|= STREAM_POSTOUV1
;
330 glMatrixMode(GL_TEXTURE
);
331 glLoadMatrixf(&losTexture
.GetTextureMatrix()._11
);
332 glMatrixMode(GL_MODELVIEW
);
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
);
344 pglActiveTextureARB(GL_TEXTURE0
);
345 pglClientActiveTextureARB(GL_TEXTURE0
);
347 PROFILE_START("render terrain streams");
348 CPatchRData::RenderStreams(visiblePatches
, dummyShader
, streamflags
);
349 PROFILE_END("render terrain streams");
351 glMatrixMode(GL_TEXTURE
);
353 glMatrixMode(GL_MODELVIEW
);
355 // restore OpenGL state
356 g_Renderer
.BindTexture(1, 0);
358 pglClientActiveTextureARB(GL_TEXTURE1
);
359 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
360 glMatrixMode(GL_TEXTURE
);
362 glMatrixMode(GL_MODELVIEW
);
364 pglClientActiveTextureARB(GL_TEXTURE0
);
365 pglActiveTextureARB(GL_TEXTURE0
);
368 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
370 glDisableClientState(GL_COLOR_ARRAY
);
371 glDisableClientState(GL_VERTEX_ARRAY
);
372 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
374 dummyShader
->Unbind();
378 void TerrainRenderer::RenderTerrainOverlayTexture(int cullGroup
, CMatrix3D
& textureMatrix
)
381 #warning TODO: implement TerrainRenderer::RenderTerrainOverlayTexture for GLES
383 UNUSED2(textureMatrix
);
385 ENSURE(m
->phase
== Phase_Render
);
387 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
389 glEnableClientState(GL_VERTEX_ARRAY
);
390 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
392 pglActiveTextureARB(GL_TEXTURE0
);
393 glEnable(GL_TEXTURE_2D
);
395 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
397 glDisable(GL_DEPTH_TEST
);
399 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
401 glMatrixMode(GL_TEXTURE
);
402 glLoadMatrixf(&textureMatrix
._11
);
403 glMatrixMode(GL_MODELVIEW
);
405 CShaderProgramPtr dummyShader
= g_Renderer
.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
407 CPatchRData::RenderStreams(visiblePatches
, dummyShader
, STREAM_POS
|STREAM_POSTOUV0
);
408 dummyShader
->Unbind();
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
)
415 CPatchRData
* data
= visiblePatches
[i
];
416 waterBounds
+= data
->GetWaterBounds();
418 if (!waterBounds
.IsEmpty())
420 float h
= g_Renderer
.GetWaterManager()->m_WaterHeight
+ 0.05f
; // add a delta to avoid z-fighting
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
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);
432 glMatrixMode(GL_TEXTURE
);
434 glMatrixMode(GL_MODELVIEW
);
437 glEnable(GL_DEPTH_TEST
);
439 glDisableClientState(GL_COLOR_ARRAY
);
440 glDisableClientState(GL_VERTEX_ARRAY
);
441 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
446 ///////////////////////////////////////////////////////////////////
449 * Set up all the uniforms for a shader pass.
451 void TerrainRenderer::PrepareShader(const CShaderProgramPtr
& shader
, ShadowMap
* shadow
)
453 shader
->Uniform(str_transform
, g_Renderer
.GetViewCamera().GetViewProjection());
454 shader
->Uniform(str_cameraPos
, g_Renderer
.GetViewCamera().GetOrientation().GetTranslation());
456 const CLightEnv
& lightEnv
= g_Renderer
.GetLightEnv();
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
);
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
);
471 shader
->Uniform(str_ambient
, lightEnv
.m_TerrainAmbientColor
);
472 shader
->Uniform(str_sunColor
, lightEnv
.m_SunColor
);
473 shader
->Uniform(str_sunDir
, lightEnv
.GetSunDir());
475 shader
->Uniform(str_fogColor
, lightEnv
.m_FogColor
);
476 shader
->Uniform(str_fogParams
, lightEnv
.m_FogFactor
, lightEnv
.m_FogMax
, 0.f
, 0.f
);
479 void TerrainRenderer::RenderTerrainShader(const CShaderDefines
& context
, int cullGroup
, ShadowMap
* shadow
)
481 ENSURE(m
->phase
== Phase_Render
);
483 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
484 std::vector
<CDecalRData
*>& visibleDecals
= m
->visibleDecals
[cullGroup
];
485 if (visiblePatches
.empty() && visibleDecals
.empty())
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
);
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");
500 techSolid
->EndPass();
502 PROFILE_START("render terrain base");
503 CPatchRData::RenderBases(visiblePatches
, context
, shadow
);
504 PROFILE_END("render terrain base");
506 // no need to write to the depth buffer a second time
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");
514 PROFILE_START("render terrain decals");
515 CDecalRData::RenderDecals(visibleDecals
, context
, shadow
, false);
516 PROFILE_END("render terrain decals");
518 // restore OpenGL state
519 g_Renderer
.BindTexture(1, 0);
520 g_Renderer
.BindTexture(2, 0);
521 g_Renderer
.BindTexture(3, 0);
524 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
529 ///////////////////////////////////////////////////////////////////
530 // Render un-textured patches as polygons
531 void TerrainRenderer::RenderPatches(int cullGroup
)
533 ENSURE(m
->phase
== Phase_Render
);
535 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
536 if (visiblePatches
.empty())
540 #warning TODO: implement TerrainRenderer::RenderPatches for GLES
542 CShaderProgramPtr dummyShader
= g_Renderer
.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
545 glEnableClientState(GL_VERTEX_ARRAY
);
546 CPatchRData::RenderStreams(visiblePatches
, dummyShader
, STREAM_POS
);
547 glDisableClientState(GL_VERTEX_ARRAY
);
549 dummyShader
->Unbind();
554 ///////////////////////////////////////////////////////////////////
555 // Render outlines of submitted patches as lines
556 void TerrainRenderer::RenderOutlines(int cullGroup
)
558 ENSURE(m
->phase
== Phase_Render
);
560 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
561 if (visiblePatches
.empty())
565 #warning TODO: implement TerrainRenderer::RenderOutlines for GLES
567 glEnableClientState(GL_VERTEX_ARRAY
);
568 for (size_t i
= 0; i
< visiblePatches
.size(); ++i
)
569 visiblePatches
[i
]->RenderOutline();
570 glDisableClientState(GL_VERTEX_ARRAY
);
575 ///////////////////////////////////////////////////////////////////
576 // Scissor rectangle of water patches
577 CBoundingBoxAligned
TerrainRenderer::ScissorWater(int cullGroup
, const CMatrix3D
&viewproj
)
579 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
581 CBoundingBoxAligned scissor
;
582 for (size_t i
= 0; i
< visiblePatches
.size(); ++i
)
584 CPatchRData
* data
= visiblePatches
[i
];
585 const CBoundingBoxAligned
& waterBounds
= data
->GetWaterBounds();
586 if (waterBounds
.IsEmpty())
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) \
596 screenBounds += CVector3D(v1.X, v1.Y, v1.Z) * (1.0f / v1.W); \
599 float t = v1.Z + v1.W; \
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); \
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); \
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); \
616 ADDBOUND(v1
, v2
, v3
, v4
);
617 ADDBOUND(v2
, v1
, v3
, v4
);
618 ADDBOUND(v3
, v1
, v2
, v4
);
619 ADDBOUND(v4
, v1
, v2
, v3
);
621 if (screenBounds
[0].X
>= 1.0f
|| screenBounds
[1].X
<= -1.0f
|| screenBounds
[0].Y
>= 1.0f
|| screenBounds
[1].Y
<= -1.0f
)
623 scissor
+= screenBounds
;
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
));
629 // Render fancy water
630 bool TerrainRenderer::RenderFancyWater(const CShaderDefines
& context
, int cullGroup
, ShadowMap
* shadow
)
632 PROFILE3_GPU("fancy water");
634 WaterManager
* WaterMgr
= g_Renderer
.GetWaterManager();
635 CShaderDefines defines
= context
;
637 // If we're using fancy water, make sure its shader is loaded
638 if (!m
->fancyWaterShader
|| WaterMgr
->m_NeedsReloading
)
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
);
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);
655 m
->fancyWaterShader
= g_Renderer
.GetShaderManager().LoadProgram("glsl/water_high", defines
);
657 if (!m
->fancyWaterShader
)
659 LOGERROR("Failed to load water shader. Falling back to fixed pipeline water.\n");
660 WaterMgr
->m_RenderWater
= false;
663 WaterMgr
->m_NeedsReloading
= false;
666 CLOSTexture
& losTexture
= g_Renderer
.GetScene().GetLOSTexture();
668 // creating the real depth texture using the depth buffer.
669 if (WaterMgr
->m_WaterRealDepth
)
671 if (WaterMgr
->m_depthTT
== 0)
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
);
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);
688 glBindTexture(GL_TEXTURE_2D
, 0);
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))
693 WaterMgr->m_NeedInfoUpdate = false;
694 WaterMgr->CreateSuperfancyInfo();
697 double time
= WaterMgr
->m_WaterTexTimer
;
699 int curTex
= (int)(time
*60/period
) % 60;
700 int nexTex
= (curTex
+ 1) % 60;
702 float repeatPeriod
= WaterMgr
->m_RepeatPeriod
;
704 // Render normals and foam to a framebuffer if we're in fancy effects
705 if (WaterMgr
->m_WaterFancyEffects
)
707 // Save the post-processing framebuffer.
709 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT
, &fbo
);
711 pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, WaterMgr
->m_FancyEffectsFBO
);
714 glEnable(GL_DEPTH_TEST
);
715 glDepthFunc(GL_LEQUAL
);
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());
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
)
727 CPatchRData
* data
= visiblePatches
[i
];
728 data
->RenderWater(dummyShader
, true, true);
730 dummyShader
->Unbind();
732 glEnable(GL_CULL_FACE
);
733 pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, fbo
);
736 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
737 glEnable(GL_DEPTH_TEST
);
738 glDepthFunc(GL_LEQUAL
);
740 m
->fancyWaterShader
->Bind();
742 const CCamera
& camera
= g_Renderer
.GetViewCamera();
743 CVector3D camPos
= camera
.m_Orientation
.GetTranslation();
745 m
->fancyWaterShader
->BindTexture(str_normalMap
, WaterMgr
->m_NormalMap
[curTex
]);
746 m
->fancyWaterShader
->BindTexture(str_normalMap2
, WaterMgr
->m_NormalMap
[nexTex
]);
748 if (WaterMgr
->m_WaterFancyEffects
)
750 m
->fancyWaterShader
->BindTexture(str_waterEffectsTexNorm
, WaterMgr
->m_FancyTextureNormal
);
751 m
->fancyWaterShader
->BindTexture(str_waterEffectsTexOther
, WaterMgr
->m_FancyTextureOther
);
754 if (WaterMgr
->m_WaterRealDepth
)
755 m
->fancyWaterShader
->BindTexture(str_depthTex
, WaterMgr
->m_depthTT
);
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());
762 m
->fancyWaterShader
->BindTexture(str_reflectionMap
, WaterMgr
->m_ReflectionTexture
);
763 m
->fancyWaterShader
->BindTexture(str_losMap
, losTexture
.GetTextureSmooth());
765 const CLightEnv
& lightEnv
= g_Renderer
.GetLightEnv();
767 m
->fancyWaterShader
->Uniform(str_transform
, g_Renderer
.GetViewCamera().GetViewProjection());
769 //TODO: bind only what's needed
770 if (WaterMgr
->m_WaterReflection
)
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
);
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
);
795 if (WaterMgr
->m_WaterType
== L
"clap")
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
);
800 else if (WaterMgr
->m_WaterType
== L
"lake")
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
);
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
);
811 if (shadow
&& WaterMgr
->m_WaterShadows
)
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
);
820 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
821 for (size_t i
= 0; i
< visiblePatches
.size(); ++i
)
823 CPatchRData
* data
= visiblePatches
[i
];
824 data
->RenderWater(m
->fancyWaterShader
);
826 m
->fancyWaterShader
->Unbind();
828 glDepthFunc(GL_LEQUAL
);
834 void TerrainRenderer::RenderSimpleWater(int cullGroup
)
839 PROFILE3_GPU("simple water");
841 WaterManager
* WaterMgr
= g_Renderer
.GetWaterManager();
842 CLOSTexture
& losTexture
= g_Game
->GetView()->GetLOSTexture();
844 glEnable(GL_DEPTH_TEST
);
845 glDepthFunc(GL_LEQUAL
);
847 double time
= WaterMgr
->m_WaterTexTimer
;
848 double period
= 1.6f
;
849 int curTex
= (int)(time
*60/period
) % 60;
851 WaterMgr
->m_WaterTexture
[curTex
]->Bind();
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
;
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
);
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
);
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
);
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
);
898 CShaderProgramPtr dummyShader
= g_Renderer
.GetShaderManager().LoadProgram("fixed:dummy", CShaderDefines());
901 glEnableClientState(GL_VERTEX_ARRAY
);
903 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
904 for (size_t i
= 0; i
< visiblePatches
.size(); ++i
)
906 CPatchRData
* data
= visiblePatches
[i
];
907 data
->RenderWater(dummyShader
, false, true);
910 glDisableClientState(GL_VERTEX_ARRAY
);
912 dummyShader
->Unbind();
914 g_Renderer
.BindTexture(1, 0);
916 glDisable(GL_TEXTURE_GEN_S
);
917 glDisable(GL_TEXTURE_GEN_T
);
918 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
920 pglActiveTextureARB(GL_TEXTURE0_ARB
);
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
);
927 glDisable(GL_TEXTURE_2D
);
931 ///////////////////////////////////////////////////////////////////
932 // Render water that is part of the terrain
933 void TerrainRenderer::RenderWater(const CShaderDefines
& context
, int cullGroup
, ShadowMap
* shadow
)
935 WaterManager
* WaterMgr
= g_Renderer
.GetWaterManager();
937 WaterMgr
->UpdateQuality();
939 if (!WaterMgr
->WillRenderFancyWater())
940 RenderSimpleWater(cullGroup
);
942 RenderFancyWater(context
, cullGroup
, shadow
);
945 void TerrainRenderer::RenderPriorities(int cullGroup
)
947 PROFILE("priorities");
949 ENSURE(m
->phase
== Phase_Render
);
951 CShaderTechniquePtr tech
= g_Renderer
.GetShaderManager().LoadEffect(str_gui_text
);
953 CTextRenderer
textRenderer(tech
->GetShader());
955 textRenderer
.Font(CStrIntern("mono-stroke-10"));
956 textRenderer
.Color(1.0f
, 1.0f
, 0.0f
);
958 std::vector
<CPatchRData
*>& visiblePatches
= m
->visiblePatches
[cullGroup
];
959 for (size_t i
= 0; i
< visiblePatches
.size(); ++i
)
960 visiblePatches
[i
]->RenderPriorities(textRenderer
);
962 textRenderer
.Render();