172 uint dim_x; //< height map size_x MapSizeX() + 1 |
172 uint dim_x; //< height map size_x MapSizeX() + 1 |
173 uint total_size; //< height map total size |
173 uint total_size; //< height map total size |
174 uint size_x; //< MapSizeX() |
174 uint size_x; //< MapSizeX() |
175 uint size_y; //< MapSizeY() |
175 uint size_y; //< MapSizeY() |
176 |
176 |
|
177 /** |
|
178 * Height map accessor |
|
179 * @param x X position |
|
180 * @param y Y position |
|
181 * @return height as fixed point number |
|
182 */ |
177 inline height_t &height(uint x, uint y) { |
183 inline height_t &height(uint x, uint y) { |
178 return h[x + y * dim_x]; |
184 return h[x + y * dim_x]; |
179 } |
185 } |
180 }; |
186 }; |
181 |
187 |
232 { |
238 { |
233 return ((int)x) >= 0 && x < _height_map.size_x && ((int)y) >= 0 && y < _height_map.size_y; |
239 return ((int)x) >= 0 && x < _height_map.size_x && ((int)y) >= 0 && y < _height_map.size_y; |
234 } |
240 } |
235 |
241 |
236 |
242 |
237 /** Allocate array of (MapSizeX()+1)*(MapSizeY()+1) heights and init the _height_map structure members */ |
243 /** |
|
244 * Allocate array of (MapSizeX()+1)*(MapSizeY()+1) heights and init the _height_map structure members |
|
245 * @return true on success |
|
246 */ |
238 static inline bool AllocHeightMap() |
247 static inline bool AllocHeightMap() |
239 { |
248 { |
240 height_t *h; |
249 height_t *h; |
241 |
250 |
242 _height_map.size_x = MapSizeX(); |
251 _height_map.size_x = MapSizeX(); |
260 if (_height_map.h == NULL) return; |
269 if (_height_map.h == NULL) return; |
261 free(_height_map.h); |
270 free(_height_map.h); |
262 _height_map.h = NULL; |
271 _height_map.h = NULL; |
263 } |
272 } |
264 |
273 |
265 /** RandomHeight() generator */ |
274 /** |
|
275 * Generates new random height in given amplitude (generated numbers will range from - amplitude to + amplitude) |
|
276 * @param rMax Limit of result |
|
277 * @return generated height |
|
278 */ |
266 static inline height_t RandomHeight(amplitude_t rMax) |
279 static inline height_t RandomHeight(amplitude_t rMax) |
267 { |
280 { |
268 amplitude_t ra = (Random() << 16) | (Random() & 0x0000FFFF); |
281 amplitude_t ra = (Random() << 16) | (Random() & 0x0000FFFF); |
269 height_t rh; |
282 height_t rh; |
270 /* Spread height into range -rMax..+rMax */ |
283 /* Spread height into range -rMax..+rMax */ |
271 rh = A2H(ra % (2 * rMax + 1) - rMax); |
284 rh = A2H(ra % (2 * rMax + 1) - rMax); |
272 return rh; |
285 return rh; |
273 } |
286 } |
274 |
287 |
275 /** One interpolation and noise round */ |
288 /** |
|
289 * One interpolation and noise round |
|
290 * |
|
291 * The heights on the map are generated in an iterative process. |
|
292 * We start off with a frequency of 1 (log_frequency == 0), and generate heights only for corners on the most coarsly mesh |
|
293 * (i.e. only for x/y coordinates which are multiples of the minimum edge length). |
|
294 * |
|
295 * After this initial step the frequency is doubled (log_frequency incremented) each iteration to generate corners on the next finer mesh. |
|
296 * The heights of the newly added corners are first set by interpolating the heights from the previous iteration. |
|
297 * Finally noise with the given amplitude is applied to all corners of the new mesh. |
|
298 * |
|
299 * Generation terminates, when the frequency has reached the map size. I.e. the mesh is as fine as the map, and every corner height |
|
300 * has been set. |
|
301 * |
|
302 * @param log_frequency frequency (logarithmic) to apply noise for |
|
303 * @param amplitude Amplitude for the noise |
|
304 * @return false if we are finished (reached the minimal step size / highest frequency) |
|
305 */ |
276 static bool ApplyNoise(uint log_frequency, amplitude_t amplitude) |
306 static bool ApplyNoise(uint log_frequency, amplitude_t amplitude) |
277 { |
307 { |
278 uint size_min = min(_height_map.size_x, _height_map.size_y); |
308 uint size_min = min(_height_map.size_x, _height_map.size_y); |
279 uint step = size_min >> log_frequency; |
309 uint step = size_min >> log_frequency; |
280 uint x, y; |
310 uint x, y; |
281 |
311 |
|
312 /* Trying to apply noise to uninitialized height map */ |
282 assert(_height_map.h != NULL); |
313 assert(_height_map.h != NULL); |
283 |
314 |
284 /* Are we finished? */ |
315 /* Are we finished? */ |
285 if (step == 0) return false; |
316 if (step == 0) return false; |
286 |
317 |
314 height_t h10 = (h00 + h20) / 2; |
345 height_t h10 = (h00 + h20) / 2; |
315 _height_map.height(x, y + 1 * step) = h10; |
346 _height_map.height(x, y + 1 * step) = h10; |
316 } |
347 } |
317 } |
348 } |
318 |
349 |
|
350 /* Add noise for next higher frequency (smaller steps) */ |
319 for (y = 0; y <= _height_map.size_y; y += step) { |
351 for (y = 0; y <= _height_map.size_y; y += step) { |
320 for (x = 0; x <= _height_map.size_x; x += step) { |
352 for (x = 0; x <= _height_map.size_x; x += step) { |
321 _height_map.height(x, y) += RandomHeight(amplitude); |
353 _height_map.height(x, y) += RandomHeight(amplitude); |
322 } |
354 } |
323 } |
355 } |
|
356 |
324 return (step > 1); |
357 return (step > 1); |
325 } |
358 } |
326 |
359 |
327 /** Base Perlin noise generator - fills height map with raw Perlin noise */ |
360 /** Base Perlin noise generator - fills height map with raw Perlin noise */ |
328 static void HeightMapGenerate() |
361 static void HeightMapGenerate() |
336 |
369 |
337 /* Find first power of two that fits */ |
370 /* Find first power of two that fits */ |
338 for (log_size_min = 6; (1U << log_size_min) < size_min; log_size_min++) { } |
371 for (log_size_min = 6; (1U << log_size_min) < size_min; log_size_min++) { } |
339 log_frequency_min = log_size_min - 6; |
372 log_frequency_min = log_size_min - 6; |
340 |
373 |
|
374 /* Keep increasing the frequency until we reach the step size equal to one tile */ |
341 do { |
375 do { |
342 log_frequency = iteration_round - log_frequency_min; |
376 log_frequency = iteration_round - log_frequency_min; |
343 if (log_frequency >= 0) { |
377 if (log_frequency >= 0) { |
|
378 /* Apply noise for the next frequency */ |
344 amplitude = _amplitudes_by_smoothness_and_frequency[_settings_game.game_creation.tgen_smoothness][log_frequency]; |
379 amplitude = _amplitudes_by_smoothness_and_frequency[_settings_game.game_creation.tgen_smoothness][log_frequency]; |
345 } else { |
380 } else { |
|
381 /* Amplitude for the low frequencies on big maps is 0, i.e. initialise with zero height */ |
346 amplitude = 0; |
382 amplitude = 0; |
347 } |
383 } |
348 continue_iteration = ApplyNoise(iteration_round, amplitude); |
384 continue_iteration = ApplyNoise(iteration_round, amplitude); |
349 iteration_round++; |
385 iteration_round++; |
350 } while(continue_iteration); |
386 } while (continue_iteration); |
351 } |
387 } |
352 |
388 |
353 /** Returns min, max and average height from height map */ |
389 /** Returns min, max and average height from height map */ |
354 static void HeightMapGetMinMaxAvg(height_t *min_ptr, height_t *max_ptr, height_t *avg_ptr) |
390 static void HeightMapGetMinMaxAvg(height_t *min_ptr, height_t *max_ptr, height_t *avg_ptr) |
355 { |
391 { |
767 |
803 |
768 return total; |
804 return total; |
769 } |
805 } |
770 |
806 |
771 |
807 |
772 /** A small helper function */ |
808 /** A small helper function to initialize the terrain */ |
773 static void TgenSetTileHeight(TileIndex tile, int height) |
809 static void TgenSetTileHeight(TileIndex tile, int height) |
774 { |
810 { |
775 SetTileHeight(tile, height); |
811 SetTileHeight(tile, height); |
776 MakeClear(tile, CLEAR_GRASS, 3); |
812 MakeClear(tile, CLEAR_GRASS, 3); |
777 } |
813 } |