diff --git a/src/openrct2/world/map_helpers.c b/src/openrct2/world/map_helpers.c index 91310549f1..9354b4c5b7 100644 --- a/src/openrct2/world/map_helpers.c +++ b/src/openrct2/world/map_helpers.c @@ -320,3 +320,96 @@ static sint32 map_smooth_wavy(sint32 l, sint32 t, sint32 r, sint32 b) return raisedLand; } + +/** + * Raises the corners based on the height offset of neightbour tiles. + * This does not change the base height, unless all corners have been raised. + * @returns 0 if no edits were made, 1 otherwise + */ +sint32 tile_smooth(sint32 x, sint32 y) +{ + rct_map_element *const surfaceElement = map_get_surface_element_at(x, y); + + // +-----+-----+-----+ + // | NW | N | NE | + // | 2 | 1 | 0 | + // +-----+-----+-----+ + // | W | _ | E | + // | 4 | | 3 | + // +-----+-----+-----+ + // | SW | S | SE | + // | 7 | 6 | 5 | + // +-----+-----+-----+ + union + { + sint32 baseheight[8]; + struct { sint32 NE, N, NW, E, W, SE, S, SW; }; + } neighbourHeightOffset = { 0 }; + + // Find the neighbour base heights + for (sint32 index = 0, y_offset = -1; y_offset <= 1; y_offset++) + { + for (sint32 x_offset = -1; x_offset <= 1; x_offset++) + { + // Skip self + if (y_offset == 0 && x_offset == 0) + continue; + + // Get neightbour height. If the element is not valid (outside of map) assume the same height + rct_map_element *neightbour_element = map_get_surface_element_at(x + x_offset, y + y_offset); + neighbourHeightOffset.baseheight[index] = neightbour_element ? neightbour_element->base_height : surfaceElement->base_height; + + // Make the height relative to the current surface element + neighbourHeightOffset.baseheight[index] -= surfaceElement->base_height; + + index++; + } + } + + // Count number from the three tiles that is currently higher + sint8 thresholdNW = clamp(neighbourHeightOffset.W, 0, 1) + clamp(neighbourHeightOffset.NW, 0, 1) + clamp(neighbourHeightOffset.N, 0, 1); + sint8 thresholdNE = clamp(neighbourHeightOffset.N, 0, 1) + clamp(neighbourHeightOffset.NE, 0, 1) + clamp(neighbourHeightOffset.E, 0, 1); + sint8 thresholdSE = clamp(neighbourHeightOffset.E, 0, 1) + clamp(neighbourHeightOffset.SE, 0, 1) + clamp(neighbourHeightOffset.S, 0, 1); + sint8 thresholdSW = clamp(neighbourHeightOffset.S, 0, 1) + clamp(neighbourHeightOffset.SW, 0, 1) + clamp(neighbourHeightOffset.W, 0, 1); + + uint8 slope = 0; + slope |= (thresholdNW >= 1) << 1; + slope |= (thresholdNE >= 1) << 2; + slope |= (thresholdSE >= 1) << 3; + slope |= (thresholdSW >= 1) << 0; + + // Set diagonal when three corners have been raised, and the middle one can be raised one more + if ((slope == 0b0111 && neighbourHeightOffset.NW >= 4) || (slope == 0b1011 && neighbourHeightOffset.SW >= 4) || + (slope == 0b1101 && neighbourHeightOffset.SE >= 4) || (slope == 0b1110 && neighbourHeightOffset.NE >= 4)) + { + slope |= 1 << 4; + } + + // Check if the calculated slope is the same already + uint8 currentSlope = surfaceElement->properties.surface.slope & 0x1F; + if (currentSlope == slope) + { + return 0; + } + + // Remove old slope value + surfaceElement->properties.surface.slope &= ~0x1F; + if ((slope & 0xF) == 0xF) + { + // All corners are raised, raise the entire tile instead. + surfaceElement->base_height = (surfaceElement->clearance_height += 2); + } + else + { + // Apply the slope to this tile + surfaceElement->properties.surface.slope |= slope; + + // Set correct clearance height + if (slope & 0x10) + surfaceElement->clearance_height = surfaceElement->base_height + 4; + else if (slope & 0x0F) + surfaceElement->clearance_height = surfaceElement->base_height + 2; + } + + return 1; +} diff --git a/src/openrct2/world/map_helpers.h b/src/openrct2/world/map_helpers.h index d830d9f2f9..b72e253d94 100644 --- a/src/openrct2/world/map_helpers.h +++ b/src/openrct2/world/map_helpers.h @@ -18,5 +18,6 @@ #define _MAP_HELPERS_H_ sint32 map_smooth(sint32 l, sint32 t, sint32 r, sint32 b); +sint32 tile_smooth(sint32 x, sint32 y); #endif diff --git a/src/openrct2/world/mapgen.c b/src/openrct2/world/mapgen.c index c960546951..0cb2c32a9e 100644 --- a/src/openrct2/world/mapgen.c +++ b/src/openrct2/world/mapgen.c @@ -767,10 +767,9 @@ static void mapgen_simplex(mapgen_settings *settings) #pragma region Heightmap -#pragma optimize("", off) void mapgen_generate_from_heightmap() { - SDL_Surface *bitmap = SDL_LoadBMP("test.bmp"); + SDL_Surface *bitmap = SDL_LoadBMP("test_blurry.bmp"); if (bitmap == NULL) { printf("Failed to load bitmap: %s\n", SDL_GetError()); @@ -804,9 +803,17 @@ void mapgen_generate_from_heightmap() } } + // smooth the entire map + for (uint32 y = 1; y <= height; y++) + { + for (uint32 x = 1; x <= width; x++) + { + tile_smooth(x, y); + } + } + SDL_UnlockSurface(bitmap); SDL_FreeSurface(bitmap); } -#pragma optimize("", on) -#pragma endregion \ No newline at end of file +#pragma endregion