Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -417,71 +417,76 @@ // 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]; + m_DistanceHeightmap = new 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. - 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) + // 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; + + u16* heightmap = terrain->GetHeightMap(); + +#define ABOVEWATER(x, z) HEIGHT_SCALE * heightmap[z*SideSize + x] >= m_WaterHeight + + auto computeDirection = [this, SideSize, &heightmap, maxLevel](bool transpose) { - float level = SideSize; - for (size_t z = 0; z < SideSize; ++z) + for (size_t id1 = 0; id1 < SideSize; ++id1) { - 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 + 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 (size_t i = lookahead; i <= id2+maxLevel && lookahead < SideSize && + ((!transpose && ABOVEWATER(lookahead, id1)) || (transpose && ABOVEWATER(id1, lookahead))); + ++i && ++lookahead) + {}; + + // start moving + for (; id2 < SideSize; ++id2) { - ++level; - if (level < m_DistanceHeightmap[z*SideSize + x]) - m_DistanceHeightmap[z*SideSize + x] = level; + // update current level + if (ABOVEWATER(x, z)) + level = 0; + else + level = std::min(level+1, maxLevel); + + // move lookahead + if (lookahead == id2) + ++lookahead; + for (size_t i = lookahead; i <= id2+maxLevel && lookahead < SideSize && + ((!transpose && ABOVEWATER(lookahead, id1)) || (transpose && ABOVEWATER(id1, lookahead))); + ++i && ++lookahead) + {}; + + if (!transpose) + m_DistanceHeightmap[z*SideSize + x] = (float)std::min(lookahead-id2, level); + else + m_DistanceHeightmap[z*SideSize + x] = std::min(m_DistanceHeightmap[z*SideSize + x], (float)std::min(lookahead-id2, level)); } } - } + }; + computeDirection(false); + computeDirection(true); +#undef ABOVEWATER } // 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 +508,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 < SideSize - 1; ++z) + for (size_t x = 1; x < SideSize - 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 +526,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 +560,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 +592,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 +729,7 @@ j += 3; continue; } - outmost = -0.5f + outmost * m_Waviness/10.0f; + outmost = -2.5f + outmost * m_Waviness/10.0f; avgDepth /= width; @@ -736,7 +742,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; 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();