--- /dev/null
+#ifndef MSP_GAME_CAMERA_H_
+#define MSP_GAME_CAMERA_H_
+
+#include <msp/geometry/angle.h>
+#include <msp/linal/vector.h>
+#include "component.h"
+
+namespace Msp::Game {
+
+enum class CameraScaling
+{
+ ORIGINAL_SIZE,
+ SCALE_TO_FIT,
+ SCALE_TO_COVER,
+ STRETCH_TO_FIT
+};
+
+struct CameraSetup
+{
+ Geometry::Angle<float> field_of_view_y = Geometry::Angle<float>::from_degrees(60);
+ LinAl::Vector<float, 2> size = { 16.0f/9.0f, 1.0f };
+ float near_clip = 0.1f;
+ float far_clip = 100.0f;
+ CameraScaling scaling = CameraScaling::SCALE_TO_FIT;
+ std::string sequence_name;
+};
+
+class Camera: public Component
+{
+public:
+ using Setup = CameraSetup;
+
+private:
+ const Setup &setup;
+ Geometry::Angle<float> fov_y;
+ LinAl::Vector<float, 2> size;
+ float height;
+ float near_clip;
+ float far_clip;
+
+public:
+ Camera(Handle<Entity>, const Setup &);
+
+ void set_field_of_view(Geometry::Angle<float>, float);
+ void set_size(const LinAl::Vector<float, 2> &);
+ bool is_orthographic() const { return fov_y==Geometry::Angle<float>::zero(); }
+ Geometry::Angle<float> get_fov_vertical() const { return fov_y; }
+ Geometry::Angle<float> get_fov_horizontal() const { return Geometry::atan(tan(fov_y/2.0f)*get_aspect())*2.0f; }
+ const LinAl::Vector<float, 2> &get_size() const { return size; }
+ float get_aspect() const { return size.x/size.y; }
+ float get_near_clip() const { return near_clip; }
+ float get_far_clip() const { return far_clip; }
+ CameraScaling get_scaling() const { return setup.scaling; }
+ const std::string &get_sequence_name() const { return setup.sequence_name; }
+};
+
+} // namespace Msp::Game
+
+#endif