// Copyright (c) 2022 Dominic Masters
// 
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

#include "Camera.hpp"
#include "scene/Scene.hpp"
#include "game/DawnGame.hpp"

using namespace Dawn;

Camera::Camera(SceneItem &item) :
  SceneItemComponent(item)
{
  this->getRenderTarget().eventRenderTargetResized.addListener(
    this, &Camera::onRenderTargetResize
  );
}

void Camera::updateProjection() {
  switch(this->type) {
    case CAMERA_TYPE_ORTHONOGRAPHIC:
      this->projection = glm::ortho(
        this->orthoLeft,
        this->orthoRight,
        this->orthoBottom,
        this->orthoTop,
        this->clipNear,
        this->clipFar
      );
      break;

    case CAMERA_TYPE_PERSPECTIVE:
      this->projection = glm::perspective(
        this->fov,
        this->getAspect(),
        this->clipNear,
        this->clipFar
      );
      break;
  }
}

void Camera::lookAt(glm::vec3 pos, glm::vec3 look) {
  this->lookAt(pos, look, glm::vec3(0, 1, 0));
}

void Camera::lookAt(glm::vec3 pos, glm::vec3 look, glm::vec3 up) {
  this->item.transform = glm::lookAt(pos, look, up);
}

RenderTarget & Camera::getRenderTarget() {
  if(this->target == nullptr) {
    return this->getGame().renderManager.getBackBuffer();
  }
  return *this->target;
}

void Camera::setRenderTarget(std::shared_ptr<RenderTarget> renderTarget) {
  if(renderTarget == this->target) return;
  this->getRenderTarget().eventRenderTargetResized.removeListener(
    this, &Camera::onRenderTargetResize
  );
  this->target = renderTarget;
  this->getRenderTarget().eventRenderTargetResized.addListener(
    this, &Camera::onRenderTargetResize
  );
  this->updateProjection();
}

float_t Camera::getAspect() {
  RenderTarget &target = this->getRenderTarget();
  return target.getWidth() / target.getHeight();
}

void Camera::start() {
  this->updateProjection();
}

void Camera::onRenderTargetResize(RenderTarget &target, float_t w, float_t h) {
  this->updateProjection();
}

Camera::~Camera() {
  this->getRenderTarget().eventRenderTargetResized.removeListener(
    this, &Camera::onRenderTargetResize
  );
}