Mapgen: Generate fuzzy ellipse shaped lakes instead of squares

pull/251/head
Jonathan G Rennison 3 years ago
parent acfdc0efe8
commit 1ef236525a

@ -1072,6 +1072,15 @@ static bool FindSpring(TileIndex tile, void *user_data)
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.
* @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)
{
uint height = *(uint*)user_data;
if (!IsValidTile(tile) || TileHeight(tile) != height || !IsTileFlat(tile)) return false;
const MakeLakeData *data = (const MakeLakeData *)user_data;
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;
/* 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++) {
TileIndex t2 = tile + TileOffsByDiagDir(d);
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);
lakeCenter = end;
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. */
lakeCenter = end;
CircularTileSearch(&lakeCenter, range, MakeLake, &height);
CircularTileSearch(&lakeCenter, range, MakeLake, &data);
found = true;
}
}

Loading…
Cancel
Save