OpenLoco/src/OpenLoco/Viewport.hpp

222 lines
6.5 KiB
C++

#pragma once
#include "Graphics/Gfx.h"
#include "Location.hpp"
#include "Map/Map.hpp"
#include "Types.hpp"
#include <algorithm>
namespace OpenLoco::Ui
{
struct SavedViewSimple;
struct viewport_pos
{
int16_t x{};
int16_t y{};
viewport_pos()
: viewport_pos(0, 0)
{
}
viewport_pos(int16_t _x, int16_t _y)
: x(_x)
, y(_y)
{
}
};
struct ViewportRect
{
int16_t left = 0;
int16_t top = 0;
int16_t bottom = 0;
int16_t right = 0;
constexpr bool contains(const viewport_pos& vpos)
{
return (left < vpos.x && top < vpos.y && right >= vpos.x && bottom >= vpos.y);
}
};
namespace ViewportFlags
{
constexpr uint32_t underground_view = 1 << 0;
constexpr uint32_t hide_foreground_tracks_roads = 1 << 1;
constexpr uint32_t height_marks_on_tracks_roads = 1 << 2;
constexpr uint32_t height_marks_on_land = 1 << 3;
constexpr uint32_t one_way_direction_arrows = 1 << 4;
constexpr uint32_t gridlines_on_landscape = 1 << 5;
constexpr uint32_t hide_foreground_scenery_buildings = 1 << 6;
constexpr uint32_t flag_7 = 1 << 7;
constexpr uint32_t flag_8 = 1 << 8;
constexpr uint32_t town_names_displayed = 1 << 9;
constexpr uint32_t station_names_displayed = 1 << 10;
}
struct Viewport;
namespace ScreenToViewport
{
[[nodiscard]] constexpr Point applyTransform(const Point& uiPoint, const Viewport& vp);
}
namespace ViewportToScreen
{
[[nodiscard]] constexpr Point applyTransform(const Point& vpPoint, const Viewport& vp);
}
struct Viewport
{
int16_t width; // 0x00
int16_t height; // 0x02
int16_t x; // 0x04
int16_t y; // 0x06
int16_t view_x; // 0x08
int16_t view_y; // 0x0A
int16_t view_width; // 0x0C
int16_t view_height; // 0x0E
uint8_t zoom; // 0x10
uint8_t pad_11;
uint16_t flags; // 0x12
constexpr bool contains(const viewport_pos& vpos)
{
return (vpos.y >= view_y && vpos.y < view_y + view_height && vpos.x >= view_x && vpos.x < view_x + view_width);
}
constexpr bool containsUi(const Point& pos)
{
return (pos.x >= x && pos.x < x + width && pos.y >= y && pos.y < y + height);
}
Ui::Rect getUiRect() const
{
return Ui::Rect::fromLTRB(x, y, x + width, y + height);
}
constexpr bool intersects(const ViewportRect& vpos)
{
if (vpos.right <= view_x)
return false;
if (vpos.bottom <= view_y)
return false;
if (vpos.left >= view_x + view_width)
return false;
if (vpos.top >= view_y + view_height)
return false;
return true;
}
constexpr ViewportRect getIntersection(const ViewportRect& rect)
{
auto out = ViewportRect();
out.left = std::max(rect.left, view_x);
out.right = std::min<int16_t>(rect.right, view_x + view_width);
out.top = std::max(rect.top, view_y);
out.bottom = std::min<int16_t>(rect.bottom, view_y + view_height);
return out;
}
int getRotation() const;
void setRotation(int32_t value);
/**
* Maps a 2D viewport position to a UI (screen) position.
*/
Point viewportToScreen(const viewport_pos& vpos) const
{
const auto vpPoint = ViewportToScreen::applyTransform({ vpos.x, vpos.y }, *this);
return vpPoint;
}
/**
* Maps a UI (screen) position to a 2D viewport position.
*/
viewport_pos screenToViewport(const Point& pos) const
{
const auto vpPoint = ScreenToViewport::applyTransform(pos, *this);
return { vpPoint.x, vpPoint.y };
}
/**
* Maps a UI (screen) rectangle to a 2D viewport rectangle.
*/
Rect screenToViewport(const Rect& rect)
{
auto leftTop = screenToViewport(Point(rect.left(), rect.top()));
auto rightBottom = screenToViewport(Point(rect.right(), rect.bottom()));
return Rect::fromLTRB(leftTop.x, leftTop.y, rightBottom.x, rightBottom.y);
}
void render(Gfx::Context* context);
viewport_pos centre2dCoordinates(const Map::Pos3& loc);
SavedViewSimple toSavedView() const;
viewport_pos getCentre() const;
Point getUiCentre() const;
Map::Pos2 getCentreMapPosition() const;
std::optional<Map::Pos2> getCentreScreenMapPosition() const;
private:
void paint(Gfx::Context* context, const Ui::Rect& rect);
};
struct ViewportConfig
{
uint16_t viewport_target_sprite; // 0x0
int16_t saved_view_x; // 0x2
int16_t saved_view_y; // 0x4
};
namespace ScreenToViewport
{
[[nodiscard]] constexpr Point uiOffsetTransform(const Point& uiPoint, const Viewport& vp)
{
return uiPoint - Point{ vp.x, vp.y };
}
[[nodiscard]] constexpr Point scaleTransform(const Point& uiPoint, const Viewport& vp)
{
return uiPoint << vp.zoom;
}
[[nodiscard]] constexpr Point viewOffsetTransform(const Point& point, const Viewport& vp)
{
return point + Point{ vp.view_x, vp.view_y };
}
[[nodiscard]] constexpr Point applyTransform(const Point& uiPoint, const Viewport& vp)
{
return viewOffsetTransform(scaleTransform(uiOffsetTransform(uiPoint, vp), vp), vp);
}
}
namespace ViewportToScreen
{
[[nodiscard]] constexpr Point uiOffsetTransform(const Point& uiPoint, const Viewport& vp)
{
return uiPoint + Point{ vp.x, vp.y };
}
[[nodiscard]] constexpr Point scaleTransform(const Point& uiPoint, const Viewport& vp)
{
return uiPoint >> vp.zoom;
}
[[nodiscard]] constexpr Point viewOffsetTransform(const Point& point, const Viewport& vp)
{
return point - Point{ vp.view_x, vp.view_y };
}
[[nodiscard]] constexpr Point applyTransform(const Point& vpPoint, const Viewport& vp)
{
return uiOffsetTransform(scaleTransform(viewOffsetTransform(vpPoint, vp), vp), vp);
}
}
}