Dawn/src/dawn/scene/components/display/Camera.cpp

109 lines
3.2 KiB
C++

// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Camera.hpp"
#include "game/DawnGame.hpp"
using namespace Dawn;
Camera::Camera(SceneItem *item) :
SceneItemComponent(item),
renderTarget(item->scene->game->renderManager.getBackBuffer()),
fov(0.785398f),// 45 degrees,
type(CAMERA_TYPE_PERSPECTIVE),
orthoLeft(0.0f),
orthoRight(1.0f),
orthoBottom(0.0f),
orthoTop(1.0f),
clipNear(0.001f),
clipFar(1000.0f)
{
}
glm::mat4 Camera::getProjection() {
if(this->projectionNeedsUpdating) {
switch(this->type) {
case CAMERA_TYPE_ORTHONOGRAPHIC:
this->projection = glm::ortho(
(float_t)this->orthoLeft,
(float_t)this->orthoRight,
(float_t)this->orthoBottom,
(float_t)this->orthoTop,
(float_t)this->clipNear,
(float_t)this->clipFar
);
break;
case CAMERA_TYPE_PERSPECTIVE:
this->projection = glm::perspective(
(float_t)this->fov,
this->getAspect(),
(float_t)this->clipNear,
(float_t)this->clipFar
);
break;
}
this->projectionNeedsUpdating = false;
}
return this->projection;
}
RenderTarget * Camera::getRenderTarget() {
return (RenderTarget*)this->renderTarget;
}
float_t Camera::getAspect() {
auto target = this->getRenderTarget();
return target->getWidth() / target->getHeight();
}
glm::vec3 Camera::getRayDirectionFromScreenSpace(glm::vec2 screenSpace) {
glm::vec4 clipCoords(screenSpace.x, -screenSpace.y, -1.0f, 1.0f);
glm::mat4 inverseProjectionMatrix = glm::inverse(this->projection);
glm::vec4 eyeCoords = inverseProjectionMatrix * clipCoords;
eyeCoords = glm::vec4(eyeCoords.x, eyeCoords.y, -1.0f, 0.0f);
glm::mat4 inverseViewMatrix = glm::inverse(transform->getWorldTransform());
glm::vec4 t = inverseViewMatrix * eyeCoords;
return glm::normalize(glm::vec3(t.x, t.y, t.z));
}
void Camera::onStart() {
useEffectWithTeardown([&]{
auto rt = this->getRenderTarget();
this->projectionNeedsUpdating = true;
if(rt == nullptr) {
return evtResized = [&]{
};
}
this->eventRenderTargetResized.invoke(rt->getWidth(), rt->getHeight());
// Subscribe to new render target resized.
return evtResized = useEventLegacy([&](RenderTarget *rt, float_t w, float_t h){
this->projectionNeedsUpdating = true;
this->eventRenderTargetResized.invoke(w, h);
}, rt->eventRenderTargetResized);
}, renderTarget);
// All regular properties.
useEffect([&]{
this->projectionNeedsUpdating = true;
}, {
&fov, &type,
&orthoLeft, &orthoRight, &orthoBottom, &orthoTop,
&clipNear, &clipFar
});
// Sub to evt legacy, we don't invoke the useTeardown to avoid invoking
// the state event for this camera when we don't need to.
if(!this->getRenderTarget()) return;
evtResized = useEventLegacy([&](RenderTarget *rt, float_t w, float_t h){
this->projectionNeedsUpdating = true;
this->eventRenderTargetResized.invoke(w, h);
}, getRenderTarget()->eventRenderTargetResized);
}