Пример #1
0
/**
 * The main new land generator using Perlin noise. Desert landscape is handled
 * different to all others to give a desert valley between two high mountains.
 * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic
 * areas won't be high enough, and there will be very little tropic on the map.
 * Thus Tropic works best on Hilly or Mountainous.
 */
void GenerateTerrainPerlin()
{
	if (!AllocHeightMap()) return;
	GenerateWorldSetAbortCallback(FreeHeightMap);

	HeightMapGenerate();

	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);

	HeightMapNormalize();

	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);

	/* First make sure the tiles at the north border are void tiles if needed. */
	if (_settings_game.construction.freeform_edges) {
		for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
		for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
	}

	int max_height = H2I(TGPGetMaxHeight());

	/* Transfer height map into OTTD map */
	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));
		}
	}

	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);

	FreeHeightMap();
	GenerateWorldSetAbortCallback(NULL);
}
Пример #2
0
/**
 * Height map terraform post processing:
 *  - water level adjusting
 *  - coast Smoothing
 *  - slope Smoothing
 *  - height histogram redistribution by sine wave transform
 */
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 = TGPGetMaxHeight();
	const height_t roughness = 7 + 3 * _settings_game.game_creation.tgen_smoothness;

	HeightMapAdjustWaterLevel(water_percent, h_max_new);

	byte water_borders = _settings_game.construction.freeform_edges ? _settings_game.game_creation.water_borders : 0xF;
	if (water_borders == BORDERS_RANDOM) water_borders = GB(Random(), 0, 4);

	HeightMapCoastLines(water_borders);
	HeightMapSmoothSlopes(roughness);

	HeightMapSmoothCoasts(water_borders);
	HeightMapSmoothSlopes(roughness);

	HeightMapSineTransform(I2H(1), h_max_new);

	if (_settings_game.game_creation.variety > 0) {
		HeightMapCurves(_settings_game.game_creation.variety);
	}

	HeightMapSmoothSlopes(I2H(1));
}
Пример #3
0
/**
 * 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 noticeable. 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;
}
Пример #4
0
/**
 * 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
 * 100% of one map applied or 25% of four maps.
 *
 * The curve maps define different land styles, i.e. lakes, low-lands, hills
 * and mountain ranges, although these are dependent on the landscape style
 * chosen as well.
 *
 * 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.
 * @param level Rough indication of the size of the grid sections to style. Small level means large grid sections.
 */
