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); }
/////////////////////////////////////////////////////////////////// // 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); }
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; } }
/////////////////////////////////////////////////////////////////////////////////////////////////// // 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) }
////////////////////////////////////////////////////////////////////////// // 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; }
////////////////////////////////////////////////////////////////////////// // 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; } }
// 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; }