openttd updated to 1.5.0-beta2
--HG-- branch : openttd
This commit is contained in:
404
src/tgp.cpp
404
src/tgp.cpp
@@ -1,4 +1,4 @@
|
||||
/* $Id: tgp.cpp 26056 2013-11-22 21:50:43Z rubidium $ */
|
||||
/* $Id: tgp.cpp 27018 2014-10-14 17:49:32Z rubidium $ */
|
||||
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "core/random_func.hpp"
|
||||
#include "landscape_type.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
/*
|
||||
*
|
||||
* Quickie guide to Perlin Noise
|
||||
@@ -163,10 +165,12 @@ static const int amplitude_decimal_bits = 10;
|
||||
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()
|
||||
/* Even though the sizes are always positive, there are many cases where
|
||||
* X and Y need to be signed integers due to subtractions. */
|
||||
int dim_x; //< height map size_x MapSizeX() + 1
|
||||
int total_size; //< height map total size
|
||||
int size_x; //< MapSizeX()
|
||||
int size_y; //< MapSizeY()
|
||||
|
||||
/**
|
||||
* Height map accessor
|
||||
@@ -200,35 +204,88 @@ static HeightMap _height_map = {NULL, 0, 0, 0, 0};
|
||||
/** 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++)
|
||||
|
||||
/** Maximum index into array of noise amplitudes */
|
||||
static const int TGP_FREQUENCY_MAX = 6;
|
||||
|
||||
/**
|
||||
* Noise amplitudes (multiplied by 1024)
|
||||
* - indexed by "smoothness setting" and log2(frequency)
|
||||
*/
|
||||
static const amplitude_t _amplitudes_by_smoothness_and_frequency[4][TGP_FREQUENCY_MAX + 1] = {
|
||||
/* lowest frequncy.... ...highest (every corner) */
|
||||
/* Very smooth */
|
||||
{16000, 5600, 1968, 688, 240, 16, 16},
|
||||
/* Smooth */
|
||||
{16000, 16000, 6448, 3200, 1024, 128, 16},
|
||||
/* Rough */
|
||||
{16000, 19200, 12800, 8000, 3200, 256, 64},
|
||||
/* Very Rough */
|
||||
{24000, 16000, 19200, 16000, 8000, 512, 320},
|
||||
};
|
||||
/** Maximum number of TGP noise frequencies. */
|
||||
static const int MAX_TGP_FREQUENCIES = 10;
|
||||
|
||||
/** Desired water percentage (100% == 1024) - indexed by _settings_game.difficulty.quantity_sea_lakes */
|
||||
static const amplitude_t _water_percent[4] = {20, 80, 250, 400};
|
||||
|
||||
/** Desired maximum height - indexed by _settings_game.difficulty.terrain_type */
|
||||
static const int8 _max_height[4] = {
|
||||
6, ///< Very flat
|
||||
9, ///< Flat
|
||||
12, ///< Hilly
|
||||
15, ///< Mountainous
|
||||
};
|
||||
/**
|
||||
* Gets the maximum allowed height while generating a map based on
|
||||
* mapsize, terraintype, and the maximum height level.
|
||||
* @return The maximum height for the map generation.
|
||||
*/
|
||||
static height_t TGPGetMaxHeight()
|
||||
{
|
||||
/**
|
||||
* Desired maximum height - indexed by:
|
||||
* - _settings_game.difficulty.terrain_type
|
||||
* - min(MapLogX(), MapLogY()) - MIN_MAP_SIZE_BITS
|
||||
*
|
||||
* It is indexed by map size as well as terrain type since the map size limits the height of
|
||||
* a usable mountain. For example, on a 64x64 map a 24 high single peak mountain (as if you
|
||||
* raised land 24 times in the center of the map) will leave only a ring of about 10 tiles
|
||||
* around the mountain to build on. On a 4096x4096 map, it won't cover any major part of the map.
|
||||
*/
|
||||
static const int max_height[5][MAX_MAP_SIZE_BITS - MIN_MAP_SIZE_BITS + 1] = {
|
||||
/* 64 128 256 512 1024 2048 4096 */
|
||||
{ 3, 3, 5, 5, 5, 5, 5 }, ///< Very flat
|
||||
{ 4, 4, 6, 10, 10, 10, 10 }, ///< Flat
|
||||
{ 6, 9, 15, 25, 31, 31, 31 }, ///< Hilly
|
||||
{ 7, 12, 23, 42, 78, 85, 85 }, ///< Mountainous
|
||||
{ 12, 21, 36, 73, 146, 170, 170 } ///< Alpinist
|
||||
};
|
||||
|
||||
int max_height_from_table = max_height[_settings_game.difficulty.terrain_type][min(MapLogX(), MapLogY()) - MIN_MAP_SIZE_BITS];
|
||||
return I2H(min(max_height_from_table, _settings_game.construction.max_heightlevel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amplitude associated with the currently selected
|
||||
* smoothness and maximum height level.
|
||||
* @param frequency The frequency to get the amplitudes for
|
||||
* @return The amplitudes to apply to the map.
|
||||
*/
|
||||
static amplitude_t GetAmplitude(int frequency)
|
||||
{
|
||||
/* Base noise amplitudes (multiplied by 1024) and indexed by "smoothness setting" and log2(frequency). */
|
||||
static const amplitude_t amplitudes[][7] = {
|
||||
/* lowest frequency ...... highest (every corner) */
|
||||
{16000, 5600, 1968, 688, 240, 16, 16}, ///< Very smooth
|
||||
{24000, 12800, 6400, 2700, 1024, 128, 16}, ///< Smooth
|
||||
{32000, 19200, 12800, 8000, 3200, 256, 64}, ///< Rough
|
||||
{48000, 24000, 19200, 16000, 8000, 512, 320}, ///< Very rough
|
||||
};
|
||||
/*
|
||||
* Extrapolation factors for ranges before the table.
|
||||
* The extrapolation is needed to account for the higher map heights. They need larger
|
||||
* areas with a particular gradient so that we are able to create maps without too
|
||||
* many steep slopes up to the wanted height level. It's definitely not perfect since
|
||||
* it will bring larger rectangles with similar slopes which makes the rectangular
|
||||
* behaviour of TGP more noticable. However, these height differentiations cannot
|
||||
* happen over much smaller areas; we basically double the "range" to give a similar
|
||||
* slope for every doubling of map height.
|
||||
*/
|
||||
static const double extrapolation_factors[] = { 3.3, 2.8, 2.3, 1.8 };
|
||||
|
||||
int smoothness = _settings_game.game_creation.tgen_smoothness;
|
||||
|
||||
/* Get the table index, and return that value if possible. */
|
||||
int index = frequency - MAX_TGP_FREQUENCIES + lengthof(amplitudes[smoothness]);
|
||||
amplitude_t amplitude = amplitudes[smoothness][max(0, index)];
|
||||
if (index >= 0) return amplitude;
|
||||
|
||||
/* We need to extrapolate the amplitude. */
|
||||
double extrapolation_factor = extrapolation_factors[smoothness];
|
||||
int height_range = I2H(16);
|
||||
do {
|
||||
amplitude = (amplitude_t)(extrapolation_factor * (double)amplitude);
|
||||
height_range <<= 1;
|
||||
index++;
|
||||
} while (index < 0);
|
||||
|
||||
return Clamp((TGPGetMaxHeight() - height_range) / height_range, 0, 1) * amplitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a X/Y set are within the map.
|
||||
@@ -236,9 +293,9 @@ static const int8 _max_height[4] = {
|
||||
* @param y coordinate y
|
||||
* @return true if within the map
|
||||
*/
|
||||
static inline bool IsValidXY(uint x, uint y)
|
||||
static inline bool IsValidXY(int x, int y)
|
||||
{
|
||||
return ((int)x) >= 0 && x < _height_map.size_x && ((int)y) >= 0 && y < _height_map.size_y;
|
||||
return x >= 0 && x < _height_map.size_x && y >= 0 && y < _height_map.size_y;
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +324,6 @@ static inline bool AllocHeightMap()
|
||||
/** Free height map */
|
||||
static inline void FreeHeightMap()
|
||||
{
|
||||
if (_height_map.h == NULL) return;
|
||||
free(_height_map.h);
|
||||
_height_map.h = NULL;
|
||||
}
|
||||
@@ -279,117 +335,74 @@ static inline void FreeHeightMap()
|
||||
*/
|
||||
static inline height_t RandomHeight(amplitude_t rMax)
|
||||
{
|
||||
amplitude_t ra = (Random() << 16) | (Random() & 0x0000FFFF);
|
||||
height_t rh;
|
||||
/* Spread height into range -rMax..+rMax */
|
||||
rh = A2H(ra % (2 * rMax + 1) - rMax);
|
||||
return rh;
|
||||
return A2H(RandomRange(2 * rMax + 1) - rMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* One interpolation and noise round
|
||||
* Base Perlin noise generator - fills height map with raw Perlin noise.
|
||||
*
|
||||
* The heights on the map are generated in an iterative process.
|
||||
* We start off with a frequency of 1 (log_frequency == 0), and generate heights only for corners on the most coarsest mesh
|
||||
* (i.e. only for x/y coordinates which are multiples of the minimum edge length).
|
||||
*
|
||||
* After this initial step the frequency is doubled (log_frequency incremented) each iteration to generate corners on the next finer mesh.
|
||||
* The heights of the newly added corners are first set by interpolating the heights from the previous iteration.
|
||||
* Finally noise with the given amplitude is applied to all corners of the new mesh.
|
||||
*
|
||||
* Generation terminates, when the frequency has reached the map size. I.e. the mesh is as fine as the map, and every corner height
|
||||
* has been set.
|
||||
*
|
||||
* @param log_frequency frequency (logarithmic) to apply noise for
|
||||
* @param amplitude Amplitude for the noise
|
||||
* @return false if we are finished (reached the minimal step size / highest frequency)
|
||||
* This runs several iterations with increasing precision; the last iteration looks at areas
|
||||
* of 1 by 1 tiles, the second to last at 2 by 2 tiles and the initial 2**MAX_TGP_FREQUENCIES
|
||||
* by 2**MAX_TGP_FREQUENCIES tiles.
|
||||
*/
|
||||
static bool ApplyNoise(uint log_frequency, amplitude_t amplitude)
|
||||
static void HeightMapGenerate()
|
||||
{
|
||||
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);
|
||||
|
||||
/* Are we finished? */
|
||||
if (step == 0) return false;
|
||||
int start = max(MAX_TGP_FREQUENCIES - (int)min(MapLogX(), MapLogY()), 0);
|
||||
bool first = true;
|
||||
|
||||
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) {
|
||||
height_t height = (amplitude > 0) ? RandomHeight(amplitude) : 0;
|
||||
_height_map.height(x, y) = height;
|
||||
for (int frequency = start; frequency < MAX_TGP_FREQUENCIES; frequency++) {
|
||||
const amplitude_t amplitude = GetAmplitude(frequency);
|
||||
|
||||
/* Ignore zero amplitudes; it means our map isn't height enough for this
|
||||
* amplitude, so ignore it and continue with the next set of amplitude. */
|
||||
if (amplitude == 0) continue;
|
||||
|
||||
const int step = 1 << (MAX_TGP_FREQUENCIES - frequency - 1);
|
||||
|
||||
if (first) {
|
||||
/* This is first round, we need to establish base heights with step = size_min */
|
||||
for (int y = 0; y <= _height_map.size_y; y += step) {
|
||||
for (int x = 0; x <= _height_map.size_x; x += step) {
|
||||
height_t height = (amplitude > 0) ? RandomHeight(amplitude) : 0;
|
||||
_height_map.height(x, y) = height;
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* It is regular iteration round.
|
||||
* Interpolate height values at odd x, even y tiles */
|
||||
for (int y = 0; y <= _height_map.size_y; y += 2 * step) {
|
||||
for (int x = 0; x <= _height_map.size_x - 2 * step; 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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
height_t h01 = (h00 + h02) / 2;
|
||||
_height_map.height(x + 1 * step, y) = h01;
|
||||
/* Interpolate height values at odd y tiles */
|
||||
for (int y = 0; y <= _height_map.size_y - 2 * step; y += 2 * step) {
|
||||
for (int 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add noise for next higher frequency (smaller steps) */
|
||||
for (int y = 0; y <= _height_map.size_y; y += step) {
|
||||
for (int x = 0; x <= _height_map.size_x; x += step) {
|
||||
_height_map.height(x, y) += RandomHeight(amplitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
height_t h10 = (h00 + h20) / 2;
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
return (step > 1);
|
||||
}
|
||||
|
||||
/** Base Perlin noise generator - fills height map with raw Perlin noise */
|
||||
static void HeightMapGenerate()
|
||||
{
|
||||
uint size_min = min(_height_map.size_x, _height_map.size_y);
|
||||
uint iteration_round = 0;
|
||||
amplitude_t amplitude;
|
||||
bool continue_iteration;
|
||||
int log_size_min, log_frequency_min;
|
||||
int log_frequency;
|
||||
|
||||
/* Find first power of two that fits, so that later log_frequency == TGP_FREQUENCY_MAX in the last iteration */
|
||||
for (log_size_min = TGP_FREQUENCY_MAX; (1U << log_size_min) < size_min; log_size_min++) { }
|
||||
log_frequency_min = log_size_min - TGP_FREQUENCY_MAX;
|
||||
|
||||
/* Zero must be part of the iteration, else initialization will fail. */
|
||||
assert(log_frequency_min >= 0);
|
||||
|
||||
/* Keep increasing the frequency until we reach the step size equal to one tile */
|
||||
do {
|
||||
log_frequency = iteration_round - log_frequency_min;
|
||||
if (log_frequency >= 0) {
|
||||
/* Apply noise for the next frequency */
|
||||
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 */
|
||||
amplitude = 0;
|
||||
}
|
||||
continue_iteration = ApplyNoise(iteration_round, amplitude);
|
||||
iteration_round++;
|
||||
} while (continue_iteration);
|
||||
assert(log_frequency == TGP_FREQUENCY_MAX);
|
||||
}
|
||||
|
||||
/** Returns min, max and average height from height map */
|
||||
@@ -507,7 +520,8 @@ static void HeightMapSineTransform(height_t h_min, height_t h_max)
|
||||
}
|
||||
}
|
||||
|
||||
/* Additional map variety is provided by applying different curve maps
|
||||
/**
|
||||
* Additional map variety is provided by applying different curve maps
|
||||
* to different parts of the map. A randomized low resolution grid contains
|
||||
* which curve map to use on each part of the make. This filtered non-linearly
|
||||
* to smooth out transitions between curves, so each tile could have between
|
||||
@@ -520,62 +534,55 @@ static void HeightMapSineTransform(height_t h_min, height_t h_max)
|
||||
* The level parameter dictates the resolution of the grid. A low resolution
|
||||
* grid will result in larger continuous areas of a land style, a higher
|
||||
* resolution grid splits the style into smaller areas.
|
||||
*
|
||||
* At this point in map generation, all height data has been normalized to 0
|
||||
* to 239.
|
||||
* @param level Rough indication of the size of the grid sections to style. Small level means large grid sections.
|
||||
*/
|
||||
struct control_point_t {
|
||||
height_t x;
|
||||
height_t y;
|
||||
};
|
||||
|
||||
struct control_point_list_t {
|
||||
size_t length;
|
||||
const control_point_t *list;
|
||||
};
|
||||
|
||||
static const control_point_t _curve_map_1[] = {
|
||||
{ 0, 0 }, { 48, 24 }, { 192, 32 }, { 240, 96 }
|
||||
};
|
||||
|
||||
static const control_point_t _curve_map_2[] = {
|
||||
{ 0, 0 }, { 16, 24 }, { 128, 32 }, { 192, 64 }, { 240, 144 }
|
||||
};
|
||||
|
||||
static const control_point_t _curve_map_3[] = {
|
||||
{ 0, 0 }, { 16, 24 }, { 128, 64 }, { 192, 144 }, { 240, 192 }
|
||||
};
|
||||
|
||||
static const control_point_t _curve_map_4[] = {
|
||||
{ 0, 0 }, { 16, 24 }, { 96, 72 }, { 160, 192 }, { 220, 239 }, { 240, 239 }
|
||||
};
|
||||
|
||||
static const control_point_list_t _curve_maps[] = {
|
||||
{ lengthof(_curve_map_1), _curve_map_1 },
|
||||
{ lengthof(_curve_map_2), _curve_map_2 },
|
||||
{ lengthof(_curve_map_3), _curve_map_3 },
|
||||
{ lengthof(_curve_map_4), _curve_map_4 },
|
||||
};
|
||||
|
||||
static void HeightMapCurves(uint level)
|
||||
{
|
||||
height_t ht[lengthof(_curve_maps)];
|
||||
int mh = TGPGetMaxHeight();
|
||||
|
||||
/** Basically scale height X to height Y. Everything in between is interpolated. */
|
||||
struct control_point_t {
|
||||
height_t x; ///< The height to scale from.
|
||||
height_t y; ///< The height to scale to.
|
||||
};
|
||||
/* Scaled curve maps; value is in height_ts. */
|
||||
#define F(fraction) ((height_t)(fraction * mh))
|
||||
const control_point_t curve_map_1[] = { { F(0.0), F(0.0) }, { F(0.6 / 3), F(0.1) }, { F(2.4 / 3), F(0.4 / 3) }, { F(1.0), F(0.4) } };
|
||||
const control_point_t curve_map_2[] = { { F(0.0), F(0.0) }, { F(0.2 / 3), F(0.1) }, { F(1.6 / 3), F(0.4 / 3) }, { F(2.4 / 3), F(0.8 / 3) }, { F(1.0), F(0.6) } };
|
||||
const control_point_t curve_map_3[] = { { F(0.0), F(0.0) }, { F(0.2 / 3), F(0.1) }, { F(1.6 / 3), F(0.8 / 3) }, { F(2.4 / 3), F(1.8 / 3) }, { F(1.0), F(0.8) } };
|
||||
const control_point_t curve_map_4[] = { { F(0.0), F(0.0) }, { F(0.2 / 3), F(0.1) }, { F(1.2 / 3), F(0.9 / 3) }, { F(2.0 / 3), F(2.4 / 3) } , { F(5.5 / 6), F(0.99) }, { F(1.0), F(0.99) } };
|
||||
#undef F
|
||||
|
||||
/** Helper structure to index the different curve maps. */
|
||||
struct control_point_list_t {
|
||||
size_t length; ///< The length of the curve map.
|
||||
const control_point_t *list; ///< The actual curve map.
|
||||
};
|
||||
const control_point_list_t curve_maps[] = {
|
||||
{ lengthof(curve_map_1), curve_map_1 },
|
||||
{ lengthof(curve_map_2), curve_map_2 },
|
||||
{ lengthof(curve_map_3), curve_map_3 },
|
||||
{ lengthof(curve_map_4), curve_map_4 },
|
||||
};
|
||||
|
||||
height_t ht[lengthof(curve_maps)];
|
||||
MemSetT(ht, 0, lengthof(ht));
|
||||
|
||||
/* Set up a grid to choose curve maps based on location */
|
||||
uint sx = Clamp(1 << level, 2, 32);
|
||||
uint sy = Clamp(1 << level, 2, 32);
|
||||
/* Set up a grid to choose curve maps based on location; attempt to get a somewhat square grid */
|
||||
float factor = sqrt((float)_height_map.size_x / (float)_height_map.size_y);
|
||||
uint sx = Clamp((int)(((1 << level) * factor) + 0.5), 1, 128);
|
||||
uint sy = Clamp((int)(((1 << level) / factor) + 0.5), 1, 128);
|
||||
byte *c = AllocaM(byte, sx * sy);
|
||||
|
||||
for (uint i = 0; i < sx * sy; i++) {
|
||||
c[i] = Random() % lengthof(_curve_maps);
|
||||
c[i] = Random() % lengthof(curve_maps);
|
||||
}
|
||||
|
||||
/* Apply curves */
|
||||
for (uint x = 0; x < _height_map.size_x; x++) {
|
||||
for (int x = 0; x < _height_map.size_x; x++) {
|
||||
|
||||
/* Get our X grid positions and bi-linear ratio */
|
||||
float fx = (float)(sx * x) / _height_map.size_x + 0.5f;
|
||||
float fx = (float)(sx * x) / _height_map.size_x + 1.0f;
|
||||
uint x1 = (uint)fx;
|
||||
uint x2 = x1;
|
||||
float xr = 2.0f * (fx - x1) - 1.0f;
|
||||
@@ -589,10 +596,10 @@ static void HeightMapCurves(uint level)
|
||||
if (x2 >= sx) x2--;
|
||||
}
|
||||
|
||||
for (uint y = 0; y < _height_map.size_y; y++) {
|
||||
for (int y = 0; y < _height_map.size_y; y++) {
|
||||
|
||||
/* Get our Y grid position and bi-linear ratio */
|
||||
float fy = (float)(sy * y) / _height_map.size_y + 0.5f;
|
||||
float fy = (float)(sy * y) / _height_map.size_y + 1.0f;
|
||||
uint y1 = (uint)fy;
|
||||
uint y2 = y1;
|
||||
float yr = 2.0f * (fy - y1) - 1.0f;
|
||||
@@ -622,11 +629,11 @@ static void HeightMapCurves(uint level)
|
||||
height_t *h = &_height_map.height(x, y);
|
||||
|
||||
/* Apply all curve maps that are used on this tile. */
|
||||
for (uint t = 0; t < lengthof(_curve_maps); t++) {
|
||||
for (uint t = 0; t < lengthof(curve_maps); t++) {
|
||||
if (!HasBit(corner_bits, t)) continue;
|
||||
|
||||
const control_point_t *cm = _curve_maps[t].list;
|
||||
for (uint i = 0; i < _curve_maps[t].length - 1; i++) {
|
||||
const control_point_t *cm = curve_maps[t].list;
|
||||
for (uint i = 0; i < curve_maps[t].length - 1; i++) {
|
||||
const control_point_t &p1 = cm[i];
|
||||
const control_point_t &p2 = cm[i + 1];
|
||||
|
||||
@@ -671,7 +678,7 @@ static void HeightMapAdjustWaterLevel(amplitude_t water_percent, height_t h_max_
|
||||
* Transform the height map into new (normalized) height map:
|
||||
* values from range: h_min..h_water_level will become negative so it will be clamped to 0
|
||||
* values from range: h_water_level..h_max are transformed into 0..h_max_new
|
||||
* where h_max_new is 4, 8, 12 or 16 depending on terrain type (very flat, flat, hilly, mountains)
|
||||
* where h_max_new is depending on terrain type and map size.
|
||||
*/
|
||||
FOR_ALL_TILES_IN_HEIGHT(h) {
|
||||
/* Transform height from range h_water_level..h_max into 0..h_max_new range */
|
||||
@@ -710,7 +717,7 @@ static void HeightMapCoastLines(uint8 water_borders)
|
||||
{
|
||||
int smallest_size = min(_settings_game.game_creation.map_x, _settings_game.game_creation.map_y);
|
||||
const int margin = 4;
|
||||
uint y, x;
|
||||
int y, x;
|
||||
double max_x;
|
||||
double max_y;
|
||||
|
||||
@@ -771,7 +778,7 @@ static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int
|
||||
int ed; // coast distance from edge
|
||||
int depth;
|
||||
|
||||
height_t h_prev = 16;
|
||||
height_t h_prev = I2H(1);
|
||||
height_t h;
|
||||
|
||||
assert(IsValidXY(org_x, org_y));
|
||||
@@ -779,7 +786,7 @@ static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int
|
||||
/* 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;
|
||||
if (_height_map.height(x, y) >= I2H(1)) 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;
|
||||
@@ -801,7 +808,7 @@ static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int
|
||||
/** Smooth coasts by modulating height of tiles close to map edges with cosine of distance from edge */
|
||||
static void HeightMapSmoothCoasts(uint8 water_borders)
|
||||
{
|
||||
uint x, y;
|
||||
int 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++) {
|
||||
if (HasBit(water_borders, BORDER_NW)) HeightMapSmoothCoastInDirection(x, 0, 0, 1);
|
||||
@@ -823,16 +830,15 @@ static void HeightMapSmoothCoasts(uint8 water_borders)
|
||||
*/
|
||||
static void HeightMapSmoothSlopes(height_t dh_max)
|
||||
{
|
||||
int x, y;
|
||||
for (y = 0; y <= (int)_height_map.size_y; y++) {
|
||||
for (x = 0; x <= (int)_height_map.size_x; x++) {
|
||||
for (int y = 0; y <= (int)_height_map.size_y; y++) {
|
||||
for (int x = 0; x <= (int)_height_map.size_x; x++) {
|
||||
height_t h_max = min(_height_map.height(x > 0 ? x - 1 : x, y), _height_map.height(x, y > 0 ? y - 1 : y)) + dh_max;
|
||||
if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max;
|
||||
}
|
||||
}
|
||||
for (y = _height_map.size_y; y >= 0; y--) {
|
||||
for (x = _height_map.size_x; x >= 0; x--) {
|
||||
height_t h_max = min(_height_map.height((uint)x < _height_map.size_x ? x + 1 : x, y), _height_map.height(x, (uint)y < _height_map.size_y ? y + 1 : y)) + dh_max;
|
||||
for (int y = _height_map.size_y; y >= 0; y--) {
|
||||
for (int x = _height_map.size_x; x >= 0; x--) {
|
||||
height_t h_max = min(_height_map.height(x < _height_map.size_x ? x + 1 : x, y), _height_map.height(x, y < _height_map.size_y ? y + 1 : y)) + dh_max;
|
||||
if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max;
|
||||
}
|
||||
}
|
||||
@@ -849,7 +855,7 @@ static void HeightMapNormalize()
|
||||
{
|
||||
int sea_level_setting = _settings_game.difficulty.quantity_sea_lakes;
|
||||
const amplitude_t water_percent = sea_level_setting != (int)CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY ? _water_percent[sea_level_setting] : _settings_game.game_creation.custom_sea_level * 1024 / 100;
|
||||
const height_t h_max_new = I2H(_max_height[_settings_game.difficulty.terrain_type]);
|
||||
const height_t h_max_new = TGPGetMaxHeight();
|
||||
const height_t roughness = 7 + 3 * _settings_game.game_creation.tgen_smoothness;
|
||||
|
||||
HeightMapAdjustWaterLevel(water_percent, h_max_new);
|
||||
@@ -932,9 +938,8 @@ static double interpolated_noise(const double x, const double y, const int prime
|
||||
static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime)
|
||||
{
|
||||
double total = 0.0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
const double frequency = (double)(1 << i);
|
||||
const double amplitude = pow(p, (double)i);
|
||||
|
||||
@@ -965,8 +970,6 @@ static void TgenSetTileHeight(TileIndex tile, int height)
|
||||
*/
|
||||
void GenerateTerrainPerlin()
|
||||
{
|
||||
uint x, y;
|
||||
|
||||
if (!AllocHeightMap()) return;
|
||||
GenerateWorldSetAbortCallback(FreeHeightMap);
|
||||
|
||||
@@ -980,17 +983,16 @@ void GenerateTerrainPerlin()
|
||||
|
||||
/* First make sure the tiles at the north border are void tiles if needed. */
|
||||
if (_settings_game.construction.freeform_edges) {
|
||||
for (y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y);
|
||||
for (x = 0; x < _height_map.size_x; x++) MakeVoid(x);
|
||||
for (int y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y);
|
||||
for (int x = 0; x < _height_map.size_x; x++) MakeVoid(x);
|
||||
}
|
||||
|
||||
int max_height = H2I(TGPGetMaxHeight());
|
||||
|
||||
/* Transfer height map into OTTD map */
|
||||
for (y = 0; y < _height_map.size_y; y++) {
|
||||
for (x = 0; x < _height_map.size_x; x++) {
|
||||
int height = H2I(_height_map.height(x, y));
|
||||
if (height < 0) height = 0;
|
||||
if (height > 15) height = 15;
|
||||
TgenSetTileHeight(TileXY(x, y), height);
|
||||
for (int y = 0; y < _height_map.size_y; y++) {
|
||||
for (int x = 0; x < _height_map.size_x; x++) {
|
||||
TgenSetTileHeight(TileXY(x, y), Clamp(H2I(_height_map.height(x, y)), 0, max_height));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user