diff options
author | Johannes E. Krause <j.k@eclipso.de> | 2019-01-13 20:52:04 +0100 |
---|---|---|
committer | Niels Martin Hansen <nielsm@indvikleren.dk> | 2019-01-24 21:17:17 +0100 |
commit | f0290d5de77176718153a2d078bee7dae57c16dc (patch) | |
tree | ac6a55827750a9937ab49bb328476df4e023a0a9 /src/landscape.cpp | |
parent | 43852baace470938c71147d9029b4679d62a05a8 (diff) | |
download | openttd-f0290d5de77176718153a2d078bee7dae57c16dc.tar.xz |
Codechange: Add InverseRemapCoords2 function for remapping viewport coordinates to underlying tile coordinates (Patch by adf88, #6583)
Diffstat (limited to 'src/landscape.cpp')
-rw-r--r-- | src/landscape.cpp | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/landscape.cpp b/src/landscape.cpp index 18f27807d..eb1e404f0 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -90,6 +90,57 @@ extern const byte _slope_to_sprite_offset[32] = { static SnowLine *_snow_line = NULL; /** + * Map 2D viewport or smallmap coordinate to 3D world or tile coordinate. + * Function takes into account height of tiles and foundations. + * + * @param x X viewport 2D coordinate. + * @param y Y viewport 2D coordinate. + * @param clamp_to_map Clamp the coordinate outside of the map to the closest, non-void tile within the map. + * @return 3D world coordinate of point visible at the given screen coordinate (3D perspective). + * + * @note Inverse of #RemapCoords2 function. Smaller values may get rounded. + * @see InverseRemapCoords + */ +Point InverseRemapCoords2(int x, int y, bool clamp_to_map) +{ + /* Initial x/y world coordinate is like if the landscape + * was completely flat on height 0. */ + Point pt = InverseRemapCoords(x, y); + + const uint min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0; + const uint max_x = MapMaxX() * TILE_SIZE - 1; + const uint max_y = MapMaxY() * TILE_SIZE - 1; + + if (clamp_to_map) { + /* Bring the coordinates near to a valid range. At the top we allow a number + * of extra tiles. This is mostly due to the tiles on the north side of + * the map possibly being drawn higher due to the extra height levels. */ + int extra_tiles = CeilDiv(_settings_game.construction.max_heightlevel * TILE_HEIGHT, TILE_PIXELS); + pt.x = Clamp(pt.x, -extra_tiles * TILE_SIZE, max_x); + pt.y = Clamp(pt.y, -extra_tiles * TILE_SIZE, max_y); + } + + /* Now find the Z-world coordinate by fix point iteration. + * This is a bit tricky because the tile height is non-continuous at foundations. + * The clicked point should be approached from the back, otherwise there are regions that are not clickable. + * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely) + * So give it a z-malus of 4 in the first iterations. */ + int z = 0; + for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(pt.x + max(z, 4) - 4, min_coord, max_x), Clamp(pt.y + max(z, 4) - 4, min_coord, max_y)) / 2; + for (int m = 3; m > 0; m--) z = GetSlopePixelZ(Clamp(pt.x + max(z, m) - m, min_coord, max_x), Clamp(pt.y + max(z, m) - m, min_coord, max_y)) / 2; + for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(pt.x + z, min_coord, max_x), Clamp(pt.y + z, min_coord, max_y)) / 2; + + pt.x += z; + pt.y += z; + if (clamp_to_map) { + pt.x = Clamp(pt.x, min_coord, max_x); + pt.y = Clamp(pt.y, min_coord, max_y); + } + + return pt; +} + +/** * Applies a foundation to a slope. * * @pre Foundation and slope must be valid combined. |