From c1b96fc14ef9b52ea396ddb745c1f3ecb58b80dd Mon Sep 17 00:00:00 2001
From: Lauchmelder <robert.trololo@gmail.com>
Date: Tue, 21 Dec 2021 18:14:01 +0100
Subject: [PATCH] added cameras

---
 backend/include/backend/Camera.hpp   | 52 ++++++++++++++++++++++++++++
 backend/include/backend/Drawable.hpp |  6 ++--
 backend/src/Drawable.cpp             |  4 +--
 src/Application.cpp                  | 48 ++++++++++++++++++++++---
 src/Application.hpp                  | 12 +++++++
 src/Cuboid.cpp                       |  7 ++--
 src/Cuboid.hpp                       |  2 +-
 7 files changed, 119 insertions(+), 12 deletions(-)
 create mode 100644 backend/include/backend/Camera.hpp

diff --git a/backend/include/backend/Camera.hpp b/backend/include/backend/Camera.hpp
new file mode 100644
index 0000000..1a6e614
--- /dev/null
+++ b/backend/include/backend/Camera.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <memory>
+#include "Transformable.hpp"
+#include "Drawable.hpp"
+
+// TODO: Find better name
+class CameraBase : public Transformable
+{
+public:
+	// "Scaling" doesn't really makes sense for a camera
+	void GetScale() = delete;
+	void SetScale(const glm::vec3&) = delete;
+	void Scale(const glm::vec3&) = delete;
+
+	inline const glm::mat4& GetView() const
+	{
+		return transformation;
+	}
+
+	inline const glm::mat4& GetProjection() const
+	{
+		return projection;
+	}
+
+	inline void Draw(const Drawable& drawable) const
+	{
+		drawable.Draw(*this);
+	}
+
+protected:
+	glm::mat4 projection;
+};
+
+
+class Camera : public CameraBase
+{
+public:
+	Camera(float fov = 90.0f, float aspect = 1.0f, float zNear = 0.01f, float zFar = 100.0f)
+	{
+		projection = glm::perspective(glm::radians(fov), aspect, zNear, zFar);
+	}
+};
+
+class OrthogonalCamera : public CameraBase
+{
+public:
+	OrthogonalCamera(float left = -1.0f, float right = 1.0f, float bottom = -1.0f, float top = 1.0f, float zNear = -100.0f, float zFar = 100.0f)
+	{
+		projection = glm::ortho(left, right, bottom, top, zNear, zFar);
+	}
+};
\ No newline at end of file
diff --git a/backend/include/backend/Drawable.hpp b/backend/include/backend/Drawable.hpp
index 129362c..a46f7b4 100644
--- a/backend/include/backend/Drawable.hpp
+++ b/backend/include/backend/Drawable.hpp
@@ -4,6 +4,8 @@
 #include "VertexArrayObject.hpp"
 #include "Shader.hpp"
 
+class CameraBase;
+
 enum class PrimitiveType
 {
 	Lines = GL_LINES,
@@ -21,8 +23,8 @@ public:
 	Drawable(const Drawable& other) = delete;
 	void operator=(const Drawable& other) = delete;
 
-	virtual void InitializeShader() = 0;
-	void Render();
+	virtual void InitializeShader(const CameraBase& camera) const = 0;
+	void Draw(const CameraBase& camera) const;
 	void SetPrimitiveType(PrimitiveType type);
 
 protected:
diff --git a/backend/src/Drawable.cpp b/backend/src/Drawable.cpp
index 95e2797..1d3a33c 100644
--- a/backend/src/Drawable.cpp
+++ b/backend/src/Drawable.cpp
@@ -1,9 +1,9 @@
 #include "backend/Drawable.hpp"
 
-void Drawable::Render()
+void Drawable::Draw(const CameraBase& camera) const
 {
 	shader->Use();
-	InitializeShader();
+	InitializeShader(camera);
 	vao->Render(static_cast<unsigned int>(type));
 }
 
diff --git a/src/Application.cpp b/src/Application.cpp
index e035daf..4ff9a73 100644
--- a/src/Application.cpp
+++ b/src/Application.cpp
@@ -87,6 +87,13 @@ void Application::Init(int width, int height, const std::string& title)
 	glfwSetFramebufferSizeCallback(window,
 		[](GLFWwindow* window, int width, int height)
 		{
+			WindowData* data = (WindowData*)glfwGetWindowUserPointer(window);
+
+			float aspectRatio = (float)width / (float)height;
+			*(data->camera) = Camera(100.0f, aspectRatio);
+			data->camera->Move(glm::vec3(0.0f, 0.0f, -4.0f));
+			*(data->orthoCam) = OrthogonalCamera(-3.0f * aspectRatio, 3.0f * aspectRatio, -3.0f, 3.0f);
+
 			glViewport(0, 0, width, height);
 		}
 	);
@@ -102,6 +109,8 @@ void Application::Init(int width, int height, const std::string& title)
 		}
 	);
 
