/** * Base Perlin noise generator - fills height map with raw Perlin noise. * * 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 void HeightMapGenerate() { /* Trying to apply noise to uninitialized height map */ assert(_height_map.h != NULL); int start = max(MAX_TGP_FREQUENCIES - (int)min(MapLogX(), MapLogY()), 0); bool first = true; 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; } } /* 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); } } } }
/** * One interpolation and noise round * * 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 coarsly 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) */ static bool ApplyNoise(uint log_frequency, amplitude_t amplitude) { 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; 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; } } 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 (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); }