From 06614dd1b0cbc01591f532db028e7f4bac39bd1c Mon Sep 17 00:00:00 2001
From: Robert <robert.trololo@gmail.com>
Date: Fri, 22 Jan 2021 19:02:14 +0100
Subject: [PATCH] Added basic camera functionality

---
 examples/model_loading/main.cpp |  16 ++---
 include/camera.hpp              | 110 ++++++++++++++++++++++++++++++++
 include/core.hpp                |   2 -
 include/openglu.hpp             |   1 +
 include/transformable.hpp       |   1 +
 src/camera.cpp                  |  68 ++++++++++++++++++++
 src/transformable.cpp           |  19 ++++--
 7 files changed, 200 insertions(+), 17 deletions(-)
 create mode 100644 include/camera.hpp
 create mode 100644 src/camera.cpp

diff --git a/examples/model_loading/main.cpp b/examples/model_loading/main.cpp
index e0e29a2..ab63ac5 100644
--- a/examples/model_loading/main.cpp
+++ b/examples/model_loading/main.cpp
@@ -69,28 +69,26 @@ int main(int argc, char** argv)
 		return -1;
 	}
 
-	glm::mat4 view = glm::mat4(1.0f);
-	view = glm::translate(view, glm::vec3(0.0f, -2.0f, -10.0f));
+	oglu::Enable(GL_DEPTH_TEST);
 
-	glm::mat4 projection;
-	projection = glm::perspective(glm::radians(45.f), 1.0f, 0.1f, 100.0f);
+	oglu::Camera camera(60.0f, 0.0f, 0.1f, 100.0f);
+	camera.Move(0.0f, -4.0f, -10.0f);
+	//camera.LookAt(utah);
+	//camera.GetMatrix();
 
 	// Window loop
