summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/Camera.cpp29
-rw-r--r--src/Camera.hpp25
-rw-r--r--src/Math/MVP.cpp82
-rw-r--r--src/Math/MVP.hpp11
-rw-r--r--src/Math/Math.hpp3
-rw-r--r--src/Math/Matrix.hpp46
-rw-r--r--src/Math/Rotation.hpp31
-rw-r--r--src/Math/Vector.hpp29
-rw-r--r--src/Shader/ShaderProgram.cpp10
-rw-r--r--src/Shader/ShaderProgram.hpp10
-rw-r--r--src/Shader/Uniform.cpp14
-rw-r--r--src/Shader/Uniform.hpp23
-rw-r--r--src/Shader/fragment.glsl5
-rw-r--r--src/Shader/vertex.glsl6
-rw-r--r--src/Window.cpp4
-rw-r--r--src/Window.hpp3
-rw-r--r--src/main.cpp76
18 files changed, 386 insertions, 23 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7fb3c37..3dd75df 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 17)
 find_package(glfw3 3.3 REQUIRED)
 find_package(GLEW REQUIRED)
 
-add_executable(meowcraft src/main.cpp src/Window.cpp src/Window.hpp src/Mesh.cpp src/Mesh.hpp src/Math/Vector.hpp src/Math/Math.hpp src/Binder.cpp src/Binder.hpp src/Shader/ShaderSources.hpp src/Shader/Shader.cpp src/Shader/Shader.hpp src/Shader/ShaderProgram.cpp src/Shader/ShaderProgram.hpp)
+add_executable(meowcraft src/main.cpp src/Window.cpp src/Window.hpp src/Mesh.cpp src/Mesh.hpp src/Math/Vector.hpp src/Math/Math.hpp src/Binder.cpp src/Binder.hpp src/Shader/ShaderSources.hpp src/Shader/Shader.cpp src/Shader/Shader.hpp src/Shader/ShaderProgram.cpp src/Shader/ShaderProgram.hpp src/Math/Matrix.hpp src/Math/MVP.cpp src/Math/MVP.hpp src/Camera.cpp src/Camera.hpp src/Math/Rotation.hpp src/Shader/Uniform.cpp src/Shader/Uniform.hpp)
 target_link_libraries(meowcraft glfw GLEW::GLEW)
 
 function(make_includable input_file output_file)
