Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -417,71 +417,98 @@ // Calculate our binary heightmap from the terrain heightmap. void WaterManager::RecomputeDistanceHeightmap() { - size_t SideSize = m_MapSize*2; + size_t SideSize = m_MapSize; if (m_DistanceHeightmap == NULL) + { m_DistanceHeightmap = new float[SideSize*SideSize]; + memset(m_DistanceHeightmap, 0, sizeof(float) * SideSize*SideSize); + } 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. + // we don't consider values above maxLevel so this is effectively our lookahead. + const size_t maxLevel = 5; + + u16* heightmap = terrain->GetHeightMap(); + + auto aboveWater = [&heightmap, &SideSize, this](int x, int z) -> bool { return HEIGHT_SCALE * heightmap[z*SideSize + x] >= m_WaterHeight; }; + auto updateLookaheadX = [&SideSize, &maxLevel, &aboveWater](size_t& lookahead, int x, int z) -> void + { + for (size_t i = lookahead; i <= x+maxLevel; ++i) + { + if (lookahead < SideSize && aboveWater(lookahead, z)) + break; + ++lookahead; + }; + }; for (size_t z = 0; z < SideSize; ++z) { - float level = SideSize; + size_t level = aboveWater(0, z) ? 0 : maxLevel; + size_t lookahead = level > 0 ? 1 : 0; + + updateLookaheadX(lookahead, 0, z); + + // start moving 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; + // increment past value + if (aboveWater(x, z)) + level = 0; else - { - ++level; - if (level < m_DistanceHeightmap[z*SideSize + x]) - m_DistanceHeightmap[z*SideSize + x] = level; - } + level = std::min(level+1, maxLevel); + + // move lookahead + if (lookahead == x) + ++lookahead; + updateLookaheadX(lookahead, x, z); + + m_DistanceHeightmap[z*SideSize + x] = std::min(lookahead-x, level); } } + // same process on the z-axis + auto updateLookaheadZ = [&SideSize, &maxLevel, &aboveWater](size_t& lookahead, int x, int z) -> void + { + for (size_t i = lookahead; i <= z+maxLevel; ++i) + { + if (lookahead < SideSize && aboveWater(x, lookahead)) + break; + ++lookahead; + }; + }; for (size_t x = 0; x < SideSize; ++x) { - float level = SideSize; + size_t level = aboveWater(x, 0) ? 0 : maxLevel; + size_t lookahead = level > 0 ? 1 : 0; + + updateLookaheadZ(lookahead, x, 0); + 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]; + if (aboveWater(x, z)) + level = 0; else - { - ++level; - if (level < m_DistanceHeightmap[z*SideSize + x]) - m_DistanceHeightmap[z*SideSize + x] = level; - } + level = std::min(level+1, maxLevel); + + // move lookahead + if (lookahead == z) + ++lookahead; + updateLookaheadZ(lookahead, x, z); + + m_DistanceHeightmap[z*SideSize + x] = std::min(m_DistanceHeightmap[z*SideSize + x], (float)std::min(lookahead-z, level)); } - } -} + }} // This requires m_DistanceHeightmap to be defined properly. void WaterManager::CreateWaveMeshes() { - size_t SideSize = m_MapSize*2; + size_t SideSize = m_MapSize; + + if (m_MapSize == 0) + return; + CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); for (WaveObject* const& obj : m_ShoreWaves) @@ -503,10 +530,11 @@ // First step: get the points near the coast. 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); + for (size_t z = 1; z < m_MapSize - 1; ++z) + for (size_t x = 1; x < m_MapSize - 1; ++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 +548,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 +582,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 +614,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 +751,7 @@ j += 3; continue; } - outmost = -0.5f + outmost * m_Waviness/10.0f; + outmost = -2.5f + outmost * m_Waviness/10.0f; avgDepth /= width; 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();