static void HeightMapCurves(uint level)
{
	height_t mh = TGPGetMaxHeight() - I2H(1); // height levels above sea level only

	/** 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.8), F(0.13) },                       { F(1.0), F(0.4)  } };
	const control_point_t curve_map_2[] = { { F(0.0), F(0.0) }, { F(0.53), F(0.13) }, { F(0.8), F(0.27) },                       { F(1.0), F(0.6)  } };
	const control_point_t curve_map_3[] = { { F(0.0), F(0.0) }, { F(0.53), F(0.27) }, { F(0.8), F(0.57) },                       { F(1.0), F(0.8)  } };
	const control_point_t curve_map_4[] = { { F(0.0), F(0.0) }, { F(0.4),  F(0.3)  }, { F(0.7), F(0.8)  }, { F(0.92), 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; 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);
	}

	/* Apply curves */
	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 + 1.0f;
		uint x1 = (uint)fx;
		uint x2 = x1;
		float xr = 2.0f * (fx - x1) - 1.0f;
		xr = sin(xr * M_PI_2);
		xr = sin(xr * M_PI_2);
		xr = 0.5f * (xr + 1.0f);
		float xri = 1.0f - xr;

		if (x1 > 0) {
			x1--;
			if (x2 >= sx) x2--;
		}

		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 + 1.0f;
			uint y1 = (uint)fy;
			uint y2 = y1;
			float yr = 2.0f * (fy - y1) - 1.0f;
			yr = sin(yr * M_PI_2);
			yr = sin(yr * M_PI_2);
			yr = 0.5f * (yr + 1.0f);
			float yri = 1.0f - yr;

			if (y1 > 0) {
				y1--;
				if (y2 >= sy) y2--;
			}

			uint corner_a = c[x1 + sx * y1];
			uint corner_b = c[x1 + sx * y2];
			uint corner_c = c[x2 + sx * y1];
			uint corner_d = c[x2 + sx * y2];

			/* Bitmask of which curve maps are chosen, so that we do not bother
			 * calculating a curve which won't be used. */
			uint corner_bits = 0;
			corner_bits |= 1 << corner_a;
			corner_bits |= 1 << corner_b;
			corner_bits |= 1 << corner_c;
			corner_bits |= 1 << corner_d;

			height_t *h = &_height_map.height(x, y);

			/* Do not touch sea level */
			if (*h < I2H(1)) continue;

			/* Only scale above sea level */
			*h -= I2H(1);

			/* Apply all curve maps that are used on this tile. */
			for (uint t = 0; t < lengthof(curve_maps); t++) {
				if (!HasBit(corner_bits, t)) continue;

				bool found = false;
				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];

					if (*h >= p1.x && *h < p2.x) {
						ht[t] = p1.y + (*h - p1.x) * (p2.y - p1.y) / (p2.x - p1.x);
						found = true;
						break;
					}
				}
				assert(found);
			}

			/* Apply interpolation of curve map results. */
			*h = (height_t)((ht[corner_a] * yri + ht[corner_b] * yr) * xri + (ht[corner_c] * yri + ht[corner_d] * yr) * xr);

			/* Readd sea level */
			*h += I2H(1);
		}
	}
}
Пример #5
0
/**
 * 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).
	 * Used for maps that have their smallest side smaller than 512. */
	static const amplitude_t amplitudes_small[][10] = {
		/* lowest frequency ...... highest (every corner) */
		{60000, 2273, 4142, 2253, 421, 213, 137, 177, 37,  16}, ///< Very smooth
		{50000, 2273, 4142, 2253, 421, 213, 137, 177, 37,  61}, ///< Smooth
		{40000, 2273, 4142, 2253, 421, 213, 137, 177, 37,  91}, ///< Rough
		{30000, 2273, 4142, 2253, 421, 213, 137, 177, 37, 161}, ///< Very rough
	};

	/* Base noise amplitudes (multiplied by 1024) and indexed by "smoothness setting" and log2(frequency).
	 * Used for maps that have their smallest side equal to 512. */
	static const amplitude_t amplitudes_middle[][10] = {
		{55000, 2273, 5142, 253, 2421, 213, 137, 177, 37,  16}, ///< Very smooth
		{45000, 2273, 5142, 253, 2421, 213, 137, 177, 37,  61}, ///< Smooth
		{35000, 2273, 5142, 253, 2421, 213, 137, 177, 37,  91}, ///< Rough
		{25000, 2273, 5142, 253, 2421, 213, 137, 177, 37, 161}, ///< Very rough
	};

	/* Base noise amplitudes (multiplied by 1024) and indexed by "smoothness setting" and log2(frequency).
	 * Used for maps that have their smallest side bigger than 512. */
	static const amplitude_t amplitudes_large[][10] = {
		/* lowest frequency ...... highest (every corner) */
		{55000, 2273, 5142, 253, 421, 2213, 137, 177, 37,  16}, ///< Very smooth
		{45000, 2273, 5142, 253, 421, 2213, 137, 177, 37,  61}, ///< Smooth
		{35000, 2273, 5142, 253, 421, 2213, 137, 177, 37,  91}, ///< Rough
		{25000, 2273, 5142, 253, 421, 2213, 137, 177, 37, 161}, ///< Very rough
	};

	/* Make sure arrays cover all smoothness settings. */
	assert_compile(lengthof(amplitudes_small)  == TGEN_SMOOTHNESS_END);
	assert_compile(lengthof(amplitudes_middle) == TGEN_SMOOTHNESS_END);
	assert_compile(lengthof(amplitudes_large)  == TGEN_SMOOTHNESS_END);

	/* 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;
	int smallest_size = min(_settings_game.game_creation.map_x, _settings_game.game_creation.map_y);

	int index;
	amplitude_t amplitude;
	if (smallest_size < 9) { // Smallest map side is less than 2^9 == 512.
		index = frequency - MAX_TGP_FREQUENCIES + lengthof(amplitudes_small[0]);
		amplitude = amplitudes_small[smoothness][max(0, index)];
	} else if (smallest_size == 9) {
		index = frequency - MAX_TGP_FREQUENCIES + lengthof(amplitudes_middle[0]);
		amplitude = amplitudes_middle[smoothness][max(0, index)];
	} else {
		index = frequency - MAX_TGP_FREQUENCIES + lengthof(amplitudes_large[0]);
		amplitude = amplitudes_large[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;
}