From 18dfad871a42fa6880fa37adfebba80c932ea048 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 8 Jul 2025 17:52:08 +0100 Subject: [PATCH] Codechange: Unify structures with sprite sub-tile bounds and simplify bounding boxes. Lots of different structs contain variations on sub-tile bounds with different naming. Unify into a single struct that can be inherited and passed directly to AddSortableSpriteToDraw. At the same time, offsets now work more logically: sub-tile bounds now specify the bounding box, and an offset can be applied to the sprite. --- src/aircraft_cmd.cpp | 19 ++--- src/clear_cmd.cpp | 25 +++++-- src/core/geometry_type.hpp | 27 +++++-- src/disaster_vehicle.cpp | 6 +- src/effectvehicle.cpp | 6 +- src/elrail.cpp | 50 ++++--------- src/industry_cmd.cpp | 8 +- src/landscape.cpp | 46 ++++++------ src/newgrf/newgrf_act0_stations.cpp | 12 +-- src/newgrf/newgrf_act2.cpp | 12 +-- src/newgrf_commons.cpp | 12 +-- src/object_cmd.cpp | 8 +- src/rail_cmd.cpp | 20 ++--- src/road_cmd.cpp | 17 +++-- src/roadveh_cmd.cpp | 69 +++++++++++------ src/ship_cmd.cpp | 30 +++----- src/sprite.cpp | 17 ++--- src/sprite.h | 32 ++++---- src/station_cmd.cpp | 4 +- src/table/elrail_data.h | 26 ++++--- src/table/industry_land.h | 12 +-- src/table/town_land.h | 12 +-- src/tile_cmd.h | 6 +- src/tile_type.h | 34 ++++----- src/town_cmd.cpp | 10 +-- src/town_gui.cpp | 2 +- src/train_cmd.cpp | 49 +++++-------- src/tree_cmd.cpp | 5 +- src/tunnelbridge_cmd.cpp | 110 +++++++++++++++++----------- src/vehicle.cpp | 17 ++++- src/vehicle_base.h | 9 +-- src/viewport.cpp | 39 +++++----- src/viewport_func.h | 7 +- src/viewport_type.h | 4 +- src/water_cmd.cpp | 6 +- 35 files changed, 394 insertions(+), 374 deletions(-) diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index aac97c84c9..54549c5ceb 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -48,10 +48,7 @@ void Aircraft::UpdateDeltaXY() { - this->x_offs = -1; - this->y_offs = -1; - this->x_extent = 2; - this->y_extent = 2; + this->bounds = {{-1, -1, 0}, {2, 2, 0}, {}}; switch (this->subtype) { default: NOT_REACHED(); @@ -64,21 +61,21 @@ void Aircraft::UpdateDeltaXY() case LANDING: case HELILANDING: case FLYING: - this->x_extent = 24; - this->y_extent = 24; + /* Bounds are not centred on the aircraft. */ + this->bounds.extent.x = 24; + this->bounds.extent.y = 24; break; } - this->z_extent = 5; + this->bounds.extent.z = 5; break; case AIR_SHADOW: - this->z_extent = 1; - this->x_offs = 0; - this->y_offs = 0; + this->bounds.extent.z = 1; + this->bounds.origin = {}; break; case AIR_ROTOR: - this->z_extent = 1; + this->bounds.extent.z = 1; break; } } diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp index 04f52cfdee..d816d66fc2 100644 --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -69,36 +69,45 @@ static void DrawClearLandFence(const TileInfo *ti) /* combine fences into one sprite object */ StartSpriteCombine(); - int maxz = GetSlopeMaxPixelZ(ti->tileh); + SpriteBounds bounds = {{}, {TILE_SIZE, TILE_SIZE, 4}, {}}; + + bounds.extent.z += GetSlopeMaxPixelZ(ti->tileh); uint fence_nw = GetFence(ti->tile, DIAGDIR_NW); if (fence_nw != 0) { - int z = GetSlopePixelZInCorner(ti->tileh, CORNER_W); + bounds.offset.x = 0; + bounds.offset.y = -static_cast(TILE_SIZE); + bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_W); SpriteID sprite = _clear_land_fence_sprites[fence_nw - 1] + _fence_mod_by_tileh_nw[ti->tileh]; - AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y - 16, 16, 32, maxz - z + 4, ti->z + z, false, 0, 16, -z); + AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false); } uint fence_ne = GetFence(ti->tile, DIAGDIR_NE); if (fence_ne != 0) { - int z = GetSlopePixelZInCorner(ti->tileh, CORNER_E); + bounds.offset.x = -static_cast(TILE_SIZE); + bounds.offset.y = 0; + bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_E); SpriteID sprite = _clear_land_fence_sprites[fence_ne - 1] + _fence_mod_by_tileh_ne[ti->tileh]; - AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x - 16, ti->y, 32, 16, maxz - z + 4, ti->z + z, false, 16, 0, -z); + AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false); } uint fence_sw = GetFence(ti->tile, DIAGDIR_SW); uint fence_se = GetFence(ti->tile, DIAGDIR_SE); if (fence_sw != 0 || fence_se != 0) { - int z = GetSlopePixelZInCorner(ti->tileh, CORNER_S); + bounds.offset.x = 0; + bounds.offset.y = 0; + bounds.offset.z = GetSlopePixelZInCorner(ti->tileh, CORNER_S); if (fence_sw != 0) { SpriteID sprite = _clear_land_fence_sprites[fence_sw - 1] + _fence_mod_by_tileh_sw[ti->tileh]; - AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z); + AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false); } if (fence_se != 0) { SpriteID sprite = _clear_land_fence_sprites[fence_se - 1] + _fence_mod_by_tileh_se[ti->tileh]; - AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z); + AddSortableSpriteToDraw(sprite, PAL_NONE, *ti, bounds, false); + } } EndSpriteCombine(); diff --git a/src/core/geometry_type.hpp b/src/core/geometry_type.hpp index d901f79fbe..2260a03075 100644 --- a/src/core/geometry_type.hpp +++ b/src/core/geometry_type.hpp @@ -28,15 +28,30 @@ inline int CentreBounds(int min, int max, int size) return (min + max - size + 1) / 2; } -/** Coordinates of a point in 2D */ -struct Point { - int x; - int y; +/** Coordinates of a point in 2D. */ +template +struct PointXy { + T x = 0; ///< X coordinate of point. + T y = 0; ///< Y coordinate of point. - constexpr Point() : x(0), y(0) {} - constexpr Point(int x, int y) : x(x), y(y) {} + constexpr PointXy() = default; + constexpr PointXy(T x, T y) : x(x), y(y) {} }; +/** Coordinates of a point in 3D. */ +template +struct PointXyz { + T x = 0; ///< X coordinate of point. + T y = 0; ///< Y coordinate of point. + T z = 0; ///< Z coordinate of point. + + constexpr PointXyz() = default; + constexpr PointXyz(T x, T y, T z) : x(x), y(y), z(z) {} +}; + +/** Coordinates of a point in 2D */ +using Point = PointXy; + /** Dimensions (a width and height) of a rectangle in 2D */ struct Dimension { uint width; diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 0b279b6059..9cecea5f7a 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -992,9 +992,5 @@ void ReleaseDisasterVehicle(VehicleID vehicle) void DisasterVehicle::UpdateDeltaXY() { - this->x_offs = -1; - this->y_offs = -1; - this->x_extent = 2; - this->y_extent = 2; - this->z_extent = 5; + this->bounds = {{-1, -1, 0}, {2, 2, 5}, {}}; } diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index 941fa1b4a5..58a6c963dd 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -619,11 +619,7 @@ bool EffectVehicle::Tick() void EffectVehicle::UpdateDeltaXY() { - this->x_offs = 0; - this->y_offs = 0; - this->x_extent = 1; - this->y_extent = 1; - this->z_extent = 1; + this->bounds = {{}, {1, 1, 1}, {}}; } /** diff --git a/src/elrail.cpp b/src/elrail.cpp index 7b8f5208d0..0d69ded928 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -248,27 +248,12 @@ static int GetPCPElevation(TileIndex tile, DiagDirection pcp_pos) */ void DrawRailCatenaryOnTunnel(const TileInfo *ti) { - /* xmin, ymin, xmax + 1, ymax + 1 of BB */ - static const int tunnel_wire_bb[4][4] = { - { 0, 1, 16, 15 }, // NE - { 1, 0, 15, 16 }, // SE - { 0, 1, 16, 15 }, // SW - { 1, 0, 15, 16 }, // NW - }; - DiagDirection dir = GetTunnelBridgeDirection(ti->tile); SpriteID wire_base = GetWireBase(ti->tile); - const SortableSpriteStruct *sss = &_rail_catenary_sprite_data_tunnel[dir]; - const int *bb_data = tunnel_wire_bb[dir]; - AddSortableSpriteToDraw( - wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, - bb_data[2] - sss->x_offset, bb_data[3] - sss->y_offset, BB_Z_SEPARATOR - sss->z_offset + 1, - GetTilePixelZ(ti->tile) + sss->z_offset, - IsTransparencySet(TO_CATENARY), - bb_data[0] - sss->x_offset, bb_data[1] - sss->y_offset, BB_Z_SEPARATOR - sss->z_offset - ); + const SortableSpriteStruct &sss = _rail_catenary_sprite_data_tunnel[dir]; + AddSortableSpriteToDraw(wire_base + sss.image_offset, PAL_NONE, ti->x, ti->y, GetTilePixelZ(ti->tile), sss, IsTransparencySet(TO_CATENARY)); } /** @@ -440,8 +425,8 @@ static void DrawRailCatenaryRailway(const TileInfo *ti) continue; // No neighbour, go looking for a better position } - AddSortableSpriteToDraw(pylon_base + _pylon_sprites[temp], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, - elevation, IsTransparencySet(TO_CATENARY), -1, -1); + AddSortableSpriteToDraw(pylon_base + _pylon_sprites[temp], PAL_NONE, x, y, elevation, + {{-1, -1, 0}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {1, 1, 0}}, IsTransparencySet(TO_CATENARY)); break; // We already have drawn a pylon, bail out } @@ -482,7 +467,7 @@ static void DrawRailCatenaryRailway(const TileInfo *ti) assert(pcp_config != 0); // We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that) assert(!IsSteepSlope(tileh[TS_HOME])); - const SortableSpriteStruct *sss = &_rail_catenary_sprite_data[_rail_wires[tileh_selector][t][pcp_config]]; + const SortableSpriteStruct &sss = _rail_catenary_sprite_data[_rail_wires[tileh_selector][t][pcp_config]]; /* * The "wire"-sprite position is inside the tile, i.e. 0 <= sss->?_offset < TILE_SIZE. @@ -490,9 +475,8 @@ static void DrawRailCatenaryRailway(const TileInfo *ti) * Also note that the result of GetSlopePixelZ() is very special for bridge-ramps, so we round the result up or * down to the nearest full height change. */ - AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, - sss->x_size, sss->y_size, sss->z_size, (GetSlopePixelZ(ti->x + sss->x_offset, ti->y + sss->y_offset, true) + 4) / 8 * 8 + sss->z_offset, - IsTransparencySet(TO_CATENARY)); + int z = (GetSlopePixelZ(ti->x + sss.origin.x, ti->y + sss.origin.y, true) + 4) / 8 * 8; + AddSortableSpriteToDraw(wire_base + sss.image_offset, PAL_NONE, ti->x, ti->y, z, sss, IsTransparencySet(TO_CATENARY)); } } @@ -530,13 +514,12 @@ void DrawRailCatenaryOnBridge(const TileInfo *ti) SpriteID wire_base = GetWireBase(end, TCX_ON_BRIDGE); - AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, - sss->x_size, sss->y_size, sss->z_size, height + sss->z_offset, - IsTransparencySet(TO_CATENARY) - ); + AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x, ti->y, height, *sss, IsTransparencySet(TO_CATENARY)); SpriteID pylon_base = GetPylonBase(end, TCX_ON_BRIDGE); + static constexpr SpriteBounds pylon_bounds{{-1, -1, 0}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {1, 1, 0}}; + /* Finished with wires, draw pylons * every other tile needs a pylon on the northern end */ if (num % 2) { @@ -545,7 +528,7 @@ void DrawRailCatenaryOnBridge(const TileInfo *ti) if (HasBit(tlg, (axis == AXIS_X ? 0 : 1))) ppp_pos = ReverseDir(ppp_pos); uint x = ti->x + _x_pcp_offsets[pcp_pos] + _x_ppp_offsets[ppp_pos]; uint y = ti->y + _y_pcp_offsets[pcp_pos] + _y_ppp_offsets[ppp_pos]; - AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, height, IsTransparencySet(TO_CATENARY), -1, -1); + AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, height, pylon_bounds, IsTransparencySet(TO_CATENARY)); } /* need a pylon on the southern end of the bridge */ @@ -555,7 +538,7 @@ void DrawRailCatenaryOnBridge(const TileInfo *ti) if (HasBit(tlg, (axis == AXIS_X ? 0 : 1))) ppp_pos = ReverseDir(ppp_pos); uint x = ti->x + _x_pcp_offsets[pcp_pos] + _x_ppp_offsets[ppp_pos]; uint y = ti->y + _y_pcp_offsets[pcp_pos] + _y_ppp_offsets[ppp_pos]; - AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, height, IsTransparencySet(TO_CATENARY), -1, -1); + AddSortableSpriteToDraw(pylon_base + _pylon_sprites[ppp_pos], PAL_NONE, x, y, height, pylon_bounds, IsTransparencySet(TO_CATENARY)); } } @@ -569,17 +552,12 @@ void DrawRailCatenary(const TileInfo *ti) switch (GetTileType(ti->tile)) { case MP_RAILWAY: if (IsRailDepot(ti->tile)) { - const SortableSpriteStruct *sss = &_rail_catenary_sprite_data_depot[GetRailDepotDirection(ti->tile)]; + const SortableSpriteStruct &sss = _rail_catenary_sprite_data_depot[GetRailDepotDirection(ti->tile)]; SpriteID wire_base = GetWireBase(ti->tile); /* This wire is not visible with the default depot sprites */ - AddSortableSpriteToDraw( - wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, - sss->x_size, sss->y_size, sss->z_size, - GetTileMaxPixelZ(ti->tile) + sss->z_offset, - IsTransparencySet(TO_CATENARY) - ); + AddSortableSpriteToDraw(wire_base + sss.image_offset, PAL_NONE, ti->x, ti->y, GetTileMaxPixelZ(ti->tile), sss, IsTransparencySet(TO_CATENARY)); return; } break; diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 18f4d94a48..f01aafc8d6 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -374,13 +374,7 @@ static void DrawTile_Industry(TileInfo *ti) image = dits->building.sprite; if (image != 0) { AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GetColourPalette(ind->random_colour)), - ti->x + dits->subtile_x, - ti->y + dits->subtile_y, - dits->width, - dits->height, - dits->dz, - ti->z, - IsTransparencySet(TO_INDUSTRIES)); + *ti, *dits, IsTransparencySet(TO_INDUSTRIES)); if (IsTransparencySet(TO_INDUSTRIES)) return; } diff --git a/src/landscape.cpp b/src/landscape.cpp index 5db1c9177a..39d5a563bb 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -450,9 +450,8 @@ void DrawFoundation(TileInfo *ti, Foundation f) if (IsSteepSlope(ti->tileh)) { if (!IsNonContinuousFoundation(f)) { /* Lower part of foundation */ - AddSortableSpriteToDraw( - leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z - ); + static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}}; + AddSortableSpriteToDraw(leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, *ti, bounds); } Corner highest_corner = GetHighestSlopeCorner(ti->tileh); @@ -462,24 +461,25 @@ void DrawFoundation(TileInfo *ti, Foundation f) /* inclined foundation */ uint8_t inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0); - AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y, - f == FOUNDATION_INCLINED_X ? TILE_SIZE : 1, - f == FOUNDATION_INCLINED_Y ? TILE_SIZE : 1, - TILE_HEIGHT, ti->z - ); + SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}}; + if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE; + if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE; + AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds); OffsetGroundSprite(0, 0); } else if (IsLeveledFoundation(f)) { - AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z - TILE_HEIGHT); + static constexpr SpriteBounds bounds{{0, 0, -(int)TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}}; + AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, *ti, bounds); OffsetGroundSprite(0, -(int)TILE_HEIGHT); } else if (f == FOUNDATION_STEEP_LOWER) { /* one corner raised */ OffsetGroundSprite(0, -(int)TILE_HEIGHT); } else { /* halftile foundation */ - int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? TILE_SIZE / 2 : 0); - int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? TILE_SIZE / 2 : 0); + int8_t x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? TILE_SIZE / 2 : 0); + int8_t y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? TILE_SIZE / 2 : 0); - AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1, ti->z + TILE_HEIGHT); + SpriteBounds bounds{{x_bb, y_bb, TILE_HEIGHT}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}}; + AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, *ti, bounds); /* Reposition ground sprite back to original position after bounding box change above. This is similar to * RemapCoords() but without zoom scaling. */ Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb}; @@ -488,15 +488,17 @@ void DrawFoundation(TileInfo *ti, Foundation f) } else { if (IsLeveledFoundation(f)) { /* leveled foundation */ - AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z); + static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}}; + AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, *ti, bounds); OffsetGroundSprite(0, -(int)TILE_HEIGHT); } else if (IsNonContinuousFoundation(f)) { /* halftile foundation */ Corner halftile_corner = GetHalftileFoundationCorner(f); - int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? TILE_SIZE / 2 : 0); - int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? TILE_SIZE / 2 : 0); + int8_t x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? TILE_SIZE / 2 : 0); + int8_t y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? TILE_SIZE / 2 : 0); - AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1, ti->z); + SpriteBounds bounds{{x_bb, y_bb, 0}, {TILE_SIZE / 2, TILE_SIZE / 2, TILE_HEIGHT - 1}, {}}; + AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, *ti, bounds); /* Reposition ground sprite back to original position after bounding box change above. This is similar to * RemapCoords() but without zoom scaling. */ Point pt = {(y_bb - x_bb) * 2, y_bb + x_bb}; @@ -511,17 +513,17 @@ void DrawFoundation(TileInfo *ti, Foundation f) /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */ spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0); } - AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1, ti->z); + static constexpr SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT - 1}, {}}; + AddSortableSpriteToDraw(spr, PAL_NONE, *ti, bounds); OffsetGroundSprite(0, 0); } else { /* inclined foundation */ uint8_t inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0); - AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y, - f == FOUNDATION_INCLINED_X ? TILE_SIZE : 1, - f == FOUNDATION_INCLINED_Y ? TILE_SIZE : 1, - TILE_HEIGHT, ti->z - ); + SpriteBounds bounds{{}, {1, 1, TILE_HEIGHT}, {}}; + if (f == FOUNDATION_INCLINED_X) bounds.extent.x = TILE_SIZE; + if (f == FOUNDATION_INCLINED_Y) bounds.extent.y = TILE_SIZE; + AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, *ti, bounds); OffsetGroundSprite(0, 0); } ti->z += ApplyPixelFoundationToSlope(f, ti->tileh); diff --git a/src/newgrf/newgrf_act0_stations.cpp b/src/newgrf/newgrf_act0_stations.cpp index e4c0a4bfc1..d5336665ea 100644 --- a/src/newgrf/newgrf_act0_stations.cpp +++ b/src/newgrf/newgrf_act0_stations.cpp @@ -90,12 +90,12 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR /* no relative bounding box support */ DrawTileSeqStruct &dtss = tmp_layout.emplace_back(); - dtss.delta_x = delta_x; - dtss.delta_y = buf.ReadByte(); - dtss.delta_z = buf.ReadByte(); - dtss.size_x = buf.ReadByte(); - dtss.size_y = buf.ReadByte(); - dtss.size_z = buf.ReadByte(); + dtss.origin.x = delta_x; + dtss.origin.y = buf.ReadByte(); + dtss.origin.z = buf.ReadByte(); + dtss.extent.x = buf.ReadByte(); + dtss.extent.y = buf.ReadByte(); + dtss.extent.z = buf.ReadByte(); ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss.image); /* On error, bail out immediately. Temporary GRF data was already freed */ diff --git a/src/newgrf/newgrf_act2.cpp b/src/newgrf/newgrf_act2.cpp index bb26fc9215..9f99cdf4ee 100644 --- a/src/newgrf/newgrf_act2.cpp +++ b/src/newgrf/newgrf_act2.cpp @@ -207,15 +207,15 @@ bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_s return true; } - seq->delta_x = buf.ReadByte(); - seq->delta_y = buf.ReadByte(); + seq->origin.x = buf.ReadByte(); + seq->origin.y = buf.ReadByte(); - if (!no_z_position) seq->delta_z = buf.ReadByte(); + if (!no_z_position) seq->origin.z = buf.ReadByte(); if (seq->IsParentSprite()) { - seq->size_x = buf.ReadByte(); - seq->size_y = buf.ReadByte(); - seq->size_z = buf.ReadByte(); + seq->extent.x = buf.ReadByte(); + seq->extent.y = buf.ReadByte(); + seq->extent.z = buf.ReadByte(); } ReadSpriteLayoutRegisters(buf, flags, seq->IsParentSprite(), dts, i + 1); diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index 98c9d434f1..61d12e9948 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -609,7 +609,7 @@ SpriteLayoutProcessor::SpriteLayoutProcessor(const NewGRFSpriteLayout &raw_layou * Also include the groundsprite into the sequence for easier processing. */ DrawTileSeqStruct © = this->result_seq.emplace_back(); copy.image = this->raw_layout->ground; - copy.delta_z = static_cast(0x80); + copy.origin.z = static_cast(0x80); this->result_seq.insert(this->result_seq.end(), this->raw_layout->seq.begin(), this->raw_layout->seq.end()); @@ -692,13 +692,13 @@ void SpriteLayoutProcessor::ProcessRegisters(const ResolverObject &object, uint8 if (result.IsParentSprite()) { if (flags & TLF_BB_XY_OFFSET) { - result.delta_x += object.GetRegister(regs->delta.parent[0]); - result.delta_y += object.GetRegister(regs->delta.parent[1]); + result.origin.x += object.GetRegister(regs->delta.parent[0]); + result.origin.y += object.GetRegister(regs->delta.parent[1]); } - if (flags & TLF_BB_Z_OFFSET) result.delta_z += object.GetRegister(regs->delta.parent[2]); + if (flags & TLF_BB_Z_OFFSET) result.origin.z += object.GetRegister(regs->delta.parent[2]); } else { - if (flags & TLF_CHILD_X_OFFSET) result.delta_x += object.GetRegister(regs->delta.child[0]); - if (flags & TLF_CHILD_Y_OFFSET) result.delta_y += object.GetRegister(regs->delta.child[1]); + if (flags & TLF_CHILD_X_OFFSET) result.origin.x += object.GetRegister(regs->delta.child[0]); + if (flags & TLF_CHILD_Y_OFFSET) result.origin.y += object.GetRegister(regs->delta.child[1]); } } } diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 0d3c7554a0..15693c90f0 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -476,13 +476,7 @@ static void DrawTile_Object(TileInfo *ti) if (!IsInvisibilitySet(TO_STRUCTURES)) { for (const DrawTileSeqStruct &dtss : dts->GetSequence()) { - AddSortableSpriteToDraw( - dtss.image.sprite, palette, - ti->x + dtss.delta_x, ti->y + dtss.delta_y, - dtss.size_x, dtss.size_y, - dtss.size_z, ti->z + dtss.delta_z, - IsTransparencySet(TO_STRUCTURES) - ); + AddSortableSpriteToDraw(dtss.image.sprite, palette, *ti, dtss, IsTransparencySet(TO_STRUCTURES)); } } } else { diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 35ed96ade6..0762099ea4 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1899,7 +1899,7 @@ static void DrawSingleSignal(TileIndex tile, const RailTypeInfo *rti, Track trac sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0); } - AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track)); + AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, GetSaveSlopeZ(x, y, track), {{}, {1, 1, BB_HEIGHT_UNDER_BRIDGE}, {}}); } static uint32_t _drawtile_track_palette; @@ -1907,12 +1907,11 @@ static uint32_t _drawtile_track_palette; /** Offsets for drawing fences */ -struct FenceOffset { - Corner height_ref; //!< Corner to use height offset from. - int x_offs; //!< Bounding box X offset. - int y_offs; //!< Bounding box Y offset. - int x_size; //!< Bounding box X size. - int y_size; //!< Bounding box Y size. +struct FenceOffset : SpriteBounds { + Corner height_ref; ///< Corner to use height offset from. + + constexpr FenceOffset(Corner height_ref, int8_t origin_x, int8_t origin_y, uint8_t extent_x, uint8_t extent_y) : + SpriteBounds({origin_x, origin_y, 0}, {extent_x, extent_y, 4}, {}), height_ref(height_ref) {} }; /** Offsets for drawing fences */ @@ -1948,12 +1947,7 @@ static void DrawTrackFence(const TileInfo *ti, SpriteID base_image, uint num_spr if (_fence_offsets[rfo].height_ref != CORNER_INVALID) { z += GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), _fence_offsets[rfo].height_ref); } - AddSortableSpriteToDraw(base_image + (rfo % num_sprites), _drawtile_track_palette, - ti->x + _fence_offsets[rfo].x_offs, - ti->y + _fence_offsets[rfo].y_offs, - _fence_offsets[rfo].x_size, - _fence_offsets[rfo].y_size, - 4, z); + AddSortableSpriteToDraw(base_image + (rfo % num_sprites), _drawtile_track_palette, ti->x, ti->y, z, _fence_offsets[rfo]); } /** diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 07d8238a57..49c2e9f69d 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1418,7 +1418,7 @@ void DrawRoadTypeCatenary(const TileInfo *ti, RoadType rt, RoadBits rb) * For tiles with OWNER_TOWN or OWNER_NONE, recolour CC to grey as a neutral colour. */ Owner owner = GetRoadOwner(ti->tile, GetRoadTramType(rt)); PaletteID pal = (owner == OWNER_NONE || owner == OWNER_TOWN ? GetColourPalette(COLOUR_GREY) : GetCompanyPalette(owner)); - int z_wires = (ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT) + BB_HEIGHT_UNDER_BRIDGE; + uint8_t z_wires = (ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT) + BB_HEIGHT_UNDER_BRIDGE; if (back != 0) { /* The "back" sprite contains the west, north and east pillars. * We cut the sprite at 3/8 of the west/east edges to create 3 sprites. @@ -1427,13 +1427,16 @@ void DrawRoadTypeCatenary(const TileInfo *ti, RoadType rt, RoadBits rb) static const SubSprite west = { -INF, -INF, -12, INF }; static const SubSprite north = { -12, -INF, 12, INF }; static const SubSprite east = { 12, -INF, INF, INF }; - AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 16, 1, z_wires, ti->z, IsTransparencySet(TO_CATENARY), 15, 0, GetSlopePixelZInCorner(ti->tileh, CORNER_W), &west); - AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 1, 1, z_wires, ti->z, IsTransparencySet(TO_CATENARY), 0, 0, GetSlopePixelZInCorner(ti->tileh, CORNER_N), &north); - AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 1, 16, z_wires, ti->z, IsTransparencySet(TO_CATENARY), 0, 15, GetSlopePixelZInCorner(ti->tileh, CORNER_E), &east); + int8_t west_z = GetSlopePixelZInCorner(ti->tileh, CORNER_W); + int8_t north_z = GetSlopePixelZInCorner(ti->tileh, CORNER_N); + int8_t east_z = GetSlopePixelZInCorner(ti->tileh, CORNER_E); + AddSortableSpriteToDraw(back, pal, *ti, {{15, 0, west_z}, {1, 1, z_wires}, {-15, 0, static_cast(-west_z)}}, IsTransparencySet(TO_CATENARY), &west); + AddSortableSpriteToDraw(back, pal, *ti, {{0, 0, north_z}, {1, 1, z_wires}, {0, 0, static_cast(-north_z)}}, IsTransparencySet(TO_CATENARY), &north); + AddSortableSpriteToDraw(back, pal, *ti, {{0, 15, east_z}, {1, 1, z_wires}, {0, -15, static_cast(-east_z)}}, IsTransparencySet(TO_CATENARY), &east); } if (front != 0) { /* Draw the "front" sprite (containing south pillar and wires) at a Z height that is both above the vehicles and above the "back" pillars. */ - AddSortableSpriteToDraw(front, pal, ti->x, ti->y, 16, 16, z_wires + 1, ti->z, IsTransparencySet(TO_CATENARY), 0, 0, z_wires); + AddSortableSpriteToDraw(front, pal, *ti, {{0, 0, static_cast(z_wires)}, {TILE_SIZE, TILE_SIZE, 1}, {0, 0, static_cast(-z_wires)}}, IsTransparencySet(TO_CATENARY)); } } @@ -1487,13 +1490,13 @@ void DrawRoadCatenary(const TileInfo *ti) * @param h the height of the sprite to draw * @param transparent whether the sprite should be transparent (used for roadside trees) */ -static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int dx, int dy, int h, bool transparent) +static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int8_t dx, int8_t dy, uint8_t h, bool transparent) { int x = ti->x | dx; int y = ti->y | dy; int z = ti->z; if (ti->tileh != SLOPE_FLAT) z = GetSlopePixelZ(x, y); - AddSortableSpriteToDraw(img, PAL_NONE, x, y, 2, 2, h, z, transparent); + AddSortableSpriteToDraw(img, PAL_NONE, ti->x, ti->y, z, {{dx, dy, 0}, {2, 2, h}, {}}, transparent); } /** diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index e3564f0991..bb19487592 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -405,29 +405,56 @@ void RoadVehicle::MarkDirty() void RoadVehicle::UpdateDeltaXY() { - static const int8_t _delta_xy_table[8][10] = { - /* y_extent, x_extent, y_offs, x_offs, y_bb_offs, x_bb_offs, y_extent_shorten, x_extent_shorten, y_bb_offs_shorten, x_bb_offs_shorten */ - {3, 3, -1, -1, 0, 0, -1, -1, -1, -1}, // N - {3, 7, -1, -3, 0, -1, 0, -1, 0, 0}, // NE - {3, 3, -1, -1, 0, 0, 1, -1, 1, -1}, // E - {7, 3, -3, -1, -1, 0, 0, 0, 1, 0}, // SE - {3, 3, -1, -1, 0, 0, 1, 1, 1, 1}, // S - {3, 7, -1, -3, 0, -1, 0, 0, 0, 1}, // SW - {3, 3, -1, -1, 0, 0, -1, 1, -1, 1}, // W - {7, 3, -3, -1, -1, 0, -1, 0, 0, 0}, // NW - }; + /* Set common defaults. */ + this->bounds = {{-1, -1, 0}, {3, 3, 6}, {}}; - int shorten = VEHICLE_LENGTH - this->gcache.cached_veh_length; - if (!IsDiagonalDirection(this->direction)) shorten >>= 1; + if (!IsDiagonalDirection(this->direction)) { + static const Point _sign_table[] = { + /* x, y */ + {-1, -1}, // DIR_N + {-1, 1}, // DIR_E + { 1, 1}, // DIR_S + { 1, -1}, // DIR_W + }; - const int8_t *bb = _delta_xy_table[this->direction]; - this->x_bb_offs = bb[5] + bb[9] * shorten; - this->y_bb_offs = bb[4] + bb[8] * shorten;; - this->x_offs = bb[3]; - this->y_offs = bb[2]; - this->x_extent = bb[1] + bb[7] * shorten; - this->y_extent = bb[0] + bb[6] * shorten; - this->z_extent = 6; + int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2; + + /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */ + this->bounds.offset.x -= half_shorten * _sign_table[DirToDiagDir(this->direction)].x; + this->bounds.offset.y -= half_shorten * _sign_table[DirToDiagDir(this->direction)].y; + } else { + /* Unlike trains, road vehicles do not have their offsets moved to the centre. */ + switch (this->direction) { + /* Shorten southern corner of the bounding box according the vehicle length. */ + case DIR_NE: + this->bounds.origin.x = -3; + this->bounds.extent.x = this->gcache.cached_veh_length; + this->bounds.offset.x = 1; + break; + + case DIR_NW: + this->bounds.origin.y = -3; + this->bounds.extent.y = this->gcache.cached_veh_length; + this->bounds.offset.y = 1; + break; + + /* Move northern corner of the bounding box down according to vehicle length. */ + case DIR_SW: + this->bounds.origin.x = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length); + this->bounds.extent.x = this->gcache.cached_veh_length; + this->bounds.offset.x = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length); + break; + + case DIR_SE: + this->bounds.origin.y = -3 + (VEHICLE_LENGTH - this->gcache.cached_veh_length); + this->bounds.extent.y = this->gcache.cached_veh_length; + this->bounds.offset.y = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length); + break; + + default: + NOT_REACHED(); + } + } } /** diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 956d730252..434f852763 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -330,32 +330,26 @@ TileIndex Ship::GetOrderStationLocation(StationID station) void Ship::UpdateDeltaXY() { - static const int8_t _delta_xy_table[8][4] = { - /* y_extent, x_extent, y_offs, x_offs */ - { 6, 6, -3, -3}, // N - { 6, 32, -3, -16}, // NE - { 6, 6, -3, -3}, // E - {32, 6, -16, -3}, // SE - { 6, 6, -3, -3}, // S - { 6, 32, -3, -16}, // SW - { 6, 6, -3, -3}, // W - {32, 6, -16, -3}, // NW + static constexpr SpriteBounds ship_bounds[DIR_END] = { + {{ -3, -3, 0}, { 6, 6, 6}, {}}, // N + {{-16, -3, 0}, {32, 6, 6}, {}}, // NE + {{ -3, -3, 0}, { 6, 6, 6}, {}}, // E + {{ -3, -16, 0}, { 6, 32, 6}, {}}, // SE + {{ -3, -3, 0}, { 6, 6, 6}, {}}, // S + {{-16, -3, 0}, {32, 6, 6}, {}}, // SW + {{ -3, -3, 0}, { 6, 6, 6}, {}}, // W + {{ -3, -16, 0}, { 6, 32, 6}, {}}, // NW }; - const int8_t *bb = _delta_xy_table[this->rotation]; - this->x_offs = bb[3]; - this->y_offs = bb[2]; - this->x_extent = bb[1]; - this->y_extent = bb[0]; - this->z_extent = 6; + this->bounds = ship_bounds[this->rotation]; if (this->direction != this->rotation) { /* If we are rotating, then it is possible the ship was moved to its next position. In that * case, because we are still showing the old direction, the ship will appear to glitch sideways * slightly. We can work around this by applying an additional offset to make the ship appear * where it was before it moved. */ - this->x_offs -= this->x_pos - this->rotation_x_pos; - this->y_offs -= this->y_pos - this->rotation_y_pos; + this->bounds.origin.x -= this->x_pos - this->rotation_x_pos; + this->bounds.origin.y -= this->y_pos - this->rotation_y_pos; } } diff --git a/src/sprite.cpp b/src/sprite.cpp index 47384e46e0..d030b73c7d 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -54,16 +54,11 @@ void DrawCommonTileSeq(const TileInfo *ti, const DrawTileSprites *dts, Transpare if (dtss.IsParentSprite()) { parent_sprite_encountered = true; - AddSortableSpriteToDraw( - image, pal, - ti->x + dtss.delta_x, ti->y + dtss.delta_y, - dtss.size_x, dtss.size_y, - dtss.size_z, ti->z + dtss.delta_z, - !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to) + AddSortableSpriteToDraw(image, pal, *ti, dtss, !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to) ); } else { - int offs_x = child_offset_is_unsigned ? static_cast(dtss.delta_x) : dtss.delta_x; - int offs_y = child_offset_is_unsigned ? static_cast(dtss.delta_y) : dtss.delta_y; + int offs_x = child_offset_is_unsigned ? static_cast(dtss.origin.x) : dtss.origin.x; + int offs_y = child_offset_is_unsigned ? static_cast(dtss.origin.y) : dtss.origin.y; bool transparent = !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to); if (parent_sprite_encountered) { AddChildSpriteScreen(image, pal, offs_x, offs_y, transparent); @@ -114,15 +109,15 @@ void DrawCommonTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32_t or pal = SpriteLayoutPaletteTransform(image, pal, default_palette); if (dtss.IsParentSprite()) { - Point pt = RemapCoords(dtss.delta_x, dtss.delta_y, dtss.delta_z); + Point pt = RemapCoords(dtss.origin.x, dtss.origin.y, dtss.origin.z); DrawSprite(image, pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y)); const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal); child_offset.x = UnScaleGUI(pt.x + spr->x_offs); child_offset.y = UnScaleGUI(pt.y + spr->y_offs); } else { - int offs_x = child_offset_is_unsigned ? static_cast(dtss.delta_x) : dtss.delta_x; - int offs_y = child_offset_is_unsigned ? static_cast(dtss.delta_y) : dtss.delta_y; + int offs_x = child_offset_is_unsigned ? static_cast(dtss.origin.x) : dtss.origin.x; + int offs_y = child_offset_is_unsigned ? static_cast(dtss.origin.y) : dtss.origin.y; DrawSprite(image, pal, x + child_offset.x + ScaleSpriteTrad(offs_x), y + child_offset.y + ScaleSpriteTrad(offs_y)); } } diff --git a/src/sprite.h b/src/sprite.h index d02ffcad77..e7c0226303 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -10,28 +10,33 @@ #ifndef SPRITE_H #define SPRITE_H +#include "core/geometry_type.hpp" #include "transparency.h" #include "table/sprites.h" +struct SpriteBounds { + PointXyz origin; ///< Position of northern corner within tile. + PointXyz extent; ///< Size of bounding box. + PointXyz offset; ///< Relative position of sprite from bounding box. +}; + /* The following describes bunch of sprites to be drawn together in a single 3D * bounding box. Used especially for various multi-sprite buildings (like * depots or stations): */ /** A tile child sprite and palette to draw for stations etc, with 3D bounding box */ -struct DrawTileSeqStruct { - int8_t delta_x = 0; - int8_t delta_y = 0; - int8_t delta_z = 0; ///< \c 0x80 identifies child sprites - uint8_t size_x = 0; - uint8_t size_y = 0; - uint8_t size_z = 0; - PalSpriteID image{}; +struct DrawTileSeqStruct : SpriteBounds { + PalSpriteID image; + + constexpr DrawTileSeqStruct() = default; + constexpr DrawTileSeqStruct(int8_t origin_x, int8_t origin_y, int8_t origin_z, uint8_t extent_x, uint8_t extent_y, uint8_t extent_z, PalSpriteID image) : + SpriteBounds({origin_x, origin_y, origin_z}, {extent_x, extent_y, extent_z}, {}), image(image) {} /** Check whether this is a parent sprite with a boundingbox. */ - bool IsParentSprite() const + inline bool IsParentSprite() const { - return (uint8_t)this->delta_z != 0x80; + return static_cast(this->origin.z) != 0x80; } }; @@ -69,14 +74,9 @@ struct DrawTileSpriteSpan : DrawTileSprites { * This structure is the same for both Industries and Houses. * Buildings here reference a general type of construction */ -struct DrawBuildingsTileStruct { +struct DrawBuildingsTileStruct : SpriteBounds { PalSpriteID ground; PalSpriteID building; - uint8_t subtile_x; - uint8_t subtile_y; - uint8_t width; - uint8_t height; - uint8_t dz; uint8_t draw_proc; // this allows to specify a special drawing procedure. }; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index a28153602f..b93533191a 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3184,7 +3184,7 @@ static void DrawTile_Station(TileInfo *ti) 7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN }; - AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z); + 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. */ @@ -3218,7 +3218,7 @@ static void DrawTile_Station(TileInfo *ti) StartSpriteCombine(); for (int i = 0; i < 8; i++) { if (HasBit(parts, i)) { - AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z); + AddSortableSpriteToDraw(image + i, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, 7}, {}}); } } EndSpriteCombine(); diff --git a/src/table/elrail_data.h b/src/table/elrail_data.h index 5be264f008..b439c0faa3 100644 --- a/src/table/elrail_data.h +++ b/src/table/elrail_data.h @@ -313,14 +313,12 @@ enum WireSpriteOffset : uint8_t { WSO_ENTRANCE_SE, }; -struct SortableSpriteStruct { +struct SortableSpriteStruct : SpriteBounds { uint8_t image_offset; - int8_t x_offset; - int8_t y_offset; - int8_t x_size; - int8_t y_size; - int8_t z_size; - int8_t z_offset; + + constexpr SortableSpriteStruct(uint8_t image_offset, const SpriteBounds &bounds) : SpriteBounds(bounds), image_offset(image_offset) {} + constexpr SortableSpriteStruct(uint8_t image_offset, int8_t x_offset, int8_t y_offset, uint8_t x_size, uint8_t y_size, uint8_t z_size, int8_t z_offset) : + SpriteBounds({x_offset, y_offset, z_offset}, {x_size, y_size, z_size}, {}), image_offset(image_offset) {} }; /** Distance between wire and rail */ @@ -398,11 +396,17 @@ static const SortableSpriteStruct _rail_catenary_sprite_data_depot[] = { { WSO_ENTRANCE_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW depot exit }; +/** + * In tunnelheads, the bounding box for wires covers nearly the full tile, and is lowered a bit. + * ELRAIL_TUNNEL_OFFSET is the difference between visual position and bounding box. + */ +static const int8_t ELRAIL_TUNNEL_OFFSET = ELRAIL_ELEVATION - BB_Z_SEPARATOR; + static const SortableSpriteStruct _rail_catenary_sprite_data_tunnel[] = { - { WSO_ENTRANCE_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE tunnel (SW facing exit) - { WSO_ENTRANCE_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! Wire for SE tunnel (NW facing exit) - { WSO_ENTRANCE_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW tunnel (NE facing exit) - { WSO_ENTRANCE_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW tunnel (SE facing exit) + { WSO_ENTRANCE_SW, {{0, 0, BB_Z_SEPARATOR}, {16, 15, 1}, {0, 7, ELRAIL_TUNNEL_OFFSET}} }, //! Wire for NE tunnel (SW facing exit) + { WSO_ENTRANCE_NW, {{0, 0, BB_Z_SEPARATOR}, {15, 16, 1}, {7, 0, ELRAIL_TUNNEL_OFFSET}} }, //! Wire for SE tunnel (NW facing exit) + { WSO_ENTRANCE_NE, {{0, 0, BB_Z_SEPARATOR}, {16, 15, 1}, {0, 7, ELRAIL_TUNNEL_OFFSET}} }, //! Wire for SW tunnel (NE facing exit) + { WSO_ENTRANCE_SE, {{0, 0, BB_Z_SEPARATOR}, {15, 16, 1}, {7, 0, ELRAIL_TUNNEL_OFFSET}} } //! Wire for NW tunnel (SE facing exit) }; diff --git a/src/table/industry_land.h b/src/table/industry_land.h index a8cae114c7..35b9d0b8e9 100644 --- a/src/table/industry_land.h +++ b/src/table/industry_land.h @@ -37,15 +37,15 @@ struct DrawIndustryCoordinates { * @param p1 palette ID of ground sprite * @param s2 sprite ID of building sprite * @param p2 palette ID of building sprite - * @param sx coordinate x of the sprite - * @param sy coordinate y of the sprite - * @param w width of the sprite - * @param h height of the sprite - * @param dz virtual height of the sprite + * @param dx The x-position of the sprite within the tile. + * @param dy the y-position of the sprite within the tile. + * @param sx the x-extent of the sprite. + * @param sy the y-extent of the sprite. + * @param sz the z-extent of the sprite. * @param p this allows to specify a special drawing procedure. * @see DrawBuildingsTileStruct */ -#define M(s1, p1, s2, p2, sx, sy, w, h, dz, p) { { s1, p1 }, { s2, p2 }, sx, sy, w, h, dz, p } +#define M(s1, p1, s2, p2, dx, dy, sx, sy, sz, p) { {{dx, dy, 0}, {sx, sy, sz}, {}}, { s1, p1 }, { s2, p2 }, p} /** Structure for industry tiles drawing */ static const DrawBuildingsTileStruct _industry_draw_tile_data[NEW_INDUSTRYTILEOFFSET * 4] = { diff --git a/src/table/town_land.h b/src/table/town_land.h index 12c9c0c1b5..9357c34c6c 100644 --- a/src/table/town_land.h +++ b/src/table/town_land.h @@ -13,15 +13,15 @@ * @param p1 The first sprite's palette of the building, mostly the ground sprite * @param s2 The second sprite of the building. * @param p2 The second sprite's palette of the building. - * @param sx The x-position of the sprite within the tile - * @param sy the y-position of the sprite within the tile - * @param w the width of the sprite - * @param h the height of the sprite - * @param dz the virtual height of the sprite + * @param dx The x-position of the sprite within the tile. + * @param dy the y-position of the sprite within the tile. + * @param sx the x-extent of the sprite. + * @param sy the y-extent of the sprite. + * @param sz the z-extent of the sprite. * @param p set to 1 if a lift is present () * @see DrawBuildingsTileStruct */ -#define M(s1, p1, s2, p2, sx, sy, w, h, dz, p) { { s1, p1 }, { s2, p2 }, sx, sy, w, h, dz, p} +#define M(s1, p1, s2, p2, dx, dy, sx, sy, sz, p) { {{dx, dy, 0}, {sx, sy, sz}, {}}, { s1, p1 }, { s2, p2 }, p} /** structure of houses graphics*/ static const DrawBuildingsTileStruct _town_draw_tile_data[] = { diff --git a/src/tile_cmd.h b/src/tile_cmd.h index ec3563887c..d5ecae6ae4 100644 --- a/src/tile_cmd.h +++ b/src/tile_cmd.h @@ -10,6 +10,7 @@ #ifndef TILE_CMD_H #define TILE_CMD_H +#include "core/geometry_type.hpp" #include "command_type.h" #include "vehicle_type.h" #include "cargo_type.h" @@ -26,12 +27,9 @@ enum class VehicleEnterTileState : uint8_t { using VehicleEnterTileStates = EnumBitSet; /** Tile information, used while rendering the tile */ -struct TileInfo { - int x; ///< X position of the tile in unit coordinates - int y; ///< Y position of the tile in unit coordinates +struct TileInfo : PointXyz { Slope tileh; ///< Slope of the tile TileIndex tile; ///< Tile index - int z; ///< Height }; /** Tile description for the 'land area information' tool */ diff --git a/src/tile_type.h b/src/tile_type.h index 45c948c3bf..498e5528c9 100644 --- a/src/tile_type.h +++ b/src/tile_type.h @@ -12,29 +12,29 @@ #include "core/strong_typedef_type.hpp" -static const uint TILE_SIZE = 16; ///< Tile size in world coordinates. -static const uint TILE_UNIT_MASK = TILE_SIZE - 1; ///< For masking in/out the inner-tile world coordinate units. -static const uint TILE_PIXELS = 32; ///< Pixel distance between tile columns/rows in #ZOOM_BASE. -static const uint TILE_HEIGHT = 8; ///< Height of a height level in world coordinate AND in pixels in #ZOOM_BASE. +static constexpr uint TILE_SIZE = 16; ///< Tile size in world coordinates. +static constexpr uint TILE_UNIT_MASK = TILE_SIZE - 1; ///< For masking in/out the inner-tile world coordinate units. +static constexpr uint TILE_PIXELS = 32; ///< Pixel distance between tile columns/rows in #ZOOM_BASE. +static constexpr uint TILE_HEIGHT = 8; ///< Height of a height level in world coordinate AND in pixels in #ZOOM_BASE. -static const uint MAX_BUILDING_PIXELS = 200; ///< Maximum height of a building in pixels in #ZOOM_BASE. (Also applies to "bridge buildings" on the bridge floor.) -static const int MAX_VEHICLE_PIXEL_X = 192; ///< Maximum width of a vehicle in pixels in #ZOOM_BASE. -static const int MAX_VEHICLE_PIXEL_Y = 96; ///< Maximum height of a vehicle in pixels in #ZOOM_BASE. +static constexpr uint MAX_BUILDING_PIXELS = 200; ///< Maximum height of a building in pixels in #ZOOM_BASE. (Also applies to "bridge buildings" on the bridge floor.) +static constexpr int MAX_VEHICLE_PIXEL_X = 192; ///< Maximum width of a vehicle in pixels in #ZOOM_BASE. +static constexpr int MAX_VEHICLE_PIXEL_Y = 96; ///< Maximum height of a vehicle in pixels in #ZOOM_BASE. -static const uint MAX_TILE_HEIGHT = 255; ///< Maximum allowed tile height +static constexpr uint MAX_TILE_HEIGHT = 255; ///< Maximum allowed tile height -static const uint MIN_HEIGHTMAP_HEIGHT = 1; ///< Lowest possible peak value for heightmap creation -static const uint MIN_CUSTOM_TERRAIN_TYPE = 1; ///< Lowest possible peak value for world generation +static constexpr uint MIN_HEIGHTMAP_HEIGHT = 1; ///< Lowest possible peak value for heightmap creation +static constexpr uint MIN_CUSTOM_TERRAIN_TYPE = 1; ///< Lowest possible peak value for world generation -static const uint MIN_MAP_HEIGHT_LIMIT = 15; ///< Lower bound of maximum allowed heightlevel (in the construction settings) -static const uint MAX_MAP_HEIGHT_LIMIT = MAX_TILE_HEIGHT; ///< Upper bound of maximum allowed heightlevel (in the construction settings) +static constexpr uint MIN_MAP_HEIGHT_LIMIT = 15; ///< Lower bound of maximum allowed heightlevel (in the construction settings) +static constexpr uint MAX_MAP_HEIGHT_LIMIT = MAX_TILE_HEIGHT; ///< Upper bound of maximum allowed heightlevel (in the construction settings) -static const uint MIN_SNOWLINE_HEIGHT = 2; ///< Minimum snowline height -static const uint DEF_SNOWLINE_HEIGHT = 10; ///< Default snowline height -static const uint MAX_SNOWLINE_HEIGHT = (MAX_TILE_HEIGHT - 2); ///< Maximum allowed snowline height +static constexpr uint MIN_SNOWLINE_HEIGHT = 2; ///< Minimum snowline height +static constexpr uint DEF_SNOWLINE_HEIGHT = 10; ///< Default snowline height +static constexpr uint MAX_SNOWLINE_HEIGHT = (MAX_TILE_HEIGHT - 2); ///< Maximum allowed snowline height -static const uint DEF_SNOW_COVERAGE = 40; ///< Default snow coverage. -static const uint DEF_DESERT_COVERAGE = 50; ///< Default desert coverage. +static constexpr uint DEF_SNOW_COVERAGE = 40; ///< Default snow coverage. +static constexpr uint DEF_DESERT_COVERAGE = 50; ///< Default desert coverage. /** diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index e9e72f1aec..21ba2a25a2 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -284,15 +284,7 @@ static void DrawTile_Town(TileInfo *ti) /* Add a house on top of the ground? */ SpriteID image = dcts->building.sprite; if (image != 0) { - AddSortableSpriteToDraw(image, dcts->building.pal, - ti->x + dcts->subtile_x, - ti->y + dcts->subtile_y, - dcts->width, - dcts->height, - dcts->dz, - ti->z, - IsTransparencySet(TO_HOUSES) - ); + AddSortableSpriteToDraw(image, dcts->building.pal, *ti, *dcts, IsTransparencySet(TO_HOUSES)); if (IsTransparencySet(TO_HOUSES)) return; } diff --git a/src/town_gui.cpp b/src/town_gui.cpp index e1f85e8024..e8904c03b4 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -1376,7 +1376,7 @@ void DrawHouseInGUI(int x, int y, HouseID house_id, int view) /* Add a house on top of the ground? */ if (dcts.building.sprite != 0) { - Point pt = RemapCoords(dcts.subtile_x, dcts.subtile_y, 0); + Point pt = RemapCoords(dcts.origin.x, dcts.origin.y, dcts.origin.z); DrawSprite(dcts.building.sprite, dcts.building.pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y)); } }; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 4d3428e9f5..a5532c34d9 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -1491,13 +1491,7 @@ CommandCost CmdSellRailWagon(DoCommandFlags flags, Vehicle *t, bool sell_chain, void Train::UpdateDeltaXY() { /* Set common defaults. */ - this->x_offs = -1; - this->y_offs = -1; - this->x_extent = 3; - this->y_extent = 3; - this->z_extent = 6; - this->x_bb_offs = 0; - this->y_bb_offs = 0; + this->bounds = {{-1, -1, 0}, {3, 3, 6}, {}}; /* Set if flipped and engine is NOT flagged with custom flip handling. */ int flipped = this->flags.Test(VehicleRailFlag::Flipped) && !EngInfo(this->engine_type)->misc_flags.Test(EngineMiscFlag::RailFlips); @@ -1508,50 +1502,47 @@ void Train::UpdateDeltaXY() if (flipped) dir = ReverseDir(dir); if (!IsDiagonalDirection(dir)) { - static const int _sign_table[] = - { + static const Point _sign_table[] = { /* x, y */ - -1, -1, // DIR_N - -1, 1, // DIR_E - 1, 1, // DIR_S - 1, -1, // DIR_W + {-1, -1}, // DIR_N + {-1, 1}, // DIR_E + { 1, 1}, // DIR_S + { 1, -1}, // DIR_W }; int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length + flipped) / 2; /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */ - this->x_offs -= half_shorten * _sign_table[dir]; - this->y_offs -= half_shorten * _sign_table[dir + 1]; - this->x_extent += this->x_bb_offs = half_shorten * _sign_table[dir]; - this->y_extent += this->y_bb_offs = half_shorten * _sign_table[dir + 1]; + this->bounds.offset.x -= half_shorten * _sign_table[DirToDiagDir(dir)].x; + this->bounds.offset.y -= half_shorten * _sign_table[DirToDiagDir(dir)].y; } else { switch (dir) { /* Shorten southern corner of the bounding box according the vehicle length * and center the bounding box on the vehicle. */ case DIR_NE: - this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs; - this->x_extent = this->gcache.cached_veh_length - 1; - this->x_bb_offs = -1; + this->bounds.origin.x = -(this->gcache.cached_veh_length + 1) / 2 + flip_offs; + this->bounds.extent.x = this->gcache.cached_veh_length; + this->bounds.offset.x = 1; break; case DIR_NW: - this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2 + flip_offs; - this->y_extent = this->gcache.cached_veh_length - 1; - this->y_bb_offs = -1; + this->bounds.origin.y = -(this->gcache.cached_veh_length + 1) / 2 + flip_offs; + this->bounds.extent.y = this->gcache.cached_veh_length; + this->bounds.offset.y = 1; break; /* Move northern corner of the bounding box down according to vehicle length * and center the bounding box on the vehicle. */ case DIR_SW: - this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs; - this->x_extent = VEHICLE_LENGTH - 1; - this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1; + this->bounds.origin.x = -(this->gcache.cached_veh_length) / 2 - flip_offs; + this->bounds.extent.x = this->gcache.cached_veh_length; + this->bounds.offset.x = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length); break; case DIR_SE: - this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH - flip_offs; - this->y_extent = VEHICLE_LENGTH - 1; - this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1; + this->bounds.origin.y = -(this->gcache.cached_veh_length) / 2 - flip_offs; + this->bounds.extent.y = this->gcache.cached_veh_length; + this->bounds.offset.y = 1 - (VEHICLE_LENGTH - this->gcache.cached_veh_length); break; default: diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index f188fc6d7b..ad7203dc00 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -635,7 +635,7 @@ CommandCost CmdPlantTree(DoCommandFlags flags, TileIndex tile, TileIndex start_t } struct TreeListEnt : PalSpriteID { - uint8_t x, y; + int8_t x, y; }; static void DrawTile_Trees(TileInfo *ti) @@ -699,7 +699,8 @@ static void DrawTile_Trees(TileInfo *ti) } } - AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x + te[mi].x, ti->y + te[mi].y, 16 - te[mi].x, 16 - te[mi].y, 0x30, z, IsTransparencySet(TO_TREES), -te[mi].x, -te[mi].y); + SpriteBounds bounds{{}, {TILE_SIZE, TILE_SIZE, 48}, {te[mi].x, te[mi].y, 0}}; + AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x, ti->y, z, bounds, IsTransparencySet(TO_TREES)); /* replace the removed one with the last one */ te[mi] = te[trees - 1]; diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 3a4e62ad1d..2e5be907c6 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1017,10 +1017,10 @@ static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlags flags) * @param h Bounding box size in Y direction * @param subsprite Optional subsprite for drawing halfpillars */ -static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, int w, int h, const SubSprite *subsprite) +static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite) { static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START; ///< Start offset of pillar wrt. bridge (downwards) - AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, w, h, BB_HEIGHT_UNDER_BRIDGE - PILLAR_Z_OFFSET, z, IsTransparencySet(TO_BRIDGES), 0, 0, -PILLAR_Z_OFFSET, subsprite); + AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, -PILLAR_Z_OFFSET}, {w, h, BB_HEIGHT_UNDER_BRIDGE}, {0, 0, PILLAR_Z_OFFSET}}, IsTransparencySet(TO_BRIDGES), subsprite); } /** @@ -1194,18 +1194,20 @@ static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int off } } - static const uint size_x[6] = { 1, 16, 16, 1, 16, 1 }; - static const uint size_y[6] = { 16, 1, 1, 16, 1, 16 }; - static const uint front_bb_offset_x[6] = { 15, 0, 0, 15, 0, 15 }; - static const uint front_bb_offset_y[6] = { 0, 15, 15, 0, 15, 0 }; + static constexpr SpriteBounds back_bounds[6] = { + {{}, {0, TILE_SIZE, 40}, {}}, + {{}, {TILE_SIZE, 0, 40}, {}}, + {{}, {TILE_SIZE, 0, 40}, {}}, + {{}, {0, TILE_SIZE, 40}, {}}, + {{}, {TILE_SIZE, 0, 40}, {}}, + {{}, {0, TILE_SIZE, 40}, {}}, + }; /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called * The bounding boxes here are the same as for bridge front/roof */ for (uint i = 0; i < lengthof(seq_back); ++i) { if (seq_back[i] != 0) { - AddSortableSpriteToDraw(seq_back[i], PAL_NONE, - x, y, size_x[offset], size_y[offset], 0x28, z, - trans_back[i]); + AddSortableSpriteToDraw(seq_back[i], PAL_NONE, x, y, z, back_bounds[offset], trans_back[i]); } } @@ -1213,12 +1215,18 @@ static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int off EndSpriteCombine(); StartSpriteCombine(); + static constexpr SpriteBounds front_bounds[6] = { + {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}}, + {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}}, + {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}}, + {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}}, + {{0, 15, 0}, {TILE_SIZE, 0, 40}, {0, -15, 0}}, + {{15, 0, 0}, {0, TILE_SIZE, 40}, {-15, 0, 0}}, + }; + for (uint i = 0; i < lengthof(seq_front); ++i) { if (seq_front[i] != 0) { - AddSortableSpriteToDraw(seq_front[i], PAL_NONE, - x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, - trans_front[i], - front_bb_offset_x[offset], front_bb_offset_y[offset]); + AddSortableSpriteToDraw(seq_front[i], PAL_NONE, x, y, z, front_bounds[offset], trans_front[i]); } } } @@ -1251,15 +1259,35 @@ static void DrawTile_TunnelBridge(TileInfo *ti) * */ - static const int _tunnel_BB[4][12] = { - /* tunnnel-roof | Z-separator | tram-catenary - * w h bb_x bb_y| x y w h |bb_x bb_y w h */ - { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // NE - { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // SE - { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // SW - { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // NW + /* Tunnel sprites are positioned at 15,15, but the bounding box covers most of the tile. */ + static constexpr SpriteBounds roof_bounds[DIAGDIR_END] = { + {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // NE + {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // SE + {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {TILE_SIZE - 1, TILE_SIZE - 2, -BB_Z_SEPARATOR}}, // SW + {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {TILE_SIZE - 2, TILE_SIZE - 1, -BB_Z_SEPARATOR}}, // NW + }; + + /* Catenary sprites are positioned at 0,0, with the same bounding box as above. */ + static constexpr SpriteBounds catenary_bounds[DIAGDIR_END] = { + {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // NE + {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // SE + {{0, 1, BB_Z_SEPARATOR}, {TILE_SIZE, TILE_SIZE - 1, 1}, {0, -1, -BB_Z_SEPARATOR}}, // SW + {{1, 0, BB_Z_SEPARATOR}, {TILE_SIZE - 1, TILE_SIZE, 1}, {-1, 0, -BB_Z_SEPARATOR}}, // NW + }; + + static constexpr SpriteBounds rear_sep[DIAGDIR_END] = { + {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE + {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE + {{}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW + {{}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW + }; + + static constexpr SpriteBounds front_sep[DIAGDIR_END] = { + {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // NE + {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // SE + {{0, TILE_SIZE - 1, 0}, {TILE_SIZE, 1, TILE_HEIGHT}, {}}, // SW + {{TILE_SIZE - 1, 0, 0}, {1, TILE_SIZE, TILE_HEIGHT}, {}}, // NW }; - const int *BB_data = _tunnel_BB[tunnelbridge_direction]; bool catenary = false; @@ -1332,7 +1360,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti) if (catenary_sprite_base != 0) { catenary = true; StartSpriteCombine(); - AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR); + AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, *ti, catenary_bounds[tunnelbridge_direction], IsTransparencySet(TO_CATENARY)); } } else { const RailTypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); @@ -1364,15 +1392,15 @@ static void DrawTile_TunnelBridge(TileInfo *ti) if (railtype_overlay != 0 && !catenary) StartSpriteCombine(); - AddSortableSpriteToDraw(image + 1, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR); + AddSortableSpriteToDraw(image + 1, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false); /* Draw railtype tunnel portal overlay if defined. */ - if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR); + if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, *ti, roof_bounds[tunnelbridge_direction], false); if (catenary || railtype_overlay != 0) EndSpriteCombine(); /* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */ - AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x, ti->y, BB_data[6], BB_data[7], TILE_HEIGHT, ti->z); - AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x + BB_data[4], ti->y + BB_data[5], BB_data[6], BB_data[7], TILE_HEIGHT, ti->z); + AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, rear_sep[tunnelbridge_direction]); + AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, *ti, front_sep[tunnelbridge_direction]); DrawBridgeMiddle(ti); } else { // IsBridge(ti->tile) @@ -1423,7 +1451,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti) * it doesn't disappear behind it */ /* Bridge heads are drawn solid no matter how invisibility/transparency is set */ - AddSortableSpriteToDraw(psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z); + AddSortableSpriteToDraw(psid->sprite, psid->pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}}); if (transport_type == TRANSPORT_ROAD) { uint offset = tunnelbridge_direction; @@ -1445,9 +1473,9 @@ static void DrawTile_TunnelBridge(TileInfo *ti) SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_BRIDGE); if (surface != 0) { if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { - AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, ti->x, ti->y, 16, 16, 0, ti->z + 8); + AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}}); } else { - AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, 16, 16, 8, ti->z); + AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}}); } } /* Don't fallback to non-overlay sprite -- the spec states that @@ -1460,15 +1488,15 @@ static void DrawTile_TunnelBridge(TileInfo *ti) if (rti->UsesOverlay()) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { - AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8); + AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}}); } else { - AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z); + AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}}); } } else { if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { - AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8); + AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, *ti, {{0, 0, TILE_HEIGHT}, {TILE_SIZE, TILE_SIZE, 0}, {}}); } else { - AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z); + AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, *ti, {{}, {TILE_SIZE, TILE_SIZE, TILE_HEIGHT}, {}}); } } } @@ -1578,7 +1606,7 @@ void DrawBridgeMiddle(const TileInfo *ti) int z = bridge_z - BRIDGE_Z_START; /* Add a bounding box that separates the bridge from things below it. */ - AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, 16, 16, 1, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR); + AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR, {{}, {TILE_SIZE, TILE_SIZE, 1}, {}}); /* Draw Trambits as SpriteCombine */ if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine(); @@ -1586,9 +1614,9 @@ void DrawBridgeMiddle(const TileInfo *ti) /* Draw floor and far part of bridge*/ if (!IsInvisibilitySet(TO_BRIDGES)) { if (axis == AXIS_X) { - AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 1, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START); + AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES)); } else { - AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START); + AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES)); } } @@ -1602,16 +1630,16 @@ void DrawBridgeMiddle(const TileInfo *ti) if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) { SpriteID surface = GetCustomRailSprite(rti, rampsouth, RTSG_BRIDGE, TCX_ON_BRIDGE); if (surface != 0) { - AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES)); + AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES)); } } if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth)) { if (rti->UsesOverlay()) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); - AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES)); + AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES)); } else { - AddSortableSpriteToDraw(axis == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES)); + AddSortableSpriteToDraw(axis == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, bridge_z, {{}, {TILE_SIZE, TILE_SIZE, 0}, {}}, IsTransparencySet(TO_BRIDGES)); } } @@ -1626,10 +1654,10 @@ void DrawBridgeMiddle(const TileInfo *ti) if (!IsInvisibilitySet(TO_BRIDGES)) { if (axis == AXIS_X) { y += 12; - if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 4, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 3, BRIDGE_Z_START); + if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 3, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, -3, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES)); } else { x += 12; - if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 4, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 3, 0, BRIDGE_Z_START); + if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{3, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {-3, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES)); } } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 4765b07c41..b94670cbac 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1109,8 +1109,7 @@ static void DoDrawVehicle(const Vehicle *v) for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) { PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal; if (!pal2 || v->vehstatus.Test(VehState::Crashed)) pal2 = pal; - AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs, - v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs); + AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos, v->y_pos, v->z_pos, v->bounds, shadowed); } EndSpriteCombine(); } @@ -1674,12 +1673,24 @@ void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const Rect new_coord; this->sprite_cache.sprite_seq.GetBounds(&new_coord); - Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos); + /* z-bounds are not used. */ + Point pt = RemapCoords(this->x_pos + this->bounds.origin.x + this->bounds.offset.x, this->y_pos + this->bounds.origin.y + this->bounds.offset.y, this->z_pos); new_coord.left += pt.x; new_coord.top += pt.y; new_coord.right += pt.x + 2 * ZOOM_BASE; new_coord.bottom += pt.y + 2 * ZOOM_BASE; + extern bool _draw_bounding_boxes; + if (_draw_bounding_boxes) { + int x = this->x_pos + this->bounds.origin.x; + int y = this->y_pos + this->bounds.origin.y; + int z = this->z_pos + this->bounds.origin.z; + new_coord.left = std::min(new_coord.left, RemapCoords(x + bounds.extent.x, y, z).x); + new_coord.right = std::max(new_coord.right, RemapCoords(x, y + bounds.extent.y, z).x + 1); + new_coord.top = std::min(new_coord.top, RemapCoords(x, y, z + bounds.extent.z).y); + new_coord.bottom = std::max(new_coord.bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1); + } + if (update_cache) { /* * If the old coordinates are invalid, set the cache to the new coordinates for correct diff --git a/src/vehicle_base.h b/src/vehicle_base.h index 58c311e804..fddc19910b 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -10,6 +10,7 @@ #ifndef VEHICLE_BASE_H #define VEHICLE_BASE_H +#include "sprite.h" #include "track_type.h" #include "command_type.h" #include "order_base.h" @@ -293,13 +294,7 @@ public: * 0xff == reserved for another custom sprite */ uint8_t spritenum = 0; - uint8_t x_extent = 0; ///< x-extent of vehicle bounding box - uint8_t y_extent = 0; ///< y-extent of vehicle bounding box - uint8_t z_extent = 0; ///< z-extent of vehicle bounding box - int8_t x_bb_offs = 0; ///< x offset of vehicle bounding box - int8_t y_bb_offs = 0; ///< y offset of vehicle bounding box - int8_t x_offs = 0; ///< x offset for vehicle sprite - int8_t y_offs = 0; ///< y offset for vehicle sprite + SpriteBounds bounds{}; ///< Bounding box of vehicle. EngineID engine_type = EngineID::Invalid(); ///< The type of engine used for this vehicle. TextEffectID fill_percent_te_id = INVALID_TE_ID; ///< a text-effect id to a loading indicator object diff --git a/src/viewport.cpp b/src/viewport.cpp index 4699990cce..1599796d1f 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -660,12 +660,17 @@ static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z * @param bb_offset_z bounding box extent towards negative Z (world) * @param sub Only draw a part of the sprite. */ -void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub) +void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent, const SubSprite *sub) { int32_t left, right, top, bottom; assert((image & SPRITE_MASK) < MAX_SPRITES); + /* Move to bounding box. */ + x += bounds.origin.x; + y += bounds.origin.y; + z += bounds.origin.z; + /* make the sprites transparent with the right palette */ if (transparent) { SetBit(image, PALETTE_MODIFIER_TRANSPARENT); @@ -673,21 +678,21 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, } if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) { - AddCombinedSprite(image, pal, x, y, z, sub); + AddCombinedSprite(image, pal, x + bounds.offset.x, y + bounds.offset.y, z + bounds.offset.z, sub); return; } _vd.last_child = LAST_CHILD_NONE; - Point pt = RemapCoords(x, y, z); + Point pt = RemapCoords(x + bounds.offset.x, y + bounds.offset.y, z + bounds.offset.z); int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y; /* Compute screen extents of sprite */ if (image == SPR_EMPTY_BOUNDING_BOX) { - left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x; - right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1; - top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y; - bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1; + left = tmp_left = RemapCoords(x + bounds.extent.x, y, z).x; + right = RemapCoords(x, y + bounds.extent.y, z).x + 1; + top = tmp_top = RemapCoords(x, y, z + bounds.extent.z).y; + bottom = RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1; } else { const Sprite *spr = GetSprite(image & SPRITE_MASK, SpriteType::Normal); left = tmp_left = (pt.x += spr->x_offs); @@ -698,10 +703,10 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) { /* Compute maximal extents of sprite and its bounding box */ - left = std::min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x); - right = std::max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1); - top = std::min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y); - bottom = std::max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1); + left = std::min(left , RemapCoords(x + bounds.extent.x, y, z).x); + right = std::max(right , RemapCoords(x, y + bounds.extent.y, z).x + 1); + top = std::min(top , RemapCoords(x, y, z + bounds.extent.z).y); + bottom = std::max(bottom, RemapCoords(x + bounds.extent.x, y + bounds.extent.y, z).y + 1); } /* Do not add the sprite to the viewport, if it is outside */ @@ -722,14 +727,14 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, ps.image = image; ps.pal = pal; ps.sub = sub; - ps.xmin = x + bb_offset_x; - ps.xmax = x + std::max(bb_offset_x, w) - 1; + ps.xmin = x; + ps.xmax = x + bounds.extent.x - 1; - ps.ymin = y + bb_offset_y; - ps.ymax = y + std::max(bb_offset_y, h) - 1; + ps.ymin = y; + ps.ymax = y + bounds.extent.y - 1; - ps.zmin = z + bb_offset_z; - ps.zmax = z + std::max(bb_offset_z, dz) - 1; + ps.zmin = z; + ps.zmax = z + bounds.extent.z - 1; ps.first_child = LAST_CHILD_NONE; diff --git a/src/viewport_func.h b/src/viewport_func.h index 88e00edd73..6aabc4dc71 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -11,6 +11,7 @@ #define VIEWPORT_FUNC_H #include "gfx_type.h" +#include "sprite.h" #include "viewport_type.h" #include "window_type.h" #include "tile_map.h" @@ -51,10 +52,14 @@ void OffsetGroundSprite(int x, int y); void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0); void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32_t x, int32_t y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0); -void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = nullptr); +void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int z, const SpriteBounds &bounds, bool transparent = false, const SubSprite *sub = nullptr); void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent = false, const SubSprite *sub = nullptr, bool scale = true, bool relative = true); std::string *ViewportAddString(const DrawPixelInfo *dpi, const ViewportSign *sign, ViewportStringFlags flags, Colours colour); +inline void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, const PointXyz &world, const SpriteBounds &bounds, bool transparent = false, const SubSprite *sub = nullptr) +{ + AddSortableSpriteToDraw(image, pal, world.x, world.y, world.z, bounds, transparent, sub); +} void StartSpriteCombine(); void EndSpriteCombine(); diff --git a/src/viewport_type.h b/src/viewport_type.h index 6e7f8b2dc7..76edb9ac12 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -89,8 +89,8 @@ enum ZoomStateChange : uint8_t { * z=6 reserved, currently unused. * z=7 Z separator between bridge/tunnel and the things under/above it. */ -static const uint BB_HEIGHT_UNDER_BRIDGE = 6; ///< Everything that can be built under low bridges, must not exceed this Z height. -static const uint BB_Z_SEPARATOR = 7; ///< Separates the bridge/tunnel from the things under/above it. +static constexpr int BB_HEIGHT_UNDER_BRIDGE = 6; ///< Everything that can be built under low bridges, must not exceed this Z height. +static constexpr int BB_Z_SEPARATOR = 7; ///< Separates the bridge/tunnel from the things under/above it. /** Viewport place method (type of highlighted area and placed objects) */ enum ViewportPlaceMethod : uint8_t { diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 9d0f976d5f..756a1d1d38 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -806,11 +806,7 @@ static void DrawWaterTileStruct(const TileInfo *ti, std::spantile, tile_offs); - AddSortableSpriteToDraw(base + tile_offs, palette, - ti->x + dtss.delta_x, ti->y + dtss.delta_y, - dtss.size_x, dtss.size_y, - dtss.size_z, ti->z + dtss.delta_z, - IsTransparencySet(TO_BUILDINGS)); + AddSortableSpriteToDraw(base + tile_offs, palette, *ti, dtss, IsTransparencySet(TO_BUILDINGS)); } }