-	oglu::Enable(GL_DEPTH_TEST);
 	while (!glfwWindowShouldClose(window))
 	{
 		processInput(window);
 
 		oglu::ClearScreen(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, oglu::Color(0.29f, 0.13f, 0.23f));
 
-		// view = glm::rotate(view, glm::radians(1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
-
 		utah.Rotate(0.0f, 1.0f, 0.0f);
 
 		shader->Use();
 		shader->SetUniform("model", utah);
-		shader->SetUniformMatrix4fv("view", 1, GL_FALSE, glm::value_ptr(view));
-		shader->SetUniformMatrix4fv("projection", 1, GL_FALSE, glm::value_ptr(projection));
+		shader->SetUniformMatrix4fv("view", 1, GL_FALSE, camera.GetMatrix());
+		shader->SetUniformMatrix4fv("projection", 1, GL_FALSE, camera.GetProjectionMatrix());
 
 		oglu::PolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 		utah.Render();
diff --git a/include/camera.hpp b/include/camera.hpp
new file mode 100644
index 0000000..f5c6567
--- /dev/null
+++ b/include/camera.hpp
@@ -0,0 +1,110 @@
+/*****************************************************************//**
+ * \file   camera.hpp
+ * \brief  Contains anything relevant to cameras
+ * 
+ * \author Lauchmelder
+ * \date   January 2021
+ *********************************************************************/
+#ifndef CAMERA_HPP
+#define CAMERA_HPP
+
+#include <core.hpp>
+#include <transformable.hpp>
+
+namespace oglu
+{
+	class Object;
+
+	/**
+	 * @brief A camera object in 3D space.
+	 * 
+	 * This class unites a world- and projection matrix.
+	 */
+	class OGLU_API Camera : public Transformable
+	{
+	public:
+		/**
+		 * @brief Create a default camera.
+		 * 
+		 * Sits at the origin, looks in negative z-direction.
+		 * FOV: 45.0�
+		 * Aspect ratio: Matches the viewport
+		 * zNear: 0.1f
+		 * zFar: 100.0f
+		 */
+		Camera();
+
+		/**
+		 * @brief Copy another camera.
+		 *
+		 * Every property of @p other is copied.
+		 * 
+		 * @param[in] other The camera to copy from
+		 */
+		Camera(const Camera& other);
+
+		/**
+		 * @brief Create a new camera.
+		 * 
+		 * Sits at the origin, looks in negative z-direction.
+		 * The other properties are set from the parameters
+		 * 
+		 * @param[in] fov The FOV (field of view) of the camera
+		 * @param[in] aspectRatio The aspect ratio of the camera. (Setting this to 0.f will use your viewport's aspect ratio)
+		 * @param[in] zNear Near z clipping plane
+		 * @param[in] zNear Far z clipping plane
+		 */
+		Camera(float fov, float aspectRatio, float zNear, float zFar);
+
+		~Camera();
+
+		/**
+		 * @brief Have camera face at a certain position.
+		 * 
+		 * This will adjust the camera's rotation in order to put the
+		 * specified coordinate at the center of the screen.
+		 * 
+		 * @param[in] x Target x coordinate
+		 * @param[in] y Target y coordinate
+		 * @param[in] z Target z coordinate
+		 */
+		void LookAt(GLfloat x, GLfloat y, GLfloat z);
+
+		/**
+		 * @brief Have camera face at a certain position.
+		 *
+		 * This will adjust the camera's rotation in order to put the
+		 * specified coordinate at the center of the screen.
+		 *
+		 * @param[in] target 3D vector with the target position
+		 */
+		void LookAt(const GLfloat* target);
+
+		/**
+		 * @brief Have camera face at a certain position.
+		 *
+		 * This will adjust the camera's rotation in order to put the
+		 * specified coordinate at the center of the screen.
+		 *
+		 * @param[in] target An object to target
+		 */
+		void LookAt(const Object& target);
+
+		/**
+		 * @brief Gets the projection matrix of the camera.
+		 * 
+		 * @returns a 4x4 projection matrix.
+		 */
+		const float* GetProjectionMatrix();
+
+	private:
+		float aspectRatio;	///< Aspect ration of the camera
+		float fov;			///< FOV of the camera
+		float zNear;		///< Near z clipping plane
+		float zFar;			///< Far z clipping plane
+
+		float* projection;
+	};
+}
+
+#endif 
\ No newline at end of file
diff --git a/include/core.hpp b/include/core.hpp
index 39d00b4..c7f2f4a 100644
--- a/include/core.hpp
+++ b/include/core.hpp
@@ -13,9 +13,7 @@
 #include <stdexcept>
 #include <string>
 
-#ifdef OGLU_BUILD_DLL
 #include <glad/glad.h>
-#endif
 
 #ifdef OGLU_WIN32
 	#ifdef OGLU_BUILD_DLL
diff --git a/include/openglu.hpp b/include/openglu.hpp
index 51a5840..46c93bd 100644
--- a/include/openglu.hpp
+++ b/include/openglu.hpp
@@ -13,6 +13,7 @@
 #include <shader.hpp>
 #include <texture.hpp>
 #include <object.hpp>
+#include <camera.hpp>
 
 namespace oglu
 {
diff --git a/include/transformable.hpp b/include/transformable.hpp
index 4b91f1b..c5137a9 100644
--- a/include/transformable.hpp
+++ b/include/transformable.hpp
@@ -262,6 +262,7 @@ namespace oglu
 		float* rotation;	///< Rotation matrix
 		float* scaling;		///< Scaling vector
 
+		float* transformation;
 		bool calculateMatrix;	///< Wether GetMatrix() needs to re-calculate the transformation matrix
 	};
 }
