示例#1
0
WaterManager::~WaterManager()
{
	// Cleanup if the caller messed up
	UnloadWaterTextures();

	for (WaveObject* const& obj : m_ShoreWaves)
	{
		if (obj->m_VBvertices)
			g_VBMan.Release(obj->m_VBvertices);
		delete obj;
	}

	if (m_ShoreWaves_VBIndices)
		g_VBMan.Release(m_ShoreWaves_VBIndices);

	delete[] m_DistanceHeightmap;
	delete[] m_BlurredNormalMap;
	delete[] m_WindStrength;
	
	if (!g_Renderer.GetCapabilities().m_PrettyWater)
		return;

	glDeleteTextures(1, &m_depthTT);
	glDeleteTextures(1, &m_FancyTextureNormal);
	glDeleteTextures(1, &m_FancyTextureOther);
	glDeleteTextures(1, &m_FancyTextureDepth);
	glDeleteTextures(1, &m_ReflFboDepthTexture);
	glDeleteTextures(1, &m_RefrFboDepthTexture);
	
	pglDeleteFramebuffersEXT(1, &m_FancyEffectsFBO);
	pglDeleteFramebuffersEXT(1, &m_RefractionFbo);
	pglDeleteFramebuffersEXT(1, &m_ReflectionFbo);
}
示例#2
0
///////////////////////////////////////////////////////////////////
// Unload water textures
void WaterManager::UnloadWaterTextures()
{
	for(size_t i = 0; i < ARRAY_SIZE(m_WaterTexture); i++)
		m_WaterTexture[i].reset();

	if (!g_Renderer.GetCapabilities().m_PrettyWater)
		return;

	for(size_t i = 0; i < ARRAY_SIZE(m_NormalMap); i++)
		m_NormalMap[i].reset();

	glDeleteTextures(1, &m_ReflectionTexture);
	glDeleteTextures(1, &m_RefractionTexture);
	pglDeleteFramebuffersEXT(1, &m_RefractionFbo);
	pglDeleteFramebuffersEXT(1, &m_ReflectionFbo);
}
示例#3
0
ShadowMap::~ShadowMap()
{
	if (m->Texture)
		glDeleteTextures(1, &m->Texture);
	if (m->DummyTexture)
		glDeleteTextures(1, &m->DummyTexture);
	if (m->Framebuffer)
		pglDeleteFramebuffersEXT(1, &m->Framebuffer);

	delete m;
}
void CPostprocManager::Cleanup()
{
	if (m_IsInitialised)
	{
		if (m_PingFbo) pglDeleteFramebuffersEXT(1, &m_PingFbo);
		if (m_PongFbo) pglDeleteFramebuffersEXT(1, &m_PongFbo);
		if (m_BloomFbo) pglDeleteFramebuffersEXT(1, &m_BloomFbo);
		m_PingFbo = m_PongFbo = m_BloomFbo = 0;
		
		if (m_ColourTex1) glDeleteTextures(1, &m_ColourTex1);
		if (m_ColourTex2) glDeleteTextures(1, &m_ColourTex2);
		if (m_DepthTex) glDeleteTextures(1, &m_DepthTex);
		m_ColourTex1 = m_ColourTex2 = m_DepthTex = 0;
		
		if (m_BlurTex2a) glDeleteTextures(1, &m_BlurTex2a);
		if (m_BlurTex2b) glDeleteTextures(1, &m_BlurTex2b);
		if (m_BlurTex4a) glDeleteTextures(1, &m_BlurTex4a);
		if (m_BlurTex4b) glDeleteTextures(1, &m_BlurTex4b);
		if (m_BlurTex8a) glDeleteTextures(1, &m_BlurTex8a);
		if (m_BlurTex8b) glDeleteTextures(1, &m_BlurTex8b);
		m_BlurTex2a = m_BlurTex2b = m_BlurTex4a = m_BlurTex4b = m_BlurTex8a = m_BlurTex8b = 0;
	}
}
示例#5
0
///////////////////////////////////////////////////////////////////////////////////////////////////
// Force the texture/buffer/etc to be recreated, particularly when the renderer's
// size has changed
void ShadowMap::RecreateTexture()
{
	if (m->Texture)
		glDeleteTextures(1, &m->Texture);
	if (m->DummyTexture)
		glDeleteTextures(1, &m->DummyTexture);
	if (m->Framebuffer)
		pglDeleteFramebuffersEXT(1, &m->Framebuffer);

	m->Texture = 0;
	m->DummyTexture = 0;
	m->Framebuffer = 0;

	// (Texture will be constructed in next SetupFrame)
}
示例#6
0
//////////////////////////////////////////////////////////////////////////
// Create the shadow map
void ShadowMapInternals::CreateTexture()
{
	// Cleanup
	if (Texture)
	{
		glDeleteTextures(1, &Texture);
		Texture = 0;
	}
	if (DummyTexture)
	{
		glDeleteTextures(1, &DummyTexture);
		DummyTexture = 0;
	}
	if (Framebuffer)
	{
		pglDeleteFramebuffersEXT(1, &Framebuffer);
		Framebuffer = 0;
	}

	pglGenFramebuffersEXT(1, &Framebuffer);

	if (g_Renderer.m_ShadowMapSize != 0)
	{
		// non-default option to override the size
		Width = Height = g_Renderer.m_ShadowMapSize;
	}
	else
	{
		// get shadow map size as next power of two up from view width and height
		Width = (int)round_up_to_pow2((unsigned)g_Renderer.GetWidth());
		Height = (int)round_up_to_pow2((unsigned)g_Renderer.GetHeight());
	}
	// Clamp to the maximum texture size
	Width = std::min(Width, (int)ogl_max_tex_size);
	Height = std::min(Height, (int)ogl_max_tex_size);

	// Since we're using a framebuffer object, the whole texture is available
	EffectiveWidth = Width;
	EffectiveHeight = Height;

	const char* formatname;

	switch(DepthTextureBits)
	{
	case 16: formatname = "DEPTH_COMPONENT16"; break;
	case 24: formatname = "DEPTH_COMPONENT24"; break;
	case 32: formatname = "DEPTH_COMPONENT32"; break;
	default: formatname = "DEPTH_COMPONENT"; break;
	}

	LOGMESSAGE(L"Creating shadow texture (size %dx%d) (format = %hs)",
		Width, Height, formatname);


	if (g_Renderer.m_Options.m_ShadowAlphaFix)
	{
		glGenTextures(1, &DummyTexture);
		g_Renderer.BindTexture(0, DummyTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	}

	glGenTextures(1, &Texture);
	g_Renderer.BindTexture(0, Texture);

	GLenum format;

	switch(DepthTextureBits)
	{
	case 16: format = GL_DEPTH_COMPONENT16; break;
	case 24: format = GL_DEPTH_COMPONENT24; break;
	case 32: format = GL_DEPTH_COMPONENT32; break;
	default: format = GL_DEPTH_COMPONENT; break;
	}

	glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);

	glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

	// set texture parameters
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	// bind to framebuffer object
	glBindTexture(GL_TEXTURE_2D, 0);
	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer);

	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Texture, 0);

	if (g_Renderer.m_Options.m_ShadowAlphaFix)
	{
		pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, DummyTexture, 0);
	}
	else
	{
		glDrawBuffer(GL_NONE);
	}

	glReadBuffer(GL_NONE);

	GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		LOGWARNING(L"Framebuffer object incomplete: %04d", status);

		// Disable shadow rendering (but let the user try again if they want)
		g_Renderer.m_Options.m_Shadows = false;
	}

	FilterOffsets[0] = -0.4f/Width;
	FilterOffsets[1] = 1.0f/Height;

	FilterOffsets[2] = -1.0f/Width;
	FilterOffsets[3] = -0.4f/Height;

	FilterOffsets[4] = 0.4f/Width;
	FilterOffsets[5] = -1.0f/Height;

	FilterOffsets[6] = 1.0f/Width;
	FilterOffsets[7] = 0.4f/Height;
}
示例#7
0
//////////////////////////////////////////////////////////////////////////
// Create the shadow map
void ShadowMapInternals::CreateTexture()
{
	// Cleanup
	if (Texture)
	{
		glDeleteTextures(1, &Texture);
		Texture = 0;
	}
	if (DummyTexture)
	{
		glDeleteTextures(1, &DummyTexture);
		DummyTexture = 0;
	}
	if (Framebuffer)
	{
		pglDeleteFramebuffersEXT(1, &Framebuffer);
		Framebuffer = 0;
	}

	pglGenFramebuffersEXT(1, &Framebuffer);

	if (g_Renderer.m_ShadowMapSize != 0)
	{
		// non-default option to override the size
		Width = Height = g_Renderer.m_ShadowMapSize;
	}
	else
	{
		// get shadow map size as next power of two up from view width/height
		Width = Height = (int)round_up_to_pow2((unsigned)std::max(g_Renderer.GetWidth(), g_Renderer.GetHeight()));
	}
	// Clamp to the maximum texture size
	Width = std::min(Width, (int)ogl_max_tex_size);
	Height = std::min(Height, (int)ogl_max_tex_size);

	// Since we're using a framebuffer object, the whole texture is available
	EffectiveWidth = Width;
	EffectiveHeight = Height;

	const char* formatname;

	switch(DepthTextureBits)
	{
	case 16: formatname = "DEPTH_COMPONENT16"; break;
	case 24: formatname = "DEPTH_COMPONENT24"; break;
	case 32: formatname = "DEPTH_COMPONENT32"; break;
	default: formatname = "DEPTH_COMPONENT"; break;
	}

	LOGMESSAGE(L"Creating shadow texture (size %dx%d) (format = %hs)",
		Width, Height, formatname);


	if (g_Renderer.m_Options.m_ShadowAlphaFix)
	{
		glGenTextures(1, &DummyTexture);
		g_Renderer.BindTexture(0, DummyTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	}

	glGenTextures(1, &Texture);
	g_Renderer.BindTexture(0, Texture);

	GLenum format;

#if CONFIG2_GLES
	format = GL_DEPTH_COMPONENT;
#else
	switch (DepthTextureBits)
	{
	case 16: format = GL_DEPTH_COMPONENT16; break;
	case 24: format = GL_DEPTH_COMPONENT24; break;
	case 32: format = GL_DEPTH_COMPONENT32; break;
	default: format = GL_DEPTH_COMPONENT; break;
	}
#endif

	glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
	// GLES requires type == UNSIGNED_SHORT or UNSIGNED_INT

	// set texture parameters
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

#if CONFIG2_GLES
	// GLES doesn't do depth comparisons, so treat it as a
	// basic unfiltered depth texture
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#else
	// Enable automatic depth comparisons
	glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

	// Use GL_LINEAR to trigger automatic PCF on some devices
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#endif

	ogl_WarnIfError();

	// bind to framebuffer object
	glBindTexture(GL_TEXTURE_2D, 0);
	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, Framebuffer);

	pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, Texture, 0);

	if (g_Renderer.m_Options.m_ShadowAlphaFix)
	{
		pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, DummyTexture, 0);
	}
	else
	{
#if CONFIG2_GLES
#warning TODO: figure out whether the glDrawBuffer/glReadBuffer stuff is needed, since it is not supported by GLES
#else
		glDrawBuffer(GL_NONE);
#endif
	}

