source: ps/trunk/source/renderer/TerrainRenderer.cpp@ 9362

Last change on this file since 9362 was 9362, checked in by Jan Wassenberg, 11 years ago

split debug_assert into ENSURE and ASSERT as discussed in a previous meeting.
the old debug_assert always ran and tested the expression, which slows down release builds. wrapping them in #ifndef NDEBUG is clumsy. the new ASSERT behaves like assert and ENSURE like the old debug_assert. Let's change any time-critical but not-super-important ENSURE to ASSERT to speed up release builds. (already done in bits.h and unique_range.h)

  • Property svn:eol-style set to native
File size: 25.2 KB
Line 
1/* Copyright (C) 2011 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/Terrain.h"
31#include "graphics/GameView.h"
32#include "graphics/Model.h"
33#include "graphics/ShaderManager.h"
34
35#include "maths/MathUtil.h"
36
37#include "ps/Filesystem.h"
38#include "ps/CLogger.h"
39#include "ps/Font.h"
40#include "ps/Game.h"
41#include "ps/Profile.h"
42#include "ps/World.h"
43
44#include "renderer/DecalRData.h"
45#include "renderer/PatchRData.h"
46#include "renderer/Renderer.h"
47#include "renderer/ShadowMap.h"
48#include "renderer/TerrainRenderer.h"
49#include "renderer/VertexArray.h"
50#include "renderer/WaterManager.h"
51
52#include "lib/res/graphics/ogl_shader.h"
53
54
55///////////////////////////////////////////////////////////////////////////////////////////////
56// TerrainRenderer implementation
57
58
59/**
60 * TerrainRenderer keeps track of which phase it is in, to detect
61 * when Submit, PrepareForRendering etc. are called in the wrong order.
62 */
63enum Phase {
64 Phase_Submit,
65 Phase_Render
66};
67
68
69/**
70 * Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
71 */
72struct TerrainRendererInternals
73{
74 /// Which phase (submitting or rendering patches) are we in right now?
75 Phase phase;
76
77 /// Patches that were submitted for this frame
78 std::vector<CPatchRData*> visiblePatches;
79
80 /// Decals that were submitted for this frame
81 std::vector<CDecalRData*> visibleDecals;
82
83 /// Fancy water shader
84 Handle fancyWaterShader;
85};
86
87
88
89///////////////////////////////////////////////////////////////////
90// Construction/Destruction
91TerrainRenderer::TerrainRenderer()
92{
93 m = new TerrainRendererInternals();
94 m->phase = Phase_Submit;
95 m->fancyWaterShader = 0;
96}
97
98TerrainRenderer::~TerrainRenderer()
99{
100 if( m->fancyWaterShader )
101 {
102 ogl_program_free( m->fancyWaterShader );
103 }
104 delete m;
105}
106
107
108///////////////////////////////////////////////////////////////////
109// Submit a patch for rendering
110void TerrainRenderer::Submit(CPatch* patch)
111{
112 ENSURE(m->phase == Phase_Submit);
113
114 CPatchRData* data = (CPatchRData*)patch->GetRenderData();
115 if (data == 0)
116 {
117 // no renderdata for patch, create it now
118 data = new CPatchRData(patch);
119 patch->SetRenderData(data);
120 }
121 data->Update();
122
123 m->visiblePatches.push_back(data);
124}
125
126///////////////////////////////////////////////////////////////////
127// Submit a decal for rendering
128void TerrainRenderer::Submit(CModelDecal* decal)
129{
130 ENSURE(m->phase == Phase_Submit);
131
132 CDecalRData* data = (CDecalRData*)decal->GetRenderData();
133 if (data == 0)
134 {
135 // no renderdata for decal, create it now
136 data = new CDecalRData(decal);
137 decal->SetRenderData(data);
138 }
139 data->Update();
140
141 m->visibleDecals.push_back(data);
142}
143
144///////////////////////////////////////////////////////////////////
145// Prepare for rendering
146void TerrainRenderer::PrepareForRendering()
147{
148 ENSURE(m->phase == Phase_Submit);
149
150 m->phase = Phase_Render;
151}
152
153///////////////////////////////////////////////////////////////////
154// Clear submissions lists
155void TerrainRenderer::EndFrame()
156{
157 ENSURE(m->phase == Phase_Render || m->phase == Phase_Submit);
158
159 m->visiblePatches.clear();
160 m->visibleDecals.clear();
161
162 m->phase = Phase_Submit;
163}
164
165
166///////////////////////////////////////////////////////////////////
167// Full-featured terrain rendering with blending and everything
168void TerrainRenderer::RenderTerrain()
169{
170 ENSURE(m->phase == Phase_Render);
171
172 // render the solid black sides of the map first
173 g_Renderer.BindTexture(0, 0);
174 glEnableClientState(GL_VERTEX_ARRAY);
175 glColor3f(0, 0, 0);
176 PROFILE_START("render terrain sides");
177 for (size_t i = 0; i < m->visiblePatches.size(); ++i)
178 m->visiblePatches[i]->RenderSides();
179 PROFILE_END("render terrain sides");
180
181 // switch on required client states
182 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
183
184 // render everything fullbright
185 // set up texture environment for base pass
186 pglActiveTextureARB(GL_TEXTURE0);
187 pglClientActiveTextureARB(GL_TEXTURE0);
188 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
189 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
190 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
191 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
192
193 // Set alpha to 1.0
194 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
195 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT);
196 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
197 static const float one[4] = { 1.f, 1.f, 1.f, 1.f };
198 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one);
199
200 PROFILE_START("render terrain base");
201 CPatchRData::RenderBases(m->visiblePatches);
202 PROFILE_END("render terrain base");
203
204 // render blends
205 // switch on the composite alpha map texture
206 (void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
207
208 // switch on second uv set
209 pglClientActiveTextureARB(GL_TEXTURE1);
210 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
211
212 // setup additional texenv required by blend pass
213 pglActiveTextureARB(GL_TEXTURE1);
214 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
215 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
216 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
217 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
218 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
219 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
220 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
221
222 // switch on blending
223 glEnable(GL_BLEND);
224 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
225
226 // no need to write to the depth buffer a second time
227 glDepthMask(0);
228
229 // The decal color array contains lighting data, which we don't want in this non-shader mode
230 glDisableClientState(GL_COLOR_ARRAY);
231
232 // render blend passes for each patch
233 PROFILE_START("render terrain blends");
234 CPatchRData::RenderBlends(m->visiblePatches);
235 PROFILE_END("render terrain blends");
236
237 // Disable second texcoord array
238 pglClientActiveTextureARB(GL_TEXTURE1);
239 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
240
241
242 // Render terrain decals
243
244 g_Renderer.BindTexture(1, 0);
245 pglActiveTextureARB(GL_TEXTURE0);
246 pglClientActiveTextureARB(GL_TEXTURE0);
247 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
248 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
249 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
250 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
251 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
252 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
253 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
254 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
255 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
256
257 PROFILE_START("render terrain decals");
258 for (size_t i = 0; i < m->visibleDecals.size(); ++i)
259 m->visibleDecals[i]->Render(CShaderProgramPtr());
260 PROFILE_END("render terrain decals");
261
262
263 // Now apply lighting
264 const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
265
266 pglClientActiveTextureARB(GL_TEXTURE0);
267 glEnableClientState(GL_COLOR_ARRAY); // diffuse lighting colours
268
269 glBlendFunc(GL_DST_COLOR, GL_ZERO);
270
271 // GL_TEXTURE_ENV_COLOR requires four floats, so we shouldn't use the RGBColor directly
272 float terrainAmbientColor[4] = {
273 lightEnv.m_TerrainAmbientColor.X,
274 lightEnv.m_TerrainAmbientColor.Y,
275 lightEnv.m_TerrainAmbientColor.Z,
276 1.f
277 };
278
279 CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();
280
281 int streamflags = STREAM_POS|STREAM_COLOR;
282
283 pglActiveTextureARB(GL_TEXTURE0);
284 // We're not going to use a texture here, but we have to have a valid texture
285 // bound else the texture unit will be disabled.
286 // We should still have a bound splat texture from some earlier rendering,
287 // so assume that's still valid to use.
288 // (TODO: That's a bit of an ugly hack.)
289
290 // No shadows: (Ambient + Diffuse) * LOS
291 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
292 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
293 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
294 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
295 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
296 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
297 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
298 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
299 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
300
301 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, terrainAmbientColor);
302
303 losTexture.BindTexture(1);
304 pglClientActiveTextureARB(GL_TEXTURE1);
305 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
306 streamflags |= STREAM_POSTOUV1;
307
308 glMatrixMode(GL_TEXTURE);
309 glLoadMatrixf(losTexture.GetTextureMatrix());
310 glMatrixMode(GL_MODELVIEW);
311
312 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
313 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
314 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
315 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
316 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
317 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
318 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
319 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
320 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
321
322 pglActiveTextureARB(GL_TEXTURE0);
323 pglClientActiveTextureARB(GL_TEXTURE0);
324
325 PROFILE_START("render terrain streams");
326 CPatchRData::RenderStreams(m->visiblePatches, streamflags);
327 PROFILE_END("render terrain streams");
328
329 glMatrixMode(GL_TEXTURE);
330 glLoadIdentity();
331 glMatrixMode(GL_MODELVIEW);
332
333 // restore OpenGL state
334 g_Renderer.BindTexture(1, 0);
335
336 pglClientActiveTextureARB(GL_TEXTURE1);
337 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
338 glMatrixMode(GL_TEXTURE);
339 glLoadIdentity();
340 glMatrixMode(GL_MODELVIEW);
341
342 pglClientActiveTextureARB(GL_TEXTURE0);
343 pglActiveTextureARB(GL_TEXTURE0);
344 glDepthMask(1);
345 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
346 glDisable(GL_BLEND);
347 glDisableClientState(GL_COLOR_ARRAY);
348 glDisableClientState(GL_VERTEX_ARRAY);
349 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
350}
351
352
353///////////////////////////////////////////////////////////////////
354
355/**
356 * Set up all the uniforms for a shader pass.
357 */
358void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow)
359{
360 const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
361
362 if (shadow)
363 {
364 shader->BindTexture("shadowTex", shadow->GetTexture());
365 shader->Uniform("shadowTransform", shadow->GetTextureMatrix());
366 }
367
368 CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
369 shader->BindTexture("losTex", los.GetTexture());
370 shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
371
372 shader->Uniform("ambient", lightEnv.m_TerrainAmbientColor);
373 shader->Uniform("sunColor", lightEnv.m_SunColor);
374}
375
376void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow)
377{
378 ENSURE(m->phase == Phase_Render);
379
380 CShaderManager& shaderManager = g_Renderer.GetShaderManager();
381
382 typedef std::map<CStr, CStr> Defines;
383 Defines defBasic;
384 if (shadow)
385 {
386 defBasic["USE_SHADOW"] = "1";
387 if (g_Renderer.m_Caps.m_ARBProgramShadow && g_Renderer.m_Options.m_ARBProgramShadow)
388 defBasic["USE_FP_SHADOW"] = "1";
389 }
390
391 defBasic["LIGHTING_MODEL_" + g_Renderer.GetLightEnv().GetLightingModel()] = "1";
392
393 CShaderProgramPtr shaderBase(shaderManager.LoadProgram("terrain_base", defBasic));
394 CShaderProgramPtr shaderBlend(shaderManager.LoadProgram("terrain_blend", defBasic));
395 CShaderProgramPtr shaderDecal(shaderManager.LoadProgram("terrain_decal", defBasic));
396
397 // render the solid black sides of the map first
398 g_Renderer.BindTexture(0, 0);
399 glEnableClientState(GL_VERTEX_ARRAY);
400 glColor3f(0, 0, 0);
401 PROFILE_START("render terrain sides");
402 for (size_t i = 0; i < m->visiblePatches.size(); ++i)
403 m->visiblePatches[i]->RenderSides();
404 PROFILE_END("render terrain sides");
405
406 // switch on required client states
407 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
408 glEnableClientState(GL_COLOR_ARRAY); // diffuse lighting colours
409
410 shaderBase->Bind();
411 PrepareShader(shaderBase, shadow);
412
413 PROFILE_START("render terrain base");
414 CPatchRData::RenderBases(m->visiblePatches);
415 PROFILE_END("render terrain base");
416
417 shaderBase->Unbind();
418
419 // render blends
420
421 shaderBlend->Bind();
422 PrepareShader(shaderBlend, shadow);
423
424 // switch on the composite alpha map texture
425 (void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
426
427 // switch on second uv set
428 pglClientActiveTextureARB(GL_TEXTURE1);
429 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
430
431 // switch on blending
432 glEnable(GL_BLEND);
433 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
434
435 // no need to write to the depth buffer a second time
436 glDepthMask(0);
437
438 // render blend passes for each patch
439 PROFILE_START("render terrain blends");
440 CPatchRData::RenderBlends(m->visiblePatches);
441 PROFILE_END("render terrain blends");
442
443 // Disable second texcoord array
444 pglClientActiveTextureARB(GL_TEXTURE1);
445 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
446
447 shaderBlend->Unbind();
448
449 // Render terrain decals
450
451 shaderDecal->Bind();
452 PrepareShader(shaderDecal, shadow);
453
454 g_Renderer.BindTexture(1, 0);
455 pglActiveTextureARB(GL_TEXTURE0);
456 pglClientActiveTextureARB(GL_TEXTURE0);
457
458 PROFILE_START("render terrain decals");
459 for (size_t i = 0; i < m->visibleDecals.size(); ++i)
460 m->visibleDecals[i]->Render(shaderDecal);
461 PROFILE_END("render terrain decals");
462
463 shaderDecal->Unbind();
464
465 // restore OpenGL state
466 g_Renderer.BindTexture(1, 0);
467 g_Renderer.BindTexture(2, 0);
468 g_Renderer.BindTexture(3, 0);
469
470 pglClientActiveTextureARB(GL_TEXTURE0);
471 pglActiveTextureARB(GL_TEXTURE0);
472 glDepthMask(1);
473 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
474 glDisable(GL_BLEND);
475 glDisableClientState(GL_COLOR_ARRAY);
476 glDisableClientState(GL_VERTEX_ARRAY);
477 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
478}
479
480
481///////////////////////////////////////////////////////////////////
482// Render un-textured patches as polygons
483void TerrainRenderer::RenderPatches()
484{
485 ENSURE(m->phase == Phase_Render);
486
487 glEnableClientState(GL_VERTEX_ARRAY);
488 CPatchRData::RenderStreams(m->visiblePatches, STREAM_POS);
489 glDisableClientState(GL_VERTEX_ARRAY);
490}
491
492
493///////////////////////////////////////////////////////////////////
494// Render outlines of submitted patches as lines
495void TerrainRenderer::RenderOutlines()
496{
497 ENSURE(m->phase == Phase_Render);
498
499 glEnableClientState(GL_VERTEX_ARRAY);
500 for (size_t i = 0; i < m->visiblePatches.size(); ++i)
501 m->visiblePatches[i]->RenderOutline();
502 glDisableClientState(GL_VERTEX_ARRAY);
503}
504
505
506///////////////////////////////////////////////////////////////////
507// Render water that is part of the terrain
508void TerrainRenderer::RenderWater()
509{
510 PROFILE( "render water" );
511
512 WaterManager* WaterMgr = g_Renderer.GetWaterManager();
513
514 bool fancy = WaterMgr->WillRenderFancyWater();
515
516 // If we're using fancy water, make sure its shader is loaded
517 if(fancy && !m->fancyWaterShader)
518 {
519 Handle h = ogl_program_load(g_VFS, L"shaders/water_high.xml");
520 if (h < 0)
521 {
522 LOGERROR(L"Failed to load water shader. Falling back to non-fancy water.\n");
523 g_Renderer.m_Options.m_FancyWater = false;
524 fancy = false;
525 }
526 else
527 {
528 m->fancyWaterShader = h;
529 }
530 }
531 CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); // TODO: stop using g_Game
532
533 CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();
534
535 glEnable(GL_BLEND);
536 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
537 glEnable(GL_DEPTH_TEST);
538 glDepthFunc(GL_LEQUAL);
539
540 double time = WaterMgr->m_WaterTexTimer;
541
542 double period = 1.6;
543 int curTex = (int)(time*60/period) % 60;
544
545 if(fancy)
546 {
547 WaterMgr->m_NormalMap[curTex]->Bind();
548 }
549 else
550 {
551 WaterMgr->m_WaterTexture[curTex]->Bind();
552 }
553
554 // Shift the texture coordinates by these amounts to make the water "flow"
555 float tx = -fmod(time, 81.0)/81.0;
556 float ty = -fmod(time, 34.0)/34.0;
557
558 if(!fancy)
559 {
560 // Perform the shifting by modifying the texture matrix
561 glMatrixMode(GL_TEXTURE);
562 glLoadIdentity();
563 glTranslatef(tx, ty, 0);
564
565 // Set up texture environment to multiply vertex RGB by texture RGB and use vertex alpha
566 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
567 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
568 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
569 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
570 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
571 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
572 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
573 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
574 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
575
576 // Multiply by LOS texture
577 losTexture.BindTexture(1);
578 pglClientActiveTextureARB(GL_TEXTURE1);
579 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
580
581 glLoadMatrixf(losTexture.GetTextureMatrix());
582
583 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
584 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
585 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
586 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
587 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
588 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
589 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
590 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
591 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
592 }
593
594 // Set the proper LOD bias
595 glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
596
597 const CCamera& camera = g_Renderer.GetViewCamera();
598 CVector3D camPos = camera.m_Orientation.GetTranslation();
599
600 GLint vertexDepth = 0; // water depth attribute, if using fancy water
601
602 if(fancy)
603 {
604 // Bind reflection and refraction textures on texture units 1 and 2
605 pglActiveTextureARB( GL_TEXTURE1_ARB );
606 glEnable( GL_TEXTURE_2D );
607 glBindTexture( GL_TEXTURE_2D, WaterMgr->m_ReflectionTexture );
608 pglActiveTextureARB( GL_TEXTURE2_ARB );
609 glEnable( GL_TEXTURE_2D );
610 glBindTexture( GL_TEXTURE_2D, WaterMgr->m_RefractionTexture );
611
612 losTexture.BindTexture(3);
613
614 // Bind water shader and set arguments
615 ogl_program_use( m->fancyWaterShader );
616
617 GLint ambient = ogl_program_get_uniform_location( m->fancyWaterShader, "ambient" );
618 GLint sunDir = ogl_program_get_uniform_location( m->fancyWaterShader, "sunDir" );
619 GLint sunColor = ogl_program_get_uniform_location( m->fancyWaterShader, "sunColor" );
620 GLint cameraPos = ogl_program_get_uniform_location( m->fancyWaterShader, "cameraPos" );
621 GLint shininess = ogl_program_get_uniform_location( m->fancyWaterShader, "shininess" );
622 GLint specularStrength = ogl_program_get_uniform_location( m->fancyWaterShader, "specularStrength" );
623 GLint waviness = ogl_program_get_uniform_location( m->fancyWaterShader, "waviness" );
624 GLint murkiness = ogl_program_get_uniform_location( m->fancyWaterShader, "murkiness" );
625 GLint fullDepth = ogl_program_get_uniform_location( m->fancyWaterShader, "fullDepth" );
626 GLint tint = ogl_program_get_uniform_location( m->fancyWaterShader, "tint" );
627 GLint reflectionTint = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionTint" );
628 GLint reflectionTintStrength = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionTintStrength" );
629 GLint translation = ogl_program_get_uniform_location( m->fancyWaterShader, "translation" );
630 GLint reflectionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMatrix" );
631 GLint refractionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMatrix" );
632 GLint losMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "losMatrix" );
633 GLint normalMap = ogl_program_get_uniform_location( m->fancyWaterShader, "normalMap" );
634 GLint reflectionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMap" );
635 GLint refractionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMap" );
636 GLint losMap = ogl_program_get_uniform_location( m->fancyWaterShader, "losMap" );
637
638 const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
639 pglUniform3fvARB( ambient, 1, &lightEnv.m_TerrainAmbientColor.X );
640 pglUniform3fvARB( sunDir, 1, &lightEnv.GetSunDir().X );
641 pglUniform3fvARB( sunColor, 1, &lightEnv.m_SunColor.X );
642 pglUniform1fARB( shininess, WaterMgr->m_Shininess );
643 pglUniform1fARB( specularStrength, WaterMgr->m_SpecularStrength );
644 pglUniform1fARB( waviness, WaterMgr->m_Waviness );
645 pglUniform1fARB( murkiness, WaterMgr->m_Murkiness );
646 pglUniform1fARB( fullDepth, WaterMgr->m_WaterFullDepth );
647 pglUniform3fvARB( tint, 1, WaterMgr->m_WaterTint.FloatArray() );
648 pglUniform1fARB( reflectionTintStrength, WaterMgr->m_ReflectionTintStrength );
649 pglUniform3fvARB( reflectionTint, 1, WaterMgr->m_ReflectionTint.FloatArray() );
650 pglUniform4fARB( translation, tx, ty, 0, 0 );
651 pglUniformMatrix4fvARB( reflectionMatrix, 1, false, &WaterMgr->m_ReflectionMatrix._11 );
652 pglUniformMatrix4fvARB( refractionMatrix, 1, false, &WaterMgr->m_RefractionMatrix._11 );
653 pglUniformMatrix4fvARB( losMatrix, 1, false, losTexture.GetTextureMatrix() );
654 pglUniform1iARB( normalMap, 0 ); // texture unit 0
655 pglUniform1iARB( reflectionMap, 1 ); // texture unit 1
656 pglUniform1iARB( refractionMap, 2 ); // texture unit 2
657 pglUniform1iARB( losMap, 3 ); // texture unit 3
658 pglUniform3fvARB( cameraPos, 1, &camPos.X );
659
660 vertexDepth = ogl_program_get_attrib_location( m->fancyWaterShader, "vertexDepth" );
661 }
662
663 float repeatPeriod = (fancy ? WaterMgr->m_RepeatPeriod : 16.0f);
664
665 glBegin(GL_QUADS);
666
667 for(size_t i=0; i<m->visiblePatches.size(); i++)
668 {
669 CPatch* patch = m->visiblePatches[i]->GetPatch();
670
671 for(ssize_t dx=0; dx<PATCH_SIZE; dx++)
672 {
673 for(ssize_t dz=0; dz<PATCH_SIZE; dz++)
674 {
675 ssize_t x = (patch->m_X*PATCH_SIZE + dx);
676 ssize_t z = (patch->m_Z*PATCH_SIZE + dz);
677
678 // Some offsets used to go around counterclockwise while keeping code concise
679 const int DX[] = {1,1,0,0};
680 const int DZ[] = {0,1,1,0};
681
682 // is any corner of the tile below the water height? if not, no point rendering it
683 bool shouldRender = false;
684 for (int j = 0; j < 4; j++)
685 {
686 float terrainHeight = terrain->GetVertexGroundLevel(x + DX[j], z + DZ[j]);
687 if (terrainHeight < WaterMgr->m_WaterHeight)
688 {
689 shouldRender = true;
690 break;
691 }
692 }
693 if (!shouldRender)
694 continue;
695
696 for (int j=0; j<4; j++)
697 {
698 ssize_t ix = x + DX[j];
699 ssize_t iz = z + DZ[j];
700
701 float vertX = ix * CELL_SIZE;
702 float vertZ = iz * CELL_SIZE;
703
704 float terrainHeight = terrain->GetVertexGroundLevel(ix, iz);
705
706 if (fancy)
707 {
708 pglVertexAttrib1fARB(vertexDepth, WaterMgr->m_WaterHeight - terrainHeight);
709 pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/repeatPeriod, vertZ/repeatPeriod);
710 glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
711 }
712 else
713 {
714 float alpha = clamp( (WaterMgr->m_WaterHeight - terrainHeight) / WaterMgr->m_WaterFullDepth + WaterMgr->m_WaterAlphaOffset,
715 WaterMgr->m_WaterAlphaOffset, WaterMgr->m_WaterMaxAlpha);
716
717 // (Crappy) fresnel effect
718 CVector3D CamFaceVertex=CVector3D(vertX,WaterMgr->m_WaterHeight,vertZ)-camPos;
719 CamFaceVertex.Normalize();
720 float FresnelScalar = CamFaceVertex.Dot(CVector3D(0.0f, -1.0f, 0.0f));
721 // Invert and set boundaries
722 FresnelScalar = 1.f - (FresnelScalar * 0.6);
723
724 glColor4f(WaterMgr->m_WaterColor.r,
725 WaterMgr->m_WaterColor.g,
726 WaterMgr->m_WaterColor.b,
727 alpha * FresnelScalar);
728 pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/repeatPeriod, vertZ/repeatPeriod);
729 pglMultiTexCoord3fARB(GL_TEXTURE1, vertX, WaterMgr->m_WaterHeight, vertZ);
730 glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
731 }
732
733 }
734 } //end of x loop
735 } //end of z loop
736 }
737 glEnd();
738
739 if (fancy)
740 {
741 // Unbind the LOS/refraction/reflection textures and the shader
742
743 g_Renderer.BindTexture(3, 0);
744 g_Renderer.BindTexture(2, 0);
745 g_Renderer.BindTexture(1, 0);
746
747 pglActiveTextureARB(GL_TEXTURE0_ARB);
748
749 ogl_program_use(0);
750 }
751
752 if (!fancy)
753 {
754 g_Renderer.BindTexture(1, 0);
755 pglClientActiveTextureARB(GL_TEXTURE1_ARB);
756 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
757
758 glLoadIdentity();
759
760 pglActiveTextureARB(GL_TEXTURE0_ARB);
761 pglClientActiveTextureARB(GL_TEXTURE0_ARB);
762
763 // Clean up the texture matrix and blend mode
764 glLoadIdentity();
765 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
766 }
767
768 glMatrixMode(GL_MODELVIEW);
769 glDisable(GL_BLEND);
770 glDisable(GL_TEXTURE_2D);
771}
772
773void TerrainRenderer::RenderPriorities()
774{
775 PROFILE("render priorities");
776
777 ENSURE(m->phase == Phase_Render);
778
779 CFont font(L"mono-stroke-10");
780 font.Bind();
781
782 glColor3f(1, 1, 0);
783
784 for (size_t i = 0; i < m->visiblePatches.size(); ++i)
785 m->visiblePatches[i]->RenderPriorities();
786}
Note: See TracBrowser for help on using the repository browser.