diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Camera.cpp | 29 | ||||
| -rw-r--r-- | src/Camera.hpp | 25 | ||||
| -rw-r--r-- | src/Math/MVP.cpp | 82 | ||||
| -rw-r--r-- | src/Math/MVP.hpp | 11 | ||||
| -rw-r--r-- | src/Math/Math.hpp | 3 | ||||
| -rw-r--r-- | src/Math/Matrix.hpp | 46 | ||||
| -rw-r--r-- | src/Math/Rotation.hpp | 31 | ||||
| -rw-r--r-- | src/Math/Vector.hpp | 29 | ||||
| -rw-r--r-- | src/Shader/ShaderProgram.cpp | 10 | ||||
| -rw-r--r-- | src/Shader/ShaderProgram.hpp | 10 | ||||
| -rw-r--r-- | src/Shader/Uniform.cpp | 14 | ||||
| -rw-r--r-- | src/Shader/Uniform.hpp | 23 | ||||
| -rw-r--r-- | src/Shader/fragment.glsl | 5 | ||||
| -rw-r--r-- | src/Shader/vertex.glsl | 6 | ||||
| -rw-r--r-- | src/Window.cpp | 4 | ||||
| -rw-r--r-- | src/Window.hpp | 3 | ||||
| -rw-r--r-- | src/main.cpp | 76 |
17 files changed, 385 insertions, 22 deletions
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) { |
