Esempio n. 1
0
/**
 * 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.
 * @note Values should never be lower than 3 since the minimum snowline height is 2.
 */
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,   3,   3,   4,   5,   7 }, ///< Very flat
		{   5,   7,   8,   9,  14,  19,  31 }, ///< Flat
		{   8,   9,  10,  15,  23,  37,  61 }, ///< Hilly
		{  10,  11,  17,  19,  49,  63,  73 }, ///< Mountainous
		{  12,  19,  25,  31,  67,  75,  87 }, ///< 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));
}
Esempio n. 2
0
/** Applies sine wave redistribution onto height map */
static void HeightMapSineTransform(height_t h_min, height_t h_max)
{
	height_t *h;

	FOR_ALL_TILES_IN_HEIGHT(h) {
		double fheight;

		if (*h < h_min) continue;

		/* Transform height into 0..1 space */
		fheight = (double)(*h - h_min) / (double)(h_max - h_min);
		/* Apply sine transform depending on landscape type */
		switch (_settings_game.game_creation.landscape) {
			case LT_TOYLAND:
			case LT_TEMPERATE:
				/* Move and scale 0..1 into -1..+1 */
				fheight = 2 * fheight - 1;
				/* Sine transform */
				fheight = sin(fheight * M_PI_2);
				/* Transform it back from -1..1 into 0..1 space */
				fheight = 0.5 * (fheight + 1);
				break;

			case LT_ARCTIC:
				{
					/* Arctic terrain needs special height distribution.
					 * Redistribute heights to have more tiles at highest (75%..100%) range */
					double sine_upper_limit = 0.75;
					double linear_compression = 2;
					if (fheight >= sine_upper_limit) {
						/* Over the limit we do linear compression up */
						fheight = 1.0 - (1.0 - fheight) / linear_compression;
					} else {
						double m = 1.0 - (1.0 - sine_upper_limit) / linear_compression;
						/* Get 0..sine_upper_limit into -1..1 */
						fheight = 2.0 * fheight / sine_upper_limit - 1.0;
						/* Sine wave transform */
						fheight = sin(fheight * M_PI_2);
						/* Get -1..1 back to 0..(1 - (1 - sine_upper_limit) / linear_compression) == 0.0..m */
						fheight = 0.5 * (fheight + 1.0) * m;
					}
				}
				break;

			case LT_TROPIC:
				{
					/* Desert terrain needs special height distribution.
					 * Half of tiles should be at lowest (0..25%) heights */
					double sine_lower_limit = 0.5;
					double linear_compression = 2;
					if (fheight <= sine_lower_limit) {
						/* Under the limit we do linear compression down */
						fheight = fheight / linear_compression;
					} else {
						double m = sine_lower_limit / linear_compression;
						/* Get sine_lower_limit..1 into -1..1 */
						fheight = 2.0 * ((fheight - sine_lower_limit) / (1.0 - sine_lower_limit)) - 1.0;
						/* Sine wave transform */
						fheight = sin(fheight * M_PI_2);
						/* Get -1..1 back to (sine_lower_limit / linear_compression)..1.0 */
						fheight = 0.5 * ((1.0 - m) * fheight + (1.0 + m));
					}
				}
				break;

			default:
				NOT_REACHED();
				break;
		}
		/* Transform it back into h_min..h_max space */
		*h = (height_t)(fheight * (h_max - h_min) + h_min);
		if (*h < 0) *h = I2H(0);
		if (*h >= h_max) *h = h_max - 1;
	}
}
Esempio n. 3
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);
		}
	}
}
Esempio n. 4
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;
}