diff --git a/src/Camera.cpp b/src/Camera.cpp
new file mode 100644
index 0000000..5bb9aa2
--- /dev/null
+++ b/src/Camera.cpp
@@ -0,0 +1,29 @@
+#include "Camera.hpp"
+
+namespace MC {
+
+Vector<3> Camera::position() {
+    return m_position;
+}
+
+void Camera::set_position(Vector<3> position) {
+    m_position = position;
+}
+
+void Camera::move(Vector<3> vector) {
+    m_position = m_position + vector;
+}
+
+Rotation Camera::angles() {
+    return m_angles;
+}
+
+void Camera::set_angles(Rotation angles) {
+    m_angles = angles;
+}
+
+void Camera::rotate(Rotation by) {
+    m_angles = m_angles + by;
+}
+
+}
diff --git a/src/Camera.hpp b/src/Camera.hpp
new file mode 100644
index 0000000..decba87
--- /dev/null
+++ b/src/Camera.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "Math/Math.hpp"
+#include "Math/Rotation.hpp"
+
+namespace MC {
+
+class Camera {
+public:
+    Camera() = default;
+
+    Vector<3> position();
+    void set_position(Vector<3> position);
+    void move(Vector<3> by);
+
+    Rotation angles();
+    void set_angles(Rotation angles);
+    void rotate(Rotation by);
+
+private:
+    Vector<3> m_position = {};
+    Rotation m_angles = {};
+};
+
+}
\ No newline at end of file
diff --git a/src/Math/MVP.cpp b/src/Math/MVP.cpp
new file mode 100644
index 0000000..37675b4
--- /dev/null
+++ b/src/Math/MVP.cpp
@@ -0,0 +1,82 @@
+#include <cmath>
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/type_ptr.hpp>
+#include <glm/gtx/string_cast.hpp>
+#include "MVP.hpp"
+#include "Math.hpp"
+
+namespace Math::MVP {
+
+Matrix<4, 4> transformation_matrix(Vector<3> position) {
+    return {
+            1.0f, 0.0f, 0.0f, position.x(),
+            0.0f, 1.0f, 0.0f, position.y(),
+            0.0f, 0.0f, 1.0f, position.z(),
+            0.0f, 0.0f, 0.0f, 1.0f
+    };
+}
+
+Matrix<4, 4> rotation_matrix(Rotation angles) {
+    auto c = angles.vector.apply(cos);
+    auto s = angles.vector.apply(sin);
+
+    Matrix<4, 4> rotation_x{
+            1.0f, 0.0f,  0.0f,   0.0f,
+            0.0f, c.x(), -s.x(), 0.0f,
+            0.0f, s.x(), c.x(),  0.0f,
+            0.0f, 0.0f,  0.0f,   1.0f,
+    };
+
+    Matrix<4, 4> rotation_y{
+            c.y(),  0.0f, s.y(),  0.0f,
+            0.0f,   1.0f, 0.0f,   0.0f,
+            -s.y(), 0.0f, c.y(),  0.0f,
+            0.0f,   0.0f, 0.0f,   1.0f,
+    };
+
+    Matrix<4, 4> rotation_z{
+            c.z(), -s.z(), 0.0f,  0.0f,
+            s.z(), c.z(),  0.0f,  0.0f,
+            0.0f,  0.0f,   1.0f,  0.0f,
+            0.0f,  0.0f,   0.0f,  1.0f,
+    };
+
+    return rotation_x * rotation_y * rotation_z;
+}
+
+Matrix<4, 4> model(Vector<3> position, Rotation angles) {
+    auto transformation = transformation_matrix(position);
+    auto rotation = rotation_matrix(angles);
+
+    return transformation * rotation;
+}
+
+Matrix<4, 4> view(Vector<3> position, Rotation angles) {
+    auto transformation = transformation_matrix(position);
+    auto rotation = rotation_matrix(angles);
+
+    return transformation * rotation;
+}
+
+Matrix<4, 4> projection(float aspect, float fov, float near, float far) {
+    auto fov_radians = (fov * M_PI) / 180.0f;
+
+    float x_scale = 1.0f / (tan(fov_radians / 2.0f) * aspect);
+    float y_scale = 1.0f / tan(fov_radians / 2.0f);
+
+    float frustum_length = far - near;
+    float z_near = -(far + near) / frustum_length;
+    float z_far = -(2 * far * near) / frustum_length;
+
+    Matrix<4, 4> projection{
+        x_scale, 0.0f,    0.0f,   0.0f,
+        0.0f,    y_scale, 0.0f,   0.0f,
+        0.0f,    0.0f,    z_near, z_far,
+        0.0f,    0.0f,    -1.0f,   0.0f,
+    };
+
+    return projection;
+}
+
+}
diff --git a/src/Math/MVP.hpp b/src/Math/MVP.hpp
new file mode 100644
index 0000000..c3fb64f
--- /dev/null
+++ b/src/Math/MVP.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "Math.hpp"
+
+namespace Math::MVP {
+
+Matrix<4, 4> model(Vector<3> position, Rotation angles);
+Matrix<4, 4> view(Vector<3> position, Rotation angles);
+Matrix<4, 4> projection(float aspect, float fov, float near, float far);
+
+}
diff --git a/src/Math/Math.hpp b/src/Math/Math.hpp
index 8204728..b8b61a1 100644
--- a/src/Math/Math.hpp
+++ b/src/Math/Math.hpp
@@ -1,4 +1,5 @@
 #pragma once
 
 #include "Vector.hpp"
-#include "Matrix.hpp"
\ No newline at end of file
+#include "Matrix.hpp"
+#include "Rotation.hpp"
\ No newline at end of file
diff --git a/src/Math/Matrix.hpp b/src/Math/Matrix.hpp
index adc34a9..9a6b7e6 100644
--- a/src/Math/Matrix.hpp
+++ b/src/Math/Matrix.hpp
@@ -1,7 +1,7 @@
 #pragma once
 
 #include <sstream>
-#include <stddef.h>
+#include <cstddef>
 #include <iostream>
 
 template <size_t R, size_t C, typename T = float>
