summaryrefslogtreecommitdiff
path: root/gfx/camera.cpp
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2025-03-05 22:16:56 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2025-03-05 22:16:56 +0000
commit2454b5449bbda815eb15327476e376d0d3a39617 (patch)
tree405643f93a6e8eb2cd3f8b38a17649fd2f85f5a6 /gfx/camera.cpp
parentHave Camera keep an array of frustum plane definitions (diff)
downloadilt-2454b5449bbda815eb15327476e376d0d3a39617.tar.bz2
ilt-2454b5449bbda815eb15327476e376d0d3a39617.tar.xz
ilt-2454b5449bbda815eb15327476e376d0d3a39617.zip
Move camera out of gl folder, it's not OpenGL specific
Diffstat (limited to 'gfx/camera.cpp')
-rw-r--r--gfx/camera.cpp67
1 files changed, 67 insertions, 0 deletions
diff --git a/gfx/camera.cpp b/gfx/camera.cpp
new file mode 100644
index 0000000..9e165fa
--- /dev/null
+++ b/gfx/camera.cpp
@@ -0,0 +1,67 @@
+#include "camera.h"
+#include <collections.h>
+#include <glm/gtx/transform.hpp>
+#include <maths.h>
+#include <ray.h>
+
+Camera::Camera(GlobalPosition3D pos, Angle fov, Angle aspect, GlobalDistance zNear, GlobalDistance zFar) :
+ position {pos}, forward {::north}, up {::up}, near {zNear}, far {zFar}, view {},
+ projection {
+ glm::perspective(fov, aspect, static_cast<RelativeDistance>(zNear), static_cast<RelativeDistance>(zFar))},
+ viewProjection {}, inverseViewProjection {}
+{
+ updateView();
+}
+
+Ray<GlobalPosition3D>
+Camera::unProject(const ScreenRelCoord & mouse) const
+{
+ static constexpr const glm::vec4 SCREEN {0, 0, 1, 1};
+ return {
+ .start = position,
+ .direction = glm::normalize(glm::unProject(mouse || 1.F, view, projection, SCREEN)),
+ };
+}
+
+void
+Camera::updateView()
+{
+ view = glm::lookAt({}, forward, up);
+ viewProjection = projection * view;
+ inverseViewProjection = glm::inverse(viewProjection);
+ static constexpr auto PLANES = std::array {0, 1, 2} * std::array {1.F, -1.F};
+ std::ranges::transform(PLANES, frustumPlanes.begin(), [vpt = glm::transpose(viewProjection)](const auto & idxs) {
+ const auto [idx, sgn] = idxs;
+ return vpt[3] + (vpt[idx] * sgn);
+ });
+}
+
+Direction3D
+Camera::upFromForward(const Direction3D & forward)
+{
+ const auto right = crossProduct(forward, ::down);
+ return crossProduct(forward, right);
+}
+
+std::array<GlobalPosition4D, 4>
+Camera::extentsAtDist(const GlobalDistance dist) const
+{
+ const auto clampToSeaFloor = [this, dist](GlobalPosition3D target) -> GlobalPosition4D {
+ target += position;
+ if (target.z < -1500) {
+ const CalcPosition3D diff = target - position;
+ const CalcDistance limit = -1500 - position.z;
+ return {position + ((limit * diff) / diff.z), (limit * dist) / diff.z};
+ }
+ return {target, dist};
+ };
+ const auto depth = -(2.F * (static_cast<float>(dist - near)) * static_cast<float>(far))
+ / (static_cast<float>(dist) * (static_cast<float>(near - far)))
+ - 1.F;
+ static constexpr const std::array extents {-1.F, 1.F};
+ static constexpr const auto cartesianExtents = extents * extents;
+ return cartesianExtents * [&depth, this, &clampToSeaFloor](const auto & extent) {
+ const glm::vec4 in {extent.first, extent.second, depth, 1.F};
+ return clampToSeaFloor(perspective_divide(inverseViewProjection * in));
+ };
+}