diff --git a/src/camera.cpp b/src/camera.cpp
new file mode 100644
index 0000000..b924a76
--- /dev/null
+++ b/src/camera.cpp
@@ -0,0 +1,68 @@
+#include "camera.hpp"
+
+#include <algorithm>
+
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+namespace oglu
+{
+	Camera::Camera() :
+		fov(45.0f), aspectRatio(0.0f), zNear(0.1f), zFar(100.0f), projection(new float[16]{ 0.0f })
+	{
+		memcpy(
+			projection,
+			glm::value_ptr(glm::perspective(glm::radians(fov), aspectRatio, zNear, zFar)),
+			16 * sizeof(float)
+		);
+	}
+
+	Camera::Camera(const Camera& other) :
+		fov(other.fov), aspectRatio(other.aspectRatio), zNear(other.zNear), zFar(other.zFar), projection(new float[16]{ 0.0f })
+	{
+		memcpy(
+			projection,
+			other.projection,
+			16 * sizeof(float)
+		);
+	}
+
+	Camera::Camera(float fov, float aspectRatio, float zNear, float zFar) :
+		fov(fov), aspectRatio(aspectRatio), zNear(zNear), zFar(zFar), projection(new float[16]{ 0.0f })
+	{
+		if (aspectRatio == 0.0f)
+		{
+			GLint viewport[4];
+			glGetIntegerv(GL_VIEWPORT, viewport);
+			aspectRatio = (float)viewport[2] / (float)viewport[3];
+		}
+
+		memcpy(
+			projection,
+			glm::value_ptr(glm::perspective(glm::radians(fov), aspectRatio, zNear, zFar)),
+			16 * sizeof(float)
+		);
+	}
+
+	Camera::~Camera()
+	{
+	}
+
+	void Camera::LookAt(GLfloat x, GLfloat y, GLfloat z)
+	{
+	}
+
+	void Camera::LookAt(const GLfloat* target)
+	{
+	}
+
+	void Camera::LookAt(const Object& target)
+	{
+	}
+
+	const float* Camera::GetProjectionMatrix()
+	{
+		return projection;
+	}
+}
diff --git a/src/transformable.cpp b/src/transformable.cpp
index a8b13c8..844e66a 100644
--- a/src/transformable.cpp
+++ b/src/transformable.cpp
@@ -9,7 +9,7 @@
 namespace oglu
 {
 	oglu::Transformable::Transformable() :
-		position(new float[3]{ 0.f }), rotation(new float[16]), scaling(new float[3]{ 1.f, 1.f, 1.f }), calculateMatrix(false)
+		position(new float[3]{ 0.f }), rotation(new float[16]), scaling(new float[3]{ 1.f, 1.f, 1.f }), transformation(new float[16]), calculateMatrix(false)
 	{
 		glm::mat4 identity(1.0f);
 		memcpy(
@@ -17,10 +17,15 @@ namespace oglu
 			glm::value_ptr(identity),
 			16 * sizeof(float)
 		);
+		memcpy(
+			transformation,
+			glm::value_ptr(identity),
+			16 * sizeof(float)
+		);
 	}
 
 	Transformable::Transformable(const Transformable& other) :
-		position(new float[3]), rotation(new float[16]), scaling(new float[3]), calculateMatrix(true)
+		position(new float[3]), rotation(new float[16]), scaling(new float[3]), transformation(new float[16]), calculateMatrix(true)
 	{
 		memcpy(
 			this->position,
@@ -232,15 +237,17 @@ namespace oglu
 
 	const float* Transformable::GetMatrix()
 	{
-		static glm::mat4 transformation(1.0f);
-
 		if (calculateMatrix)
 		{
-			transformation = glm::translate(glm::mat4(1.0f), glm::make_vec3(position)) * glm::make_mat4(rotation) * glm::scale(glm::mat4(1.0f), glm::make_vec3(scaling));
+			memcpy(
+				transformation,
+				glm::value_ptr(glm::translate(glm::mat4(1.0f), glm::make_vec3(position)) * glm::make_mat4(rotation) * glm::scale(glm::mat4(1.0f), glm::make_vec3(scaling))),
+				16 * sizeof(float)
+			);
 			calculateMatrix = false;
 		}
 
-		return glm::value_ptr(transformation);
+		return transformation;
 	}
 
 	const float* Transformable::GetPosition()