From edfe997e783b871e89ef1a84beba1c65aa9fc018 Mon Sep 17 00:00:00 2001 From: Broxzier Date: Sat, 11 Feb 2017 15:35:06 +0100 Subject: [PATCH] Add option to normalize height map --- src/openrct2/windows/mapgen.c | 90 ++++++++++++++++++++++++++++++++--- src/openrct2/world/mapgen.c | 47 ++++++++++++++++-- src/openrct2/world/mapgen.h | 1 + 3 files changed, 128 insertions(+), 10 deletions(-) diff --git a/src/openrct2/windows/mapgen.c b/src/openrct2/windows/mapgen.c index 1334ac443c..59f0bf4d42 100644 --- a/src/openrct2/windows/mapgen.c +++ b/src/openrct2/windows/mapgen.c @@ -88,6 +88,13 @@ enum { WIDX_HEIGHTMAP_SMOOTH = TAB_BEGIN, WIDX_HEIGHTMAP_STRONG, + WIDX_HEIGHTMAP_NORMALIZE, + WIDX_HEIGHTMAP_LOW, + WIDX_HEIGHTMAP_LOW_UP, + WIDX_HEIGHTMAP_LOW_DOWN, + WIDX_HEIGHTMAP_HIGH, + WIDX_HEIGHTMAP_HIGH_UP, + WIDX_HEIGHTMAP_HIGH_DOWN, WIDX_HEIGHTMAP_WATER_LEVEL, WIDX_HEIGHTMAP_WATER_LEVEL_UP, WIDX_HEIGHTMAP_WATER_LEVEL_DOWN, @@ -197,9 +204,19 @@ static rct_widget HeightmapWidgets[] = { { 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_SPINNER, 1, 104, 198, 124, 135, STR_NONE, STR_NONE }, // WIDX_HEIGHTMAP_WATER_LEVEL - { WWT_DROPDOWN_BUTTON, 1, 187, 197, 125, 129, STR_NUMERIC_UP, STR_NONE }, // WIDX_HEIGHTMAP_WATER_LEVEL_UP - { WWT_DROPDOWN_BUTTON, 1, 187, 197, 130, 134, STR_NUMERIC_DOWN, STR_NONE }, // WIDX_HEIGHTMAP_WATER_LEVEL_DOWN + { 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 + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 112, 116, STR_NUMERIC_DOWN, STR_NONE }, // WIDX_HEIGHTMAP_LOW_DOWN + + { WWT_SPINNER, 1, 104, 198, 124, 135, STR_NONE, STR_NONE }, // WIDX_HEIGHTMAP_HIGH + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 125, 129, STR_NUMERIC_UP, STR_NONE }, // WIDX_HEIGHTMAP_HIGH_UP + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 130, 134, STR_NUMERIC_DOWN, STR_NONE }, // WIDX_HEIGHTMAP_HIGH_DOWN + + { WWT_SPINNER, 1, 104, 198, 142, 153, STR_NONE, STR_NONE }, // WIDX_HEIGHTMAP_WATER_LEVEL + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 143, 147, STR_NUMERIC_UP, STR_NONE }, // WIDX_HEIGHTMAP_WATER_LEVEL_UP + { WWT_DROPDOWN_BUTTON, 1, 187, 197, 148, 152, STR_NUMERIC_DOWN, STR_NONE }, // WIDX_HEIGHTMAP_WATER_LEVEL_DOWN { WIDGETS_END }, }; @@ -214,6 +231,13 @@ static rct_widget *PageWidgets[] = { HeightmapWidgets }; +static uint64 PressedWidgets[] = { + 0, + 0, + 0, + (1ULL << WIDX_HEIGHTMAP_SMOOTH) +}; + #pragma endregion #pragma region Events @@ -442,6 +466,13 @@ static uint32 PageEnabledWidgets[] = { (1ULL << WIDX_GENERATE) | (1ULL << WIDX_HEIGHTMAP_SMOOTH) | (1ULL << WIDX_HEIGHTMAP_STRONG) | + (1ULL << WIDX_HEIGHTMAP_NORMALIZE) | + (1ULL << WIDX_HEIGHTMAP_LOW) | + (1ULL << WIDX_HEIGHTMAP_LOW_UP) | + (1ULL << WIDX_HEIGHTMAP_LOW_DOWN) | + (1ULL << WIDX_HEIGHTMAP_HIGH) | + (1ULL << WIDX_HEIGHTMAP_HIGH_UP) | + (1ULL << WIDX_HEIGHTMAP_HIGH_DOWN) | (1ULL << WIDX_HEIGHTMAP_WATER_LEVEL) | (1ULL << WIDX_HEIGHTMAP_WATER_LEVEL_UP) | (1ULL << WIDX_HEIGHTMAP_WATER_LEVEL_DOWN) @@ -507,7 +538,7 @@ static char WallTextureOrder[] = { static sint32 _mapSize = 150; static sint32 _baseHeight = 12; -static sint32 _waterLevel = 16; +static sint32 _waterLevel = 6; static sint32 _floorTexture = TERRAIN_GRASS; static sint32 _wallTexture = TERRAIN_EDGE_ROCK; static sint32 _randomTerrrain = 1; @@ -518,6 +549,10 @@ static sint32 _simplex_high = 10; static sint32 _simplex_base_freq = 60; static sint32 _simplex_octaves = 4; +static bool _heightmapNormalize = true; +static sint32 _heightmapLow = 10; +static sint32 _heightmapHigh = 14; + rct_window *window_mapgen_open() { rct_window *w; @@ -1114,12 +1149,43 @@ static void window_mapgen_heightmap_mouseup(rct_window *w, sint32 widgetIndex) mapgenSettings.water_level = _waterLevel; mapgenSettings.smooth = widget_is_pressed(w, WIDX_HEIGHTMAP_SMOOTH); mapgenSettings.strong_smooth = widget_is_pressed(w, WIDX_HEIGHTMAP_STRONG); + 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); + break; case WIDX_HEIGHTMAP_STRONG: - widget_set_checkbox_value(w, widgetIndex, !widget_is_pressed(w, widgetIndex)); + widget_set_checkbox_value(w, WIDX_HEIGHTMAP_STRONG, !widget_is_pressed(w, WIDX_HEIGHTMAP_STRONG)); + break; + case WIDX_HEIGHTMAP_NORMALIZE: + _heightmapNormalize = !_heightmapNormalize; + widget_set_checkbox_value(w, WIDX_HEIGHTMAP_NORMALIZE, _heightmapNormalize); + widget_invalidate(w, WIDX_HEIGHTMAP_NORMALIZE); + break; + case WIDX_HEIGHTMAP_HIGH_UP: + _heightmapHigh = min(_heightmapHigh + 1, 142); + window_invalidate(w); + break; + case WIDX_HEIGHTMAP_HIGH_DOWN: + _heightmapHigh = max(_heightmapHigh - 1, 2 + 1); + _heightmapLow = min(_heightmapLow, _heightmapHigh - 1); + window_invalidate(w); + break; + case WIDX_HEIGHTMAP_LOW_UP: + _heightmapLow = min(_heightmapLow + 1, 142 - 1); + _heightmapHigh = max(_heightmapHigh, _heightmapLow + 1); + window_invalidate(w); + break; + case WIDX_HEIGHTMAP_LOW_DOWN: + _heightmapLow = max(_heightmapLow - 1, 2); + window_invalidate(w); break; case WIDX_HEIGHTMAP_WATER_LEVEL_UP: _waterLevel = min(_waterLevel + 2, 54); @@ -1142,6 +1208,8 @@ static void window_mapgen_heightmap_invalidate(rct_window *w) window_init_scroll_widgets(w); } + widget_set_checkbox_value(w, WIDX_HEIGHTMAP_NORMALIZE, _heightmapNormalize); + window_mapgen_set_pressed_tab(w); window_mapgen_anchor_border_widgets(w); } @@ -1151,7 +1219,15 @@ static void window_mapgen_heightmap_paint(rct_window *w, rct_drawpixelinfo *dpi) window_draw_widgets(w, dpi); window_mapgen_draw_tab_images(dpi, w); - // water level label and value + // Low label and value + gfx_draw_string_left(dpi, STR_MAPGEN_SIMPLEX_NOISE_LOW_, NULL, COLOUR_BLACK, w->x + 5, w->y + w->widgets[WIDX_HEIGHTMAP_LOW].top + 1); + gfx_draw_string_left(dpi, STR_COMMA16, &_heightmapLow, w->colours[1], w->x + w->widgets[WIDX_HEIGHTMAP_LOW].left + 1, w->y + w->widgets[WIDX_HEIGHTMAP_LOW].top + 1); + + // High label and value + gfx_draw_string_left(dpi, STR_MAPGEN_SIMPLEX_NOISE_HIGH, NULL, COLOUR_BLACK, w->x + 5, w->y + w->widgets[WIDX_HEIGHTMAP_HIGH].top + 1); + gfx_draw_string_left(dpi, STR_COMMA16, &_heightmapHigh, w->colours[1], w->x + w->widgets[WIDX_HEIGHTMAP_HIGH].left + 1, w->y + w->widgets[WIDX_HEIGHTMAP_HIGH].top + 1); + + // Water level label and value gfx_draw_string_left(dpi, STR_WATER_LEVEL_LABEL, NULL, COLOUR_BLACK, w->x + 5, w->y + w->widgets[WIDX_HEIGHTMAP_WATER_LEVEL].top + 1); gfx_draw_string_left(dpi, STR_COMMA16, &_waterLevel, w->colours[1], w->x + w->widgets[WIDX_HEIGHTMAP_WATER_LEVEL].left + 1, w->y + w->widgets[WIDX_HEIGHTMAP_WATER_LEVEL].top + 1); } @@ -1174,7 +1250,7 @@ static void window_mapgen_set_page(rct_window *w, sint32 page) w->event_handlers = PageEvents[page]; w->widgets = PageWidgets[page]; w->disabled_widgets = 0; - w->pressed_widgets = 0; + w->pressed_widgets = PressedWidgets[page]; window_init_scroll_widgets(w); window_invalidate(w); diff --git a/src/openrct2/world/mapgen.c b/src/openrct2/world/mapgen.c index 75bdb09f1b..f0f6383a9e 100644 --- a/src/openrct2/world/mapgen.c +++ b/src/openrct2/world/mapgen.c @@ -15,8 +15,7 @@ #pragma endregion #include "../common.h" -#include - +#include "../core/Guard.hpp" #include "../object.h" #include "../util/util.h" #include "map.h" @@ -767,8 +766,11 @@ static void mapgen_simplex(mapgen_settings *settings) #pragma region Heightmap +#pragma optimize("", off) void mapgen_generate_from_heightmap(mapgen_settings *settings) { + openrct2_assert(settings->simplex_high != settings->simplex_low, "Low and high setting cannot be the same"); + SDL_Surface *bitmap = SDL_LoadBMP("test_blurry.bmp"); if (bitmap == NULL) { @@ -782,15 +784,53 @@ void mapgen_generate_from_heightmap(mapgen_settings *settings) map_init(width + 2); // + 2 for the black tiles around the map + uint8 maxValue = 255; + uint8 minValue = 0; + SDL_LockSurface(bitmap); uint8 *src = (uint8*)bitmap->pixels; + if (settings->normalize_height) + { + // Get highest and lowest pixel value + maxValue = 0; + minValue = 0xff; + for (uint32 y = 0; y < height; y++) + { + for (uint32 x = 0; x < width; x++) + { + uint8 value = src[x * numChannels + y * bitmap->pitch]; + maxValue = max(maxValue, value); + minValue = min(minValue, value); + } + } + + if (minValue == maxValue) + { + // TODO: Show warning about the height map being flat + log_warning("The height map cannot be normalized, it is flat."); + return; + } + } + + openrct2_assert(maxValue > minValue, "Input range is invalid"); + openrct2_assert(settings->simplex_high > settings->simplex_low, "Output range is invalid"); + + const uint8 rangeIn = maxValue - minValue; + const uint8 rangeOut = settings->simplex_high - settings->simplex_low; + for (uint32 y = 0; y < height; y++) { for (uint32 x = 0; x < width; x++) { // The x and y axis are flipped in the world, so this uses y for x and x for y. rct_map_element *const surfaceElement = map_get_surface_element_at(y + 1, x + 1); - surfaceElement->base_height = src[x * numChannels + y * bitmap->pitch] / 3 + 2; + + // Read value from bitmap, and convert its range + uint8 value = src[x * numChannels + y * bitmap->pitch]; + value = (uint8)((float)(value - minValue) / rangeIn * rangeOut) + settings->simplex_low; + surfaceElement->base_height = value; + + // Floor to even number surfaceElement->base_height /= 2; surfaceElement->base_height *= 2; surfaceElement->clearance_height = surfaceElement->base_height; @@ -833,5 +873,6 @@ void mapgen_generate_from_heightmap(mapgen_settings *settings) 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 42efdf3c98..5dd71a0eba 100644 --- a/src/openrct2/world/mapgen.h +++ b/src/openrct2/world/mapgen.h @@ -37,6 +37,7 @@ typedef struct mapgen_settings { // Height map settings bool smooth; bool strong_smooth; + bool normalize_height; } mapgen_settings; void mapgen_generate_blank(mapgen_settings *settings);