// Copyright 2024 SquareBlock Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard)

#pragma once

#include <opencv2/core/core.hpp>

#include "mesh.h"
#include "rasterizer.h"
#include "util/math_util.h"

class MinusRenderer {
public:
  MinusRenderer(float near, float far, float fov, float aspect_ratio);

public:
  void set_meshes(const std::vector<Mesh> &meshes);
  void set_lamps(const std::vector<std::shared_ptr<PointLamp>> &lamps);

  cv::Mat render(const int resolution_width, const int resolution_height);

public:
  void model_transform(const TransformMatrix &mtx);
  void view_transform(const TransformMatrix &mtx);

private:
  static float calculate_height(const float fov, const float near);
  static float calculate_width(const float height, const float ratio);
  static std::tuple<double, double, double>
  calculate_barycentric_coordinate(const Triangle &t, const Point3d &p);

private:
  std::pair<TransformMatrix, TransformMatrix>
  construct_transform(const int resolution_width,
                      const int resolution_height) const;

private:
  cv::Vec3b fragment_shader(const RasterizerResult &fragment,
                            const Point3d &position, const Mesh &mesh);

private:
  float near_;
  float far_;
  float fov_; // In radian
  float aspect_ratio_;

  std::vector<Mesh> meshes_;
  std::vector<std::shared_ptr<PointLamp>> lamps_;

  std::unique_ptr<Rasterizer> rasterizer_;
};
