tron@3636: /* $Id$ */ tron@3636: truelight@7805: /** @file slope.h Definitions of a slope. truelight@7805: * This file defines the enumeration and helper functions for handling truelight@7805: * the slope info of a tile. truelight@7805: */ belugas@6916: tron@3636: #ifndef SLOPE_H tron@3636: #define SLOPE_H tron@3636: truelight@7805: /** rubidium@8260: * Enumeration of tile corners rubidium@8260: */ rubidium@8260: enum Corner { rubidium@8260: CORNER_W = 0, rubidium@8260: CORNER_S = 1, rubidium@8260: CORNER_E = 2, rubidium@8260: CORNER_N = 3, rubidium@8260: CORNER_END rubidium@8260: }; rubidium@8260: rubidium@8260: /** truelight@7805: * Enumeration for the slope-type. truelight@7805: * truelight@7805: * This enumeration use the chars N,E,S,W corresponding the truelight@7805: * direction north, east, south and west. The top corner of a tile truelight@7805: * is the north-part of the tile. The whole slope is encoded with truelight@7805: * 5 bits, 4 bits for each corner and 1 bit for a steep-flag. rubidium@8260: * rubidium@8260: * For halftile slopes an extra 3 bits are used to represent this rubidium@8260: * properly; 1 bit for a halftile-flag and 2 bits to encode which rubidium@8260: * extra side (corner) is leveled when the slope of the first 5 rubidium@8260: * bits is applied. This means that there can only be one leveled rubidium@8260: * slope for steep slopes, which is logical because two leveled rubidium@8260: * slopes would mean that it is not a steep slope as halftile rubidium@8260: * slopes only span one height level. truelight@7805: */ rubidium@6574: enum Slope { truelight@7805: SLOPE_FLAT = 0x00, ///< a flat tile truelight@7805: SLOPE_W = 0x01, ///< the west corner of the tile is raised truelight@7805: SLOPE_S = 0x02, ///< the south corner of the tile is raised truelight@7805: SLOPE_E = 0x04, ///< the east corner of the tile is raised truelight@7805: SLOPE_N = 0x08, ///< the north corner of the tile is raised truelight@7805: SLOPE_STEEP = 0x10, ///< indicates the slope is steep truelight@7805: SLOPE_NW = SLOPE_N | SLOPE_W, ///< north and west corner are raised truelight@7805: SLOPE_SW = SLOPE_S | SLOPE_W, ///< south and west corner are raised truelight@7805: SLOPE_SE = SLOPE_S | SLOPE_E, ///< south and east corner are raised truelight@7805: SLOPE_NE = SLOPE_N | SLOPE_E, ///< north and east corner are raised truelight@7805: SLOPE_EW = SLOPE_E | SLOPE_W, ///< east and west corner are raised truelight@7805: SLOPE_NS = SLOPE_N | SLOPE_S, ///< north and south corner are raised truelight@7805: SLOPE_ELEVATED = SLOPE_N | SLOPE_E | SLOPE_S | SLOPE_W, ///< all corner are raised, similar to SLOPE_FLAT truelight@7805: SLOPE_NWS = SLOPE_N | SLOPE_W | SLOPE_S, ///< north, west and south corner are raised truelight@7805: SLOPE_WSE = SLOPE_W | SLOPE_S | SLOPE_E, ///< west, south and east corner are raised truelight@7805: SLOPE_SEN = SLOPE_S | SLOPE_E | SLOPE_N, ///< south, east and north corner are raised truelight@7805: SLOPE_ENW = SLOPE_E | SLOPE_N | SLOPE_W, ///< east, north and west corner are raised truelight@7805: SLOPE_STEEP_W = SLOPE_STEEP | SLOPE_NWS, ///< a steep slope falling to east (from west) truelight@7805: SLOPE_STEEP_S = SLOPE_STEEP | SLOPE_WSE, ///< a steep slope falling to north (from south) truelight@7805: SLOPE_STEEP_E = SLOPE_STEEP | SLOPE_SEN, ///< a steep slope falling to west (from east) rubidium@8260: SLOPE_STEEP_N = SLOPE_STEEP | SLOPE_ENW, ///< a steep slope falling to south (from north) tron@3636: rubidium@8260: SLOPE_HALFTILE = 0x20, ///< one halftile is leveled (non continuous slope) rubidium@8260: SLOPE_HALFTILE_MASK = 0xE0, ///< three bits used for halftile slopes rubidium@8260: SLOPE_HALFTILE_W = SLOPE_HALFTILE | (CORNER_W << 6), ///< the west halftile is leveled (non continuous slope) rubidium@8260: SLOPE_HALFTILE_S = SLOPE_HALFTILE | (CORNER_S << 6), ///< the south halftile is leveled (non continuous slope) rubidium@8260: SLOPE_HALFTILE_E = SLOPE_HALFTILE | (CORNER_E << 6), ///< the east halftile is leveled (non continuous slope) rubidium@8260: SLOPE_HALFTILE_N = SLOPE_HALFTILE | (CORNER_N << 6), ///< the north halftile is leveled (non continuous slope) rubidium@8174: }; rubidium@8174: rubidium@8174: /** rubidium@8199: * Rangecheck for Corner enumeration. rubidium@8199: * rubidium@8199: * @param corner A #Corner. rubidium@8199: * @return true iff corner is in a valid range. rubidium@8199: */ rubidium@8199: static inline bool IsValidCorner(Corner corner) rubidium@8199: { rubidium@8199: return IS_INT_INSIDE(corner, 0, CORNER_END); rubidium@8199: } rubidium@8199: rubidium@8199: /** truelight@7805: * Checks if a slope is steep. truelight@7805: * truelight@7805: * @param s The given #Slope. truelight@7805: * @return True if the slope is steep, else false. truelight@7805: */ tron@3636: static inline bool IsSteepSlope(Slope s) tron@3636: { tron@3636: return (s & SLOPE_STEEP) != 0; tron@3636: } tron@3636: truelight@7805: /** rubidium@8260: * Checks for non-continuous slope on halftile foundations. rubidium@8260: * rubidium@8260: * @param s The given #Slope. rubidium@8260: * @return True if the slope is non-continuous, else false. rubidium@8260: */ rubidium@8260: static inline bool IsHalftileSlope(Slope s) rubidium@8260: { rubidium@8260: return (s & SLOPE_HALFTILE) != 0; rubidium@8260: } rubidium@8260: rubidium@8260: /** truelight@7805: * Return the complement of a slope. truelight@7805: * truelight@7805: * This method returns the complement of a slope. The complement of a truelight@7805: * slope is a slope with raised corner which aren't raised in the given truelight@7805: * slope. truelight@7805: * rubidium@8260: * @pre The slope must neither be steep nor a halftile slope. truelight@7805: * @param s The #Slope to get the complement. truelight@7805: * @return a complement Slope of the given slope. truelight@7805: */ tron@3636: static inline Slope ComplementSlope(Slope s) tron@3636: { rubidium@8260: assert(!IsSteepSlope(s) && !IsHalftileSlope(s)); tron@3636: return (Slope)(0xF ^ s); tron@3636: } tron@3636: rubidium@7831: /** rubidium@8199: * Tests if a slope has a highest corner (i.e. one corner raised or a steep slope). rubidium@8199: * rubidium@8260: * Note: A halftile slope is ignored. rubidium@8260: * rubidium@8199: * @param s The #Slope. rubidium@8199: * @return true iff the slope has a highest corner. rubidium@8199: */ rubidium@8199: static inline bool HasSlopeHighestCorner(Slope s) rubidium@8199: { rubidium@8260: s = (Slope)(s & ~SLOPE_HALFTILE_MASK); rubidium@8199: return IsSteepSlope(s) || (s == SLOPE_W) || (s == SLOPE_S) || (s == SLOPE_E) || (s == SLOPE_N); rubidium@8199: } rubidium@8199: rubidium@8199: /** rubidium@7831: * Returns the highest corner of a slope (one corner raised or a steep slope). rubidium@7831: * rubidium@8260: * @pre The slope must be a slope with one corner raised or a steep slope. A halftile slope is ignored. rubidium@7831: * @param s The #Slope. rubidium@8174: * @return Highest corner. rubidium@7831: */ rubidium@8174: static inline Corner GetHighestSlopeCorner(Slope s) rubidium@7831: { rubidium@8260: switch (s & ~SLOPE_HALFTILE_MASK) { rubidium@7831: case SLOPE_W: rubidium@8174: case SLOPE_STEEP_W: return CORNER_W; rubidium@7831: case SLOPE_S: rubidium@8174: case SLOPE_STEEP_S: return CORNER_S; rubidium@7831: case SLOPE_E: rubidium@8174: case SLOPE_STEEP_E: return CORNER_E; rubidium@7831: case SLOPE_N: rubidium@8174: case SLOPE_STEEP_N: return CORNER_N; rubidium@7831: default: NOT_REACHED(); rubidium@7831: } rubidium@7831: } rubidium@7831: rubidium@8078: /** rubidium@8260: * Returns the leveled halftile of a halftile slope. rubidium@8260: * rubidium@8260: * @pre The slope must be a halftile slope. rubidium@8260: * @param s The #Slope. rubidium@8260: * @return The corner of the leveled halftile. rubidium@8260: */ rubidium@8260: static inline Corner GetHalftileSlopeCorner(Slope s) rubidium@8260: { rubidium@8260: assert(IsHalftileSlope(s)); rubidium@8260: return (Corner)((s >> 6) & 3); rubidium@8260: } rubidium@8260: rubidium@8260: /** rubidium@8078: * Returns the height of the highest corner of a slope relative to TileZ (= minimal height) rubidium@8078: * rubidium@8078: * @param s The #Slope. rubidium@8078: * @return Relative height of highest corner. rubidium@8078: */ rubidium@8078: static inline uint GetSlopeMaxZ(Slope s) rubidium@8078: { rubidium@8078: if (s == SLOPE_FLAT) return 0; rubidium@8078: if (IsSteepSlope(s)) return 2 * TILE_HEIGHT; rubidium@8078: return TILE_HEIGHT; rubidium@8078: } rubidium@8078: rubidium@8174: /** rubidium@8174: * Returns the opposite corner. rubidium@8174: * rubidium@8174: * @param corner A #Corner. rubidium@8174: * @return The opposite corner to "corner". rubidium@8174: */ rubidium@8174: static inline Corner OppositeCorner(Corner corner) rubidium@8174: { rubidium@8174: return (Corner)(corner ^ 2); rubidium@8174: } rubidium@8174: rubidium@8174: /** rubidium@8174: * Returns the slope with a specific corner raised. rubidium@8174: * rubidium@8174: * @param corner The #Corner. rubidium@8174: * @return The #Slope with corner "corner" raised. rubidium@8174: */ rubidium@8174: static inline Slope SlopeWithOneCornerRaised(Corner corner) rubidium@8174: { rubidium@8199: assert(IsValidCorner(corner)); rubidium@8174: return (Slope)(1 << corner); rubidium@8174: } rubidium@8174: rubidium@8174: /** rubidium@8174: * Returns the slope with all except one corner raised. rubidium@8174: * rubidium@8174: * @param corner The #Corner. rubidium@8174: * @return The #Slope with all corners but "corner" raised. rubidium@8174: */ rubidium@8174: static inline Slope SlopeWithThreeCornersRaised(Corner corner) rubidium@8174: { rubidium@8174: return ComplementSlope(SlopeWithOneCornerRaised(corner)); rubidium@8174: } rubidium@8174: rubidium@8260: /** rubidium@8260: * Adds a halftile slope to a slope. rubidium@8260: * rubidium@8260: * @param s #Slope without a halftile slope. rubidium@8260: * @param corner The #Corner of the halftile. rubidium@8260: * @return The #Slope s with the halftile slope added. rubidium@8260: */ rubidium@8260: static inline Slope HalftileSlope(Slope s, Corner corner) rubidium@8260: { rubidium@8260: assert(IsValidCorner(corner)); rubidium@8260: return (Slope)(s | SLOPE_HALFTILE | (corner << 6)); rubidium@8260: } rubidium@8260: rubidium@7831: rubidium@7831: /** rubidium@7831: * Enumeration for Foundations. rubidium@7831: */ rubidium@7831: enum Foundation { rubidium@7831: FOUNDATION_NONE, ///< The tile has no foundation, the slope remains unchanged. rubidium@7831: FOUNDATION_LEVELED, ///< The tile is leveled up to a flat slope. rubidium@7831: FOUNDATION_INCLINED_X, ///< The tile has an along X-axis inclined foundation. rubidium@7831: FOUNDATION_INCLINED_Y, ///< The tile has an along Y-axis inclined foundation. rubidium@7831: FOUNDATION_STEEP_LOWER, ///< The tile has a steep slope. The lowerst corner is raised by a foundation to allow building railroad on the lower halftile. rubidium@7831: FOUNDATION_STEEP_HIGHER, ///< The tile has a steep slope. Three corners are raised by a foundation to allow building railroad on the higher halftile. rubidium@8199: rubidium@8199: FOUNDATION_INVALID = 0xFF ///< Used inside "rail_cmd.cpp" to indicate invalid slope/track combination. rubidium@7831: }; rubidium@7831: rubidium@7831: /** rubidium@7831: * Tests for FOUNDATION_NONE. rubidium@7831: * rubidium@7831: * @param f Maybe a #Foundation. rubidium@7831: * @return true iff f is a foundation. rubidium@7831: */ rubidium@7831: static inline bool IsFoundation(Foundation f) rubidium@7831: { rubidium@7831: return f != FOUNDATION_NONE; rubidium@7831: } rubidium@7831: rubidium@7831: /** rubidium@7831: * Tests if the foundation is a leveled foundation. rubidium@7831: * rubidium@7831: * @param f The #Foundation. rubidium@7831: * @return true iff f is a leveled foundation. rubidium@7831: */ rubidium@7831: static inline bool IsLeveledFoundation(Foundation f) rubidium@7831: { rubidium@7831: return f == FOUNDATION_LEVELED; rubidium@7831: } rubidium@7831: rubidium@7831: /** rubidium@7831: * Tests if the foundation is an inclined foundation. rubidium@7831: * rubidium@7831: * @param f The #Foundation. rubidium@7831: * @return true iff f is an inclined foundation. rubidium@7831: */ rubidium@7831: static inline bool IsInclinedFoundation(Foundation f) rubidium@7831: { rubidium@7831: return (f == FOUNDATION_INCLINED_X) || (f == FOUNDATION_INCLINED_Y); rubidium@7831: } rubidium@7831: rubidium@7831: /** rubidium@7831: * Returns the foundation needed to flatten a slope. rubidium@7831: * The returned foundation is either FOUNDATION_NONE if the tile was already flat, or FOUNDATION_LEVELED. rubidium@7831: * rubidium@7831: * @pre The slope must not be steep. rubidium@7831: * @param s The current #Slope. rubidium@7831: * @return The needed #Foundation. rubidium@7831: */ rubidium@7831: static inline Foundation FlatteningFoundation(Slope s) rubidium@7831: { rubidium@7831: assert(!IsSteepSlope(s)); rubidium@7831: return (s == SLOPE_FLAT ? FOUNDATION_NONE : FOUNDATION_LEVELED); rubidium@7831: } rubidium@7831: rubidium@7831: /** rubidium@7831: * Returns the along a specific axis inclined foundation. rubidium@7831: * rubidium@7831: * @param axis The #Axis. rubidium@7831: * @return The needed #Foundation. rubidium@7831: */ rubidium@7831: static inline Foundation InclinedFoundation(Axis axis) rubidium@7831: { rubidium@7831: return (axis == AXIS_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y); rubidium@7831: } rubidium@7831: peter1138@4666: #endif /* SLOPE_H */