From 1ccbd735d83cedd8cf8a138d63a6f24c5a7abff1 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 6 Aug 2025 23:46:53 +0100 Subject: [PATCH] Codechange: Extract function to draw custom rail station foundations. (#14492) --- src/station_cmd.cpp | 133 +++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 1ca967f7d8..35b3693bb5 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3073,6 +3073,74 @@ bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrack return true; } +/** + * Draw custom station foundations for a NewGRF station if provided. + * @param statspec Custom NewGRF station. + * @param st Station being drawn. + * @param ti Tile being drawn. + * @param gfx Graphics layout for tile. + * @return true iff a custom foundation was drawn. + */ +static bool DrawCustomStationFoundations(const StationSpec *statspec, BaseStation *st, TileInfo *ti, StationGfx gfx) +{ + if (statspec == nullptr || !statspec->flags.Test(StationSpecFlag::CustomFoundations)) return false; + + /* Station has custom foundations. + * Check whether the foundation continues beyond the tile's upper sides. */ + uint edge_info = 0; + auto [slope, z] = GetFoundationPixelSlope(ti->tile); + if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0); + if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1); + + SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, gfx, edge_info); + if (image == 0) return false; + + if (statspec->flags.Test(StationSpecFlag::ExtendedFoundations)) { + /* Station provides extended foundations. */ + static constexpr uint8_t foundation_parts[] = { + UINT8_MAX, UINT8_MAX, UINT8_MAX, 0, // Invalid, Invalid, Invalid, SLOPE_SW + UINT8_MAX, 1, 2, 3, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE + UINT8_MAX, 4, 5, 6, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS + 7, 8, 9, // SLOPE_NE, SLOPE_ENW, SLOPE_SEN + }; + assert(ti->tileh < std::size(foundation_parts)); + if (foundation_parts[ti->tileh] == UINT8_MAX) return false; + + AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}}); + } else { + /* Draw simple foundations, built up from 8 possible foundation sprites. + * Each set bit represents one of the eight composite sprites to be drawn. + * 'Invalid' entries will not drawn but are included for completeness. */ + static constexpr uint8_t composite_foundation_parts[] = { + 0b0000'0000, 0b1101'0001, 0b1110'0100, 0b1110'0000, // Invalid, Invalid, Invalid, SLOPE_SW + 0b1100'1010, 0b1100'1001, 0b1100'0100, 0b1100'0000, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE + 0b1101'0010, 0b1001'0001, 0b1110'0100, 0b1010'0000, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS + 0b0100'1010, 0b0000'1001, 0b0100'0100, // SLOPE_NE, SLOPE_ENW, SLOPE_SEN + }; + assert(ti->tileh < std::size(composite_foundation_parts)); + + uint8_t parts = composite_foundation_parts[ti->tileh]; + + /* If foundations continue beyond the tile's upper sides then mask out the last two pieces. */ + if (HasBit(edge_info, 0)) ClrBit(parts, 6); + if (HasBit(edge_info, 1)) ClrBit(parts, 7); + + /* We always have to draw at least one sprite, so if we have no parts to draw fall back to default foundation. */ + if (parts == 0) return false; + + StartSpriteCombine(); + for (uint i : SetBitIterator(parts)) { + AddSortableSpriteToDraw(image + i, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}}); + } + EndSpriteCombine(); + } + + OffsetGroundSprite(0, -static_cast(TILE_HEIGHT)); + ti->z += ApplyPixelFoundationToSlope(FOUNDATION_LEVELED, ti->tileh); + + return true; +} + static void DrawTile_Station(TileInfo *ti) { const NewGRFSpriteLayout *layout = nullptr; @@ -3164,70 +3232,7 @@ static void DrawTile_Station(TileInfo *ti) /* don't show foundation for docks */ if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) { - if (statspec != nullptr && statspec->flags.Test(StationSpecFlag::CustomFoundations)) { - /* Station has custom foundations. - * Check whether the foundation continues beyond the tile's upper sides. */ - uint edge_info = 0; - auto [slope, z] = GetFoundationPixelSlope(ti->tile); - if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0); - if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1); - SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, tile_layout, edge_info); - if (image == 0) goto draw_default_foundation; - - if (statspec->flags.Test(StationSpecFlag::ExtendedFoundations)) { - /* Station provides extended foundations. */ - - static const uint8_t foundation_parts[] = { - 0, 0, 0, 0, // Invalid, Invalid, Invalid, SLOPE_SW - 0, 1, 2, 3, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE - 0, 4, 5, 6, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS - 7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN - }; - - AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, 7}, {}}); - } else { - /* Draw simple foundations, built up from 8 possible foundation sprites. */ - - /* Each set bit represents one of the eight composite sprites to be drawn. - * 'Invalid' entries will not drawn but are included for completeness. */ - static const uint8_t composite_foundation_parts[] = { - /* Invalid (00000000), Invalid (11010001), Invalid (11100100), SLOPE_SW (11100000) */ - 0x00, 0xD1, 0xE4, 0xE0, - /* Invalid (11001010), SLOPE_EW (11001001), SLOPE_SE (11000100), SLOPE_WSE (11000000) */ - 0xCA, 0xC9, 0xC4, 0xC0, - /* Invalid (11010010), SLOPE_NW (10010001), SLOPE_NS (11100100), SLOPE_NWS (10100000) */ - 0xD2, 0x91, 0xE4, 0xA0, - /* SLOPE_NE (01001010), SLOPE_ENW (00001001), SLOPE_SEN (01000100) */ - 0x4A, 0x09, 0x44 - }; - - uint8_t parts = composite_foundation_parts[ti->tileh]; - - /* If foundations continue beyond the tile's upper sides then - * mask out the last two pieces. */ - if (HasBit(edge_info, 0)) ClrBit(parts, 6); - if (HasBit(edge_info, 1)) ClrBit(parts, 7); - - if (parts == 0) { - /* We always have to draw at least one sprite to make sure there is a boundingbox and a sprite with the - * correct offset for the childsprites. - * So, draw the (completely empty) sprite of the default foundations. */ - goto draw_default_foundation; - } - - StartSpriteCombine(); - for (int i = 0; i < 8; i++) { - if (HasBit(parts, i)) { - AddSortableSpriteToDraw(image + i, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, 7}, {}}); - } - } - EndSpriteCombine(); - } - - OffsetGroundSprite(0, -8); - ti->z += ApplyPixelFoundationToSlope(FOUNDATION_LEVELED, ti->tileh); - } else { -draw_default_foundation: + if (!DrawCustomStationFoundations(statspec, st, ti, tile_layout)) { DrawFoundation(ti, FOUNDATION_LEVELED); } }