Index: ps/trunk/source/renderer/WaterManager.cpp =================================================================== --- ps/trunk/source/renderer/WaterManager.cpp (revision 14548) +++ ps/trunk/source/renderer/WaterManager.cpp (revision 14549) @@ -1,671 +1,674 @@ /* Copyright (C) 2013 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /* * Water settings (speed, height) and texture management */ #include "precompiled.h" #include "graphics/Terrain.h" #include "graphics/TextureManager.h" #include "lib/bits.h" #include "lib/timer.h" #include "lib/tex/tex.h" #include "lib/res/graphics/ogl_tex.h" #include "maths/MathUtil.h" #include "maths/Vector2D.h" #include "ps/Game.h" #include "ps/World.h" #include "renderer/WaterManager.h" #include "renderer/Renderer.h" #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpWaterManager.h" #include "simulation2/components/ICmpRangeManager.h" /////////////////////////////////////////////////////////////////////////////////////////////// // WaterManager implementation /////////////////////////////////////////////////////////////////// // Construction/Destruction WaterManager::WaterManager() { // water m_RenderWater = false; // disabled until textures are successfully loaded m_WaterHeight = 5.0f; m_WaterColor = CColor(0.3f, 0.35f, 0.7f, 1.0f); m_WaterFullDepth = 5.0f; m_WaterMaxAlpha = 1.0f; m_WaterAlphaOffset = -0.05f; m_SWaterTrans = 0; m_TWaterTrans = 0; m_SWaterSpeed = 0.0015f; m_TWaterSpeed = 0.0015f; m_SWaterScrollCounter = 0; m_TWaterScrollCounter = 0; m_WaterCurrentTex = 0; m_ReflectionTexture = 0; m_RefractionTexture = 0; m_ReflectionTextureSize = 0; m_RefractionTextureSize = 0; m_WaterTexTimer = 0.0; m_SpecularStrength = 0.6f; m_Waviness = 8.0f; m_ReflectionTint = CColor(0.28f, 0.3f, 0.59f, 1.0f); m_ReflectionTintStrength = 0.0f; m_WaterTint = CColor(0.28f, 0.3f, 0.59f, 1.0f); m_Murkiness = 0.45f; m_RepeatPeriod = 16.0f; m_WaveX = NULL; m_WaveZ = NULL; m_DistanceToShore = NULL; m_FoamFactor = NULL; m_WaterNormal = false; m_WaterRealDepth = false; m_WaterFoam = false; m_WaterCoastalWaves = false; m_WaterRefraction = false; m_WaterReflection = false; m_WaterShadows = false; m_NeedsReloading = false; m_NeedInfoUpdate = true; m_VBWaves = NULL; m_VBWavesIndices = NULL; m_depthTT = 0; m_waveTT = 0; m_MapSize = 0; m_updatei0 = 0; m_updatej0 = 0; m_updatei1 = 0; m_updatej1 = 0; } WaterManager::~WaterManager() { // Cleanup if the caller messed up UnloadWaterTextures(); delete[] m_WaveX; delete[] m_WaveZ; delete[] m_DistanceToShore; delete[] m_FoamFactor; glDeleteTextures(1, &m_depthTT); glDeleteTextures(1, &m_waveTT); if (m_VBWaves) g_VBMan.Release(m_VBWaves); if (m_VBWavesIndices) g_VBMan.Release(m_VBWavesIndices); } /////////////////////////////////////////////////////////////////// // Progressive load of water textures int WaterManager::LoadWaterTextures() { // TODO: this doesn't need to be progressive-loading any more // (since texture loading is async now) // TODO: add a member variable and setter for this. (can't make this // a parameter because this function is called via delay-load code) static const wchar_t* const water_type = L"default"; wchar_t pathname[PATH_MAX]; // Load diffuse grayscale images (for non-fancy water) for (size_t i = 0; i < ARRAY_SIZE(m_WaterTexture); ++i) { swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/%ls/diffuse%02d.dds", water_type, (int)i+1); CTextureProperties textureProps(pathname); textureProps.SetWrap(GL_REPEAT); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_WaterTexture[i] = texture; } // Load normalmaps (for fancy water) for (size_t i = 0; i < ARRAY_SIZE(m_NormalMap); ++i) { swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/%ls/normal%02d.dds", water_type, (int)i+1); CTextureProperties textureProps(pathname); textureProps.SetWrap(GL_REPEAT); textureProps.SetMaxAnisotropy(4); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_NormalMap[i] = texture; } // Load foam (for fancy water) { CTextureProperties textureProps("art/textures/terrain/types/water/foam.png"); textureProps.SetWrap(GL_REPEAT); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_Foam = texture; } // Load waves (for fancy water) { CTextureProperties textureProps("art/textures/terrain/types/water/shore_wave.png"); textureProps.SetWrap(GL_REPEAT); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); m_Wave = texture; } // Set the size to the largest power of 2 that is <= to the window height, so // the reflection/refraction images will fit within the window // (alternative: use FBO's, which can have arbitrary size - but do we need // the reflection/refraction textures to be that large?) int size = (int)round_up_to_pow2((unsigned)g_Renderer.GetHeight()); if(size > g_Renderer.GetHeight()) size /= 2; m_ReflectionTextureSize = size; m_RefractionTextureSize = size; // Create reflection texture glGenTextures(1, &m_ReflectionTexture); glBindTexture(GL_TEXTURE_2D, m_ReflectionTexture); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)m_ReflectionTextureSize, (GLsizei)m_ReflectionTextureSize, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); // Create refraction texture glGenTextures(1, &m_RefractionTexture); glBindTexture(GL_TEXTURE_2D, m_RefractionTexture); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)m_RefractionTextureSize, (GLsizei)m_RefractionTextureSize, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 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_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); // Enable rendering, now that we've succeeded this far m_RenderWater = true; return 0; } /////////////////////////////////////////////////////////////////// // Unload water textures void WaterManager::UnloadWaterTextures() { for(size_t i = 0; i < ARRAY_SIZE(m_WaterTexture); i++) { m_WaterTexture[i].reset(); } for(size_t i = 0; i < ARRAY_SIZE(m_NormalMap); i++) { m_NormalMap[i].reset(); } } /////////////////////////////////////////////////////////////////// // Create information about the terrain and wave vertices. void WaterManager::CreateSuperfancyInfo(CSimulation2* simulation) { if (m_VBWaves) { g_VBMan.Release(m_VBWaves); m_VBWaves = NULL; } if (m_VBWavesIndices) { g_VBMan.Release(m_VBWavesIndices); m_VBWavesIndices = NULL; } CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); CmpPtr cmpWaterManager(*simulation, SYSTEM_ENTITY); if (!cmpWaterManager) return; // REALLY shouldn't happen and will most likely crash. // Using this to get some more optimization on circular maps CmpPtr cmpRangeManager(*simulation, SYSTEM_ENTITY); if (!cmpRangeManager) return; bool circular = cmpRangeManager->GetLosCircular(); float mSize = m_MapSize*m_MapSize; float halfSize = (m_MapSize/2.0); // Warning: this won't work with multiple water planes m_WaterHeight = cmpWaterManager->GetExactWaterLevel(0,0); // Get the square we want to work on. ssize_t Xstart = m_updatei0 < 0 ? 0 : (m_updatei0 >= (ssize_t)m_MapSize ? (ssize_t)m_MapSize-1 : m_updatei0); ssize_t Xend = m_updatei1 < 0 ? 0 : (m_updatei1 >= (ssize_t)m_MapSize ? (ssize_t)m_MapSize-1 : m_updatei1); ssize_t Zstart = m_updatej0 < 0 ? 0 : (m_updatej0 >= (ssize_t)m_MapSize ? (ssize_t)m_MapSize-1 : m_updatej0); ssize_t Zend = m_updatej1 < 0 ? 0 : (m_updatej1 >= (ssize_t)m_MapSize ? (ssize_t)m_MapSize-1 : m_updatej1); if (!(Xend > Xstart && Zend > Zstart)) { // it corrupts every now and then for reasons I don't get. std::cout << m_updatei0 << " , " << Xstart << std::endl; std::cout << m_MapSize << "," << (ssize_t)m_MapSize << std::endl; } if (m_WaveX == NULL) { m_WaveX = new float[m_MapSize*m_MapSize]; m_WaveZ = new float[m_MapSize*m_MapSize]; m_DistanceToShore = new float[m_MapSize*m_MapSize]; m_FoamFactor = new float[m_MapSize*m_MapSize]; } u16* heightmap = terrain->GetHeightMap(); // some temporary stuff for wave intensity // not really used too much right now. //u8* waveForceHQ = new u8[mapSize*mapSize]; // used to cache terrain normals since otherwise we'd recalculate them a lot (I'm blurring the "normal" map). // this might be updated to actually cache in the terrain manager but that's not for now. CVector3D* normals = new CVector3D[m_MapSize*m_MapSize]; // taken out of the bottom loop, blurs the normal map // To remove if below is reactivated ssize_t blurZstart = Zstart-4 < 0 ? 0 : Zstart - 4; ssize_t blurZend = Zend+4 >= (ssize_t)m_MapSize ? (ssize_t)m_MapSize-1 : Zend + 4; ssize_t blurXstart = Xstart-4 < 0 ? 0 : Xstart - 4; ssize_t blurXend = Xend+4 >= (ssize_t)m_MapSize ? (ssize_t)m_MapSize-1 : Xend + 4; for (ssize_t j = blurZstart; j < blurZend; ++j) { for (ssize_t i = blurXstart; i < blurXend; ++i) { normals[j*m_MapSize + i] = terrain->CalcExactNormal(((float)i)*4.0f,((float)j)*4.0f); } } // TODO: reactivate? /* // calculate wave force (not really used right now) // and puts into "normals" the terrain normal at that point // so as to avoid recalculating terrain normals too often. for (ssize_t i = 0; i < mapSize; ++i) { for (ssize_t j = 0; j < mapSize; ++j) { normals[j*mapSize + i] = terrain->CalcExactNormal(((float)i)*4.0f,((float)j)*4.0f); if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize) { waveForceHQ[j*mapSize + i] = 255; continue; } u8 color = 0; for (int v = 0; v <= 18; v += 3){ if (j-v >= 0 && i-v >= 0 && heightmap[(j-v)*mapSize + i-v] > waterHeightInu16) { if (color == 0) color = 5; else color++; } } waveForceHQ[j*mapSize + i] = 255 - color * 40; } } */ // this creates information for waves and stores it in float arrays. PatchRData then puts it in the vertex info for speed. for (ssize_t j = Zstart; j < Zend; ++j) { for (ssize_t i = Xstart; i < Xend; ++i) { ssize_t index = j*m_MapSize + i; if (circular && (i-halfSize)*(i-halfSize)+(j-halfSize)*(j-halfSize) > mSize) { m_WaveX[index] = 0.0f; m_WaveZ[index] = 0.0f; m_DistanceToShore[index] = 100; m_FoamFactor[index] = 0.0f; continue; } float depth = m_WaterHeight - heightmap[index]*HEIGHT_SCALE; float distanceToShore = 10000; // calculation of the distance to the shore. if (i > 0 && i < (ssize_t)m_MapSize-1 && j > 0 && j < (ssize_t)m_MapSize-1) { + // this is needed otherwise I get many warnings for the code below + ssize_t mapSize = (ssize_t)m_MapSize; + // search a 5x5 array with us in the center (do not search me) // much faster since we spiral search and can just stop once we've found the shore. // also everything is precomputed and we get exact results instead. - ssize_t offset[24] = { -1,1,-m_MapSize,+m_MapSize, -1-m_MapSize,+1-m_MapSize,-1+m_MapSize,1+m_MapSize, - -2,2,-2*m_MapSize,2*m_MapSize,-2-m_MapSize,-2+m_MapSize,2-m_MapSize,2+m_MapSize, - -1-2*m_MapSize,+1-2*m_MapSize,-1+2*m_MapSize,1+2*m_MapSize, - -2-2*m_MapSize,2+2*m_MapSize,-2+2*m_MapSize,2-2*m_MapSize }; + ssize_t offset[24] = { -1,1,-mapSize,+mapSize, -1-mapSize,+1-mapSize,-1+mapSize,1+mapSize, + -2,2,-2*mapSize,2*mapSize,-2-mapSize,-2+mapSize,2-mapSize,2+mapSize, + -1-2*mapSize,+1-2*mapSize,-1+2*mapSize,1+2*mapSize, + -2-2*mapSize,2+2*mapSize,-2+2*mapSize,2-2*mapSize }; float dist[24] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.414f, 1.414f, 1.414f, 1.414f, 2.0f, 2.0f, 2.0f, 2.0f, 2.236f, 2.236f, 2.236f, 2.236f, 2.236f, 2.236f, 2.236f, 2.236f, 2.828f, 2.828f, 2.828f, 2.828f }; int max = 8; if (i > 1 && i < (ssize_t)m_MapSize-2 && j > 1 && j < (ssize_t)m_MapSize-2) max = 24; for(int lookupI = 0; lookupI < max;++lookupI) { float hereDepth = m_WaterHeight - heightmap[index+offset[lookupI]]*HEIGHT_SCALE; distanceToShore = hereDepth <= 0 && depth >= 0 ? dist[lookupI] : (depth < 0 ? 1 : distanceToShore); if (distanceToShore != 10000) break; } } else { // revert to for and if-based because I can't be bothered to special case all that. for (int xx = -1; xx <= 1;++xx) for (int yy = -1; yy <= 1;++yy) { if (i+xx >= 0 && i+xx < (ssize_t)m_MapSize && j+yy >= 0 && j+yy < (ssize_t)m_MapSize) { float hereDepth = m_WaterHeight - heightmap[index+xx+yy*m_MapSize]*HEIGHT_SCALE; distanceToShore = (hereDepth < 0 && sqrt((double)xx*xx+yy*yy) < distanceToShore) ? sqrt((double)xx*xx+yy*yy) : distanceToShore; } } } // speedup with default values for land squares if (distanceToShore == 10000) { m_WaveX[index] = 0.0f; m_WaveZ[index] = 0.0f; m_DistanceToShore[index] = 100.0f; m_FoamFactor[index] = 0.0f; continue; } // We'll compute the normals and the "water raise", to know about foam // Normals are a pretty good calculation but it's slow since we normalize so much. CVector3D normal; int waterRaise = 0; for (int yy = -3; yy <= 3; yy += 2) { for (int xx = -3; xx <= 3; xx += 2) // every 2 tile is good enough. { if (j+yy < (long)m_MapSize && i+xx < (long)m_MapSize && i+xx >= 0 && j+yy >= 0) normal += normals[(j+yy)*m_MapSize + (i+xx)]; waterRaise += heightmap[index]*HEIGHT_SCALE - terrain->GetVertexGroundLevel(i+xx,j+yy) > 0 ? heightmap[index]*HEIGHT_SCALE - terrain->GetVertexGroundLevel(i+xx,j+yy) : 0.0f; } } // normalizes the terrain info to avoid foam moving at too different speeds. normal *= 0.08f; normal[1] = 0.1f; normal = normal.Normalized(); m_WaveX[index] = normal[0]; m_WaveZ[index] = normal[2]; // distance is /5.0 to be a [0,1] value. m_DistanceToShore[index] = distanceToShore; // computing the amount of foam I want depth = clamp(depth,0.0f,10.0f); float foamAmount = (waterRaise/255.0f) * (1.0f - depth/10.0f) /** (waveForceHQ[j*m_MapSize+i]/255.0f)*/ * (m_Waviness/8.0f); foamAmount += clamp(m_Waviness/2.0f,0.0f,m_Waviness/2.0f)/(m_Waviness/2.0f) * clamp(m_Waviness/9.0f,0.3f,1.0f); foamAmount *= (m_Waviness/4.0f - distanceToShore); foamAmount = foamAmount > 1.0f ? 1.0f: (foamAmount < 0.0f ? 0.0f : foamAmount); m_FoamFactor[index] = foamAmount; } } delete[] normals; //delete[] waveForceHQ; // TODO: reactivate this with something that looks good and is efficient. /* // okay let's create the waves squares. i'll divide the map in arbitrary squares // For each of these squares, check if waves are needed. // If yes, look for the best positionning (in order to have a nice blending with the shore) // Then clean-up: remove squares that are too close to each other std::vector waveSquares; int size = 8; // I think this is the size of the squares. for (size_t j = 0; j < m_MapSize/size; ++j) { for (size_t i = 0; i < m_MapSize/size; ++i) { int landTexel = 0; int waterTexel = 0; CVector3D avnormal (0.0f,0.0f,0.0f); CVector2D landPosition(0.0f,0.0f); CVector2D waterPosition(0.0f,0.0f); for (int yy = 0; yy < size; ++yy) { for (int xx = 0; xx < size; ++xx) { if (terrain->GetVertexGroundLevel(i*size+xx,j*size+yy) > m_WaterHeight) { landTexel++; landPosition += CVector2D(i*size+xx,j*size+yy); } else { waterPosition += CVector2D(i*size+xx,j*size+yy); waterTexel++; avnormal += terrain->CalcExactNormal( (i*size+xx)*4.0f,(j*size+yy)*4.0f); } } } if (landTexel < size/2) continue; landPosition /= landTexel; waterPosition /= waterTexel; avnormal[1] = 1.0f; avnormal.Normalize(); avnormal[1] = 0.0f; // this should help ensure that the shore is pretty flat. if (avnormal.Length() <= 0.2f) continue; // To get the best position for squares, I start at the mean "ocean" position // And step by step go to the mean "land" position. I keep the position where I change from water to land. // If this never happens, the square is scrapped. if (terrain->GetExactGroundLevel(waterPosition.X*4.0f,waterPosition.Y*4.0f) > m_WaterHeight) continue; CVector2D squarePos(-1,-1); for (u8 i = 0; i < 40; i++) { squarePos = landPosition * (i/40.0f) + waterPosition * (1.0f-(i/40.0f)); if (terrain->GetExactGroundLevel(squarePos.X*4.0f,squarePos.Y*4.0f) > m_WaterHeight) break; } if (squarePos.X == -1) continue; u8 enter = 1; // okaaaaaay. Got a square. Check for proximity. for (unsigned long i = 0; i < waveSquares.size(); i++) { if ( CVector2D(waveSquares[i]-squarePos).LengthSquared() < 80) { enter = 0; break; } } if (enter == 1) waveSquares.push_back(squarePos); } } // Actually create the waves' meshes. std::vector waves_vertex_data; std::vector waves_indices; // loop through each square point. Look in the square around it, calculate the normal // create the square. for (unsigned long i = 0; i < waveSquares.size(); i++) { CVector2D pos(waveSquares[i]); CVector3D avgnorm(0.0f,0.0f,0.0f); for (int yy = -size/2; yy < size/2; ++yy) { for (int xx = -size/2; xx < size/2; ++xx) { avgnorm += terrain->CalcExactNormal((pos.X+xx)*4.0f,(pos.Y+yy)*4.0f); } } avgnorm[1] = 0.1f; // okay crank out a square. // we have the direction of the square. We'll get the perpendicular vector too CVector2D perp(-avgnorm[2],avgnorm[0]); perp = perp.Normalized(); avgnorm = avgnorm.Normalized(); GLushort index[4]; SWavesVertex vertex[4]; vertex[0].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y + perp.Y*(size/2.2f) - avgnorm[2]*1.0f); vertex[0].m_Position *= 4.0f; vertex[0].m_Position.Y = m_WaterHeight + 1.0f; vertex[0].m_UV[1] = 1; vertex[0].m_UV[0] = 0; index[0] = waves_vertex_data.size(); waves_vertex_data.push_back(vertex[0]); vertex[1].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) - avgnorm[0]*1.0f, 0.0f,pos.Y - perp.Y*(size/2.2f) - avgnorm[2]*1.0f); vertex[1].m_Position *= 4.0f; vertex[1].m_Position.Y = m_WaterHeight + 1.0f; vertex[1].m_UV[1] = 1; vertex[1].m_UV[0] = 1; index[1] = waves_vertex_data.size(); waves_vertex_data.push_back(vertex[1]); vertex[3].m_Position = CVector3D(pos.X + perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y + perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f)); vertex[3].m_Position *= 4.0f; vertex[3].m_Position.Y = m_WaterHeight + 1.0f; vertex[3].m_UV[1] = 0; vertex[3].m_UV[0] = 0; index[3] = waves_vertex_data.size(); waves_vertex_data.push_back(vertex[3]); vertex[2].m_Position = CVector3D(pos.X - perp.X*(size/2.2f) + avgnorm[0]*(size/1.5f), 0.0f,pos.Y - perp.Y*(size/2.2f) + avgnorm[2]*(size/1.5f)); vertex[2].m_Position *= 4.0f; vertex[2].m_Position.Y = m_WaterHeight + 1.0f; vertex[2].m_UV[1] = 0; vertex[2].m_UV[0] = 1; index[2] = waves_vertex_data.size(); waves_vertex_data.push_back(vertex[2]); waves_indices.push_back(index[0]); waves_indices.push_back(index[1]); waves_indices.push_back(index[2]); waves_indices.push_back(index[2]); waves_indices.push_back(index[3]); waves_indices.push_back(index[0]); } // no vertex buffers if no data generated if (waves_indices.empty()) return; // waves // allocate vertex buffer m_VBWaves = g_VBMan.Allocate(sizeof(SWavesVertex), waves_vertex_data.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); m_VBWaves->m_Owner->UpdateChunkVertices(m_VBWaves, &waves_vertex_data[0]); // Construct indices buffer m_VBWavesIndices = g_VBMan.Allocate(sizeof(GLushort), waves_indices.size(), GL_STATIC_DRAW, GL_ELEMENT_ARRAY_BUFFER); m_VBWavesIndices->m_Owner->UpdateChunkVertices(m_VBWavesIndices, &waves_indices[0]); */ } //////////////////////////////////////////////////////////////////////// // This will always recalculate for now void WaterManager::SetMapSize(size_t size) { // TODO: Im' blindly trusting the user here. m_MapSize = size; m_NeedInfoUpdate = true; m_updatei0 = 0; m_updatei1 = size; m_updatej0 = 0; m_updatej1 = size; SAFE_ARRAY_DELETE(m_WaveX); SAFE_ARRAY_DELETE(m_WaveZ); SAFE_ARRAY_DELETE(m_DistanceToShore); SAFE_ARRAY_DELETE(m_FoamFactor); } //////////////////////////////////////////////////////////////////////// // This will set the bools properly void WaterManager::UpdateQuality() { if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERNORMAL) != m_WaterNormal) { m_WaterNormal = g_Renderer.GetOptionBool(CRenderer::OPT_WATERNORMAL); m_NeedsReloading = true; } if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERREALDEPTH) != m_WaterRealDepth) { m_WaterRealDepth = g_Renderer.GetOptionBool(CRenderer::OPT_WATERREALDEPTH); m_NeedsReloading = true; } if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERFOAM) != m_WaterFoam) { m_WaterFoam = g_Renderer.GetOptionBool(CRenderer::OPT_WATERFOAM); m_NeedsReloading = true; m_NeedInfoUpdate = true; } if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERCOASTALWAVES) != m_WaterCoastalWaves) { m_WaterCoastalWaves = g_Renderer.GetOptionBool(CRenderer::OPT_WATERCOASTALWAVES); m_NeedsReloading = true; m_NeedInfoUpdate = true; } if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFRACTION) != m_WaterRefraction) { m_WaterRefraction = g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFRACTION); m_NeedsReloading = true; } if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFLECTION) != m_WaterReflection) { m_WaterReflection = g_Renderer.GetOptionBool(CRenderer::OPT_WATERREFLECTION); m_NeedsReloading = true; } if (g_Renderer.GetOptionBool(CRenderer::OPT_WATERSHADOW) != m_WaterShadows) { m_WaterShadows = g_Renderer.GetOptionBool(CRenderer::OPT_WATERSHADOW); m_NeedsReloading = true; } } bool WaterManager::WillRenderFancyWater() { if (!g_Renderer.GetCapabilities().m_FragmentShader) return false; if (!m_RenderWater) return false; return true; }