Index: src/table/elrail_data.h =================================================================== --- src/table/elrail_data.h (revision 11015) +++ src/table/elrail_data.h (working copy) @@ -229,13 +229,13 @@ } }; /* Geometric placement of the PCP relative to the tile origin */ -static const int8 x_pcp_offsets[DIAGDIR_END] = {0, 8, 15, 8}; -static const int8 y_pcp_offsets[DIAGDIR_END] = {8, 15, 8, 0}; +static const int8 x_pcp_offsets[DIAGDIR_END] = {0, 8, 16, 8}; +static const int8 y_pcp_offsets[DIAGDIR_END] = {8, 16, 8, 0}; /* Geometric placement of the PPP relative to the PCP*/ -static const int8 x_ppp_offsets[DIR_END] = {-3, -4, -3, 0, 3, 4, 3, 0}; -static const int8 y_ppp_offsets[DIR_END] = {-3, 0, 3, 4, 3, 0, -3, -4}; +static const int8 x_ppp_offsets[DIR_END] = {-2, -4, -2, 0, 2, 4, 2, 0}; +static const int8 y_ppp_offsets[DIR_END] = {-2, 0, 2, 4, 2, 0, -2, -4}; /* The type of pylon to draw at each PPP */ -static const SpriteID pylons_normal[] = { +static const SpriteID pylon_sprites[] = { SPR_PYLON_EW_N, SPR_PYLON_Y_NE, SPR_PYLON_NS_E, @@ -246,13 +246,6 @@ SPR_PYLON_X_NW }; -static const SpriteID pylons_bridge[] = { - SPR_PYLON_X_NW, - SPR_PYLON_X_SE, - SPR_PYLON_Y_NE, - SPR_PYLON_Y_SW -}; - struct SortableSpriteStruct { SpriteID image; int8 x_offset; @@ -265,9 +258,7 @@ enum { /** Distance between wire and rail */ - ELRAIL_ELEVATION = 8, - /** Corrects an off-by-one error in some places (tileh 12 and 9) (TODO -- find source of error) */ - ELRAIL_ELEV_CORR = ELRAIL_ELEVATION + 1, + ELRAIL_ELEVATION = 10, /** Wires that a draw one level higher than the north corner. */ ELRAIL_ELEVRAISE = ELRAIL_ELEVATION + TILE_HEIGHT }; @@ -276,41 +267,41 @@ /* X direction */ /* Flat tiles: */ /* Wires */ - { SPR_WIRE_X_SW, 0, 8, 16, 1, 1, ELRAIL_ELEVATION }, //! 0: Wire in X direction, pylon on the SW end only - { SPR_WIRE_X_NE, 0, 8, 16, 1, 1, ELRAIL_ELEVATION }, //! 1: Wire in X direction, pylon on the NE end - { SPR_WIRE_X_SHORT, 0, 8, 16, 1, 1, ELRAIL_ELEVATION }, //! 2: Wire in X direction, pylon on both ends + { SPR_WIRE_X_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! 0: Wire in X direction, pylon on the SW end only + { SPR_WIRE_X_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! 1: Wire in X direction, pylon on the NE end + { SPR_WIRE_X_SHORT, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! 2: Wire in X direction, pylon on both ends /* "up" tiles */ /* Wires */ - { SPR_WIRE_X_SW_UP, 0, 8, 16, 8, 1, ELRAIL_ELEVRAISE }, //! 3: Wire in X pitch up, pylon on the SW end only - { SPR_WIRE_X_NE_UP, 0, 8, 16, 8, 1, ELRAIL_ELEVRAISE }, //! 4: Wire in X pitch up, pylon on the NE end - { SPR_WIRE_X_SHORT_UP, 0, 8, 16, 8, 1, ELRAIL_ELEVRAISE }, //! 5: Wire in X pitch up, pylon on both ends + { SPR_WIRE_X_SW_UP, 0, 7, 15, 8, 1, ELRAIL_ELEVRAISE }, //! 3: Wire in X pitch up, pylon on the SW end only + { SPR_WIRE_X_NE_UP, 0, 7, 15, 8, 1, ELRAIL_ELEVRAISE }, //! 4: Wire in X pitch up, pylon on the NE end + { SPR_WIRE_X_SHORT_UP, 0, 7, 15, 8, 1, ELRAIL_ELEVRAISE }, //! 5: Wire in X pitch up, pylon on both ends /* "down" tiles */ /* Wires */ - { SPR_WIRE_X_SW_DOWN, 0, 8, 16, 8, 1, ELRAIL_ELEV_CORR }, //! 6: Wire in X pitch down, pylon on the SW end - { SPR_WIRE_X_NE_DOWN, 0, 8, 16, 8, 1, ELRAIL_ELEV_CORR }, //! 7: Wire in X pitch down, pylon on the NE end - { SPR_WIRE_X_SHORT_DOWN, 0, 8, 16, 8, 1, ELRAIL_ELEV_CORR }, //! 8: Wire in X pitch down, pylon on both ends + { SPR_WIRE_X_SW_DOWN, 0, 7, 15, 8, 1, ELRAIL_ELEVATION }, //! 6: Wire in X pitch down, pylon on the SW end + { SPR_WIRE_X_NE_DOWN, 0, 7, 15, 8, 1, ELRAIL_ELEVATION }, //! 7: Wire in X pitch down, pylon on the NE end + { SPR_WIRE_X_SHORT_DOWN, 0, 7, 15, 8, 1, ELRAIL_ELEVATION }, //! 8: Wire in X pitch down, pylon on both ends /* Y direction */ /* Flat tiles: */ /* Wires */ - { SPR_WIRE_Y_SE, 8, 0, 1, 16, 1, ELRAIL_ELEVATION }, //! 9: Wire in Y direction, pylon on the SE end only - { SPR_WIRE_Y_NW, 8, 0, 1, 16, 1, ELRAIL_ELEVATION }, //!10: Wire in Y direction, pylon on the NW end - { SPR_WIRE_Y_SHORT, 8, 0, 1, 16, 1, ELRAIL_ELEVATION }, //!11: Wire in Y direction, pylon on both ends + { SPR_WIRE_Y_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! 9: Wire in Y direction, pylon on the SE end only + { SPR_WIRE_Y_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //!10: Wire in Y direction, pylon on the NW end + { SPR_WIRE_Y_SHORT, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //!11: Wire in Y direction, pylon on both ends /* "up" tiles */ /* Wires */ - { SPR_WIRE_Y_SE_UP, 8, 0, 8, 16, 1, ELRAIL_ELEVRAISE }, //!12: Wire in Y pitch up, pylon on the SE end only - { SPR_WIRE_Y_NW_UP, 8, 0, 8, 16, 1, ELRAIL_ELEVRAISE }, //!13: Wire in Y pitch up, pylon on the NW end - { SPR_WIRE_Y_SHORT_UP, 8, 0, 8, 16, 1, ELRAIL_ELEVRAISE }, //!14: Wire in Y pitch up, pylon on both ends + { SPR_WIRE_Y_SE_UP, 7, 0, 8, 15, 1, ELRAIL_ELEVRAISE }, //!12: Wire in Y pitch up, pylon on the SE end only + { SPR_WIRE_Y_NW_UP, 7, 0, 8, 15, 1, ELRAIL_ELEVRAISE }, //!13: Wire in Y pitch up, pylon on the NW end + { SPR_WIRE_Y_SHORT_UP, 7, 0, 8, 15, 1, ELRAIL_ELEVRAISE }, //!14: Wire in Y pitch up, pylon on both ends /* "down" tiles */ /* Wires */ - { SPR_WIRE_Y_SE_DOWN, 8, 0, 8, 16, 1, ELRAIL_ELEV_CORR }, //!15: Wire in Y pitch down, pylon on the SE end - { SPR_WIRE_Y_NW_DOWN, 8, 0, 8, 16, 1, ELRAIL_ELEV_CORR }, //!16: Wire in Y pitch down, pylon on the NW end - { SPR_WIRE_Y_SHORT_DOWN, 8, 0, 8, 16, 1, ELRAIL_ELEV_CORR }, //!17: Wire in Y pitch down, pylon on both ends + { SPR_WIRE_Y_SE_DOWN, 7, 0, 8, 15, 1, ELRAIL_ELEVATION }, //!15: Wire in Y pitch down, pylon on the SE end + { SPR_WIRE_Y_NW_DOWN, 7, 0, 8, 15, 1, ELRAIL_ELEVATION }, //!16: Wire in Y pitch down, pylon on the NW end + { SPR_WIRE_Y_SHORT_DOWN, 7, 0, 8, 15, 1, ELRAIL_ELEVATION }, //!17: Wire in Y pitch down, pylon on both ends /* NS Direction */ { SPR_WIRE_NS_SHORT, 8, 0, 8, 8, 1, ELRAIL_ELEVATION }, //!18: LEFT trackbit wire, pylon on both ends @@ -323,28 +314,28 @@ { SPR_WIRE_NS_S, 0, 8, 8, 8, 1, ELRAIL_ELEVATION }, //!23: RIGHT trackbit wire, pylon on S end /* EW Direction */ - { SPR_WIRE_EW_SHORT, 8, 0, 8, 8, 1, ELRAIL_ELEVATION }, //!24: UPPER trackbit wire, pylon on both ends - { SPR_WIRE_EW_SHORT, 16, 8, 8, 8, 1, ELRAIL_ELEVATION }, //!25: LOWER trackbit wire, pylon on both ends + { SPR_WIRE_EW_SHORT, 7, 0, 1, 1, 1, ELRAIL_ELEVATION }, //!24: UPPER trackbit wire, pylon on both ends + { SPR_WIRE_EW_SHORT, 15, 8, 3, 3, 1, ELRAIL_ELEVATION }, //!25: LOWER trackbit wire, pylon on both ends - { SPR_WIRE_EW_W, 8, 0, 8, 8, 1, ELRAIL_ELEVATION }, //!28: UPPER trackbit wire, pylon on both ends - { SPR_WIRE_EW_W, 16, 8, 8, 8, 1, ELRAIL_ELEVATION }, //!29: LOWER trackbit wire, pylon on both ends + { SPR_WIRE_EW_W, 7, 0, 1, 1, 1, ELRAIL_ELEVATION }, //!28: UPPER trackbit wire, pylon on both ends + { SPR_WIRE_EW_W, 15, 8, 3, 3, 1, ELRAIL_ELEVATION }, //!29: LOWER trackbit wire, pylon on both ends - { SPR_WIRE_EW_E, 8, 0, 8, 8, 1, ELRAIL_ELEVATION }, //!32: UPPER trackbit wire, pylon on both ends - { SPR_WIRE_EW_E, 16, 8, 8, 8, 1, ELRAIL_ELEVATION } //!33: LOWER trackbit wire, pylon on both ends + { SPR_WIRE_EW_E, 7, 0, 1, 1, 1, ELRAIL_ELEVATION }, //!32: UPPER trackbit wire, pylon on both ends + { SPR_WIRE_EW_E, 15, 8, 3, 3, 1, ELRAIL_ELEVATION } //!33: LOWER trackbit wire, pylon on both ends }; static const SortableSpriteStruct CatenarySpriteData_Depot[] = { - { SPR_WIRE_DEPOT_NE, 0, 8, 8, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE depot exit - { SPR_WIRE_DEPOT_SE, 8, 0, 1, 8, 1, ELRAIL_ELEVATION }, //! Wire for SE depot exit - { SPR_WIRE_DEPOT_SW, 0, 8, 8, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW depot exit - { SPR_WIRE_DEPOT_NW, 8, 0, 1, 8, 1, ELRAIL_ELEVATION } //! Wire for NW depot exit + { SPR_WIRE_DEPOT_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE depot exit + { SPR_WIRE_DEPOT_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! Wire for SE depot exit + { SPR_WIRE_DEPOT_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW depot exit + { SPR_WIRE_DEPOT_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW depot exit }; static const SortableSpriteStruct CatenarySpriteData_Tunnel[] = { - { SPR_WIRE_TUNNEL_NE, 0, 8, 8, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE tunnel exit - { SPR_WIRE_TUNNEL_SE, 8, 0, 1, 8, 1, ELRAIL_ELEVATION }, //! Wire for SE tunnel exit - { SPR_WIRE_TUNNEL_SW, 0, 8, 8, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW tunnel exit - { SPR_WIRE_TUNNEL_NW, 8, 0, 1, 8, 1, ELRAIL_ELEVATION } //! Wire for NW tunnel exit + { SPR_WIRE_TUNNEL_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE tunnel exit + { SPR_WIRE_TUNNEL_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! Wire for SE tunnel exit + { SPR_WIRE_TUNNEL_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW tunnel exit + { SPR_WIRE_TUNNEL_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW tunnel exit }; Index: src/elrail.cpp =================================================================== --- src/elrail.cpp (revision 11015) +++ src/elrail.cpp (working copy) @@ -141,6 +141,33 @@ } } +/** + * Returns the Z position of a Pylon Control Point. + * + * @param tile The tile the pylon should stand on. + * @param PCPpos The PCP of the tile. + * @return The Z position of the PCP. + */ +static byte GetPCPElevation(TileIndex tile, DiagDirection PCPpos) +{ + /* The elevation of the "pylon"-sprite should be the elevation at the PCP. + * PCPs are always on a tile edge. + * + * This position can be outside of the tile, i.e. ?_pcp_offset == TILE_SIZE > TILE_SIZE - 1. + * So we have to move it inside the tile, because if the neighboured tile has a foundation, + * that does not smoothly connect to the current tile, we will get a wrong elevation from GetSlopeZ(). + * + * When we move the position inside the tile, we will get a wrong elevation if we have a slope. + * To catch all cases we round the Z position to the next (TILE_HEIGHT / 2). + * This will return the correct elevation for slopes and will also detect non-continuous elevation on edges. + * + * Also note that the result of GetSlopeZ() is very special on bridge-ramps. + */ + + byte z = GetSlopeZ(TileX(tile) * TILE_SIZE + min(x_pcp_offsets[PCPpos], TILE_SIZE - 1), TileY(tile) * TILE_SIZE + min(y_pcp_offsets[PCPpos], TILE_SIZE - 1)); + return (z + 2) & ~3; // this means z = (z + TILE_HEIGHT / 4) / (TILE_HEIGHT / 2) * (TILE_HEIGHT / 2); +} + /** Draws wires and, if required, pylons on a given tile * @param ti The Tileinfo to draw the tile for */ @@ -184,6 +211,11 @@ tileh[TS_NEIGHBOUR] = GetTileSlope(neighbour, NULL); trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, NULL); if (IsTunnelTile(neighbour) && i != GetTunnelDirection(neighbour)) trackconfig[TS_NEIGHBOUR] = TRACK_BIT_NONE; + + /* If the neighboured tile does not smoothly connect to the current tile (because of a foundation), + * we have to draw all pillars on the current tile. */ + if (GetPCPElevation(ti->tile, i) != GetPCPElevation(neighbour, ReverseDiagDir(i))) trackconfig[TS_NEIGHBOUR] = TRACK_BIT_NONE; + isflat[TS_NEIGHBOUR] = ((trackconfig[TS_NEIGHBOUR] & (TRACK_BIT_HORZ | TRACK_BIT_VERT)) != 0); PPPpreferred[i] = 0xFF; // We start with preferring everything (end-of-line in any direction) @@ -220,7 +252,7 @@ if (IsTileType(neighbour, MP_STATION)) tileh[TS_NEIGHBOUR] = SLOPE_FLAT; /* Read the foundataions if they are present, and adjust the tileh */ - if (IsTileType(neighbour, MP_RAILWAY) && GetRailType(neighbour) == RAILTYPE_ELECTRIC) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]); + if (trackconfig[TS_NEIGHBOUR] != TRACK_BIT_NONE && IsTileType(neighbour, MP_RAILWAY) && GetRailType(neighbour) == RAILTYPE_ELECTRIC) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]); if (IsBridgeTile(neighbour)) { foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetBridgeRampDirection(neighbour))); } @@ -268,8 +300,8 @@ continue; /* No neighbour, go looking for a better position */ } - AddSortableSpriteToDraw(pylons_normal[temp], PAL_NONE, x, y, 1, 1, 10, - GetSlopeZ(ti->x + x_pcp_offsets[i], ti->y + y_pcp_offsets[i]), + AddSortableSpriteToDraw(pylon_sprites[temp], PAL_NONE, x, y, 1, 1, 10, + GetPCPElevation(ti->tile, i), HASBIT(_transparent_opt, TO_BUILDINGS)); break; /* We already have drawn a pylon, bail out */ } @@ -308,8 +340,13 @@ assert(!IsSteepSlope(tileh[TS_HOME])); sss = &CatenarySpriteData[Wires[tileh_selector][t][PCPconfig]]; + /* + * The "wire"-sprite position is inside the tile, i.e. 0 <= sss->?_offset < TILE_SIZE. + * Therefore it is save to use GetSlopeZ() for the elevation. + * Also note, that the result of GetSlopeZ() is very special for bridge-ramps. + */ AddSortableSpriteToDraw(sss->image, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, - sss->x_size, sss->y_size, sss->z_size, GetSlopeZ(ti->x + min(sss->x_offset, TILE_SIZE - 1), ti->y + min(sss->y_offset, TILE_SIZE - 1)) + sss->z_offset, + sss->x_size, sss->y_size, sss->z_size, GetSlopeZ(ti->x + sss->x_offset, ti->y + sss->y_offset) + sss->z_offset, HASBIT(_transparent_opt, TO_BUILDINGS)); } } @@ -349,20 +386,22 @@ /* Finished with wires, draw pylons */ /* every other tile needs a pylon on the northern end */ if (num % 2) { - if (axis == AXIS_X) { - AddSortableSpriteToDraw(pylons_bridge[0 + HASBIT(tlg, 0)], PAL_NONE, ti->x, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, height, HASBIT(_transparent_opt, TO_BUILDINGS)); - } else { - AddSortableSpriteToDraw(pylons_bridge[2 + HASBIT(tlg, 1)], PAL_NONE, ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y, 1, 1, 10, height, HASBIT(_transparent_opt, TO_BUILDINGS)); - } + DiagDirection PCPpos = (axis == AXIS_X ? DIAGDIR_NE : DIAGDIR_NW); + Direction PPPpos = (axis == AXIS_X ? DIR_NW : DIR_NE); + if (HASBIT(tlg, (axis == AXIS_X ? 0 : 1))) PPPpos = ReverseDir(PPPpos); + uint x = ti->x + x_pcp_offsets[PCPpos] + x_ppp_offsets[PPPpos]; + uint y = ti->y + y_pcp_offsets[PCPpos] + y_ppp_offsets[PPPpos]; + AddSortableSpriteToDraw(pylon_sprites[PPPpos], PAL_NONE, x, y, 1, 1, 10, height, HASBIT(_transparent_opt, TO_BUILDINGS)); } /* need a pylon on the southern end of the bridge */ if (DistanceMax(ti->tile, start) == length) { - if (axis == AXIS_X) { - AddSortableSpriteToDraw(pylons_bridge[0 + HASBIT(tlg, 0)], PAL_NONE, ti->x + 16, ti->y + 4 + 8 * HASBIT(tlg, 0), 1, 1, 10, height, HASBIT(_transparent_opt, TO_BUILDINGS)); - } else { - AddSortableSpriteToDraw(pylons_bridge[2 + HASBIT(tlg, 1)], PAL_NONE, ti->x + 4 + 8 * HASBIT(tlg, 1), ti->y + 16, 1, 1, 10, height, HASBIT(_transparent_opt, TO_BUILDINGS)); - } + DiagDirection PCPpos = (axis == AXIS_X ? DIAGDIR_SW : DIAGDIR_SE); + Direction PPPpos = (axis == AXIS_X ? DIR_NW : DIR_NE); + if (HASBIT(tlg, (axis == AXIS_X ? 0 : 1))) PPPpos = ReverseDir(PPPpos); + uint x = ti->x + x_pcp_offsets[PCPpos] + x_ppp_offsets[PPPpos]; + uint y = ti->y + y_pcp_offsets[PCPpos] + y_ppp_offsets[PPPpos]; + AddSortableSpriteToDraw(pylon_sprites[PPPpos], PAL_NONE, x, y, 1, 1, 10, height, HASBIT(_transparent_opt, TO_BUILDINGS)); } } @@ -383,6 +422,7 @@ if (IsRailDepot(ti->tile)) { const SortableSpriteStruct *sss = &CatenarySpriteData_Depot[GetRailDepotDirection(ti->tile)]; + /* This wire is not visible with the default depot sprites */ AddSortableSpriteToDraw( sss->image, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, sss->x_size, sss->y_size, sss->z_size,