Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/rendering/StarWorldCamera.hpp
blob: d83a31a2bb3a38fb4ede93e1c9953768a0e6b565 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once

#include "StarWorldGeometry.hpp"
#include "StarGameTypes.hpp"
#include "StarInterpolation.hpp"

namespace Star {

class WorldCamera {
public:
  void setScreenSize(Vec2U screenSize);
  Vec2U screenSize() const;

  void setTargetPixelRatio(float targetPixelRatio);
  void setPixelRatio(float pixelRatio);
  float pixelRatio() const;

  void setWorldGeometry(WorldGeometry geometry);
  WorldGeometry worldGeometry() const;

  // Set the camera center position (in world space) to as close to the given
  // location as possible while keeping the screen within world bounds.
  // Returns the actual camera position.
  void setCenterWorldPosition(Vec2F const& position);
  Vec2F centerWorldPosition() const;

  // Transforms world coordinates into one set of screen coordinates.  Since
  // the world is non-euclidean, one world coordinate can transform to
  // potentially an infinite number of screen coordinates.  This will retrun
  // the closest to the center of the screen.
  Vec2F worldToScreen(Vec2F const& worldCoord) const;

  // Assumes top left corner of screen is (0, 0) in screen coordinates.
  Vec2F screenToWorld(Vec2F const& screen) const;

  // Returns screen dimensions in world space.
  RectF worldScreenRect() const;

  // Returns tile dimensions of the tiles that overlap with the screen
  RectI worldTileRect() const;

  // Returns the position of the lower left corner of the lower left tile of
  // worldTileRect, in screen coordinates.
  Vec2F tileMinScreen() const;

  void update(float dt);

private:
  WorldGeometry m_worldGeometry;
  Vec2U m_screenSize;
  float m_pixelRatio = 1.0f;
  float m_targetPixelRatio = 1.0f;
  Vec2F m_worldCenter;
};

inline void WorldCamera::setScreenSize(Vec2U screenSize) {
  m_screenSize = screenSize;
}

inline Vec2U WorldCamera::screenSize() const {
  return m_screenSize;
}

inline void WorldCamera::setTargetPixelRatio(float targetPixelRatio) {
  m_targetPixelRatio = targetPixelRatio;
}

inline void WorldCamera::setPixelRatio(float pixelRatio) {
  m_pixelRatio = m_targetPixelRatio = pixelRatio;
}

inline float WorldCamera::pixelRatio() const {
  return m_pixelRatio;
}

inline void WorldCamera::setWorldGeometry(WorldGeometry geometry) {
  m_worldGeometry = std::move(geometry);
}

inline WorldGeometry WorldCamera::worldGeometry() const {
  return m_worldGeometry;
}

inline Vec2F WorldCamera::centerWorldPosition() const {
  return Vec2F(m_worldCenter);
}

inline Vec2F WorldCamera::worldToScreen(Vec2F const& worldCoord) const {
  Vec2F wrappedCoord = m_worldGeometry.nearestTo(Vec2F(m_worldCenter), worldCoord);
  return Vec2F(
      (wrappedCoord[0] - m_worldCenter[0]) * (TilePixels * m_pixelRatio) + m_screenSize[0] / 2.0,
      (wrappedCoord[1] - m_worldCenter[1]) * (TilePixels * m_pixelRatio) + m_screenSize[1] / 2.0
    );
}

inline Vec2F WorldCamera::screenToWorld(Vec2F const& screen) const {
  return Vec2F(
      (screen[0] - m_screenSize[0] / 2.0) / (TilePixels * m_pixelRatio) + m_worldCenter[0],
      (screen[1] - m_screenSize[1] / 2.0) / (TilePixels * m_pixelRatio) + m_worldCenter[1]
    );
}

inline RectF WorldCamera::worldScreenRect() const {
  // screen dimensions in world space
  float w = (float)m_screenSize[0] / (TilePixels * m_pixelRatio);
  float h = (float)m_screenSize[1] / (TilePixels * m_pixelRatio);
  return RectF::withSize(Vec2F(m_worldCenter[0] - w / 2, m_worldCenter[1] - h / 2), Vec2F(w, h));
}

inline RectI WorldCamera::worldTileRect() const {
  RectF screen = worldScreenRect();
  Vec2I min = Vec2I::floor(screen.min());
  Vec2I size = Vec2I::ceil(Vec2F(m_screenSize) / (TilePixels * m_pixelRatio) + (screen.min() - Vec2F(min)));
  return RectI::withSize(min, size);
}

inline Vec2F WorldCamera::tileMinScreen() const {
  RectF screenRect = worldScreenRect();
  RectI tileRect = worldTileRect();
  return (Vec2F(tileRect.min()) - screenRect.min()) * (TilePixels * m_pixelRatio);
}

inline void WorldCamera::update(float dt) {
  m_pixelRatio = lerp(exp(-20.0f * dt), m_targetPixelRatio, m_pixelRatio);
}

}