Repository navigation
Expand file tree
/
Copy pathCameraComponent.h
More file actions
140 lines (119 loc) · 5.89 KB
/
Copy pathCameraComponent.h
File metadata and controls
140 lines (119 loc) · 5.89 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
#pragma once
#include <cstdint>
#include <cmath>
#include <deki/Component.h>
#include <deki/ICamera.h>
#include "FrameCamera.h"
#include <deki/reflection/Property.h>
#include <deki/Color.h>
namespace DekiRendering
{
/// The scene's camera: what part of the world the player sees.
///
/// Every screen renders at its own native size; the camera decides how much
/// world that shows. It fixes the height and the width follows the screen, so
/// a bigger screen of the same shape shows the same world drawn bigger, and a
/// wider one shows more at the sides:
///
/// Orthographic screen_px = (world - camera) * ppm + buffer_center
/// ppm = OrthoPixelsPerMeter(h, orthoHeight, ...)
/// Perspective 3D passes (deki-3d) use fieldOfView, vertical. Sprites
/// still draw flat through the orthographic mapping.
///
/// With Pixel Perfect on, the scale is a whole multiple of the art density and
/// the camera sits on the art-pixel grid.
DEKI_CATEGORY("Core")
DEKI_DESCRIPTION("The view: position, how much world it shows, and clear color.")
class CameraComponent : public Deki::Component, public Deki::ICamera
{
public:
DEKI_EXPORT
DEKI_TOOLTIP("Colour the screen is filled with before anything is drawn. What shows wherever nothing covers it.")
Deki::Color clearColor = Deki::Color(49, 77, 121);
DEKI_TOOLTIP("Orthographic shows a fixed height of world, flat. Perspective shows a field of view in depth, for 3D "
"meshes; sprites still draw flat.")
DEKI_EXPORT
Deki::ProjectionMode projection = Deki::ProjectionMode::Orthographic;
DEKI_TOOLTIP(
"How much world the camera shows top to bottom. Every screen scales it to fill its height (the x beside it).")
DEKI_UNIT(Distance)
DEKI_RANGE(0.01f, 100000.0f)
DEKI_VISIBLE_WHEN(projection, Orthographic)
DEKI_EXPORT
float orthoHeight = 15.0f;
DEKI_TOOLTIP("For pixel art. Scales by whole numbers only, so every art pixel is the same size on screen, and "
"snaps the camera to the art-pixel grid. Rounds down: the camera shows a little more than its ortho "
"height, and a screen too small for 1x crops.")
DEKI_VISIBLE_WHEN(projection, Orthographic)
DEKI_EXPORT
bool pixelPerfect = false;
DEKI_TOOLTIP("Vertical field of view in degrees. A wider screen sees more at the sides. 60 is a common default; "
"larger looks wider and more distorted at the edges.")
DEKI_RANGE(10, 150)
DEKI_VISIBLE_WHEN(projection, Perspective)
DEKI_EXPORT
float fieldOfView = 60.0f;
DEKI_TOOLTIP("Nothing closer than this is drawn. Raising it costs nothing and buys depth precision, so keep it as "
"large as the scene allows.")
DEKI_VISIBLE_WHEN(projection, Perspective)
DEKI_EXPORT
float nearPlane = 0.1f;
DEKI_TOOLTIP("Nothing further than this is drawn.")
DEKI_VISIBLE_WHEN(projection, Perspective)
DEKI_EXPORT
float farPlane = 100.0f;
// The clear is a full framebuffer write per frame, so turning it off pays
// when the first thing drawn covers the whole screen (a full-screen
// background sprite or tilemap).
DEKI_TOOLTIP("Clear before each frame. Off, the previous frame stays underneath: faster when a full-screen "
"background covers everything, and occasionally what you want for trails.")
DEKI_EXPORT
bool clearEveryFrame = true;
CameraComponent();
virtual ~CameraComponent() = default;
// ICamera: scale for a buffer of this size (its height over orthoHeight).
float GetPixelsPerMeter(int bufferWidth, int bufferHeight) const override;
float GetOrthoHeight() const override { return orthoHeight; }
void SetOrthoHeight(float meters) override { orthoHeight = meters; }
void SetFixedPixelsPerMeter(float ppm) override { m_FixedPixelsPerMeter = ppm > 0.0f ? ppm : 0.0f; }
Deki::ProjectionMode GetProjectionMode() const override { return projection; }
void SetProjectionMode(Deki::ProjectionMode mode) override { projection = mode; }
float GetFieldOfView() const override { return fieldOfView; }
float GetNearPlane() const override { return nearPlane; }
float GetFarPlane() const override { return farPlane; }
Deki::Mat4 GetProjectionMatrix(int bufferWidth, int bufferHeight) const override;
// ICamera: clear colour
void GetClearColor(uint8_t& r, uint8_t& g, uint8_t& b) const override
{
r = clearColor.r;
g = clearColor.g;
b = clearColor.b;
}
void SetClearColor(uint8_t r, uint8_t g, uint8_t b) override
{
clearColor.r = r;
clearColor.g = g;
clearColor.b = b;
}
// Camera world position in meters, from the owner object's transform.
float GetPositionX() const;
float GetPositionY() const;
// Visible world size in meters on a buffer of this size.
float GetVisibleWidth(int32_t bufferWidth, int32_t bufferHeight) const;
float GetVisibleHeight(int32_t bufferWidth, int32_t bufferHeight) const;
// Snapshot of this camera's world-to-screen mapping for a target of the
// given size: position (snapped under Pixel Perfect), pixels per meter,
// centre. WorldToScreen below goes through this snapshot, so the two agree
// exactly; the renderer captures it once per frame (RenderContext::cam).
FrameCamera CaptureFrameCamera(int screenWidth, int screenHeight) const;
// ICamera: coordinate conversion
void WorldToScreen(float worldX, float worldY, int screenWidth, int screenHeight, float& screenX,
float& screenY) const override;
void ScreenToWorld(float screenX, float screenY, int screenWidth, int screenHeight, float& worldX,
float& worldY) const override;
private:
// Not exported: set by views that are not a screen (the editor's scene
// view). 0 means "derive from the buffer".
float m_FixedPixelsPerMeter = 0.0f;
};
} // namespace DekiRendering