Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -413,75 +413,79 @@ pglDeleteFramebuffersEXT(1, &m_ReflectionFbo); } +template +static inline void ComputeDirection(float* distanceMap, const u16* heightmap, float waterHeight, size_t SideSize, size_t maxLevel) +{ +#define ABOVEWATER(x, z) HEIGHT_SCALE * heightmap[z*SideSize + x] >= waterHeight + for (size_t id1 = 0; id1 < SideSize; ++id1) + { + size_t id2 = 0; + size_t& x = Transpose ? id1 : id2; + size_t& z = Transpose ? id2 : id1; + + size_t level = ABOVEWATER(x, z) ? 0 : maxLevel; + size_t lookahead = level > 0 ? 1 : 0; + + for (; lookahead <= id2+maxLevel && lookahead < SideSize && + ((!Transpose && ABOVEWATER(lookahead, id1)) || (Transpose && ABOVEWATER(id1, lookahead))); ++lookahead) + ; + + // start moving + for (; id2 < SideSize; ++id2) + { + // update current level + if (ABOVEWATER(x, z)) + level = 0; + else + level = std::min(level+1, maxLevel); + + // move lookahead + if (lookahead == id2) + ++lookahead; + for (; lookahead <= id2+maxLevel && lookahead < SideSize && + ((!Transpose && ABOVEWATER(lookahead, id1)) || (Transpose && ABOVEWATER(id1, lookahead))); ++lookahead) + ; + + distanceMap[z*SideSize + x] = std::min(distanceMap[z*SideSize + x], (float)std::min(lookahead-id2, level)); + } + } +#undef ABOVEWATER +} + /////////////////////////////////////////////////////////////////// // Calculate our binary heightmap from the terrain heightmap. void WaterManager::RecomputeDistanceHeightmap() { - size_t SideSize = m_MapSize*2; + size_t SideSize = m_MapSize; + + // we want to look ahead some distance, but not too much (less efficient and not interesting). This is our lookahead. + const size_t maxLevel = 5; + if (m_DistanceHeightmap == NULL) + { m_DistanceHeightmap = new float[SideSize*SideSize]; + std::fill(m_DistanceHeightmap, m_DistanceHeightmap + SideSize*SideSize, (float)maxLevel); + } CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); // Create a manhattan-distance heightmap. - // This is currently upsampled by a factor of 2 to get more precision // This could be refined to only be done near the coast itself, but it's probably not necessary. - for (size_t z = 0; z < SideSize; ++z) - { - float level = SideSize; - for (size_t x = 0; x < SideSize; ++x) - m_DistanceHeightmap[z*SideSize + x] = terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight ? level = 0.f : ++level; - level = SideSize; - for (size_t x = SideSize-1; x != (size_t)-1; --x) - { - if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight) - level = 0.f; - else - { - ++level; - if (level < m_DistanceHeightmap[z*SideSize + x]) - m_DistanceHeightmap[z*SideSize + x] = level; - } - } - } - for (size_t x = 0; x < SideSize; ++x) - { - float level = SideSize; - for (size_t z = 0; z < SideSize; ++z) - { - if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight) - level = 0.f; - else if (level > m_DistanceHeightmap[z*SideSize + x]) - level = m_DistanceHeightmap[z*SideSize + x]; - else - { - ++level; - if (level < m_DistanceHeightmap[z*SideSize + x]) - m_DistanceHeightmap[z*SideSize + x] = level; - } - } - level = SideSize; - for (size_t z = SideSize-1; z != (size_t)-1; --z) - { - if (terrain->GetExactGroundLevel(x*2, z*2) >= m_WaterHeight) - level = 0.f; - else if (level > m_DistanceHeightmap[z*SideSize + x]) - level = m_DistanceHeightmap[z*SideSize + x]; - else - { - ++level; - if (level < m_DistanceHeightmap[z*SideSize + x]) - m_DistanceHeightmap[z*SideSize + x] = level; - } - } - } + u16* heightmap = terrain->GetHeightMap(); + + ComputeDirection(m_DistanceHeightmap, heightmap, m_WaterHeight, SideSize, maxLevel); + ComputeDirection(m_DistanceHeightmap, heightmap, m_WaterHeight, SideSize, maxLevel); } // This requires m_DistanceHeightmap to be defined properly. void WaterManager::CreateWaveMeshes() { - size_t SideSize = m_MapSize*2; + size_t SideSize = m_MapSize; + + if (SideSize == 0) + return; + CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); for (WaveObject* const& obj : m_ShoreWaves) @@ -505,8 +509,9 @@ std::set CoastalPointsSet; for (size_t z = 1; z < SideSize-1; ++z) for (size_t x = 1; x < SideSize-1; ++x) - if (fabs(m_DistanceHeightmap[z*SideSize + x]-1.0f) < 0.2f) - CoastalPointsSet.insert(z*SideSize + x); + // get the points not on the shore but near it, ocean-side + if (m_DistanceHeightmap[z*m_MapSize + x] > 0.5f && m_DistanceHeightmap[z*m_MapSize + x] < 1.5f) + CoastalPointsSet.insert((z)*SideSize + x); // Second step: create chains out of those coastal points. static const int around[8][2] = { { -1,-1 }, { -1,0 }, { -1,1 }, { 0,1 }, { 1,1 }, { 1,0 }, { 1,-1 }, { 0,-1 } }; @@ -520,7 +525,7 @@ std::deque Chain; - Chain.push_front(CoastalPoint(index,CVector2D(x*2,y*2))); + Chain.push_front(CoastalPoint(index,CVector2D(x*4,y*4))); // Erase us. CoastalPointsSet.erase(CoastalPointsSet.begin()); @@ -554,9 +559,9 @@ int endedChain = false; if (i == 0) - Chain.push_back(CoastalPoint(indexx,CVector2D(xx*2,yy*2))); + Chain.push_back(CoastalPoint(indexx,CVector2D(xx*4,yy*4))); else - Chain.push_front(CoastalPoint(indexx,CVector2D(xx*2,yy*2))); + Chain.push_front(CoastalPoint(indexx,CVector2D(xx*4,yy*4))); // If there's a loop we'll be the "other" neighboring point already so check for that. // We'll readd at the end/front the other one to have full squares. @@ -586,9 +591,9 @@ yy = yy + around[p][1]; indexx = xx + yy*SideSize; if (i == 0) - Chain.push_back(CoastalPoint(indexx,CVector2D(xx*2,yy*2))); + Chain.push_back(CoastalPoint(indexx,CVector2D(xx*4,yy*4))); else - Chain.push_front(CoastalPoint(indexx,CVector2D(xx*2,yy*2))); + Chain.push_front(CoastalPoint(indexx,CVector2D(xx*4,yy*4))); CoastalPointsSet.erase(xx + yy*SideSize); found = true; break; @@ -723,7 +728,7 @@ j += 3; continue; } - outmost = -0.5f + outmost * m_Waviness/10.0f; + outmost = -2.5f + outmost * m_Waviness/10.0f; avgDepth /= width; @@ -736,7 +741,8 @@ WaveObject* shoreWave = new WaveObject; std::vector vertices; - + vertices.reserve(9*width); + shoreWave->m_Width = width; shoreWave->m_TimeDiff = diff; diff += (rand() % 100) / 25.0f + 4.0f; @@ -845,16 +851,8 @@ } if (sign == 1) - { - // Let's do some fancy reversing. - std::vector reversed; - for (int a = width-1; a >= 0; --a) - { - for (size_t t = 0; t < 9; ++t) - reversed.push_back(vertices[a*9+t]); - } - vertices = reversed; - } + std::reverse(vertices.begin(), vertices.end()); + j += width/2-1; shoreWave->m_VBvertices = g_VBMan.Allocate(sizeof(SWavesVertex), vertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); Index: source/simulation2/components/CCmpWaterManager.cpp =================================================================== --- source/simulation2/components/CCmpWaterManager.cpp +++ source/simulation2/components/CCmpWaterManager.cpp @@ -97,7 +97,6 @@ { if (CRenderer::IsInitialised()) { - g_Renderer.GetWaterManager()->RecomputeBlurredNormalMap(); g_Renderer.GetWaterManager()->RecomputeDistanceHeightmap(); g_Renderer.GetWaterManager()->RecomputeWindStrength(); g_Renderer.GetWaterManager()->CreateWaveMeshes();