OpenRCT2/src/openrct2/world/Location.hpp

668 lines
14 KiB
C++
Raw Normal View History

/*****************************************************************************
* Copyright (c) 2014-2019 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#pragma once
#include "../common.h"
2019-01-02 12:59:37 +01:00
#include <algorithm>
2020-05-11 14:32:56 +02:00
constexpr const int16_t LOCATION_NULL = -32768;
constexpr const int32_t COORDS_XY_STEP = 32;
2020-05-13 11:51:38 +02:00
constexpr const int32_t COORDS_XY_HALF_TILE = (COORDS_XY_STEP / 2);
constexpr const int32_t COORDS_Z_STEP = 8;
2020-03-07 21:07:18 +01:00
constexpr const int32_t COORDS_Z_PER_TINY_Z = 16;
2019-12-30 12:29:08 +01:00
constexpr const auto NumOrthogonalDirections = 4;
#pragma pack(push, 1)
2018-06-22 23:17:03 +02:00
struct LocationXY16
{
int16_t x, y;
};
assert_struct_size(LocationXY16, 4);
2018-06-22 23:17:03 +02:00
struct LocationXYZ16
{
int16_t x, y, z;
};
assert_struct_size(LocationXYZ16, 6);
#pragma pack(pop)
constexpr int32_t COORDS_NULL = 0xFFFF8000;
struct ScreenCoordsXY
{
int32_t x = 0;
int32_t y = 0;
ScreenCoordsXY() = default;
constexpr ScreenCoordsXY(int32_t _x, int32_t _y)
: x(_x)
, y(_y)
{
}
const ScreenCoordsXY operator-(const ScreenCoordsXY& rhs) const
{
2019-10-21 04:44:26 +02:00
return { x - rhs.x, y - rhs.y };
}
ScreenCoordsXY& operator+=(const ScreenCoordsXY& rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
ScreenCoordsXY& operator-=(const ScreenCoordsXY& rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
const ScreenCoordsXY operator+(const ScreenCoordsXY& rhs) const
{
return { x + rhs.x, y + rhs.y };
}
bool operator==(const ScreenCoordsXY& other) const
{
return x == other.x && y == other.y;
}
bool operator!=(const ScreenCoordsXY& other) const
{
return !(*this == other);
}
};
2020-05-02 21:11:07 +02:00
struct ScreenSize
{
int32_t width{};
int32_t height{};
ScreenSize() = default;
constexpr ScreenSize(int32_t _width, int32_t _height)
: width(_width)
, height(_height)
{
}
bool operator==(const ScreenSize& other) const
{
return width == other.width && height == other.height;
}
bool operator!=(const ScreenSize& other) const
{
return !(*this == other);
}
};
/**
* Tile coordinates use 1 x/y increment per tile and 1 z increment per step.
* Regular ('big', 'sprite') coordinates use 32 x/y increments per tile and 8 z increments per step.
*/
struct CoordsXY
{
2019-01-02 12:59:37 +01:00
int32_t x = 0;
int32_t y = 0;
CoordsXY() = default;
constexpr CoordsXY(int32_t _x, int32_t _y)
: x(_x)
, y(_y)
{
}
CoordsXY& operator+=(const CoordsXY& rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
CoordsXY& operator-=(const CoordsXY& rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
bool operator>=(const CoordsXY& rhs) const
{
return x >= rhs.x && y >= rhs.y;
}
bool operator<=(const CoordsXY& rhs) const
{
return x <= rhs.x && y <= rhs.y;
}
2019-08-10 09:17:47 +02:00
const CoordsXY operator+(const CoordsXY& rhs) const
{
return { x + rhs.x, y + rhs.y };
2019-08-10 09:17:47 +02:00
}
const CoordsXY operator-(const CoordsXY& rhs) const
{
return { x - rhs.x, y - rhs.y };
2019-08-10 09:17:47 +02:00
}
CoordsXY Rotate(int32_t direction) const
{
CoordsXY rotatedCoords;
switch (direction & 3)
{
default:
case 0:
rotatedCoords.x = x;
rotatedCoords.y = y;
break;
case 1:
rotatedCoords.x = y;
rotatedCoords.y = -x;
break;
case 2:
rotatedCoords.x = -x;
rotatedCoords.y = -y;
break;
case 3:
rotatedCoords.x = -y;
rotatedCoords.y = x;
break;
}
return rotatedCoords;
}
bool operator==(const CoordsXY& other) const
{
return x == other.x && y == other.y;
}
bool operator!=(const CoordsXY& other) const
{
return !(*this == other);
}
CoordsXY ToTileCentre() const
{
2020-05-13 11:51:38 +02:00
return ToTileStart() + CoordsXY{ COORDS_XY_HALF_TILE, COORDS_XY_HALF_TILE };
}
CoordsXY ToTileStart() const
{
2020-03-07 21:07:18 +01:00
return { floor2(x, COORDS_XY_STEP), floor2(y, COORDS_XY_STEP) };
}
bool isNull() const
{
return x == COORDS_NULL;
};
void setNull()
{
x = COORDS_NULL;
y = 0;
}
};
struct CoordsXYRangedZ : public CoordsXY
{
int32_t baseZ = 0;
int32_t clearanceZ = 0;
CoordsXYRangedZ() = default;
constexpr CoordsXYRangedZ(int32_t _x, int32_t _y, int32_t _baseZ, int32_t _clearanceZ)
: CoordsXY(_x, _y)
, baseZ(_baseZ)
, clearanceZ(_clearanceZ)
{
}
constexpr CoordsXYRangedZ(const CoordsXY& _c, int32_t _baseZ, int32_t _clearanceZ)
: CoordsXY(_c)
, baseZ(_baseZ)
, clearanceZ(_clearanceZ)
{
}
};
struct TileCoordsXY
{
int32_t x = 0;
int32_t y = 0;
TileCoordsXY() = default;
2019-11-01 02:07:14 +01:00
constexpr TileCoordsXY(int32_t x_, int32_t y_)
2018-06-22 23:17:03 +02:00
: x(x_)
, y(y_)
{
}
explicit TileCoordsXY(const CoordsXY& c)
2020-03-07 21:07:18 +01:00
: x(c.x / COORDS_XY_STEP)
, y(c.y / COORDS_XY_STEP)
2018-06-22 23:17:03 +02:00
{
}
const TileCoordsXY operator+(const TileCoordsXY& rhs) const
{
return { x + rhs.x, y + rhs.y };
}
TileCoordsXY& operator+=(const TileCoordsXY& rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
TileCoordsXY& operator-=(const TileCoordsXY& rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
CoordsXY ToCoordsXY() const
{
if (isNull())
{
CoordsXY ret{};
ret.setNull();
return ret;
}
2020-03-07 21:07:18 +01:00
return { x * COORDS_XY_STEP, y * COORDS_XY_STEP };
}
TileCoordsXY Rotate(int32_t direction) const
{
TileCoordsXY rotatedCoords;
switch (direction & 3)
{
default:
case 0:
rotatedCoords.x = x;
rotatedCoords.y = y;
break;
case 1:
rotatedCoords.x = y;
rotatedCoords.y = -x;
break;
case 2:
rotatedCoords.x = -x;
rotatedCoords.y = -y;
break;
case 3:
rotatedCoords.x = -y;
rotatedCoords.y = x;
break;
}
return rotatedCoords;
}
bool operator==(const TileCoordsXY& other) const
{
return x == other.x && y == other.y;
}
bool operator!=(const TileCoordsXY& other) const
{
return !(*this == other);
}
bool isNull() const
{
return x == COORDS_NULL;
};
2019-12-21 12:48:13 +01:00
void setNull()
{
x = COORDS_NULL;
y = 0;
2019-12-21 12:48:13 +01:00
}
};
2019-08-16 19:32:44 +02:00
struct CoordsXYZ : public CoordsXY
{
2019-01-02 12:59:37 +01:00
int32_t z = 0;
CoordsXYZ() = default;
constexpr CoordsXYZ(int32_t _x, int32_t _y, int32_t _z)
2019-08-16 19:32:44 +02:00
: CoordsXY(_x, _y)
2019-01-02 12:59:37 +01:00
, z(_z)
{
}
2019-08-10 09:17:47 +02:00
constexpr CoordsXYZ(const CoordsXY& c, int32_t _z)
2019-08-16 19:32:44 +02:00
: CoordsXY(c)
2019-08-10 09:17:47 +02:00
, z(_z)
{
}
2019-12-09 21:55:57 +01:00
const CoordsXYZ operator+(const CoordsXYZ& rhs) const
{
return { x + rhs.x, y + rhs.y, z + rhs.z };
}
const CoordsXYZ operator-(const CoordsXYZ& rhs) const
{
return { x - rhs.x, y - rhs.y, z - rhs.z };
}
bool operator==(const CoordsXYZ& other) const
{
return x == other.x && y == other.y && z == other.z;
}
CoordsXYZ ToTileStart() const
{
2020-03-07 21:07:18 +01:00
return { floor2(x, COORDS_XY_STEP), floor2(y, COORDS_XY_STEP), z };
}
CoordsXYZ ToTileCentre() const
{
2020-05-13 11:51:38 +02:00
return ToTileStart() + CoordsXYZ{ COORDS_XY_HALF_TILE, COORDS_XY_HALF_TILE, 0 };
}
};
struct TileCoordsXYZ : public TileCoordsXY
{
int32_t z = 0;
TileCoordsXYZ() = default;
constexpr TileCoordsXYZ(int32_t x_, int32_t y_, int32_t z_)
: TileCoordsXY(x_, y_)
2018-06-22 23:17:03 +02:00
, z(z_)
{
}
TileCoordsXYZ(const TileCoordsXY& c, int32_t z_)
: TileCoordsXY(c.x, c.y)
, z(z_)
{
}
TileCoordsXYZ(const CoordsXY& c, int32_t z_)
: TileCoordsXY(c)
2018-06-22 23:17:03 +02:00
, z(z_)
{
}
explicit TileCoordsXYZ(const CoordsXYZ& c)
: TileCoordsXY(c)
2020-03-13 12:03:43 +01:00
, z(c.z / COORDS_Z_STEP)
2018-06-22 23:17:03 +02:00
{
}
TileCoordsXYZ& operator+=(const TileCoordsXY& rhs)
2018-04-18 20:56:09 +02:00
{
x += rhs.x;
y += rhs.y;
return *this;
2018-04-18 20:56:09 +02:00
}
TileCoordsXYZ& operator-=(const TileCoordsXY& rhs)
{
x -= rhs.x;
y -= rhs.y;
return *this;
}
bool operator==(const TileCoordsXYZ& other) const
{
return x == other.x && y == other.y && z == other.z;
}
bool operator!=(const TileCoordsXYZ& other) const
{
return !(*this == other);
}
CoordsXYZ ToCoordsXYZ() const
{
if (isNull())
{
CoordsXYZ ret{};
ret.setNull();
return ret;
}
2020-03-07 21:07:18 +01:00
return { x * COORDS_XY_STEP, y * COORDS_XY_STEP, z * COORDS_Z_STEP };
}
};
/**
* Cardinal directions are represented by the Direction type. It has four
* possible values:
* 0 is X-decreasing
* 1 is Y-increasing
* 2 is X-increasing
* 3 is Y-decreasing
* Direction is not used to model up/down, or diagonal directions.
*/
using Direction = uint8_t;
2019-08-26 11:57:44 +02:00
const Direction INVALID_DIRECTION = 0xFF;
2019-08-26 19:50:37 +02:00
/**
2019-09-01 20:10:27 +02:00
* Array of all valid cardinal directions, to make it easy to write range-based for loops like:
* for (Direction d : ALL_DIRECTIONS)
2019-08-26 19:50:37 +02:00
*/
constexpr Direction ALL_DIRECTIONS[] = { 0, 1, 2, 3 };
/**
* Given a direction, return the direction that points the other way,
* on the same axis.
*/
2019-02-09 22:56:50 +01:00
[[maybe_unused]] static constexpr Direction direction_reverse(Direction dir)
{
return dir ^ 2;
}
[[maybe_unused]] static constexpr bool direction_valid(Direction dir)
{
2019-12-30 12:29:08 +01:00
return dir < NumOrthogonalDirections;
}
/**
2019-09-01 20:10:27 +02:00
* Given a direction, return the next cardinal direction, wrapping around if necessary.
* (TODO: Figure out if this is CW or CCW)
*/
[[maybe_unused]] static constexpr Direction direction_next(Direction dir)
{
return (dir + 1) & 0x03;
}
/**
2019-09-01 20:10:27 +02:00
* Given a direction, return the previous cardinal direction, wrapping around if necessary.
* (TODO: Figure out if this is CW or CCW)
*/
[[maybe_unused]] static constexpr Direction direction_prev(Direction dir)
{
return (dir - 1) & 0x03;
}
2019-08-16 19:32:44 +02:00
struct CoordsXYZD : public CoordsXYZ
{
2019-08-16 19:32:44 +02:00
Direction direction = 0;
CoordsXYZD() = default;
constexpr CoordsXYZD(int32_t _x, int32_t _y, int32_t _z, Direction _d)
: CoordsXYZ(_x, _y, _z)
, direction(_d)
{
}
constexpr CoordsXYZD(const CoordsXY& _c, int32_t _z, Direction _d)
: CoordsXYZ(_c, _z)
, direction(_d)
{
}
constexpr CoordsXYZD(const CoordsXYZ& _c, Direction _d)
2019-12-11 21:33:58 +01:00
: CoordsXYZ(_c)
, direction(_d)
{
}
bool operator==(const CoordsXYZD& other) const
{
return x == other.x && y == other.y && z == other.z && direction == other.direction;
}
bool operator!=(const CoordsXYZD& other) const
{
return !(*this == other);
}
2020-03-07 21:07:18 +01:00
CoordsXYZD& operator+=(const CoordsXY& rhs)
{
x += rhs.x;
y += rhs.y;
return *this;
}
const CoordsXYZD operator+(const CoordsXY& rhs) const
{
return { x + rhs.x, y + rhs.y, z, direction };
}
const CoordsXYZD operator+(const CoordsXYZ& rhs) const
{
return { x + rhs.x, y + rhs.y, z + rhs.z, direction };
}
const CoordsXYZD operator-(const CoordsXYZ& rhs) const
{
return { x - rhs.x, y - rhs.y, z - rhs.z, direction };
}
CoordsXYZD ToTileStart() const
{
return { floor2(x, COORDS_XY_STEP), floor2(y, COORDS_XY_STEP), z, direction };
}
CoordsXYZD ToTileCentre() const
{
2020-05-13 11:51:38 +02:00
return ToTileStart() + CoordsXYZD{ COORDS_XY_HALF_TILE, COORDS_XY_HALF_TILE, 0, 0 };
2020-03-07 21:07:18 +01:00
}
};
struct TileCoordsXYZD : public TileCoordsXYZ
{
Direction direction;
TileCoordsXYZD() = default;
constexpr TileCoordsXYZD(int32_t x_, int32_t y_, int32_t z_, Direction d_)
: TileCoordsXYZ(x_, y_, z_)
, direction(d_)
2018-06-22 23:17:03 +02:00
{
}
TileCoordsXYZD(const TileCoordsXY& t_, int32_t z_, Direction d_)
: TileCoordsXYZ(t_, z_)
, direction(d_)
{
}
TileCoordsXYZD(const CoordsXY& c_, int32_t z_, Direction d_)
: TileCoordsXYZ(c_, z_)
, direction(d_)
{
}
TileCoordsXYZD(const CoordsXYZ& c_, Direction d_)
: TileCoordsXYZ(c_)
, direction(d_)
{
}
TileCoordsXYZD(const CoordsXYZD& c_)
: TileCoordsXYZ(c_)
, direction(c_.direction)
{
}
CoordsXYZD ToCoordsXYZD() const
{
if (isNull())
{
CoordsXYZD ret{};
ret.setNull();
return ret;
}
2020-03-07 21:07:18 +01:00
return { x * COORDS_XY_STEP, y * COORDS_XY_STEP, z * COORDS_Z_STEP, direction };
}
};
2019-01-02 12:59:37 +01:00
/**
* Represents a range of the map using regular coordinates.
2019-01-02 12:59:37 +01:00
*/
template<class T> struct CoordsRange
2019-01-02 12:59:37 +01:00
{
T LeftTop{ 0, 0 };
T RightBottom{ 0, 0 };
2019-01-02 12:59:37 +01:00
int32_t GetLeft() const
{
return LeftTop.x;
}
int32_t GetTop() const
{
return LeftTop.y;
}
int32_t GetRight() const
{
return RightBottom.x;
}
int32_t GetBottom() const
{
return RightBottom.y;
}
CoordsRange() = default;
CoordsRange(int32_t left, int32_t top, int32_t right, int32_t bottom)
2019-01-02 12:59:37 +01:00
: LeftTop(left, top)
, RightBottom(right, bottom)
{
}
};
2019-01-02 12:59:37 +01:00
/**
* Represents a rectangular range of the map using regular coordinates (32 per tile).
*/
struct MapRange : public CoordsRange<CoordsXY>
{
using CoordsRange::CoordsRange;
MapRange(int32_t left, int32_t top, int32_t right, int32_t bottom)
: CoordsRange<CoordsXY>(left, top, right, bottom)
{
// Make sure it's a rectangle
assert(std::abs(GetLeft() - GetRight()) > 0);
assert(std::abs(GetTop() - GetBottom()) > 0);
}
2019-01-02 12:59:37 +01:00
MapRange Normalise() const
{
auto result = MapRange(
std::min(GetLeft(), GetRight()), std::min(GetTop(), GetBottom()), std::max(GetLeft(), GetRight()),
std::max(GetTop(), GetBottom()));
return result;
}
};