1
0
forked from 0ad/0ad
0ad/source/renderer/TerrainRenderer.cpp
janwas 5814e10126 # complete revamp of build system in preparation for automated self tests.
* now splits everything up into independent static libraries.
* fixed a great deal of incorrect #include statements. all headers must
now be specified with their full path relative to source. exception: if
file being included and including file are in the same directory, no
path needed.
use <> when relying on the build system's include path (e.g. for system
headers and external libraries, e.g. boost), otherwise "".

* temporarily renamed maths/Vector2D to Vector2D_Maths to avoid
conflict. these should be merged.
* hacked around VC linker stupidness when building static libs; texture
codecs must now be registered manually.

This was SVN commit r3931.
2006-06-02 03:56:24 +00:00

607 lines
20 KiB
C++

/**
* =========================================================================
* File : TerrainRenderer.cpp
* Project : Pyrogenesis
* Description : Terrain rendering (everything related to patches and
* : water) is encapsulated in TerrainRenderer
*
* @author Nicolai Hähnle <nicolai@wildfiregames.com>
* =========================================================================
*/
#include "precompiled.h"
#include "graphics/Camera.h"
#include "graphics/LightEnv.h"
#include "graphics/Patch.h"
#include "graphics/Terrain.h"
#include "graphics/GameView.h"
#include "maths/MathUtil.h"
#include "ps/Game.h"
#include "ps/Profile.h"
#include "ps/Pyrogenesis.h" // MICROLOG
#include "simulation/LOSManager.h"
#include "renderer/PatchRData.h"
#include "renderer/Renderer.h"
#include "renderer/ShadowMap.h"
#include "renderer/TerrainRenderer.h"
#include "renderer/WaterManager.h"
#include "lib/res/graphics/ogl_shader.h"
///////////////////////////////////////////////////////////////////////////////////////////////
// TerrainRenderer implementation
/**
* TerrainRenderer keeps track of which phase it is in, to detect
* when Submit, PrepareForRendering etc. are called in the wrong order.
*/
enum Phase {
Phase_Submit,
Phase_Render
};
/**
* Struct TerrainRendererInternals: Internal variables used by the TerrainRenderer class.
*/
struct TerrainRendererInternals
{
/// Which phase (submitting or rendering patches) are we in right now?
Phase phase;
/**
* VisiblePatches: Patches that were submitted for this frame
*
* @todo Merge this list with CPatchRData list
*/
std::vector<CPatch*> visiblePatches;
/// Fancy water shader
Handle fancyWaterShader;
};
///////////////////////////////////////////////////////////////////
// Construction/Destruction
TerrainRenderer::TerrainRenderer()
{
m = new TerrainRendererInternals();
m->phase = Phase_Submit;
m->fancyWaterShader = 0;
}
TerrainRenderer::~TerrainRenderer()
{
if( m->fancyWaterShader )
{
ogl_program_free( m->fancyWaterShader );
}
delete m;
}
///////////////////////////////////////////////////////////////////
// Submit a patch for rendering
void TerrainRenderer::Submit(CPatch* patch)
{
debug_assert(m->phase == Phase_Submit);
CPatchRData* data=(CPatchRData*) patch->GetRenderData();
if (data == 0)
{
// no renderdata for patch, create it now
data = new CPatchRData(patch);
patch->SetRenderData(data);
}
data->Update();
m->visiblePatches.push_back(patch);
}
///////////////////////////////////////////////////////////////////
// Prepare for rendering
void TerrainRenderer::PrepareForRendering()
{
debug_assert(m->phase == Phase_Submit);
m->phase = Phase_Render;
}
///////////////////////////////////////////////////////////////////
// Clear submissions lists
void TerrainRenderer::EndFrame()
{
debug_assert(m->phase == Phase_Render);
m->visiblePatches.clear();
m->phase = Phase_Submit;
}
///////////////////////////////////////////////////////////////////
// Query if patches have been submitted this frame
bool TerrainRenderer::HaveSubmissions()
{
return m->visiblePatches.size() > 0;
}
///////////////////////////////////////////////////////////////////
// Full-featured terrain rendering with blending and everything
void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
{
debug_assert(m->phase == Phase_Render);
// switch on required client states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// render everything fullbright
// set up texture environment for base pass
MICROLOG(L"base splat textures");
pglActiveTextureARB(GL_TEXTURE0);
pglClientActiveTextureARB(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
// Set alpha to 1.0
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
static const float one[4] = { 1.f, 1.f, 1.f, 1.f };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one);
for(uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderBase(true); // with LOS color
}
// render blends
// switch on the composite alpha map texture
(void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
// switch on second uv set
pglClientActiveTextureARB(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// setup additional texenv required by blend pass
pglActiveTextureARB(GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA);
// switch on blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// no need to write to the depth buffer a second time
glDepthMask(0);
// render blend passes for each patch
for(uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderBlends();
}
// Disable second texcoord array
pglClientActiveTextureARB(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Now apply lighting
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
glBlendFunc(GL_DST_COLOR, GL_ZERO);
if (!shadow)
{
pglActiveTextureARB(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
// Shadow rendering disabled: Ambient + Diffuse
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X);
}
else
{
const CMatrix3D& texturematrix = shadow->GetTextureMatrix();
pglActiveTextureARB(GL_TEXTURE0);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&texturematrix._11);
glMatrixMode(GL_MODELVIEW);
glBindTexture(GL_TEXTURE_2D, shadow->GetTexture());
if (shadow->GetUseDepthTexture())
{
// Ambient + ShTranslucency * Diffuse * (1 - Shadow) + Diffuse * Shadow
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
float shadowTransp = g_Renderer.GetLightEnv().GetTerrainShadowTransparency();
float color[4] = { shadowTransp, shadowTransp, shadowTransp, 1.0 };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
pglActiveTextureARB(GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, shadow->GetTexture()); // Need a valid texture or the unit will be disabled
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X);
}
else
{
// Ambient + Diffuse * Shadow
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE1); // + Ambient
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &lightEnv.m_TerrainAmbientColor.X);
}
}
pglActiveTextureARB(GL_TEXTURE0);
pglClientActiveTextureARB(GL_TEXTURE0);
for (uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderStreams(STREAM_POS|STREAM_COLOR|STREAM_POSTOUV0, false);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
// restore OpenGL state
if ( shadow )
{
if ( shadow->GetUseDepthTexture() )
g_Renderer.BindTexture(2,0);
}
g_Renderer.BindTexture(1,0);
pglClientActiveTextureARB(GL_TEXTURE0);
pglActiveTextureARB(GL_TEXTURE0);
glDepthMask(1);
glDisable(GL_BLEND);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
///////////////////////////////////////////////////////////////////
// Render un-textured patches as polygons
void TerrainRenderer::RenderPatches()
{
debug_assert(m->phase == Phase_Render);
glEnableClientState(GL_VERTEX_ARRAY);
for(uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderStreams(STREAM_POS, true);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
///////////////////////////////////////////////////////////////////
// Render outlines of submitted patches as lines
void TerrainRenderer::RenderOutlines()
{
glEnableClientState(GL_VERTEX_ARRAY);
for(uint i = 0; i < m->visiblePatches.size(); ++i)
{
CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
patchdata->RenderOutline();
}
glDisableClientState(GL_VERTEX_ARRAY);
}
///////////////////////////////////////////////////////////////////
// Render water that is part of the terrain
void TerrainRenderer::RenderWater()
{
PROFILE( "render water" );
bool fancy = g_Renderer.m_Options.m_FancyWater;
// If we're using fancy water, make sure its shader is loaded
if(fancy && !m->fancyWaterShader)
{
m->fancyWaterShader = ogl_program_load( "shaders/water_high.xml" );
}
//(Crappy) fresnel effect
CCamera* Camera=g_Game->GetView()->GetCamera();
CVector3D CamFace=Camera->m_Orientation.GetIn();
CamFace.Normalize();
float FresnelScalar = CamFace.Dot( CVector3D(0.0f, -1.0f, 0.0f) );
//Invert and set boundaries
FresnelScalar = (1 - FresnelScalar) * 0.4f + 0.6f;
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
int mapSize = terrain->GetVerticesPerSide();
CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager();
WaterManager* WaterMgr = g_Renderer.GetWaterManager();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
double time = WaterMgr->m_WaterTexTimer;
double period = 1.6;
int curTex = (int)(time*60/period) % 60;
if(fancy)
{
ogl_tex_bind(WaterMgr->m_NormalMap[curTex], 0);
}
else
{
ogl_tex_bind(WaterMgr->m_WaterTexture[curTex], 0);
}
if(!fancy)
{
// Shift the texture coordinates to make it "flow"
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
float tx = -fmod(time, 20.0)/20.0;
float ty = fmod(time, 35.0)/35.0;
glTranslatef(tx, ty, 0);
// Set up texture environment to multiply vertex RGB by texture RGB and use vertex alpha
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
}
// Set the proper LOD bias
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
// Some offsets used to go around counterclockwise while keeping code concise
const int DX[] = {1,1,0,0};
const int DZ[] = {0,1,1,0};
GLint vertexDepth = 0; // water depth attribute, if using fancy water
if(fancy)
{
// Bind reflection and refraction textures on texture units 1 and 2
pglActiveTextureARB( GL_TEXTURE1_ARB );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, WaterMgr->m_ReflectionTexture );
pglActiveTextureARB( GL_TEXTURE2_ARB );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, WaterMgr->m_RefractionTexture );
// Bind water shader and set arguments
ogl_program_use( m->fancyWaterShader );
GLint ambient = ogl_program_get_uniform_location( m->fancyWaterShader, "ambient" );
GLint sunDir = ogl_program_get_uniform_location( m->fancyWaterShader, "sunDir" );
GLint sunColor = ogl_program_get_uniform_location( m->fancyWaterShader, "sunColor" );
GLint shininess = ogl_program_get_uniform_location( m->fancyWaterShader, "shininess" );
GLint waviness = ogl_program_get_uniform_location( m->fancyWaterShader, "waviness" );
GLint cameraPos = ogl_program_get_uniform_location( m->fancyWaterShader, "cameraPos" );
GLint reflectionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMatrix" );
GLint refractionMatrix = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMatrix" );
GLint normalMap = ogl_program_get_uniform_location( m->fancyWaterShader, "normalMap" );
GLint reflectionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "reflectionMap" );
GLint refractionMap = ogl_program_get_uniform_location( m->fancyWaterShader, "refractionMap" );
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
pglUniform3fvARB( ambient, 1, &lightEnv.m_TerrainAmbientColor.X );
pglUniform3fvARB( sunDir, 1, &lightEnv.GetSunDir().X );
pglUniform3fvARB( sunColor, 1, &lightEnv.m_SunColor.X );
pglUniform1fARB( shininess, WaterMgr->m_Shininess );
pglUniform1fARB( waviness, WaterMgr->m_Waviness );
pglUniformMatrix4fvARB( reflectionMatrix, 1, false, &WaterMgr->m_ReflectionMatrix._11 );
pglUniformMatrix4fvARB( refractionMatrix, 1, false, &WaterMgr->m_RefractionMatrix._11 );
pglUniform1iARB( normalMap, 0 ); // texture unit 0
pglUniform1iARB( reflectionMap, 1 ); // texture unit 1
pglUniform1iARB( refractionMap, 2 ); // texture unit 2
const CCamera& camera = g_Renderer.GetViewCamera();
CVector3D camPos = camera.m_Orientation.GetTranslation();
pglUniform3fvARB( cameraPos, 1, &camPos.X );
vertexDepth = ogl_program_get_attrib_location( m->fancyWaterShader, "vertexDepth" );
}
float repeatPeriod = (fancy ? WaterMgr->m_RepeatPeriod : 16.0f);
glBegin(GL_QUADS);
for(size_t i=0; i<m->visiblePatches.size(); i++)
{
CPatch* patch = m->visiblePatches[i];
for(int dx=0; dx<PATCH_SIZE; dx++)
{
for(int dz=0; dz<PATCH_SIZE; dz++)
{
int x = (patch->m_X*PATCH_SIZE + dx);
int z = (patch->m_Z*PATCH_SIZE + dz);
// is any corner of the tile below the water height? if not, no point rendering it
bool shouldRender = false;
for(int j=0; j<4; j++)
{
float terrainHeight = terrain->getVertexGroundLevel(x + DX[j], z + DZ[j]);
if( terrainHeight < WaterMgr->m_WaterHeight )
{
shouldRender = true;
break;
}
}
if(!shouldRender)
{
continue;
}
for(int j=0; j<4; j++)
{
int ix = x + DX[j];
int iz = z + DZ[j];
float vertX = ix * CELL_SIZE;
float vertZ = iz * CELL_SIZE;
float terrainHeight = terrain->getVertexGroundLevel(ix, iz);
float alpha = clamp(
(WaterMgr->m_WaterHeight - terrainHeight) / WaterMgr->m_WaterFullDepth + WaterMgr->m_WaterAlphaOffset,
-100.0f, WaterMgr->m_WaterMaxAlpha);
float losMod = 1.0f;
for(int k=0; k<4; k++)
{
int tx = ix - DX[k];
int tz = iz - DZ[k];
if(tx >= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2)
{
ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer());
if(s == LOS_EXPLORED && losMod > 0.7f)
losMod = 0.7f;
else if(s==LOS_UNEXPLORED && losMod > 0.0f)
losMod = 0.0f;
}
}
if(fancy)
{
pglVertexAttrib1fARB( vertexDepth, WaterMgr->m_WaterHeight - terrainHeight );
}
glColor4f(WaterMgr->m_WaterColor.r*losMod, WaterMgr->m_WaterColor.g*losMod, WaterMgr->m_WaterColor.b*losMod, alpha * FresnelScalar);
pglMultiTexCoord2fARB(GL_TEXTURE0, vertX/repeatPeriod, vertZ/repeatPeriod);
glVertex3f(vertX, WaterMgr->m_WaterHeight, vertZ);
}
} //end of x loop
} //end of z loop
}
glEnd();
if(fancy)
{
// Unbind the refraction/reflection textures and the shader
pglActiveTextureARB( GL_TEXTURE1_ARB );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
pglActiveTextureARB( GL_TEXTURE2_ARB );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisable( GL_TEXTURE_2D );
pglActiveTextureARB( GL_TEXTURE0_ARB );
ogl_program_use( 0 );
}
if(!fancy)
{
// Clean up the texture matrix and blend mode
glLoadIdentity();
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
glMatrixMode(GL_MODELVIEW);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}