Files
TSE/TSE_Core/src/BehaviourScripts/Camera.cpp
2026-03-15 17:46:11 +01:00

218 lines
5.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Camera.hpp"
#include "elements/Transformable.hpp"
#include "interfaces/IRenderer.hpp"
#include "uuid.h"
TSE::Camera* TSE::Camera::mainCamera = nullptr;
TSE::ICameraHelper* TSE::Camera::helper = nullptr;
float TSE::Camera::GetRenderScale() const
{
return RenderScale;
}
TSE::ProjectionType TSE::Camera::GetProjection() const
{
return projection;
}
float TSE::Camera::GetNearClippingPlane() const
{
return nearClippingPlane;
}
float TSE::Camera::GetFarClippingPlane() const
{
return farClippingPlane;
}
float TSE::Camera::GetFov() const
{
return fov;
}
const TSE::Vector2 &TSE::Camera::GetRenderTargetSize() const
{
return lastRtSize;
}
TSE::Vector3 TSE::Camera::SceenPositionToGamePosition(Vector2 screenPos)
{
float x = 2.0f * screenPos.x / lastRtSize.x -1.0f;
float y = 1.0f - 2.0f * screenPos.y / lastRtSize.y;
float z = -1.0f;
Vector4 ndc(x,y,x,1);
Matrix4x4 InversProj = Matrix4x4(*projectionMatrix);
InversProj.Invert();
Vector4 camSpace = InversProj * ndc;
camSpace = camSpace / camSpace.w;
Vector3 relativPos(camSpace);
relativPos.z = 0;
return baseObject->LocalToGlobalPosition(relativPos);
}
void TSE::Camera::SetRenderScale(float v)
{
RenderScale = v; RecalculateProjMatrix();
}
void TSE::Camera::SetProjection(ProjectionType v)
{
projection = v; RecalculateProjMatrix();
}
void TSE::Camera::SetNearClippingPlane(float v)
{
nearClippingPlane = v; RecalculateProjMatrix();
}
void TSE::Camera::SetFarClippingPlane(float v)
{
farClippingPlane = v; RecalculateProjMatrix();
}
void TSE::Camera::SetFov(float v)
{
fov = v; RecalculateProjMatrix();
}
TSE::Camera::Camera()
{
}
TSE::Camera::~Camera()
{
delete(projectionMatrix);
if(mainCamera == this)
mainCamera = nullptr;
}
void TSE::Camera::OnResize(float width, float height, IResizable *wnd)
{
lastRtSize = {width, height};
RecalculateProjMatrix();
}
void TSE::Camera::SetRenderTarget(IRenderTarget *target)
{
if(rt != nullptr)
rt->RemoveResizeNotifiable(this);
if(target != nullptr)
target->AddResizeNotifiable(this);
rt = target;
if(lastRtSize != rt->GetRawIResizableSize())
{
lastRtSize = rt->GetRawIResizableSize();
RecalculateProjMatrix();
}
}
TSE::IRenderTarget *TSE::Camera::GetRenderTarget()
{
return rt;
}
void TSE::Camera::RecalculateProjMatrix()
{
if(projectionMatrix)
delete(projectionMatrix);
if(projection == ProjectionType::Orthographic)
{
float x = lastRtSize.x / RenderScale;
float y = lastRtSize.y / RenderScale;
float mx = -x;
float my = -y;
projectionMatrix = new Matrix4x4(Matrix4x4::Orthographic(mx, x, my, y, nearClippingPlane, farClippingPlane));
}
else if(projection == ProjectionType::Perspective)
{
float x = lastRtSize.x / RenderScale;
float y = lastRtSize.y / RenderScale;
float aspectRatio = x / y;
projectionMatrix = new Matrix4x4(Matrix4x4::Perspective(fov, aspectRatio, nearClippingPlane, farClippingPlane));
}
}
void TSE::Camera::OnUpdate()
{
if(mainCamera == nullptr && baseObject->name != ".EditorCamera")
{
mainCamera = this;
}
if(rt != nullptr)
IRenderer::camerasToRenderWith.push_back(this);
}
void TSE::Camera::Start()
{
if(mainCamera == nullptr && baseObject->name != ".EditorCamera")
{
mainCamera = this;
}
}
TSE::Matrix4x4 BuildView_Zplus_RH(const TSE::Matrix4x4& world)
{
using namespace TSE;
// Welt-Position (w=1)
Vector3 pos = Vector3(world * Vector4(0,0,0,1));
// Richtungsachsen in Welt (w=0, KEINE Translation!)
Vector3 fwdWS = Vector3(world * Vector4(0,0,1,0)); // +Z vorwärts in Welt
Vector3 upWS = Vector3(world * Vector4(0,1,0,0)); // +Y oben in Welt
// Orthonormale Basis aufbauen (X+ soll "right" sein)
Vector3 f = Vector3::Normalize(fwdWS);
Vector3 r = Vector3::Normalize(Vector3::Cross(upWS, f)); // right = up × forward => (+1,0,0) im Identity-Fall
Vector3 u = Vector3::Cross(f, r); // re-orthonormalisiertes up
Matrix4x4 view(1.0f); // Identität als Basis
// Row-major befüllen (Zeilen = r,u,-f), letzte Spalte = -dot(row, pos) bzw. +dot(f,pos)
view.m[0][0] = r.x; view.m[0][1] = r.y; view.m[0][2] = r.z; view.m[0][3] = -Vector3::Dot(r, pos);
view.m[1][0] = u.x; view.m[1][1] = u.y; view.m[1][2] = u.z; view.m[1][3] = -Vector3::Dot(u, pos);
view.m[2][0] = -f.x; view.m[2][1] = -f.y; view.m[2][2] = -f.z; view.m[2][3] = Vector3::Dot(f, pos);
view.m[3][0] = 0.0f; view.m[3][1] = 0.0f; view.m[3][2] = 0.0f; view.m[3][3] = 1.0f;
return view;
}
void TSE::Camera::PreDraw(IShader *shader)
{
rt->Bind();
shader->SetUniform("prMatrix", projectionMatrix);
auto worlmatrix = baseObject->GetGlobalMatrix();
viewMatrix = BuildView_Zplus_RH(worlmatrix);
shader->SetUniform("camMatrix", &viewMatrix);
helper->OnRenderTargetChanged(lastRtSize.x, lastRtSize.y);
}
void TSE::Camera::PostDraw()
{
rt->Unbind();
}
void TSE::Camera::Bind()
{
rt->Bind();
}
void TSE::Camera::Unbind()
{
rt->Unbind();
}
void TSE::Camera::UpdateRenderTarget()
{
rt->Update();
}