1 /* $Id: tile_map.cpp 25849 2013-10-12 22:07:58Z zuu $ */
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file tile_map.cpp Global tile accessors. */
15 #include "safeguards.h"
18 * Returns the tile height for a coordinate outside map. Such a height is
19 * needed for painting the area outside map using completely black tiles.
20 * The idea is descending to heightlevel 0 as fast as possible.
21 * @param x The X-coordinate (same unit as TileX).
22 * @param y The Y-coordinate (same unit as TileY).
23 * @return The height in the same unit as TileHeight.
25 uint
TileHeightOutsideMap(int x
, int y
)
27 /* In all cases: Descend to heightlevel 0 as fast as possible.
28 * So: If we are at the 0-side of the map (x<0 or y<0), we must
29 * subtract the distance to coordinate 0 from the heightlevel at
31 * In other words: Subtract e.g. -x. If we are at the MapMax
32 * side of the map, we also need to subtract the distance to
33 * the edge of map, e.g. MapMaxX - x.
35 * NOTE: Assuming constant heightlevel outside map would be
36 * simpler here. However, then we run into painting problems,
37 * since whenever a heightlevel change at the map border occurs,
38 * we would need to repaint anything outside map.
39 * In contrast, by doing it this way, we can localize this change,
40 * which means we may assume constant heightlevel for all tiles
41 * at more than <heightlevel at map border> distance from the
46 return max((int)TileHeight(TileXY(0, 0)) - (-x
) - (-y
), 0);
47 } else if (y
< (int)MapMaxY()) {
48 return max((int)TileHeight(TileXY(0, y
)) - (-x
), 0);
50 return max((int)TileHeight(TileXY(0, (int)MapMaxY())) - (-x
) - (y
- (int)MapMaxY()), 0);
52 } else if (x
< (int)MapMaxX()) {
54 return max((int)TileHeight(TileXY(x
, 0)) - (-y
), 0);
55 } else if (y
< (int)MapMaxY()) {
56 return TileHeight(TileXY(x
, y
));
58 return max((int)TileHeight(TileXY(x
, (int)MapMaxY())) - (y
- (int)MapMaxY()), 0);
62 return max((int)TileHeight(TileXY((int)MapMaxX(), 0)) - (x
- (int)MapMaxX()) - (-y
), 0);
63 } else if (y
< (int)MapMaxY()) {
64 return max((int)TileHeight(TileXY((int)MapMaxX(), y
)) - (x
- (int)MapMaxX()), 0);
66 return max((int)TileHeight(TileXY((int)MapMaxX(), (int)MapMaxY())) - (x
- (int)MapMaxX()) - (y
- (int)MapMaxY()), 0);
72 * Get a tile's slope given the heigh of its four corners.
73 * @param hnorth The height at the northern corner in the same unit as TileHeight.
74 * @param hwest The height at the western corner in the same unit as TileHeight.
75 * @param heast The height at the eastern corner in the same unit as TileHeight.
76 * @param hsouth The height at the southern corner in the same unit as TileHeight.
77 * @param [out] h The lowest height of the four corners.
80 static Slope
GetTileSlopeGivenHeight(int hnorth
, int hwest
, int heast
, int hsouth
, int *h
)
82 /* Due to the fact that tiles must connect with each other without leaving gaps, the
83 * biggest difference in height between any corner and 'min' is between 0, 1, or 2.
85 * Also, there is at most 1 corner with height difference of 2.
87 int hminnw
= min(hnorth
, hwest
);
88 int hmines
= min(heast
, hsouth
);
89 int hmin
= min(hminnw
, hmines
);
91 if (h
!= nullptr) *h
= hmin
;
93 int hmaxnw
= max(hnorth
, hwest
);
94 int hmaxes
= max(heast
, hsouth
);
95 int hmax
= max(hmaxnw
, hmaxes
);
99 if (hnorth
!= hmin
) r
|= SLOPE_N
;
100 if (hwest
!= hmin
) r
|= SLOPE_W
;
101 if (heast
!= hmin
) r
|= SLOPE_E
;
102 if (hsouth
!= hmin
) r
|= SLOPE_S
;
104 if (hmax
- hmin
== 2) r
|= SLOPE_STEEP
;
110 * Return the slope of a given tile inside the map.
111 * @param tile Tile to compute slope of
112 * @param h If not \c nullptr, pointer to storage of z height
113 * @return Slope of the tile, except for the HALFTILE part
115 Slope
GetTileSlope(TileIndex tile
, int *h
)
117 assert(tile
< MapSize());
119 uint x
= TileX(tile
);
120 uint y
= TileY(tile
);
121 if (x
== MapMaxX() || y
== MapMaxY()) {
122 if (h
!= nullptr) *h
= TileHeight(tile
);
126 int hnorth
= TileHeight(tile
); // Height of the North corner.
127 int hwest
= TileHeight(tile
+ TileDiffXY(1, 0)); // Height of the West corner.
128 int heast
= TileHeight(tile
+ TileDiffXY(0, 1)); // Height of the East corner.
129 int hsouth
= TileHeight(tile
+ TileDiffXY(1, 1)); // Height of the South corner.
131 return GetTileSlopeGivenHeight(hnorth
, hwest
, heast
, hsouth
, h
);
135 * Return the slope of a given tile outside the map.
137 * @param tile Tile outside the map to compute slope of.
138 * @param h If not \c nullptr, pointer to storage of z height.
139 * @return Slope of the tile outside map, except for the HALFTILE part.
141 Slope
GetTilePixelSlopeOutsideMap(int x
, int y
, int *h
)
143 int hnorth
= TileHeightOutsideMap(x
, y
); // N corner.
144 int hwest
= TileHeightOutsideMap(x
+ 1, y
); // W corner.
145 int heast
= TileHeightOutsideMap(x
, y
+ 1); // E corner.
146 int hsouth
= TileHeightOutsideMap(x
+ 1, y
+ 1); // S corner.
148 Slope s
= GetTileSlopeGivenHeight(hnorth
, hwest
, heast
, hsouth
, h
);
149 if (h
!= nullptr) *h
*= TILE_HEIGHT
;
154 * Check if a given tile is flat
155 * @param tile Tile to check
156 * @param h If not \c nullptr, pointer to storage of z height (only if tile is flat)
157 * @return Whether the tile is flat
159 bool IsTileFlat(TileIndex tile
, int *h
)
161 assert(tile
< MapSize());
163 if (!IsInnerTile(tile
)) {
164 if (h
!= nullptr) *h
= TileHeight(tile
);
168 uint z
= TileHeight(tile
);
169 if (TileHeight(tile
+ TileDiffXY(1, 0)) != z
) return false;
170 if (TileHeight(tile
+ TileDiffXY(0, 1)) != z
) return false;
171 if (TileHeight(tile
+ TileDiffXY(1, 1)) != z
) return false;
173 if (h
!= nullptr) *h
= z
;
178 * Get bottom height of the tile
179 * @param tile Tile to compute height of
180 * @return Minimum height of the tile
182 int GetTileZ(TileIndex tile
)
184 if (TileX(tile
) == MapMaxX() || TileY(tile
) == MapMaxY()) return 0;
186 int h
= TileHeight(tile
); // N corner
187 h
= min(h
, TileHeight(tile
+ TileDiffXY(1, 0))); // W corner
188 h
= min(h
, TileHeight(tile
+ TileDiffXY(0, 1))); // E corner
189 h
= min(h
, TileHeight(tile
+ TileDiffXY(1, 1))); // S corner
195 * Get bottom height of the tile outside map.
197 * @param tile Tile outside the map to compute height of.
198 * @return Minimum height of the tile outside the map.
200 int GetTilePixelZOutsideMap(int x
, int y
)
202 uint h
= TileHeightOutsideMap(x
, y
); // N corner.
203 h
= min(h
, TileHeightOutsideMap(x
+ 1, y
)); // W corner.
204 h
= min(h
, TileHeightOutsideMap(x
, y
+ 1)); // E corner.
205 h
= min(h
, TileHeightOutsideMap(x
+ 1, y
+ 1)); // S corner
207 return h
* TILE_HEIGHT
;
211 * Get top height of the tile inside the map.
212 * @param t Tile to compute height of
213 * @return Maximum height of the tile
215 int GetTileMaxZ(TileIndex t
)
217 if (TileX(t
) == MapMaxX() || TileY(t
) == MapMaxY()) return TileHeightOutsideMap(TileX(t
), TileY(t
));
219 int h
= TileHeight(t
); // N corner
220 h
= max
<int>(h
, TileHeight(t
+ TileDiffXY(1, 0))); // W corner
221 h
= max
<int>(h
, TileHeight(t
+ TileDiffXY(0, 1))); // E corner
222 h
= max
<int>(h
, TileHeight(t
+ TileDiffXY(1, 1))); // S corner
228 * Get top height of the tile outside the map.
230 * @see Detailed description in header.
232 * @param tile Tile outside to compute height of.
233 * @return Maximum height of the tile.
235 int GetTileMaxPixelZOutsideMap(int x
, int y
)
237 uint h
= TileHeightOutsideMap(x
, y
);
238 h
= max(h
, TileHeightOutsideMap(x
+ 1, y
));
239 h
= max(h
, TileHeightOutsideMap(x
, y
+ 1));
240 h
= max(h
, TileHeightOutsideMap(x
+ 1, y
+ 1));
242 return h
* TILE_HEIGHT
;