+	glfwSetWindowUserPointer(window, &data);
+
 	// Set up ImGui
 	IMGUI_CHECKVERSION();
 	ImGui::CreateContext();
@@ -112,10 +121,22 @@ void Application::Init(int width, int height, const std::string& title)
 
 	ImGui::StyleColorsDark();
 
+	float aspectRatio = (float)windowWidth / (float)windowHeight;
+	camera = Camera(100.0f, aspectRatio);
+	camera.Move(glm::vec3(0.0f, 0.0f, -4.0f));
+
+	orthoCam = OrthogonalCamera(-3.0f * aspectRatio, 3.0f * aspectRatio, -3.0f, 3.0f);
+
+	activeCamera = &camera;
+
 	cube = new Cuboid();
 	cubePosition = glm::vec3(0.0f);
 	cubeOrientation = glm::vec3(0.0f);
 	cubeScale = glm::vec3(1.0f);
+
+	data.camera = &camera;
+	data.orthoCam = &orthoCam;
+
 }
 
 void Application::Launch()
@@ -135,12 +156,31 @@ void Application::Launch()
 		ImGui_ImplGlfw_NewFrame();
 		ImGui::NewFrame();
 
-		cube->Render();
+		cube->Draw(*activeCamera);
 
 		ImGui::Begin("Debug");
-		ImGui::SliderFloat3("Position", &(cubePosition[0]), -2.0f, 2.0f);
-		ImGui::SliderFloat3("Orientation", &(cubeOrientation[0]), 0.0f, glm::two_pi<float>());
-		ImGui::SliderFloat3("Scale", &(cubeScale[0]), 0.0f, 2.0f);
+
+		if (ImGui::CollapsingHeader("Cube"))
+		{
+			ImGui::SliderFloat3("Position", &(cubePosition[0]), -2.0f, 2.0f);
+			ImGui::SliderFloat3("Orientation", &(cubeOrientation[0]), 0.0f, glm::two_pi<float>());
+			ImGui::SliderFloat3("Scale", &(cubeScale[0]), 0.0f, 2.0f);
+		}
+
+		if (ImGui::CollapsingHeader("Camera"))
+		{
+			ImGui::Columns(2);
+			ImGui::Text("Projection: ");
+			ImGui::NextColumn();
+			if (ImGui::Button((activeCamera == &camera) ? "Perspective" : "Orthographic"))
+			{
+				if (activeCamera == &camera)
+					activeCamera = &orthoCam;
+				else
+					activeCamera = &camera;
+			}
+		}
+
 		ImGui::End();
 
 		ImGui::Render();
diff --git a/src/Application.hpp b/src/Application.hpp
index c5c0e78..c06fc8a 100644
--- a/src/Application.hpp
+++ b/src/Application.hpp
@@ -1,10 +1,17 @@
 #pragma once
 
 #include <string>
+#include "backend/Camera.hpp"
 #include "Cuboid.hpp"
 
 struct GLFWwindow;
 
+struct WindowData
+{
+	Camera* camera;
+	OrthogonalCamera* orthoCam;
+};
+
 class Application
 {
 /////////////////////////////////////////////////////////
@@ -33,6 +40,11 @@ public:
 
 private:
 	GLFWwindow* window = nullptr;
+	WindowData data;
+
+	Camera camera;
+	OrthogonalCamera orthoCam;
+	CameraBase* activeCamera;
 
 	glm::vec3 cubeOrientation, cubePosition, cubeScale;
 	Cuboid* cube;
diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp
index a0563c2..a43ea44 100644
--- a/src/Cuboid.cpp
+++ b/src/Cuboid.cpp
@@ -6,6 +6,7 @@
 #include <glm/gtc/matrix_transform.hpp>
 
 #include "backend/ObjectManager.hpp"
+#include "backend/Camera.hpp"
 #include "Util.hpp"
 
 Cuboid::Cuboid()
@@ -81,9 +82,9 @@ Cuboid::Cuboid()
 	perspective = glm::perspective(glm::radians(100.0f), 16.0f / 9.0f, 0.01f, 100.0f);
 }
 
-void Cuboid::InitializeShader()
+void Cuboid::InitializeShader(const CameraBase& camera) const
 {
 	shader->SetUniform("model", transformation);
-	shader->SetUniform("view", view);
-	shader->SetUniform("perspective", perspective);
+	shader->SetUniform("view", camera.GetView());
+	shader->SetUniform("perspective", camera.GetProjection());
 }
diff --git a/src/Cuboid.hpp b/src/Cuboid.hpp
index 3d96069..2a01ec0 100644
--- a/src/Cuboid.hpp
+++ b/src/Cuboid.hpp
@@ -14,7 +14,7 @@ class Cuboid :
 public:
 	Cuboid();
 
-	void InitializeShader() override;
+	void InitializeShader(const CameraBase& camera) const override;
 
 private: