Changeset View
Changeset View
Standalone View
Standalone View
source/renderer/WaterManager.cpp
/* Copyright (C) 2017 Wildfire Games. | /* Copyright (C) 2017 Wildfire Games. | ||||
Stan: Year. | |||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 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 | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
▲ Show 20 Lines • Show All 1,007 Lines • ▼ Show 20 Lines | void WaterManager::RecomputeWaterData() | ||||
RecomputeDistanceHeightmap(); | RecomputeDistanceHeightmap(); | ||||
RecomputeWindStrength(); | RecomputeWindStrength(); | ||||
CreateWaveMeshes(); | CreateWaveMeshes(); | ||||
} | } | ||||
/////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////// | ||||
// Calculate the strength of the wind at a given point on the map. | // Calculate the strength of the wind at a given point on the map. | ||||
// This is too slow and should support limited recomputation. | |||||
void WaterManager::RecomputeWindStrength() | void WaterManager::RecomputeWindStrength() | ||||
{ | { | ||||
if (m_MapSize <= 0) | |||||
StanUnsubmitted Not Done Inline ActionsCan that happen ? Stan: Can that happen ? | |||||
wraitiiAuthorUnsubmitted Done Inline ActionsYes before init. wraitii: Yes before init. | |||||
return; | |||||
if (m_WindStrength == NULL) | if (m_WindStrength == NULL) | ||||
Not Done Inline ActionsNullptr Stan: Nullptr | |||||
m_WindStrength = new float[m_MapSize*m_MapSize]; | m_WindStrength = new float[m_MapSize*m_MapSize]; | ||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); | CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); | ||||
if (!terrain || !terrain->GetHeightMap()) | if (!terrain || !terrain->GetHeightMap()) | ||||
return; | return; | ||||
float waterLevel = m_WaterHeight; | float waterLevel = m_WaterHeight; | ||||
CVector2D windDir = CVector2D(cos(m_WindAngle),sin(m_WindAngle)); | CVector2D windDir = CVector2D(cos(m_WindAngle),sin(m_WindAngle)); | ||||
CVector2D perp = CVector2D(-windDir.Y, windDir.X); | |||||
// Our kernel will sample 5 points going towards the wind (generally). | ssize_t windX = round(1.0 / windDir.X); | ||||
StanUnsubmitted Not Done Inline Actions1.0f ? Stan: 1.0f ? | |||||
int kernel[5][2] = { {(int)windDir.X*2,(int)windDir.Y*2}, {(int)windDir.X*5,(int)windDir.Y*5}, {(int)windDir.X*9,(int)windDir.Y*9}, {(int)windDir.X*16,(int)windDir.Y*16}, {(int)windDir.X*25,(int)windDir.Y*25} }; | ssize_t windY = round(1.0 / windDir.Y); | ||||
float* Temp = new float[m_MapSize*m_MapSize]; | struct SWindPoint { | ||||
StanUnsubmitted Not Done Inline ActionsMaybe it should be declared out of the scope ? Stan: Maybe it should be declared out of the scope ? | |||||
std::fill(Temp, Temp + m_MapSize*m_MapSize, 1.0f); | SWindPoint(ssize_t x, ssize_t y, float strength) : X(x), Y(y), windStrength(strength) {} | ||||
ssize_t X; | |||||
ssize_t Y; | |||||
float windStrength; | |||||
}; | |||||
for (size_t j = 0; j < m_MapSize; ++j) | std::vector<SWindPoint> startingPoints; | ||||
for (size_t i = 0; i < m_MapSize; ++i) | std::vector<std::pair<ssize_t, ssize_t>> movement; // Every increment, move each starting point by all of these. | ||||
StanUnsubmitted Not Done Inline ActionsPut comment on top ? Stan: Put comment on top ? | |||||
{ | |||||
float curHeight = terrain->GetVertexGroundLevel(i,j); | // Compute starting points (one or two edges of the map) and how much to move each computation increment. | ||||
if (curHeight >= waterLevel) | if (fabs(windDir.X) < 0.01f) | ||||
{ | { | ||||
Temp[j*m_MapSize + i] = 0.3f; // blurs too strong otherwise | movement.push_back({0, windY}); | ||||
continue; | startingPoints.reserve(m_MapSize); | ||||
ssize_t start = windY > 0 ? 0 : m_MapSize-1; | |||||
StanUnsubmitted Not Done Inline Actionsspaces between operators. Stan: spaces between operators. | |||||
for (ssize_t x = 0; x < (ssize_t)m_MapSize; ++x) | |||||
StanUnsubmitted Not Done Inline Actionsstatic_cast Also can't you just use a normal a size_t ? size_t m_MapSize; Stan: static_cast
Also can't you just use a normal a size_t ?
size_t m_MapSize; | |||||
startingPoints.push_back({x, start, 0.0f}); | |||||
} | |||||
else if (fabs(windDir.Y) < 0.01f) | |||||
{ | |||||
movement.push_back({windX, 0}); | |||||
ssize_t start = windX > 0 ? 0 : m_MapSize-1; | |||||
StanUnsubmitted Not Done Inline Actionsspaces between operators. Stan: spaces between operators. | |||||
for (ssize_t z = 0; z < (ssize_t)m_MapSize; ++z) | |||||
StanUnsubmitted Not Done Inline ActionsSame here. Stan: Same here. | |||||
startingPoints.push_back({start, z, 0.0f}); | |||||
} | } | ||||
if (terrain->GetVertexGroundLevel(i + ceil(windDir.X),j + ceil(windDir.Y)) < waterLevel) | else | ||||
continue; | { | ||||
startingPoints.reserve(m_MapSize*2); | |||||
StanUnsubmitted Not Done Inline Actionsspaces between operators. Stan: spaces between operators. | |||||
// points along X | |||||
ssize_t start = windY > 0 ? 0 : m_MapSize-1; | |||||
StanUnsubmitted Not Done Inline Actionsspaces between operators. Stan: spaces between operators. | |||||
for (ssize_t x = 0; x < (ssize_t)m_MapSize; ++x) | |||||
StanUnsubmitted Not Done Inline ActionsSame here. Stan: Same here. | |||||
startingPoints.push_back({x, start, 0.0f}); | |||||
// points along Z, avoid repeating the corner point. | |||||
Not Done Inline Actionscomments start with capital :) Silier: comments start with capital :) | |||||
start = windX > 0 ? 0 : m_MapSize-1; | |||||
if (windY > 0) | |||||
StanUnsubmitted Not Done Inline Actionscan't this be 'simplified' using a ternary and a 'end' variable ? Stan: can't this be 'simplified' using a ternary and a 'end' variable ? | |||||
for (ssize_t z = 1; z < (ssize_t)m_MapSize; ++z) | |||||
startingPoints.push_back({start, z, 0.0f}); | |||||
else | |||||
for (ssize_t z = 0; z < (ssize_t)m_MapSize-1; ++z) | |||||
startingPoints.push_back({start, z, 0.0f}); | |||||
// Calculate how dampened our waves should be. | // compute movement array. | ||||
StanUnsubmitted Not Done Inline ActionsComments start with caps. Stan: Comments start with caps. | |||||
float oldHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[4][0],j+kernel[4][1])); | movement.reserve(std::max(std::abs(windX),std::abs(windY))); | ||||
float currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[3][0],j+kernel[3][1])); | while (windX != 0 || windY != 0) | ||||
float avgheight = oldHeight + currentHeight; | { | ||||
float tendency = currentHeight - oldHeight; | std::pair<ssize_t, ssize_t> move = {0,0}; | ||||
StanUnsubmitted Not Done Inline Actionsmissing spaces ? Stan: missing spaces ? | |||||
oldHeight = currentHeight; | move.first = windX == 0 ? 0 : windX > 0 ? +1 : -1; | ||||
currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[2][0],j+kernel[2][1])); | move.second = windY == 0 ? 0 : windY > 0 ? +1 : -1; | ||||
avgheight += currentHeight; | windX -= move.first; | ||||
tendency += currentHeight - oldHeight; | windY -= move.second; | ||||
oldHeight = currentHeight; | movement.push_back(move); | ||||
currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[1][0],j+kernel[1][1])); | |||||
avgheight += currentHeight; | |||||
tendency += currentHeight - oldHeight; | |||||
oldHeight = currentHeight; | |||||
currentHeight = std::max(waterLevel,terrain->GetVertexGroundLevel(i+kernel[0][0],j+kernel[0][1])); | |||||
avgheight += currentHeight; | |||||
tendency += currentHeight - oldHeight; | |||||
float baseLevel = std::max(0.0f,1.0f - (avgheight/5.0f-waterLevel)/20.0f); | |||||
baseLevel *= baseLevel; | |||||
tendency /= 15.0f; | |||||
baseLevel -= tendency; // if the terrain was sloping downwards, increase baselevel. Otherwise reduce. | |||||
baseLevel = clamp(baseLevel,0.0f,1.0f); | |||||
// Draw on map. This is pretty slow. | |||||
float length = 35.0f * (1.0f-baseLevel/1.8f); | |||||
for (float y = 0; y < length; y += 0.6f) | |||||
{ | |||||
int xx = clamp(i - y * windDir.X,0.0f,(float)(m_MapSize-1)); | |||||
int yy = clamp(j - y * windDir.Y,0.0f,(float)(m_MapSize-1)); | |||||
Temp[yy*m_MapSize + xx] = Temp[yy*m_MapSize + xx] < (0.0f+baseLevel/1.5f) * (1.0f-y/length) + y/length * 1.0f ? | |||||
Temp[yy*m_MapSize + xx] : (0.0f+baseLevel/1.5f) * (1.0f-y/length) + y/length * 1.0f; | |||||
} | } | ||||
} | } | ||||
int blurKernel[4][2] = { {(int)ceil(windDir.X),(int)ceil(windDir.Y)}, {(int)windDir.X*3,(int)windDir.Y*3}, {(int)ceil(perp.X),(int)ceil(perp.Y)}, {(int)-ceil(perp.X),(int)-ceil(perp.Y)} }; | // We have all starting points ready, move them all until the map is covered. | ||||
float blurValue; | for (SWindPoint& point : startingPoints) | ||||
for (size_t j = 2; j < m_MapSize-2; ++j) | { | ||||
for (size_t i = 2; i < m_MapSize-2; ++i) | // Starting velocity is 1.0 unless in shallow water. | ||||
{ | m_WindStrength[point.Y * m_MapSize + point.X] = 1.0; | ||||
StanUnsubmitted Not Done Inline Actions1.0f ? Stan: 1.0f ? | |||||
blurValue = Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]]; | float depth = waterLevel - terrain->GetVertexGroundLevel(point.X, point.Y); | ||||
blurValue += Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]]; | if (depth > 0.0f && depth < 2.0f) | ||||
blurValue += Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]]; | m_WindStrength[point.Y * m_MapSize + point.X] = depth/2.0f; | ||||
StanUnsubmitted Not Done Inline Actionsspaces between operators. Stan: spaces between operators. | |||||
blurValue += Temp[(j+blurKernel[0][1])*m_MapSize + i+blurKernel[0][0]]; | point.windStrength = m_WindStrength[point.Y * m_MapSize + point.X]; | ||||
m_WindStrength[j*m_MapSize + i] = blurValue * 0.25f; | |||||
bool onMap = true; | |||||
while (onMap) | |||||
StanUnsubmitted Not Done Inline ActionsMissing braces. Stan: Missing braces. | |||||
for (size_t step = 0; step < movement.size(); ++step) | |||||
{ | |||||
// Move wind speed towards the mean | |||||
point.windStrength = 0.15 + point.windStrength * 0.85; | |||||
// Adjust speed based on height difference, a positive height difference slowly increases speed (simulate venturi effect) | |||||
// and a lower height reduces speed (wind protection from hills/...) | |||||
float heightDiff = std::max(waterLevel, terrain->GetVertexGroundLevel(point.X + movement[step].first, point.Y + movement[step].second)) - | |||||
std::max(waterLevel, terrain->GetVertexGroundLevel(point.X, point.Y)); | |||||
if (heightDiff > 0.0) | |||||
Not Done Inline ActionsF ? Stan: F ? | |||||
point.windStrength = std::min(2.0f, point.windStrength + std::min(4.0f, heightDiff) / 40.0f); | |||||
else | |||||
point.windStrength = std::max(0.0f, point.windStrength + std::max(-4.0f, heightDiff) / 5.0f); | |||||
point.X += movement[step].first; | |||||
point.Y += movement[step].second; | |||||
if (point.X < 0 || point.X >= (ssize_t)m_MapSize || point.Y < 0 || point.Y >= (ssize_t)m_MapSize) | |||||
StanUnsubmitted Not Done Inline Actionsstatic_cast / why the cast ? Stan: static_cast / why the cast ? | |||||
{ | |||||
onMap = false; | |||||
break; | |||||
} | |||||
m_WindStrength[point.Y * m_MapSize + point.X] = point.windStrength; | |||||
} | |||||
} | } | ||||
delete[] Temp; | // TODO: should perhaps blur a little, or change the above code to incorporate neighboring tiles a bit. | ||||
} | } | ||||
//////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
// TODO: This will always recalculate for now | // TODO: This will always recalculate for now | ||||
void WaterManager::SetMapSize(size_t size) | void WaterManager::SetMapSize(size_t size) | ||||
{ | { | ||||
// TODO: Im' blindly trusting the user here. | // TODO: Im' blindly trusting the user here. | ||||
m_MapSize = size; | m_MapSize = size; | ||||
▲ Show 20 Lines • Show All 46 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
Year.