#if !CONFIG2_GLES
	glReadBuffer(GL_NONE);
#endif

	ogl_WarnIfError();

	GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);

	pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

	if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
	{
		LOGWARNING(L"Framebuffer object incomplete: 0x%04X", status);

		// Disable shadow rendering (but let the user try again if they want)
		g_Renderer.m_Options.m_Shadows = false;
	}
}
示例#8
0
// Render fancy water
bool TerrainRenderer::RenderFancyWater(const CShaderDefines& context, ShadowMap* shadow)
{
	PROFILE3_GPU("fancy water");
	
	WaterManager* WaterMgr = g_Renderer.GetWaterManager();
	CShaderDefines defines = context;
	
	WaterMgr->UpdateQuality();

	// If we're using fancy water, make sure its shader is loaded
	if (!m->fancyWaterShader || WaterMgr->m_NeedsReloading)
	{
		if (WaterMgr->m_WaterNormal)
			defines.Add(str_USE_NORMALS, str_1);
		if (WaterMgr->m_WaterRealDepth)
			defines.Add(str_USE_REAL_DEPTH, str_1);
		if (WaterMgr->m_WaterFoam)
			defines.Add(str_USE_FOAM, str_1);
		if (WaterMgr->m_WaterCoastalWaves && false)
			defines.Add(str_USE_WAVES, str_1);
		if (WaterMgr->m_WaterRefraction)
			defines.Add(str_USE_REFRACTION, str_1);
		if (WaterMgr->m_WaterReflection)
			defines.Add(str_USE_REFLECTION, str_1);
		if (shadow && WaterMgr->m_WaterShadows)
			defines.Add(str_USE_SHADOWS, str_1);

		m->wavesShader = g_Renderer.GetShaderManager().LoadProgram("glsl/waves", defines);
		if (!m->wavesShader)
		{
			LOGERROR(L"Failed to load waves shader. Deactivating waves.\n");
			g_Renderer.SetOptionBool(CRenderer::OPT_WATERCOASTALWAVES, false);
			defines.Add(str_USE_WAVES, str_0);
		}
		
		// haven't updated the ARB shader yet so I'll always load the GLSL
		/*if (!g_Renderer.m_Options.m_PreferGLSL && !superFancy)
			m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("arb/water_high", defines);
		else*/
			m->fancyWaterShader = g_Renderer.GetShaderManager().LoadProgram("glsl/water_high", defines);
		
		if (!m->fancyWaterShader)
		{
			LOGERROR(L"Failed to load water shader. Falling back to non-fancy water.\n");
			WaterMgr->m_RenderWater = false;
			return false;
		}
		WaterMgr->m_NeedsReloading = false;
	}
	
	CLOSTexture& losTexture = g_Renderer.GetScene().GetLOSTexture();

	GLuint depthTex;
	// creating the real depth texture using the depth buffer.
	if (WaterMgr->m_WaterRealDepth)
	{
		if (WaterMgr->m_depthTT == 0)
		{
			glGenTextures(1, (GLuint*)&depthTex);
			WaterMgr->m_depthTT = depthTex;
			glBindTexture(GL_TEXTURE_2D, WaterMgr->m_depthTT);
			
#if CONFIG2_GLES
			GLenum format = GL_DEPTH_COMPONENT;
#else
			GLenum format = GL_DEPTH_COMPONENT32;
#endif
			
			// TODO: use POT texture
			glTexImage2D(GL_TEXTURE_2D, 0, format, g_Renderer.GetWidth(), g_Renderer.GetHeight(),
						 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL);
		}
		glBindTexture(GL_TEXTURE_2D, WaterMgr->m_depthTT);
#if !CONFIG2_GLES
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
#endif
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		
		glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, 0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight(), 0);
		
		glBindTexture(GL_TEXTURE_2D, 0);
	}
	// Calculating the advanced informations about Foam and all if the quality calls for it.
	/*if (WaterMgr->m_NeedInfoUpdate && (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves))
	{
		WaterMgr->m_NeedInfoUpdate = false;
		WaterMgr->CreateSuperfancyInfo();
	}*/
	
	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 = 8;
	int curTex = (int)(time*60/period) % 60;
	int nexTex = (curTex + 1) % 60;

	GLuint FramebufferName = 0;

	// rendering waves to a framebuffer
	// TODO: reactivate this with something that looks good.
	if (false && WaterMgr->m_WaterCoastalWaves && WaterMgr->m_VBWaves && !g_AtlasGameLoop->running)
	{
		// Save the post-processing framebuffer.
		GLint fbo;
		glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo);

		pglGenFramebuffersEXT(1, &FramebufferName);
		pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FramebufferName);
		
		GLuint renderedTexture;
		if (WaterMgr->m_waveTT == 0)
		{
			glGenTextures(1, &renderedTexture);
			WaterMgr->m_waveTT = renderedTexture;
			
			glBindTexture(GL_TEXTURE_2D, WaterMgr->m_waveTT);
			// TODO: use POT texture
			glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0,GL_RGBA, GL_UNSIGNED_BYTE, 0);

		}
		glBindTexture(GL_TEXTURE_2D, WaterMgr->m_waveTT);
		
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		
		pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, WaterMgr->m_waveTT, 0);
		
		glClearColor(0.5f,0.5f,1.0f,0.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		
		// rendering
		m->wavesShader->Bind();
		m->wavesShader->BindTexture(str_waveTex, WaterMgr->m_Wave);
		m->wavesShader->Uniform(str_time, (float)time);
		m->wavesShader->Uniform(str_waviness, WaterMgr->m_Waviness);
		m->wavesShader->Uniform(str_mapSize, (float)(WaterMgr->m_TexSize));
		
		SWavesVertex *base=(SWavesVertex *)WaterMgr->m_VBWaves->m_Owner->Bind();
		GLsizei stride = sizeof(SWavesVertex);
		m->wavesShader->VertexPointer(3, GL_FLOAT, stride, &base[WaterMgr->m_VBWaves->m_Index].m_Position);
		m->wavesShader->TexCoordPointer(GL_TEXTURE0,2,GL_BYTE, stride,&base[WaterMgr->m_VBWaves->m_Index].m_UV);
		m->wavesShader->AssertPointersBound();

		u8* indexBase = WaterMgr->m_VBWavesIndices->m_Owner->Bind();
		glDrawElements(GL_TRIANGLES, (GLsizei) WaterMgr->m_VBWavesIndices->m_Count, GL_UNSIGNED_SHORT, indexBase + sizeof(u16)*(WaterMgr->m_VBWavesIndices->m_Index));

		g_Renderer.m_Stats.m_DrawCalls++;
		CVertexBuffer::Unbind();
		m->wavesShader->Unbind();
		
		// rebind post-processing frambuffer.
		pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
		glBindTexture(GL_TEXTURE_2D, 0);
		
	}
	
	m->fancyWaterShader->Bind();

	
	// Shift the texture coordinates by these amounts to make the water "flow"
	float tx = -fmod(time, 81.0 / (WaterMgr->m_Waviness/20.0 + 0.8) )/(81.0/ (WaterMgr->m_Waviness/20.0 + 0.8) );
	float ty = -fmod(time, 34.0 / (WaterMgr->m_Waviness/20.0 + 0.8) )/(34.0/ (WaterMgr->m_Waviness/20.0 + 0.8) );
	
	float repeatPeriod = WaterMgr->m_RepeatPeriod;
	
	const CCamera& camera = g_Renderer.GetViewCamera();
	CVector3D camPos = camera.m_Orientation.GetTranslation();

	m->fancyWaterShader->BindTexture(str_normalMap, WaterMgr->m_NormalMap[curTex]);
	m->fancyWaterShader->BindTexture(str_normalMap2, WaterMgr->m_NormalMap[nexTex]);
	
	if (WaterMgr->m_WaterFoam || WaterMgr->m_WaterCoastalWaves)
	{
		m->fancyWaterShader->BindTexture(str_Foam, WaterMgr->m_Foam);
		m->fancyWaterShader->Uniform(str_mapSize, (float)(WaterMgr->m_TexSize));
	}
	if (WaterMgr->m_WaterRealDepth)
		m->fancyWaterShader->BindTexture(str_depthTex, WaterMgr->m_depthTT);
	if (WaterMgr->m_WaterCoastalWaves)
		m->fancyWaterShader->BindTexture(str_waveTex, WaterMgr->m_waveTT);
	if (WaterMgr->m_WaterReflection)
	m->fancyWaterShader->BindTexture(str_reflectionMap, WaterMgr->m_ReflectionTexture);
	if (WaterMgr->m_WaterRefraction)
	m->fancyWaterShader->BindTexture(str_refractionMap, WaterMgr->m_RefractionTexture);

	m->fancyWaterShader->BindTexture(str_losMap, losTexture.GetTextureSmooth());

	const CLightEnv& lightEnv = g_Renderer.GetLightEnv();

	// TODO: only bind what's really needed for that.
	m->fancyWaterShader->Uniform(str_sunDir, lightEnv.GetSunDir());
	m->fancyWaterShader->Uniform(str_sunColor, lightEnv.m_SunColor.X);
	m->fancyWaterShader->Uniform(str_color, WaterMgr->m_WaterColor);
	m->fancyWaterShader->Uniform(str_specularStrength, WaterMgr->m_SpecularStrength);
	m->fancyWaterShader->Uniform(str_waviness, WaterMgr->m_Waviness);
	m->fancyWaterShader->Uniform(str_murkiness, WaterMgr->m_Murkiness);
	m->fancyWaterShader->Uniform(str_tint, WaterMgr->m_WaterTint);
	m->fancyWaterShader->Uniform(str_reflectionTintStrength, WaterMgr->m_ReflectionTintStrength);
	m->fancyWaterShader->Uniform(str_reflectionTint, WaterMgr->m_ReflectionTint);
	m->fancyWaterShader->Uniform(str_translation, tx, ty);
	m->fancyWaterShader->Uniform(str_repeatScale, 1.0f / repeatPeriod);
	m->fancyWaterShader->Uniform(str_reflectionMatrix, WaterMgr->m_ReflectionMatrix);
	m->fancyWaterShader->Uniform(str_refractionMatrix, WaterMgr->m_RefractionMatrix);
	m->fancyWaterShader->Uniform(str_losMatrix, losTexture.GetTextureMatrix());
	m->fancyWaterShader->Uniform(str_cameraPos, camPos);
	m->fancyWaterShader->Uniform(str_fogColor, lightEnv.m_FogColor);
	m->fancyWaterShader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f);
	m->fancyWaterShader->Uniform(str_time, (float)time);
	m->fancyWaterShader->Uniform(str_screenSize, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0.0f, 0.0f);
	m->fancyWaterShader->BindTexture(str_skyCube, g_Renderer.GetSkyManager()->GetSkyCube());

	if (shadow && WaterMgr->m_WaterShadows)
	{
		m->fancyWaterShader->BindTexture(str_shadowTex, shadow->GetTexture());
		m->fancyWaterShader->Uniform(str_shadowTransform, shadow->GetTextureMatrix());
		int width = shadow->GetWidth();
		int height = shadow->GetHeight();
		m->fancyWaterShader->Uniform(str_shadowScale, width, height, 1.0f / width, 1.0f / height);
	}

	for (size_t i = 0; i < m->visiblePatches.size(); ++i)
	{
		CPatchRData* data = m->visiblePatches[i];
		data->RenderWater(m->fancyWaterShader);
	}

	m->fancyWaterShader->Unbind();

	pglActiveTextureARB(GL_TEXTURE0);
	pglDeleteFramebuffersEXT(1, &FramebufferName);

	glDisable(GL_BLEND);

	return true;
}