// 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); }