diff --git a/src/openrct2/windows/mapgen.c b/src/openrct2/windows/mapgen.c index 59f0bf4d42..20611f003b 100644 --- a/src/openrct2/windows/mapgen.c +++ b/src/openrct2/windows/mapgen.c @@ -86,8 +86,8 @@ enum { WIDX_SIMPLEX_FLOOR_TEXTURE, WIDX_SIMPLEX_WALL_TEXTURE, - WIDX_HEIGHTMAP_SMOOTH = TAB_BEGIN, - WIDX_HEIGHTMAP_STRONG, + WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP = TAB_BEGIN, + WIDX_HEIGHTMAP_SMOOTH_TILES, WIDX_HEIGHTMAP_NORMALIZE, WIDX_HEIGHTMAP_LOW, WIDX_HEIGHTMAP_LOW_UP, @@ -201,10 +201,10 @@ static rct_widget HeightmapWidgets[] = { { WWT_DROPDOWN_BUTTON, 1, 104, 198, 52, 63, STR_MAPGEN_ACTION_GENERATE, STR_NONE }, // WIDX_GENERATE - { WWT_CHECKBOX, 1, 4, 103, 52, 63, STR_MAPGEN_SMOOTH_TILE, STR_NONE }, // WIDX_HEIGHTMAP_SMOOTH - { WWT_CHECKBOX, 1, 4, 103, 70, 81, STR_MAPGEN_SMOOTH_STRONG, STR_NONE }, // WIDX_HEIGHTMAP_STRONG + { WWT_CHECKBOX, 1, 4, 103, 52, 63, STR_MAPGEN_SMOOTH_HEIGHTMAP,STR_NONE }, // WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP + { WWT_CHECKBOX, 1, 4, 103, 70, 81, STR_MAPGEN_SMOOTH_TILE, STR_NONE }, // WIDX_HEIGHTMAP_SMOOTH_TILES - { WWT_CHECKBOX, 1, 4, 103, 88, 99, STR_MAPGEN_NORMALIZE, STR_NONE }, // WIDX_HEIGHTMAP_NORMALIZE + { WWT_CHECKBOX, 1, 4, 103, 88, 99, STR_MAPGEN_NORMALIZE, STR_NONE }, // WIDX_HEIGHTMAP_NORMALIZE { WWT_SPINNER, 1, 104, 198, 106, 117, STR_NONE, STR_NONE }, // WIDX_HEIGHTMAP_LOW { WWT_DROPDOWN_BUTTON, 1, 187, 197, 107, 111, STR_NUMERIC_UP, STR_NONE }, // WIDX_HEIGHTMAP_LOW_UP @@ -235,7 +235,7 @@ static uint64 PressedWidgets[] = { 0, 0, 0, - (1ULL << WIDX_HEIGHTMAP_SMOOTH) + (1ULL << WIDX_HEIGHTMAP_SMOOTH_TILES) }; #pragma endregion @@ -464,8 +464,8 @@ static uint32 PageEnabledWidgets[] = { (1ULL << WIDX_TAB_3) | (1ULL << WIDX_TAB_4) | (1ULL << WIDX_GENERATE) | - (1ULL << WIDX_HEIGHTMAP_SMOOTH) | - (1ULL << WIDX_HEIGHTMAP_STRONG) | + (1ULL << WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP) | + (1ULL << WIDX_HEIGHTMAP_SMOOTH_TILES) | (1ULL << WIDX_HEIGHTMAP_NORMALIZE) | (1ULL << WIDX_HEIGHTMAP_LOW) | (1ULL << WIDX_HEIGHTMAP_LOW_UP) | @@ -551,7 +551,7 @@ static sint32 _simplex_octaves = 4; static bool _heightmapNormalize = true; static sint32 _heightmapLow = 10; -static sint32 _heightmapHigh = 14; +static sint32 _heightmapHigh = 40; rct_window *window_mapgen_open() { @@ -1147,22 +1147,21 @@ static void window_mapgen_heightmap_mouseup(rct_window *w, sint32 widgetIndex) break; case WIDX_GENERATE: mapgenSettings.water_level = _waterLevel; - mapgenSettings.smooth = widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH); - mapgenSettings.strong_smooth = widget_is_pressed(w, WIDX_HEIGHTMAP_STRONG); + mapgenSettings.smooth = widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH_TILES); + mapgenSettings.smooth_height_map = widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP); mapgenSettings.normalize_height = _heightmapNormalize; mapgenSettings.simplex_low = _heightmapLow; mapgenSettings.simplex_high = _heightmapHigh; mapgen_generate_from_heightmap(&mapgenSettings); gfx_invalidate_screen(); break; - case WIDX_HEIGHTMAP_SMOOTH: - widget_set_checkbox_value(w, WIDX_HEIGHTMAP_SMOOTH, !widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH)); - widget_set_enabled(w, WIDX_HEIGHTMAP_STRONG, widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH)); - widget_invalidate(w, WIDX_HEIGHTMAP_SMOOTH); - widget_invalidate(w, WIDX_HEIGHTMAP_STRONG); + case WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP: + widget_set_checkbox_value(w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP, !widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP)); + widget_invalidate(w, WIDX_HEIGHTMAP_SMOOTH_HEIGHTMAP); break; - case WIDX_HEIGHTMAP_STRONG: - widget_set_checkbox_value(w, WIDX_HEIGHTMAP_STRONG, !widget_is_pressed(w, WIDX_HEIGHTMAP_STRONG)); + case WIDX_HEIGHTMAP_SMOOTH_TILES: + widget_set_checkbox_value(w, WIDX_HEIGHTMAP_SMOOTH_TILES, !widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH_TILES)); + widget_invalidate(w, WIDX_HEIGHTMAP_SMOOTH_TILES); break; case WIDX_HEIGHTMAP_NORMALIZE: _heightmapNormalize = !_heightmapNormalize; diff --git a/src/openrct2/world/mapgen.c b/src/openrct2/world/mapgen.c index f0f6383a9e..35b9292570 100644 --- a/src/openrct2/world/mapgen.c +++ b/src/openrct2/world/mapgen.c @@ -766,7 +766,61 @@ static void mapgen_simplex(mapgen_settings *settings) #pragma region Heightmap -#pragma optimize("", off) +/** + * Applies box Gaussian blur to the surface + */ +void mapgen_smooth_heightmap(SDL_Surface *surface) +{ + SDL_LockSurface(surface); + + // Apply box Gaussian blur + const uint32 width = surface->w; + const uint32 height = surface->h; + const uint32 numChannels = surface->format->BytesPerPixel; + const size_t pitch = surface->pitch; + + // Create buffer to store one channel + uint8 *dest = (uint8*)malloc(width * height); + uint8 *src = surface->pixels; + + // Calculate box Gaussian blur value to all pixels of the surface + for (uint32 y = 0; y < height; y++) + { + for (uint32 x = 0; x < width; x++) + { + uint32 sum = 0; + + // Loop over neightbour pixels, all of them have the same weight + for (sint8 offsetX = -1; offsetX <= 1; offsetX++) + { + for (sint8 offsetY = -1; offsetY <= 1; offsetY++) + { + // Clamp x and y so they stay within the image + // This assumes the height map is not tiled, and increases the weight of the edges + const sint32 readX = clamp(x + offsetX, 0, width - 1); + const sint32 readY = clamp(y + offsetY, 0, height - 1); + sum += src[readX * numChannels + readY * pitch]; + } + } + + // Take average + dest[x + y * width] = sum / 9; + } + } + + // Now apply the Gaussian blur to the real pixels + for (uint32 y = 0; y < height; y++) + { + for (uint32 x = 0; x < width; x++) + { + src[x * numChannels + y * pitch] = dest[x + y * width]; + } + } + + free(dest); + SDL_UnlockSurface(surface); +} + void mapgen_generate_from_heightmap(mapgen_settings *settings) { openrct2_assert(settings->simplex_high != settings->simplex_low, "Low and high setting cannot be the same"); @@ -778,15 +832,21 @@ void mapgen_generate_from_heightmap(mapgen_settings *settings) return; } - uint32 width = bitmap->w; - uint32 height = bitmap->h; - uint8 numChannels = bitmap->format->BytesPerPixel; + const uint32 width = bitmap->w; + const uint32 height = bitmap->h; + const uint8 numChannels = bitmap->format->BytesPerPixel; map_init(width + 2); // + 2 for the black tiles around the map uint8 maxValue = 255; uint8 minValue = 0; + if (settings->smooth_height_map) + { + // Smooth height map + mapgen_smooth_heightmap(bitmap); + } + SDL_LockSurface(bitmap); uint8 *src = (uint8*)bitmap->pixels; if (settings->normalize_height) @@ -846,33 +906,25 @@ void mapgen_generate_from_heightmap(mapgen_settings *settings) // Smooth map if (settings->smooth) { - if (settings->strong_smooth) + // Keep smoothing the entire map until no tiles are changed anymore + while (true) { - map_smooth(1, 1, width, height); - } - else - { - // Keep smoothing the entire map until no tiles are changed anymore - while (true) + sint32 numTilesChanged = 0; + for (uint32 y = 1; y <= height; y++) { - sint32 numTilesChanged = 0; - for (uint32 y = 1; y <= height; y++) + for (uint32 x = 1; x <= width; x++) { - for (uint32 x = 1; x <= width; x++) - { - numTilesChanged += tile_smooth(x, y); - } + numTilesChanged += tile_smooth(x, y); } - - if (numTilesChanged == 0) - break; } + + if (numTilesChanged == 0) + break; } } SDL_UnlockSurface(bitmap); SDL_FreeSurface(bitmap); } -#pragma optimize("", on) #pragma endregion diff --git a/src/openrct2/world/mapgen.h b/src/openrct2/world/mapgen.h index 5dd71a0eba..86c173dc7f 100644 --- a/src/openrct2/world/mapgen.h +++ b/src/openrct2/world/mapgen.h @@ -36,7 +36,7 @@ typedef struct mapgen_settings { // Height map settings bool smooth; - bool strong_smooth; + bool smooth_height_map; bool normalize_height; } mapgen_settings;