@@ -9,8 +9,24 @@ struct Matrix {
 public:
     Matrix<R, C, T>() : elements{} {};
 
+    Matrix<R, C, T>(T scalar) {
+        std::fill(elements, elements + R * C, scalar);
+    };
+
     template<typename ...Args>
-    explicit Matrix<R, C, T>(Args... args): elements{ args... } {};
+    Matrix<R, C, T>(Args... args): elements{ args... } {};
+
+    Matrix<R, C, T>(T values[R * C]) {
+        std::copy(values, values + R * C, elements);
+    };
+
+    static Matrix<R, R, T> identity() {
+        Matrix<R, R, T> result{};
+        for (int i = 0; i < R; i++) {
+            result(i, i) = 1;
+        }
+        return result;
+    }
 
     Vector<C, T> row(size_t index) {
         return { &elements[index * C] };
@@ -24,6 +40,22 @@ public:
         return result;
     }
 
+    Matrix<R, C, T> operator+(Matrix<R, C, T> other) {
+        Matrix<R, C, T> result{};
+        for (int i = 0; i < R * C; i++) {
+            result.elements[i] = elements[i] + other.elements[i];
+        }
+        return result;
+    }
+
+    Matrix<R, C, T> operator*(float scalar) {
+        Matrix<R, C, T> result{};
+        for (int i = 0; i < R * C; i++) {
+            result.elements[i] = elements[i] * scalar;
+        }
+        return result;
+    }
+
     template<size_t N>
     Matrix<R, N, T> operator*(Matrix<C, N, T> other) {
         Matrix<R, N, T> result{};
@@ -34,16 +66,18 @@ public:
 
                 auto dot = r * c;
 
-                std::cout << x << ", " << y << ": "
-                    << "(" << r.string() << ", " << c.string() << ")"
-                    << dot << std::endl;
-
                 result(x, y) = dot;
             }
         }
         return result;
     }
 
+    Vector<R, T> operator*(Vector<R, T> vector) {
+        Matrix<R, 1, T> matrix(vector.elements);
+        matrix = this->operator*(matrix);
+        return { matrix.elements };
+    }
+
     auto& operator()(size_t x, size_t y) {
         return elements[y * C + x];
     }
diff --git a/src/Math/Rotation.hpp b/src/Math/Rotation.hpp
new file mode 100644
index 0000000..334ede2
--- /dev/null
+++ b/src/Math/Rotation.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <cmath>
+#include "Vector.hpp"
+
+struct Rotation {
+public:
+    Rotation() : vector{} {};
+
+    Rotation(Vector<3> vector) : vector{ wrap(vector) } {};
+
+    Rotation(float angles[3]) : Rotation(angles[0], angles[1], angles[2]) {};
+
+    Rotation(float x, float y, float z) {
+        vector = wrap({ x, y, z });
+    };
+
+    Rotation operator+(Rotation other) const {
+        return wrap(vector + other.vector);
+    }
+
+    std::string string() const {
+        return vector.string();
+    }
+
+    static Vector<3> wrap(Vector<3> v) {
+        return v.apply([=](float a) -> float { return fmod(a, 360.0f); });
+    }
+
+    Vector<3> vector;
+};
\ No newline at end of file
diff --git a/src/Math/Vector.hpp b/src/Math/Vector.hpp
index 0145b58..2e97217 100644
--- a/src/Math/Vector.hpp
+++ b/src/Math/Vector.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <stddef.h>
+#include <cstddef>
 #include <sstream>
 #include <iostream>
 #include <iterator>
@@ -17,10 +17,35 @@ public:
         std::copy(values, values + S, elements);
     };
 
+    Vector<S, T>(Vector<S - 1, T> vector, T scalar) {
+        std::copy(vector.elements, vector.elements + S - 1, elements);
+        elements[S - 1] = scalar;
+    }
+
+    Vector<S, T> apply(T f(T)) {
+        return apply(static_cast<std::function<T(T)>>(f));
+    }
+
+    Vector<S, T> apply(std::function<T(T)> f) {
+        Vector<S, T> result{};
+        for (int i = 0; i < S; i++) {
+            result[i] = f(elements[i]);
+        }
+        return result;
+    }
+
     T& operator[](size_t index) {
         return elements[index];
     }
 
