Index: src/landscape.cpp =================================================================== --- src/landscape.cpp (revision 13992) +++ src/landscape.cpp (working copy) @@ -826,7 +826,7 @@ LoadHeightmap(_file_to_saveload.name); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) { - SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 3 + gwp_desert_amount : 3); + SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 3 + gwp_desert_amount : 5); // we have 5 landscape generation steps now GenerateTerrainPerlin(); } else { switch (_settings_game.game_creation.landscape) { Index: src/tgp.cpp =================================================================== --- src/tgp.cpp (revision 13992) +++ src/tgp.cpp (working copy) @@ -151,59 +151,55 @@ * */ + #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 #define M_PI 3.14159265358979323846 #endif /* M_PI_2 */ /** Fixed point type for heights */ -typedef int16 height_t; static const int height_decimal_bits = 4; static const height_t _invalid_height = -32768; /** Fixed point array for amplitudes (and percent values) */ -typedef int amplitude_t; static const int amplitude_decimal_bits = 10; -/** Height map - allocated array of heights (MapSizeX() + 1) x (MapSizeY() + 1) */ -struct HeightMap -{ - height_t *h; //< array of heights - uint dim_x; //< height map size_x MapSizeX() + 1 - uint total_size; //< height map total size - uint size_x; //< MapSizeX() - uint size_y; //< MapSizeY() +/** Global height map instance */ +//static HeightMap* _height_map; - /** - * Height map accessor - * @param x X position - * @param y Y position - * @return height as fixed point number - */ - inline height_t &height(uint x, uint y) { - return h[x + y * dim_x]; - } -}; +/** Global noise map instance */ +//static HeightMap* _noise_height_map; -/** Global height map instance */ -static HeightMap _height_map = {NULL, 0, 0, 0, 0}; -/** Conversion: int to height_t */ -#define I2H(i) ((i) << height_decimal_bits) -/** Conversion: height_t to int */ -#define H2I(i) ((i) >> height_decimal_bits) +/* Conversion helpers */ -/** Conversion: int to amplitude_t */ -#define I2A(i) ((i) << amplitude_decimal_bits) -/** Conversion: amplitude_t to int */ -#define A2I(i) ((i) >> amplitude_decimal_bits) +/** Integer to height_t conversion */ +inline height_t I2H(int i){ + return (i) << height_decimal_bits; +} -/** Conversion: amplitude_t to height_t */ -#define A2H(a) ((a) >> (amplitude_decimal_bits - height_decimal_bits)) +/** height_t to integer conversion */ +inline height_t H2I(height_t i){ + return (i) >> height_decimal_bits; +} +/** Integer to amplitude_t conversion */ +inline amplitude_t I2A(int i){ + return (i) << amplitude_decimal_bits; +} +/** Amplitude_t to integer conversion */ +inline int A2I(amplitude_t i){ + return (i) >> amplitude_decimal_bits; +} + +/** Amplitude_t to height_t conversion */ +inline height_t A2H(amplitude_t a){ + return (a) >> (amplitude_decimal_bits - height_decimal_bits); +} + /** Walk through all items of _height_map.h */ -#define FOR_ALL_TILES_IN_HEIGHT(h) for (h = _height_map.h; h < &_height_map.h[_height_map.total_size]; h++) +#define FOR_ALL_TILES_IN_HEIGHT(h) for (h = height_map.h; h < &height_map.h[height_map.total_size]; h++) /** Maximum index into array of noise amplitudes */ static const int TGP_FREQUENCY_MAX = 6; @@ -222,10 +218,10 @@ {24000, 16000, 19200, 16000, 8000, 512, 320}, }; -/** Desired water percentage (100% == 1024) - indexed by _settings_game.difficulty.quantity_sea_lakes */ +/** Desired water percentage (100% == 1024) - indexed by _opt.diff.quantity_sea_lakes */ static const amplitude_t _water_percent[4] = {20, 80, 250, 400}; -/** Desired maximum height - indexed by _settings_game.difficulty.terrain_type */ +/** Desired maximum height - indexed by _opt.diff.terrain_type */ static const int8 _max_height[4] = { 6, ///< Very flat 9, ///< Flat @@ -233,48 +229,43 @@ 15 ///< Mountainous }; -/** Check if a X/Y set are within the map. - * @param x coordinate x - * @param y coordinate y - * @return true if within the map - */ -static inline bool IsValidXY(uint x, uint y) -{ - return ((int)x) >= 0 && x < _height_map.size_x && ((int)y) >= 0 && y < _height_map.size_y; -} - - /** * Allocate array of (MapSizeX()+1)*(MapSizeY()+1) heights and init the _height_map structure members * @return true on success */ -static inline bool AllocHeightMap() +HeightMap::HeightMap(uint width, uint height)//: size_x(width), size_y(height) { - height_t *h; + size_x=width; + size_y=height; + + //height_t *h = NULL; - _height_map.size_x = MapSizeX(); - _height_map.size_y = MapSizeY(); + height_t *i = NULL; /* Allocate memory block for height map row pointers */ - _height_map.total_size = (_height_map.size_x + 1) * (_height_map.size_y + 1); - _height_map.dim_x = _height_map.size_x + 1; - _height_map.h = CallocT(_height_map.total_size); - if (_height_map.h == NULL) return false; + total_size = (width + 1) * (height + 1); + dim_x = width + 1; + h = CallocT(total_size); - /* Iterate through height map initialize values */ - FOR_ALL_TILES_IN_HEIGHT(h) *h = _invalid_height; - - return true; + /* Iterate through height map and initialize values */ + for (i = h; i < &h[total_size]; i++) *i = _invalid_height; } -/** Free height map */ -static inline void FreeHeightMap() +HeightMap::~HeightMap() { - if (_height_map.h == NULL) return; - free(_height_map.h); - _height_map.h = NULL; + if (h == NULL) return; + free(h); + h = NULL; } + +/* +inline void FreeHeightMaps(){ +// delete _height_map; +// delete _noise_height_map; +}*/ + + /** * Generates new random height in given amplitude (generated numbers will range from - amplitude to + amplitude) * @param rMax Limit of result @@ -284,6 +275,10 @@ { amplitude_t ra = (Random() << 16) | (Random() & 0x0000FFFF); height_t rh; + + /* Scale the amplitude for better resolution */ + //rMax *= 16; + /* Spread height into range -rMax..+rMax */ rh = A2H(ra % (2 * rMax + 1) - rMax); return rh; @@ -307,24 +302,23 @@ * @param amplitude Amplitude for the noise * @return false if we are finished (reached the minimal step size / highest frequency) */ -static bool ApplyNoise(uint log_frequency, amplitude_t amplitude) +static bool ApplyNoise(HeightMap &height_map, uint log_frequency, amplitude_t amplitude) { - uint size_min = min(_height_map.size_x, _height_map.size_y); + uint size_min = min(height_map.size_x, height_map.size_y); uint step = size_min >> log_frequency; - uint x, y; /* Trying to apply noise to uninitialized height map */ - assert(_height_map.h != NULL); + assert(height_map.h != NULL); /* Are we finished? */ if (step == 0) return false; + /* This is first round, we need to establish base heights with step = size_min */ if (log_frequency == 0) { - /* This is first round, we need to establish base heights with step = size_min */ - for (y = 0; y <= _height_map.size_y; y += step) { - for (x = 0; x <= _height_map.size_x; x += step) { + for (uint y = 0; y <= height_map.size_y; y += step) { + for (uint x = 0; x <= height_map.size_x; x += step) { height_t height = (amplitude > 0) ? RandomHeight(amplitude) : 0; - _height_map.height(x, y) = height; + height_map.height(x, y) = height; } } return true; @@ -332,39 +326,42 @@ /* It is regular iteration round. * Interpolate height values at odd x, even y tiles */ - for (y = 0; y <= _height_map.size_y; y += 2 * step) { - for (x = 0; x < _height_map.size_x; x += 2 * step) { - height_t h00 = _height_map.height(x + 0 * step, y); - height_t h02 = _height_map.height(x + 2 * step, y); + for (uint y = 0; y <= height_map.size_y; y += 2 * step) { + for (uint x = 0; x < height_map.size_x; x += 2 * step) { + height_t h00 = height_map.height(x + 0 * step, y); + height_t h02 = height_map.height(x + 2 * step, y); height_t h01 = (h00 + h02) / 2; - _height_map.height(x + 1 * step, y) = h01; + height_map.height(x + 1 * step, y) = h01; } } /* Interpolate height values at odd y tiles */ - for (y = 0; y < _height_map.size_y; y += 2 * step) { - for (x = 0; x <= _height_map.size_x; x += step) { - height_t h00 = _height_map.height(x, y + 0 * step); - height_t h20 = _height_map.height(x, y + 2 * step); + for (uint y = 0; y < height_map.size_y; y += 2 * step) { + for (uint x = 0; x <= height_map.size_x; x += step) { + height_t h00 = height_map.height(x, y + 0 * step); + height_t h20 = height_map.height(x, y + 2 * step); height_t h10 = (h00 + h20) / 2; - _height_map.height(x, y + 1 * step) = h10; + height_map.height(x, y + 1 * step) = h10; } } - /* Add noise for next higher frequency (smaller steps) */ - for (y = 0; y <= _height_map.size_y; y += step) { - for (x = 0; x <= _height_map.size_x; x += step) { - _height_map.height(x, y) += RandomHeight(amplitude); + /* Add some more smaller noise */ + if(amplitude>0){ + for (uint y = 0; y <= height_map.size_y; y += step) { + for (uint x = 0; x <= height_map.size_x; x += step) { + height_map.height(x, y) += RandomHeight(amplitude); + } } } + /* Return false if we are finished (reached the minimal step size) */ return (step > 1); } /** Base Perlin noise generator - fills height map with raw Perlin noise */ -static void HeightMapGenerate() +static void HeightMapGenerate(HeightMap &height_map, byte smoothness) { - uint size_min = min(_height_map.size_x, _height_map.size_y); + uint size_min = min(height_map.size_x, height_map.size_y); uint iteration_round = 0; amplitude_t amplitude; bool continue_iteration; @@ -386,23 +383,23 @@ assert(log_frequency <= TGP_FREQUENCY_MAX); amplitude = _amplitudes_by_smoothness_and_frequency[_settings_game.game_creation.tgen_smoothness][log_frequency]; } else { - /* Amplitude for the low frequencies on big maps is 0, i.e. initialise with zero height */ + /* Once amplitude reaches zero, we will keep smoothing the terrain */ amplitude = 0; } - continue_iteration = ApplyNoise(iteration_round, amplitude); + continue_iteration = ApplyNoise(height_map, iteration_round, amplitude); iteration_round++; } while (continue_iteration); assert(log_frequency == TGP_FREQUENCY_MAX); } /** Returns min, max and average height from height map */ -static void HeightMapGetMinMaxAvg(height_t *min_ptr, height_t *max_ptr, height_t *avg_ptr) +static void HeightMapGetMinMaxAvg(HeightMap &height_map, height_t *min_ptr, height_t *max_ptr, height_t *avg_ptr) { height_t h_min, h_max, h_avg, *h; int64 h_accu = 0; - h_min = h_max = _height_map.height(0, 0); + h_min = h_max = height_map.height(0, 0); - /* Get h_min, h_max and accumulate heights into h_accu */ + /* Calculate the sum of all heights in the height map */ FOR_ALL_TILES_IN_HEIGHT(h) { if (*h < h_min) h_min = *h; if (*h > h_max) h_max = *h; @@ -410,7 +407,7 @@ } /* Get average height */ - h_avg = (height_t)(h_accu / (_height_map.size_x * _height_map.size_y)); + h_avg = (height_t)(h_accu / (height_map.size_x * height_map.size_y)); /* Return required results */ if (min_ptr != NULL) *min_ptr = h_min; @@ -419,7 +416,7 @@ } /** Dill histogram and return pointer to its base point - to the count of zero heights */ -static int *HeightMapMakeHistogram(height_t h_min, height_t h_max, int *hist_buf) +static int *HeightMapMakeHistogram(HeightMap &height_map, height_t h_min, height_t h_max, int *hist_buf) { int *hist = hist_buf - h_min; height_t *h; @@ -434,7 +431,7 @@ } /** Applies sine wave redistribution onto height map */ -static void HeightMapSineTransform(height_t h_min, height_t h_max) +static void HeightMapSineTransform(HeightMap &height_map, height_t h_min, height_t h_max) { height_t *h; @@ -511,22 +508,24 @@ } /** Adjusts heights in height map to contain required amount of water tiles */ -static void HeightMapAdjustWaterLevel(amplitude_t water_percent, height_t h_max_new) +static void HeightMapAdjustWaterLevel(HeightMap &height_map,amplitude_t water_percent, height_t h_max_new) { height_t h_min, h_max, h_avg, h_water_level; int water_tiles, desired_water_tiles; height_t *h; int *hist; - HeightMapGetMinMaxAvg(&h_min, &h_max, &h_avg); + /* Get some info (minimal height, maximal height and average height) of the height map */ + HeightMapGetMinMaxAvg(height_map, &h_min, &h_max, &h_avg); /* Allocate histogram buffer and clear its cells */ int *hist_buf = CallocT(h_max - h_min + 1); + /* Fill histogram */ - hist = HeightMapMakeHistogram(h_min, h_max, hist_buf); + hist = HeightMapMakeHistogram(height_map, h_min, h_max, hist_buf); /* How many water tiles do we want? */ - desired_water_tiles = (int)(((int64)water_percent) * (int64)(_height_map.size_x * _height_map.size_y)) >> amplitude_decimal_bits; + desired_water_tiles = (int)(((int64)water_percent) * (int64)(height_map.size_x * height_map.size_y)) >> amplitude_decimal_bits; /* Raise water_level and accumulate values from histogram until we reach required number of water tiles */ for (h_water_level = h_min, water_tiles = 0; h_water_level < h_max; h_water_level++) { @@ -551,272 +550,106 @@ free(hist_buf); } -static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime); - /** - * This routine sculpts in from the edge a random amount, again a Perlin - * sequence, to avoid the rigid flat-edge slopes that were present before. The - * Perlin noise map doesnt know where we are going to slice across, and so we - * often cut straight through high terrain. the smoothing routine makes it - * legal, gradually increasing up from the edge to the original terrain height. - * By cutting parts of this away, it gives a far more irregular edge to the - * map-edge. Sometimes it works beautifully with the existing sea & lakes, and - * creates a very realistic coastline. Other times the variation is less, and - * the map-edge shows its cliff-like roots. - * - * This routine may be extended to randomly sculpt the height of the terrain - * near the edge. This will have the coast edge at low level (1-3), rising in - * smoothed steps inland to about 15 tiles in. This should make it look as - * though the map has been built for the map size, rather than a slice through - * a larger map. - * - * Please note that all the small numbers; 53, 101, 167, etc. are small primes - * to help give the perlin noise a bit more of a random feel. - */ -static void HeightMapCoastLines() -{ - int smallest_size = min(_settings_game.game_creation.map_x, _settings_game.game_creation.map_y); - const int margin = 4; - uint y, x; - double max_x; - double max_y; - - /* Lower to sea level */ - for (y = 0; y <= _height_map.size_y; y++) { - /* Top right */ - max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.9, 53) + 0.25) * 5 + (perlin_coast_noise_2D(y, y, 0.35, 179) + 1) * 12); - max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x); - if (smallest_size < 8 && max_x > 5) max_x /= 1.5; - for (x = 0; x < max_x; x++) { - _height_map.height(x, y) = 0; - } - - /* Bottom left */ - max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.85, 101) + 0.3) * 6 + (perlin_coast_noise_2D(y, y, 0.45, 67) + 0.75) * 8); - max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x); - if (smallest_size < 8 && max_x > 5) max_x /= 1.5; - for (x = _height_map.size_x; x > (_height_map.size_x - 1 - max_x); x--) { - _height_map.height(x, y) = 0; - } - } - - /* Lower to sea level */ - for (x = 0; x <= _height_map.size_x; x++) { - /* Top left */ - max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 2, 0.9, 167) + 0.4) * 5 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.4, 211) + 0.7) * 9); - max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y); - if (smallest_size < 8 && max_y > 5) max_y /= 1.5; - for (y = 0; y < max_y; y++) { - _height_map.height(x, y) = 0; - } - - - /* Bottom right */ - max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.85, 71) + 0.25) * 6 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.35, 193) + 0.75) * 12); - max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y); - if (smallest_size < 8 && max_y > 5) max_y /= 1.5; - for (y = _height_map.size_y; y > (_height_map.size_y - 1 - max_y); y--) { - _height_map.height(x, y) = 0; - } - } -} - -/** Start at given point, move in given direction, find and Smooth coast in that direction */ -static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int dir_y) -{ - const int max_coast_dist_from_edge = 35; - const int max_coast_Smooth_depth = 35; - - int x, y; - int ed; // coast distance from edge - int depth; - - height_t h_prev = 16; - height_t h; - - assert(IsValidXY(org_x, org_y)); - - /* Search for the coast (first non-water tile) */ - for (x = org_x, y = org_y, ed = 0; IsValidXY(x, y) && ed < max_coast_dist_from_edge; x += dir_x, y += dir_y, ed++) { - /* Coast found? */ - if (_height_map.height(x, y) > 15) break; - - /* Coast found in the neighborhood? */ - if (IsValidXY(x + dir_y, y + dir_x) && _height_map.height(x + dir_y, y + dir_x) > 0) break; - - /* Coast found in the neighborhood on the other side */ - if (IsValidXY(x - dir_y, y - dir_x) && _height_map.height(x - dir_y, y - dir_x) > 0) break; - } - - /* Coast found or max_coast_dist_from_edge has been reached. - * Soften the coast slope */ - for (depth = 0; IsValidXY(x, y) && depth <= max_coast_Smooth_depth; depth++, x += dir_x, y += dir_y) { - h = _height_map.height(x, y); - h = min(h, h_prev + (4 + depth)); // coast softening formula - _height_map.height(x, y) = h; - h_prev = h; - } -} - -/** Smooth coasts by modulating height of tiles close to map edges with cosine of distance from edge */ -static void HeightMapSmoothCoasts() -{ - uint x, y; - /* First Smooth NW and SE coasts (y close to 0 and y close to size_y) */ - for (x = 0; x < _height_map.size_x; x++) { - HeightMapSmoothCoastInDirection(x, 0, 0, 1); - HeightMapSmoothCoastInDirection(x, _height_map.size_y - 1, 0, -1); - } - /* First Smooth NE and SW coasts (x close to 0 and x close to size_x) */ - for (y = 0; y < _height_map.size_y; y++) { - HeightMapSmoothCoastInDirection(0, y, 1, 0); - HeightMapSmoothCoastInDirection(_height_map.size_x - 1, y, -1, 0); - } -} - -/** * This routine provides the essential cleanup necessary before OTTD can * display the terrain. When generated, the terrain heights can jump more than * one level between tiles. This routine smooths out those differences so that * the most it can change is one level. When OTTD can support cliffs, this * routine may not be necessary. */ -static void HeightMapSmoothSlopes(height_t dh_max) +static void HeightMapSmoothSlopes(HeightMap &height_map, height_t dh_max) { - int x, y; - for (y = 1; y <= (int)_height_map.size_y; y++) { - for (x = 1; x <= (int)_height_map.size_x; x++) { - height_t h_max = min(_height_map.height(x - 1, y), _height_map.height(x, y - 1)) + dh_max; - if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max; + for (int y = 1; y <= (int)height_map.size_y; y++) { + for (uint x = 1; x <= (int)height_map.size_x; x++) { + height_t h_max = min(height_map.height(x - 1, y), height_map.height(x, y - 1)) + dh_max; + if (height_map.height(x, y) > h_max) height_map.height(x, y) = h_max; } } - for (y = _height_map.size_y - 1; y >= 0; y--) { - for (x = _height_map.size_x - 1; x >= 0; x--) { - height_t h_max = min(_height_map.height(x + 1, y), _height_map.height(x, y + 1)) + dh_max; - if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max; + for (int y = height_map.size_y - 1; y >= 0; y--) { + for (int x = height_map.size_x - 1; x >= 0; x--) { + height_t h_max = min(height_map.height(x + 1, y), height_map.height(x, y + 1)) + dh_max; + if (height_map.height(x, y) > h_max) height_map.height(x, y) = h_max; } } } +/** In map border areas substracts the given noise map from the existing terrain. */ +static void HeightMapApplyBorders(HeightMap &height_map, HeightMap &noise_map, byte smoothness){ + /* Calculate width of the outmost map zone. This will mostly be covered with water with only ocassional + * peninsulas and islands. Clamp this value between 11 (to prevent artifacts on very small maps) and 80 + * (to prevent the zone of water from being too wide) + */ + uint coast_free_length = max(18, min(min(height_map.size_x, height_map.size_y) / 10, 80)); + + /* Calculates the length of coastline slopes. The smoother the map, the gentlier the slopes will be. */ + uint slope_length = 32 + 12 * (3 - smoothness); + + /* Walk through all tiles and apply the noise map */ + for (uint y = 1; y <= height_map.size_y; y++) { + for (uint x = 1; x <= height_map.size_x; x++) { + /* Calculate the distance from edge. This is very simple, since we are in a square tile based matrix */ + uint distance_from_edge=min(min(x, y), min(height_map.size_x - 1 - x, height_map.size_y - 1 - y)); + + /* The first zone - the coastline itself is mostly defined now. We don't have to start from -256 since + * there are no that high hills to neutralize in the noise heightmap. + */ + if(distance_from_edge < coast_free_length){ + height_map.height(x, y) = min(height_map.height(x, y), - 144 * (int)(coast_free_length - distance_from_edge ) / (int) coast_free_length + noise_map.height(x, y)); + } + /* the second zone - here are smoothed hills on the ground to fit the coastline*/ + else if(distance_from_edge < coast_free_length+slope_length){ + height_map.height(x, y) = min(height_map.height(x, y), 256 * (distance_from_edge - coast_free_length) / slope_length + noise_map.height(x, y)); + } + } + } + + /* Remove any potential double slopes */ + HeightMapSmoothSlopes(height_map, 16); +} + /** Height map terraform post processing: * - water level adjusting - * - coast Smoothing * - slope Smoothing * - height histogram redistribution by sine wave transform */ -static void HeightMapNormalize() -{ - const amplitude_t water_percent = _water_percent[_settings_game.difficulty.quantity_sea_lakes]; - const height_t h_max_new = I2H(_max_height[_settings_game.difficulty.terrain_type]); - const height_t roughness = 7 + 3 * _settings_game.game_creation.tgen_smoothness; - HeightMapAdjustWaterLevel(water_percent, h_max_new); - - HeightMapCoastLines(); - HeightMapSmoothSlopes(roughness); - - HeightMapSmoothCoasts(); - HeightMapSmoothSlopes(roughness); - - HeightMapSineTransform(12, h_max_new); - HeightMapSmoothSlopes(16); -} - -/** - * The Perlin Noise calculation using large primes - * The initial number is adjusted by two values; the generation_seed, and the - * passed parameter; prime. - * prime is used to allow the perlin noise generator to create useful random - * numbers from slightly different series. - */ -static double int_noise(const long x, const long y, const int prime) +static void HeightMapNormalize(HeightMap &height_map, byte sea_quantity, byte terrain_type, byte smoothness) { - long n = x + y * prime + _settings_game.game_creation.generation_seed; + const amplitude_t water_percent = _water_percent[sea_quantity]; + const height_t h_max_new = I2H(_max_height[terrain_type]); + const height_t roughness = 7 + 3 * smoothness; - n = (n << 13) ^ n; + HeightMapAdjustWaterLevel(height_map, water_percent, h_max_new); - /* Pseudo-random number generator, using several large primes */ - return 1.0 - (double)((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0; -} + HeightMapSmoothSlopes(height_map, roughness); + HeightMapSineTransform(height_map, 12, h_max_new); -/** - * Hj. Malthaner's routine included 2 different noise smoothing methods. - * We now use the "raw" int_noise one. - * However, it may be useful to move to the other routine in future. - * So it is included too. - */ -static double smoothed_noise(const int x, const int y, const int prime) -{ -#if 0 - /* A hilly world (four corner smooth) */ - const double sides = int_noise(x - 1, y) + int_noise(x + 1, y) + int_noise(x, y - 1) + int_noise(x, y + 1); - const double center = int_noise(x, y); - return (sides + sides + center * 4) / 8.0; -#endif - - /* This gives very hilly world */ - return int_noise(x, y, prime); + HeightMapSmoothSlopes(height_map, 16); } +/** Creates the alternative noise map */ +static void CreateNoiseMap(HeightMap &height_map,HeightMap &noise_map, byte smoothness){ + /* Allocate and initialize noise height map */ + //AllocHeightMap(noise_map,height_map.size_x,height_map.size_y); -/** - * This routine determines the interpolated value between a and b - */ -static inline double linear_interpolate(const double a, const double b, const double x) -{ - return a + x * (b - a); -} + /* Make small height noise map siginificantly rougher to prevent long straight + * shores, which could be part of longer curves on larger maps, but look very + * bad on small maps + */ + if(min(height_map.size_x,height_map.size_y)<=128) smoothness=3; + else if(min(height_map.size_x,height_map.size_y)<=256) smoothness=2; - -/** - * This routine returns the smoothed interpolated noise for an x and y, using - * the values from the surrounding positions. - */ -static double interpolated_noise(const double x, const double y, const int prime) -{ - const int integer_X = (int)x; - const int integer_Y = (int)y; - - const double fractional_X = x - (double)integer_X; - const double fractional_Y = y - (double)integer_Y; - - const double v1 = smoothed_noise(integer_X, integer_Y, prime); - const double v2 = smoothed_noise(integer_X + 1, integer_Y, prime); - const double v3 = smoothed_noise(integer_X, integer_Y + 1, prime); - const double v4 = smoothed_noise(integer_X + 1, integer_Y + 1, prime); - - const double i1 = linear_interpolate(v1, v2, fractional_X); - const double i2 = linear_interpolate(v3, v4, fractional_X); - - return linear_interpolate(i1, i2, fractional_Y); + /* Create the noise map landscape. Use mountainous map with very low water level. + * Smoothnes should be rough or very rough. Smooth or very smooth usually create too + * artificial shores + */ + HeightMapGenerate(noise_map,smoothness); + HeightMapNormalize(noise_map, 0, 1,2); } - -/** - * This is a similar function to the main perlin noise calculation, but uses - * the value p passed as a parameter rather than selected from the predefined - * sequences. as you can guess by its title, i use this to create the indented - * coastline, which is just another perlin sequence. - */ -static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime) +/** A small helper function to set tile height in the main map array */ +inline void TgenSetTileHeight(TileIndex tile, int height) { - double total = 0.0; - int i; - - for (i = 0; i < 6; i++) { - const double frequency = (double)(1 << i); - const double amplitude = pow(p, (double)i); - - total += interpolated_noise((x * frequency) / 64.0, (y * frequency) / 64.0, prime) * amplitude; - } - - return total; -} - - -/** A small helper function to initialize the terrain */ -static void TgenSetTileHeight(TileIndex tile, int height) -{ SetTileHeight(tile, height); MakeClear(tile, CLEAR_GRASS, 3); } @@ -832,21 +665,41 @@ { uint x, y; - if (!AllocHeightMap()) return; - GenerateWorldSetAbortCallback(FreeHeightMap); + //_height_map = new HeightMap(MapSizeX(), MapSizeY()); + //_noise_height_map = new HeightMap(MapSizeX(), MapSizeY()); - HeightMapGenerate(); + HeightMap _height_map(MapSizeX(), MapSizeY()); + HeightMap _noise_height_map(MapSizeX(), MapSizeY()); + //if (!_height_map) return; + //GenerateWorldSetAbortCallback(FreeHeightMaps); + + /* Generate the main terrain. Apply user defined smoothness */ + HeightMapGenerate(_height_map, _settings_game.game_creation.tgen_smoothness); + IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + + /* Generate the additional noise which would be used to make shores look more naturally. + * Override Very Smooth smoothness setting, it creates way too smooth coastlines + */ + CreateNoiseMap(_height_map, _noise_height_map,max((byte)1, _settings_game.game_creation.tgen_smoothness)); - HeightMapNormalize(); + IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + /* Adjust water level, apply sine transformation. Map borders are no longer created in this function */ + HeightMapNormalize(_height_map, _settings_game.difficulty.quantity_sea_lakes, _settings_game.difficulty.terrain_type, _settings_game.game_creation.tgen_smoothness); + IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + + /* Create the outer coastlines */ + HeightMapApplyBorders(_height_map, _noise_height_map, _settings_game.game_creation.tgen_smoothness); + IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); + /* Transfer height map into OTTD map */ for (y = 2; y < _height_map.size_y - 2; y++) { for (x = 2; x < _height_map.size_x - 2; x++) { - int height = H2I(_height_map.height(x, y)); + int height = H2I(_height_map.h[(x) + (y) * _height_map.dim_x]); if (height < 0) height = 0; if (height > 15) height = 15; TgenSetTileHeight(TileXY(x, y), height); @@ -859,6 +712,6 @@ for (y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y + _height_map.size_x - 1); for (x = 0; x < _height_map.size_x; x++) MakeVoid(_height_map.size_x * y + x); - FreeHeightMap(); + //FreeHeightMaps(); GenerateWorldSetAbortCallback(NULL); } Index: src/tgp.h =================================================================== --- src/tgp.h (revision 13992) +++ src/tgp.h (working copy) @@ -7,4 +7,38 @@ void GenerateTerrainPerlin(); +/** Fixed point array for amplitudes (and percent values) */ +typedef int amplitude_t; + +/** Fixed point type for heights */ +typedef int16 height_t; + +class HeightMap{ + public: + uint size_x; //< MapSizeX() + uint size_y; //< MapSizeY() + uint dim_x; //< MapSizeX() + 1 + uint total_size; //< height map total size + height_t *h; //< array of heights + HeightMap(uint width, uint height); + ~HeightMap(); + //inline height_t height(uint x, uint y); + + inline height_t &height(uint x, uint y) { + return h[x + y * dim_x]; + } + + /** Check if a X/Y set are within the map. + * @param height_map height map to be the coord validated on + * @param x coordinate x + * @param y coordinate y + * @return true if within the map + */ + inline bool HeightMap::IsValidXY(uint x, uint y) + { + return ((int)x) >= 0 && x < size_x && ((int)y) >= 0 && y < size_y; + } + +}; + #endif /* TGP_H */ Index: src/unmovable_cmd.cpp =================================================================== --- src/unmovable_cmd.cpp (revision 13992) +++ src/unmovable_cmd.cpp (working copy) @@ -419,7 +419,10 @@ case DIAGDIR_NW: tile = TileXY(r % maxx, maxy); break; } - for (int j = 0; j < 20; j++) { + /* Walk through up to 60 tiles from the map border and try to place a lighthouse there. Lighthouses + * can be placed only on flat, clear tiles. + */ + for (int j = 0; j < 60; j++) { uint h; if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h <= TILE_HEIGHT * 2 && !IsBridgeAbove(tile)) { MakeLighthouse(tile);