Mapgen: Generate fuzzy ellipse shaped lakes instead of squares

This commit is contained in:
Jonathan G Rennison
2021-04-14 01:22:32 +01:00
parent acfdc0efe8
commit 1ef236525a

View File

@@ -1072,6 +1072,15 @@ static bool FindSpring(TileIndex tile, void *user_data)
return true; return true;
} }
struct MakeLakeData {
TileIndex centre; ///< Lake centre tile
uint height; ///< Lake height
int max_distance; ///< Max radius
int secondary_axis_scale; ///< Multiplier for ellipse narrow axis, 16 bit fixed point
int sin_fp; ///< sin of ellipse rotation angle, 16 bit fixed point
int cos_fp; ///< cos of ellipse rotation angle, 16 bit fixed point
};
/** /**
* Make a connected lake; fill all tiles in the circular tile search that are connected. * Make a connected lake; fill all tiles in the circular tile search that are connected.
* @param tile The tile to consider for lake making. * @param tile The tile to consider for lake making.
@@ -1080,10 +1089,29 @@ static bool FindSpring(TileIndex tile, void *user_data)
*/ */
static bool MakeLake(TileIndex tile, void *user_data) static bool MakeLake(TileIndex tile, void *user_data)
{ {
uint height = *(uint*)user_data; const MakeLakeData *data = (const MakeLakeData *)user_data;
if (!IsValidTile(tile) || TileHeight(tile) != height || !IsTileFlat(tile)) return false; if (!IsValidTile(tile) || TileHeight(tile) != data->height || !IsTileFlat(tile)) return false;
if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_DESERT) return false; if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_DESERT) return false;
/* Offset from centre tile */
const int64 x_delta = (int)TileX(tile) - (int)TileX(data->centre);
const int64 y_delta = (int)TileY(tile) - (int)TileY(data->centre);
/* Rotate to new coordinate system */
const int64 a_delta = (x_delta * data->cos_fp + y_delta * data->sin_fp) >> 8;
const int64 b_delta = (-x_delta * data->sin_fp + y_delta * data->cos_fp) >> 8;
int max_distance = data->max_distance;
if (max_distance >= 6) {
/* Vary radius a bit for larger lakes */
uint coord = (std::abs(x_delta) > std::abs(y_delta)) ? TileY(tile) : TileX(tile);
static const int8 offset_fuzz[4] = { 0, 1, 0, -1 };
max_distance += offset_fuzz[(coord / 3) & 3];
}
/* Check if inside ellipse */
if ((a_delta * a_delta) + ((data->secondary_axis_scale * b_delta * b_delta) >> 16) > ((int64)(max_distance * max_distance) << 16)) return false;
for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) { for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
TileIndex t2 = tile + TileOffsByDiagDir(d); TileIndex t2 = tile + TileOffsByDiagDir(d);
if (IsWaterTile(t2)) { if (IsWaterTile(t2)) {
@@ -1280,10 +1308,25 @@ static bool FlowRiver(TileIndex spring, TileIndex begin)
CircularTileSearch(&lakeCenter, _settings_game.game_creation.river_tropics_width, RiverModifyDesertZone, nullptr); CircularTileSearch(&lakeCenter, _settings_game.game_creation.river_tropics_width, RiverModifyDesertZone, nullptr);
lakeCenter = end; lakeCenter = end;
uint range = RandomRange(_settings_game.game_creation.lake_size) + 3; uint range = RandomRange(_settings_game.game_creation.lake_size) + 3;
CircularTileSearch(&lakeCenter, range, MakeLake, &height);
MakeLakeData data;
data.centre = lakeCenter;
data.height = height;
data.max_distance = range / 2;
/* Square of ratio of ellipse dimensions: 1 to 5 (16 bit fixed point) */
data.secondary_axis_scale = (1 << 16) + RandomRange(1 << 18);
/* Range from -1 to 1 (16 bit fixed point) */
data.sin_fp = RandomRange(1 << 17) - (1 << 16);
/* sin^2 + cos^2 = 1 */
data.cos_fp = IntSqrt64(((int64)1 << 32) - ((int64)data.sin_fp * (int64)data.sin_fp));
CircularTileSearch(&lakeCenter, range, MakeLake, &data);
/* Call the search a second time so artefacts from going circular in one direction get (mostly) hidden. */ /* Call the search a second time so artefacts from going circular in one direction get (mostly) hidden. */
lakeCenter = end; lakeCenter = end;
CircularTileSearch(&lakeCenter, range, MakeLake, &height); CircularTileSearch(&lakeCenter, range, MakeLake, &data);
found = true; found = true;
} }
} }