mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-15 11:03:00 +01:00
Add option to normalize height map
This commit is contained in:
committed by
Michał Janiszewski
parent
fda415cd44
commit
edfe997e78
@@ -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);
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
#pragma endregion
|
||||
|
||||
#include "../common.h"
|
||||
#include <SDL.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user