summaryrefslogtreecommitdiff
path: root/src/landscape.cpp
diff options
context:
space:
mode:
authorJohannes E. Krause <j.k@eclipso.de>2019-01-13 20:52:04 +0100
committerNiels Martin Hansen <nielsm@indvikleren.dk>2019-01-24 21:17:17 +0100
commitf0290d5de77176718153a2d078bee7dae57c16dc (patch)
treeac6a55827750a9937ab49bb328476df4e023a0a9 /src/landscape.cpp
parent43852baace470938c71147d9029b4679d62a05a8 (diff)
downloadopenttd-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.cpp51
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.