+    Vector<S, T> operator+(Vector<S, T> other) const {
+        Vector<S, T> result{};
+        for (int i = 0; i < S; i++) {
+            result[i] = elements[i] + other[i];
+        }
+        return result;
+    }
+
     Vector<S, T> operator*(T scalar) const {
         Vector<S, T> result;
         for (size_t index; index < S; index++) {
@@ -57,7 +82,7 @@ public:
         return elements[3];
     }
 
-    std::string string() {
+    std::string string() const {
         std::stringstream str{};
 
         str << "[ ";
diff --git a/src/Shader/ShaderProgram.cpp b/src/Shader/ShaderProgram.cpp
index 854b1bf..4d0b684 100644
--- a/src/Shader/ShaderProgram.cpp
+++ b/src/Shader/ShaderProgram.cpp
@@ -29,4 +29,14 @@ void ShaderProgram::bind() const {
     glUseProgram(m_program);
 }
 
+Uniform ShaderProgram::uniform(const std::string& name) const {
+    auto index = glGetUniformLocation(m_program, name.c_str());
+
+    return {name, static_cast<uint32_t>(index)};
+}
+
+uint32_t ShaderProgram::get() const {
+    return m_program;
+}
+
 }
diff --git a/src/Shader/ShaderProgram.hpp b/src/Shader/ShaderProgram.hpp
index 800e3ff..857dc2f 100644
--- a/src/Shader/ShaderProgram.hpp
+++ b/src/Shader/ShaderProgram.hpp
@@ -1,6 +1,10 @@
 #pragma once
 
+#include <string>
+#include <vector>
 #include "Shader.hpp"
+#include "../Math/Math.hpp"
+#include "Uniform.hpp"
 
 namespace MC {
 
@@ -8,9 +12,11 @@ class ShaderProgram {
 public:
     ShaderProgram(Shader fragment, Shader vertex);
 
-    void bind() const;
+    uint32_t get() const;
+
+    Uniform uniform(const std::string& name) const;
 
-    uint32_t get();
+    void bind() const;
 
 private:
     uint32_t m_program;
diff --git a/src/Shader/Uniform.cpp b/src/Shader/Uniform.cpp
new file mode 100644
index 0000000..71b7633
--- /dev/null
+++ b/src/Shader/Uniform.cpp
@@ -0,0 +1,14 @@
+#include <GL/glew.h>
+#include "Uniform.hpp"
+
+namespace MC {
+
+void Uniform::set(Matrix<4, 4> value) const {
+    glUniformMatrix4fv(m_index, 1, GL_TRUE, value.elements);
+}
+
+void Uniform::set(Vector<3> value) const {
+    glUniform3f(m_index, value.x(), value.y(), value.z());
+}
+
+}
diff --git a/src/Shader/Uniform.hpp b/src/Shader/Uniform.hpp
new file mode 100644
index 0000000..58cdc28
--- /dev/null
+++ b/src/Shader/Uniform.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include <utility>
+#include "../Math/Math.hpp"
+
+namespace MC {
+
+class Uniform {
+public:
+    Uniform(std::string name, uint32_t index)
+        : m_name(std::move(name)), m_index(index) {};
+
+    void set(Matrix<4, 4> value) const;
+    void set(Vector<3> value) const;
+
+private:
+    std::string m_name;
+    uint32_t m_index;
+};
+
+}
diff --git a/src/Shader/fragment.glsl b/src/Shader/fragment.glsl
index 017a2c8..ba5ed93 100644
--- a/src/Shader/fragment.glsl
+++ b/src/Shader/fragment.glsl
@@ -2,7 +2,6 @@
 
 out vec4 color;
 
-void main()
-{
-    color = vec4(1.0f, 0.5f, 0.2f, 1.0f);
+void main() {
+    color = vec4(0.2f, 0.6f, 0.6f, 1.0f); // #339999
 }
\ No newline at end of file
diff --git a/src/Shader/vertex.glsl b/src/Shader/vertex.glsl
index 8b1bbbd..e7b9e3d 100644
--- a/src/Shader/vertex.glsl
+++ b/src/Shader/vertex.glsl
@@ -1,7 +1,11 @@
 #version 330 core
 
+uniform mat4 model_matrix;
+uniform mat4 view_matrix;
+uniform mat4 projection_matrix;
+
 in vec3 position;
 
 void main() {
-    gl_Position = vec4(position.x, position.y, position.z, 1.0);
+    gl_Position = projection_matrix * view_matrix * model_matrix * vec4(position, 1.0);
 }
\ No newline at end of file
diff --git a/src/Window.cpp b/src/Window.cpp
index 54d70f9..413cd47 100644
--- a/src/Window.cpp
+++ b/src/Window.cpp
@@ -43,4 +43,8 @@ void Window::start_frame() {
     glfwPollEvents();
 }
 
+void Window::on_size_change(void (callback)(GLFWwindow*, int, int)) {
+    glfwSetFramebufferSizeCallback(m_window, static_cast<GLFWframebuffersizefun>(callback));
+}
+
 }
\ No newline at end of file
diff --git a/src/Window.hpp b/src/Window.hpp
index acd39fe..5a2b640 100644
--- a/src/Window.hpp
+++ b/src/Window.hpp
@@ -12,6 +12,8 @@ public:
 
     GLFWwindow* get();
 
+    void on_size_change(void (* callback)(GLFWwindow*, int, int));
+
     void close();
     void start_frame();
 
@@ -19,6 +21,7 @@ public:
     bool should_close();
 private:
     GLFWwindow* m_window;
+
 };
 
 }
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 0893849..16eda51 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,19 +1,27 @@
 #include <iostream>
 #include <GL/glew.h>
 #include <GLFW/glfw3.h>
+#include <cmath>
+#include <cstdint>
 
 #include "Window.hpp"
 #include "Mesh.hpp"
+#include "Camera.hpp"
 #include "Binder.hpp"
+#include "Math/MVP.hpp"
 #include "Shader/ShaderProgram.hpp"
 
 #define APP_NAME "Meowcraft"
 
 #define WINDOW_WIDTH 1000
 #define WINDOW_HEIGHT 800
+#define ASPECT static_cast<float>(WINDOW_WIDTH) / WINDOW_HEIGHT
+
+#define FOV 45
 
 void run();
 void render(MC::BindableMesh&);
+void process_input(MC::Window&, MC::Camera&);
 void setup_gl();
 void fix_macos_render(MC::Window&);
 
@@ -37,18 +45,45 @@ void run() {
     setup_gl();
 
     glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
+    window.on_size_change([](GLFWwindow* window, int w, int h) {
+        glViewport(0, 0, w, h);
+    });
 
     MC::Mesh shape({
-        {-0.5f, -0.5f, 0.0f}, {0.5f, -0.5f, 0.0f},
-        {-0.5f, 0.5f, 0.0f},  {0.5f, 0.5f, 0.0f},
-    }, {0, 1, 2, 3, 2, 1});
+       {-0.5f, -0.5f,  0.5f},
+       {0.5f, -0.5f,  0.5f},
+       {0.5f,  0.5f,  0.5f},
+       {-0.5f,  0.5f,  0.5f},
+
+       {-0.5f, -0.5f, -0.5f},
+       {0.5f, -0.5f, -0.5f},
+       {0.5f,  0.5f, -0.5f},
+       {-0.5f,  0.5f, -0.5f}
+    }, {
+        0, 1, 2, 2, 3, 0,
+        1, 5, 6, 6, 2, 1,
+        7, 6, 5, 5, 4, 7,
+        4, 0, 3, 3, 7, 4,
+        4, 5, 1, 1, 0, 4,
+        3, 2, 6, 6, 7, 3
+    });
 
     auto mesh = MC::Binder::load(shape);
 
-    auto mesh = MC::Binder::load(quad);
+    MC::Camera camera{};
+    camera.set_position({0.0f, 0.0f, -3.0f});
 
     MC::ShaderProgram program(MC::Shader::create_fragment(), MC::Shader::create_vertex());
+
+    auto model_uniform = program.uniform("model_matrix");
+    auto view_uniform = program.uniform("view_matrix");
+    auto projection_uniform = program.uniform("projection_matrix");
+
     program.bind();
+    auto projection = Math::MVP::projection(ASPECT, FOV, 0.1f, 100.0f);
+    projection_uniform.set(projection);
+
+    uint64_t time = 0;
 
     while (!window.should_close()) {
         window.start_frame();
@@ -57,11 +92,19 @@ void run() {
         fix_macos_render(window);
 #endif
 
-        if (window.key(GLFW_KEY_ESCAPE, GLFW_PRESS)) {
-            window.close();
-        }
+        process_input(window, camera);
+
+        program.bind();
+
+        auto angle = fmod(time / 10.0f, 360.0f);
+        auto model = Math::MVP::model({0.0f, 0.0f, 0.0f}, {angle, angle, 0.0f});
+        model_uniform.set(model);
+
+        auto view = Math::MVP::view(camera.position(), camera.angles());
+        view_uniform.set(view);
 
         render(mesh);
+        time++;
     }
 }
 
@@ -74,6 +117,25 @@ void render(MC::BindableMesh& mesh) {
     mesh.unbind();
 }
 
+void process_input(MC::Window& window, MC::Camera& camera) {
+    if (window.key(GLFW_KEY_ESCAPE, GLFW_PRESS)) {
+        window.close();
+    }
+
+    auto key = [&](int key) -> float { return window.key(key, GLFW_PRESS); };
+
+    float forward = key(GLFW_KEY_W) - key(GLFW_KEY_S);
+    float side = key(GLFW_KEY_D) - key(GLFW_KEY_A);
+
+    float vertical = key(GLFW_KEY_UP) - key(GLFW_KEY_DOWN);
+    float horizontal = key(GLFW_KEY_LEFT) - key(GLFW_KEY_RIGHT);
+
+    auto speed = 0.05f;
+
+    camera.move({side * speed, forward * speed, 0.0f});
+    camera.rotate({vertical * speed, horizontal * speed, 0.0f});
+}
+
 void setup_gl() {
     GLenum error;
     if ((error = glewInit()) != GLEW_OK) {