From 6ed978051668c08f5a957c97570f364dd580c807 Mon Sep 17 00:00:00 2001 From: Mel Date: Fri, 21 Oct 2022 01:03:18 +0200 Subject: Namespace and Folder refactor --- src/GFX/Binder.cpp | 65 +++++++++++++++++++ src/GFX/Binder.hpp | 38 +++++++++++ src/GFX/Camera.cpp | 42 ++++++++++++ src/GFX/Camera.hpp | 26 ++++++++ src/GFX/Image/PPMParser.cpp | 154 ++++++++++++++++++++++++++++++++++++++++++++ src/GFX/Image/PPMParser.hpp | 44 +++++++++++++ src/GFX/Image/RawImage.cpp | 29 +++++++++ src/GFX/Image/RawImage.hpp | 37 +++++++++++ src/GFX/Mesh.cpp | 29 +++++++++ src/GFX/Mesh.hpp | 34 ++++++++++ src/GFX/Mouse.cpp | 24 +++++++ src/GFX/Mouse.hpp | 21 ++++++ src/GFX/Shading/Program.cpp | 42 ++++++++++++ src/GFX/Shading/Program.hpp | 25 +++++++ src/GFX/Shading/Shader.cpp | 24 +++++++ src/GFX/Shading/Shader.hpp | 29 +++++++++ src/GFX/Shading/Uniform.cpp | 14 ++++ src/GFX/Shading/Uniform.hpp | 23 +++++++ src/GFX/Texture.cpp | 29 +++++++++ src/GFX/Texture.hpp | 17 +++++ src/GFX/Window.cpp | 55 ++++++++++++++++ src/GFX/Window.hpp | 30 +++++++++ 22 files changed, 831 insertions(+) create mode 100644 src/GFX/Binder.cpp create mode 100644 src/GFX/Binder.hpp create mode 100644 src/GFX/Camera.cpp create mode 100644 src/GFX/Camera.hpp create mode 100644 src/GFX/Image/PPMParser.cpp create mode 100644 src/GFX/Image/PPMParser.hpp create mode 100644 src/GFX/Image/RawImage.cpp create mode 100644 src/GFX/Image/RawImage.hpp create mode 100644 src/GFX/Mesh.cpp create mode 100644 src/GFX/Mesh.hpp create mode 100644 src/GFX/Mouse.cpp create mode 100644 src/GFX/Mouse.hpp create mode 100644 src/GFX/Shading/Program.cpp create mode 100644 src/GFX/Shading/Program.hpp create mode 100644 src/GFX/Shading/Shader.cpp create mode 100644 src/GFX/Shading/Shader.hpp create mode 100644 src/GFX/Shading/Uniform.cpp create mode 100644 src/GFX/Shading/Uniform.hpp create mode 100644 src/GFX/Texture.cpp create mode 100644 src/GFX/Texture.hpp create mode 100644 src/GFX/Window.cpp create mode 100644 src/GFX/Window.hpp (limited to 'src/GFX') diff --git a/src/GFX/Binder.cpp b/src/GFX/Binder.cpp new file mode 100644 index 0000000..e7b7e4c --- /dev/null +++ b/src/GFX/Binder.cpp @@ -0,0 +1,65 @@ +#include +#include "Binder.hpp" +#include "Mesh.hpp" + +namespace MC::GFX { + +BindableMesh Binder::load(Mesh& mesh) { + auto vao = create_vao(); + if (mesh.indices_size() > 0) { + store_indices(mesh.raw_indices(), mesh.indices_size()); + } + store_in_attribute_list(0, 3, mesh.raw(), mesh.size() * 3); + store_in_attribute_list(1, 2, mesh.raw_tex_coords(), mesh.tex_coords_size() * 2); + unbind_vao(); + + return {vao, mesh.indices_size()}; +} + +uint32_t Binder::create_vao() { + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + return static_cast(vao); +} + +void Binder::unbind_vao() { + glBindVertexArray(0); +} + +void Binder::store_indices(uint32_t* indices, size_t indices_size) { + GLuint ebo; + glGenBuffers(1, &ebo); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_size * sizeof(float), indices, GL_STATIC_DRAW); +} + +void Binder::store_in_attribute_list(uint32_t attribute, size_t size, float* data, size_t data_size) { + GLuint vbo; + glGenBuffers(1, &vbo); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, data_size * sizeof(float), data, GL_STATIC_DRAW); + glVertexAttribPointer(attribute, size, GL_FLOAT, GL_FALSE, size * sizeof(float), nullptr); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void BindableMesh::bind() const { + glBindVertexArray(m_vao); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); +} + +void BindableMesh::unbind() { + glBindVertexArray(0); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); +} + +size_t BindableMesh::size() const { + return m_vertex_count; +} + +} \ No newline at end of file diff --git a/src/GFX/Binder.hpp b/src/GFX/Binder.hpp new file mode 100644 index 0000000..99f9791 --- /dev/null +++ b/src/GFX/Binder.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include "Mesh.hpp" + +namespace MC::GFX { + +class BindableMesh { +public: + void bind() const; + void unbind(); + + size_t size() const; + +private: + BindableMesh(uint32_t vao, size_t vertex_count) : m_vao(vao), m_vertex_count(vertex_count) {}; + + uint32_t m_vao; + size_t m_vertex_count; + + friend class Binder; +}; + +class Binder { +public: + Binder() = default;; + + static BindableMesh load(Mesh& mesh); + +private: + static uint32_t create_vao(); + static void unbind_vao(); + + static void store_in_attribute_list(uint32_t attribute, size_t size, float* data, size_t data_size); + static void store_indices(uint32_t* indices, size_t indices_size); +}; + +} \ No newline at end of file diff --git a/src/GFX/Camera.cpp b/src/GFX/Camera.cpp new file mode 100644 index 0000000..6b25347 --- /dev/null +++ b/src/GFX/Camera.cpp @@ -0,0 +1,42 @@ +#include "Camera.hpp" + +namespace MC::GFX { + +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; +} + +void Camera::move_relative(Vector<3> by) { + auto rotation = Matrix<4, 4>::rotation(m_angles); + + auto result = rotation.transpose() * Vector<4>{by.x(), by.y(), by.z(), 1.0f}; + move(result.elements); +} + +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; + + if (m_angles.pitch() > 89.0f) { + m_angles.pitch() = 89.0f; + } else if (m_angles.pitch() < -89.0f) { + m_angles.pitch() = -89.0f; + } +} + +} diff --git a/src/GFX/Camera.hpp b/src/GFX/Camera.hpp new file mode 100644 index 0000000..f03f009 --- /dev/null +++ b/src/GFX/Camera.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../Math/Math.hpp" +#include "../Math/Rotation.hpp" + +namespace MC::GFX { + +class Camera { +public: + Camera() = default; + + Vector<3> position(); + void set_position(Vector<3> position); + void move(Vector<3> by); + void move_relative(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/GFX/Image/PPMParser.cpp b/src/GFX/Image/PPMParser.cpp new file mode 100644 index 0000000..7fc2359 --- /dev/null +++ b/src/GFX/Image/PPMParser.cpp @@ -0,0 +1,154 @@ +#include +#include +#include "PPMParser.hpp" + +namespace MC::GFX::Image { + +RawImage PPMParser::parse() { + auto header = parse_header(); + + if (header.max_color != 255) { + throw std::logic_error("PPM max color values other than 255 are not implemented."); + } + + if (header.type != P3) { + throw std::logic_error("Raw PPM not implemented."); + } + + auto pixel_count = header.width * header.height; + + RawImage image(pixel_count, header.width, header.height, 3); + for (uint64_t pixel_index = 0; pixel_index < pixel_count; pixel_index++) { + RawImage::Pixel pixel = parse_pixel(header.max_color); + image.add(pixel); + } + + return image; +} + +PPMParser::PPMHeader PPMParser::parse_header() { + PPMHeader header{}; + + skip_whitespace(); + + auto type_part = chomp_part(); + skip_whitespace(); + + if (type_part == "P3") { + header.type = P3; + } else if (type_part == "P6") { + header.type = P6; + } else { + throw std::runtime_error("Unknown PPM type."); + } + + auto width_part = chomp_number(); + skip_whitespace(); + header.width = width_part; + + auto height_part = chomp_number(); + skip_whitespace(); + header.height = height_part; + + auto max_color_part = chomp_number(); + skip_whitespace(); + header.max_color = max_color_part; + + return header; +} + +RawImage::Pixel PPMParser::parse_pixel(uint8_t max_color) { + auto r_sample = parse_sample(); + auto g_sample = parse_sample(); + auto b_sample = parse_sample(); + + if (r_sample > max_color || g_sample > max_color || b_sample > max_color) { + throw std::runtime_error("Sample can not be greater than Maxval."); + } + + auto map_to_range = [=](uint64_t s) -> uint8_t { return (s * 255) / max_color; }; + + RawImage::Pixel pixel{}; + pixel.r = map_to_range(r_sample); + pixel.g = map_to_range(g_sample); + pixel.b = map_to_range(b_sample); + + return pixel; +} + +uint64_t PPMParser::parse_sample() { + skip_whitespace(); + auto sample = chomp_number(); + skip_whitespace(); + return sample; +} + +uint64_t PPMParser::chomp_number() { + auto raw = chomp_part(); + + uint64_t number = 0; + for (uint8_t digit_ascii : raw) { + if (digit_ascii < '0' || digit_ascii > '9') { + throw std::runtime_error("Number contains non ASCII digits."); + } + + uint8_t digit = digit_ascii - '0'; + + number *= 10; + number += digit; + } + + return number; +} + +std::string_view PPMParser::chomp_part() { + uint64_t length = 0; + + while (!is_eof()) { + auto c = m_source[m_cursor + length]; + if (std::isspace(c)) { + break; + } + + length++; + } + + auto part = m_source.substr(m_cursor, length); + m_cursor += length; + + return part; +} + +void PPMParser::skip_whitespace() { + uint8_t c; + while (!is_eof()) { + c = m_source[m_cursor]; + if (c == '#') { + skip_comment(); + continue; + } + + if (!std::isspace(c)) { + break; + } + + m_cursor++; + } +} + +void PPMParser::skip_comment() { + uint8_t c = m_source[m_cursor]; + if (c != '#') { + return; + } + + while (c != '\n' && !is_eof()) { + c = m_source[++m_cursor]; + } +} + +bool PPMParser::is_eof() { + return m_cursor >= m_source.size(); +} + +} \ No newline at end of file diff --git a/src/GFX/Image/PPMParser.hpp b/src/GFX/Image/PPMParser.hpp new file mode 100644 index 0000000..3909cee --- /dev/null +++ b/src/GFX/Image/PPMParser.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include "RawImage.hpp" + +namespace MC::GFX::Image { + +class PPMParser { +public: + explicit PPMParser(std::string_view source) : m_source(source) {}; + + RawImage parse(); +private: + enum PPMType { + None, + P3, + P6 + }; + + struct PPMHeader { + PPMType type; + uint32_t width; + uint32_t height; + uint8_t max_color; + }; + + PPMHeader parse_header(); + RawImage::Pixel parse_pixel(uint8_t max_color); + uint64_t parse_sample(); + + uint64_t chomp_number(); + std::string_view chomp_part(); + + void skip_whitespace(); + void skip_comment(); + + bool is_eof(); + + std::string_view m_source; + uint64_t m_cursor = 0; +}; + +} diff --git a/src/GFX/Image/RawImage.cpp b/src/GFX/Image/RawImage.cpp new file mode 100644 index 0000000..aca8fbc --- /dev/null +++ b/src/GFX/Image/RawImage.cpp @@ -0,0 +1,29 @@ +#include "RawImage.hpp" + +namespace MC::GFX::Image { + +void RawImage::add(RawImage::Pixel pixel) { + m_pixels.push_back(pixel); +} + +size_t RawImage::size() const { + return m_pixels.size(); +} + +uint8_t* RawImage::raw() const { + return (uint8_t*)m_pixels.data(); +} + +uint32_t RawImage::width() const { + return m_width; +} + +uint32_t RawImage::height() const { + return m_height; +} + +uint8_t RawImage::channels() const { + return m_channels; +} + +} \ No newline at end of file diff --git a/src/GFX/Image/RawImage.hpp b/src/GFX/Image/RawImage.hpp new file mode 100644 index 0000000..916671b --- /dev/null +++ b/src/GFX/Image/RawImage.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +namespace MC::GFX::Image { + +class RawImage { +public: + RawImage() : m_pixels(), m_width(0), m_height(0), m_channels(0) {}; + + explicit RawImage(size_t pixel_count, uint32_t width, uint32_t height, uint8_t channels) + : m_pixels(), m_width(width), m_height(height), m_channels(channels) { + m_pixels.reserve(pixel_count); + } + + struct Pixel { + uint8_t r, g, b; + }; + + void add(Pixel pixel); + + size_t size() const; + uint8_t* raw() const; + + uint32_t width() const; + uint32_t height() const; + uint8_t channels() const; +private: + std::vector m_pixels; + + uint32_t m_width, m_height; + uint8_t m_channels; +}; + +} diff --git a/src/GFX/Mesh.cpp b/src/GFX/Mesh.cpp new file mode 100644 index 0000000..12f8aaa --- /dev/null +++ b/src/GFX/Mesh.cpp @@ -0,0 +1,29 @@ +#include "Mesh.hpp" + +namespace MC::GFX { + +float* Mesh::raw() { + return (float*) m_positions.data(); +} + +size_t Mesh::size() { + return m_positions.size(); +} + +uint32_t* Mesh::raw_indices() { + return m_indices.data(); +} + +size_t Mesh::indices_size() { + return m_indices.size(); +} + +float* Mesh::raw_tex_coords() { + return (float*) m_tex_coords.data(); +} + +size_t Mesh::tex_coords_size() { + return m_tex_coords.size(); +} + +} \ No newline at end of file diff --git a/src/GFX/Mesh.hpp b/src/GFX/Mesh.hpp new file mode 100644 index 0000000..f027c8c --- /dev/null +++ b/src/GFX/Mesh.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include "../Math/Math.hpp" + +namespace MC::GFX { + +class Mesh { +public: + Mesh(std::vector> positions, std::vector> tex_coords, std::vector indices) + : m_positions(std::move(positions)), m_tex_coords(std::move(tex_coords)), m_indices(std::move(indices)) {}; + + Mesh(std::vector> positions, std::vector> tex_coords) + : m_positions(std::move(positions)), m_tex_coords(std::move(tex_coords)), m_indices() {}; + + float* raw(); + size_t size(); + + uint32_t* raw_indices(); + size_t indices_size(); + + float* raw_tex_coords(); + size_t tex_coords_size(); + +private: + std::vector> m_positions; + std::vector> m_tex_coords; + std::vector m_indices; + +}; + +} \ No newline at end of file diff --git a/src/GFX/Mouse.cpp b/src/GFX/Mouse.cpp new file mode 100644 index 0000000..5cd2698 --- /dev/null +++ b/src/GFX/Mouse.cpp @@ -0,0 +1,24 @@ +#include "Mouse.hpp" + +namespace MC::GFX { + +Vector<2> Mouse::update(GLFWwindow* window) { + double x, y; + glfwGetCursorPos(window, &x, &y); + + if (m_first_event) { + m_last_x = x; + m_last_y = y; + + m_first_event = false; + } + + Vector<2> movement{static_cast(x) - m_last_x, static_cast(y) - m_last_y}; + + m_last_x = x; + m_last_y = y; + + return movement; +} + +} \ No newline at end of file diff --git a/src/GFX/Mouse.hpp b/src/GFX/Mouse.hpp new file mode 100644 index 0000000..3ed57a2 --- /dev/null +++ b/src/GFX/Mouse.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include "../Math/Vector.hpp" + +namespace MC::GFX { + +class Mouse { +public: + Mouse() = default; + + Vector<2> update(GLFWwindow* window); +private: + bool m_first_event = true; + + float m_last_x = 0.0f; + float m_last_y = 0.0f; +}; + +} \ No newline at end of file diff --git a/src/GFX/Shading/Program.cpp b/src/GFX/Shading/Program.cpp new file mode 100644 index 0000000..39393f8 --- /dev/null +++ b/src/GFX/Shading/Program.cpp @@ -0,0 +1,42 @@ +#include +#include +#include "Program.hpp" + +namespace MC::GFX::Shading { + +Program::Program(Shader fragment, Shader vertex) { + m_program = glCreateProgram(); + + glAttachShader(m_program, fragment.get()); + glAttachShader(m_program, vertex.get()); + + glLinkProgram(m_program); + + glDeleteShader(fragment.get()); + glDeleteShader(vertex.get()); + + GLint success; + glGetProgramiv(m_program, GL_LINK_STATUS, &success); + if(!success) { + char message[512] = {}; + glGetProgramInfoLog(m_program, 512, nullptr, message); + + throw std::runtime_error(message); + } +} + +void Program::bind() const { + glUseProgram(m_program); +} + +Uniform Program::uniform(const std::string& name) const { + auto index = glGetUniformLocation(m_program, name.c_str()); + + return {name, static_cast(index)}; +} + +uint32_t Program::get() const { + return m_program; +} + +} diff --git a/src/GFX/Shading/Program.hpp b/src/GFX/Shading/Program.hpp new file mode 100644 index 0000000..15c9899 --- /dev/null +++ b/src/GFX/Shading/Program.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include "Shader.hpp" +#include "../../Math/Math.hpp" +#include "Uniform.hpp" + +namespace MC::GFX::Shading { + +class Program { +public: + Program(Shader fragment, Shader vertex); + + uint32_t get() const; + + Uniform uniform(const std::string& name) const; + + void bind() const; + +private: + uint32_t m_program; +}; + +} \ No newline at end of file diff --git a/src/GFX/Shading/Shader.cpp b/src/GFX/Shading/Shader.cpp new file mode 100644 index 0000000..ff954a5 --- /dev/null +++ b/src/GFX/Shading/Shader.cpp @@ -0,0 +1,24 @@ +#include +#include +#include "Shader.hpp" + +namespace MC::GFX::Shading { + +Shader::Shader(uint32_t type, const char* source) { + m_shader = glCreateShader(type); + + glShaderSource(m_shader, 1, &source, nullptr); + glCompileShader(m_shader); + + GLint success; + glGetShaderiv(m_shader, GL_COMPILE_STATUS, &success); + if(!success) { + char message[512] = {}; + glGetShaderInfoLog(m_shader, 512, nullptr, message); + + throw std::runtime_error(message); + } +} + + +} \ No newline at end of file diff --git a/src/GFX/Shading/Shader.hpp b/src/GFX/Shading/Shader.hpp new file mode 100644 index 0000000..4a3d9cf --- /dev/null +++ b/src/GFX/Shading/Shader.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "../../Assets.hpp" + +namespace MC::GFX::Shading { + +class Shader { + +public: + uint32_t get() const { + return m_shader; + } + + static Shader create_vertex() { + return {GL_VERTEX_SHADER, Assets::Shaders::vertex}; + } + + static Shader create_fragment() { + return {GL_FRAGMENT_SHADER, Assets::Shaders::fragment}; + } + +private: + Shader(uint32_t type, const char* source); + + uint32_t m_shader; +}; + +} \ No newline at end of file diff --git a/src/GFX/Shading/Uniform.cpp b/src/GFX/Shading/Uniform.cpp new file mode 100644 index 0000000..9448574 --- /dev/null +++ b/src/GFX/Shading/Uniform.cpp @@ -0,0 +1,14 @@ +#include +#include "Uniform.hpp" + +namespace MC::GFX::Shading { + +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/GFX/Shading/Uniform.hpp b/src/GFX/Shading/Uniform.hpp new file mode 100644 index 0000000..8035dfe --- /dev/null +++ b/src/GFX/Shading/Uniform.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include "../../Math/Math.hpp" + +namespace MC::GFX::Shading { + +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/GFX/Texture.cpp b/src/GFX/Texture.cpp new file mode 100644 index 0000000..1942128 --- /dev/null +++ b/src/GFX/Texture.cpp @@ -0,0 +1,29 @@ +#include +#include "Texture.hpp" + +namespace MC::GFX { + +Texture::Texture(const Image::RawImage& image) { + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.raw()); + glGenerateMipmap(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, 0); +} + +void Texture::bind() { + glBindTexture(GL_TEXTURE_2D, m_texture); +} + +void Texture::unbind() { + glBindTexture(GL_TEXTURE_2D, 0); +} +} \ No newline at end of file diff --git a/src/GFX/Texture.hpp b/src/GFX/Texture.hpp new file mode 100644 index 0000000..ff86634 --- /dev/null +++ b/src/GFX/Texture.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "Image/RawImage.hpp" + +namespace MC::GFX { + +class Texture { +public: + explicit Texture(const Image::RawImage& image); + + void bind(); + void unbind(); +private: + uint32_t m_texture; +}; + +} \ No newline at end of file diff --git a/src/GFX/Window.cpp b/src/GFX/Window.cpp new file mode 100644 index 0000000..0a1828c --- /dev/null +++ b/src/GFX/Window.cpp @@ -0,0 +1,55 @@ +#include +#include "Window.hpp" + +namespace MC::GFX { + +Window::Window(const char *title, uint32_t width, uint32_t height) { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_DOUBLEBUFFER, GL_TRUE); + + m_window = glfwCreateWindow(width, height, title, nullptr, nullptr); + if (m_window == nullptr) { + throw std::runtime_error("Failed to create window."); + } + + glfwMakeContextCurrent(m_window); + glfwSetInputMode(m_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +} + +Window::~Window() { + glfwDestroyWindow(m_window); +} + +bool Window::should_close() { + return glfwWindowShouldClose(m_window); +} + +GLFWwindow* Window::get() { + return m_window; +} + +void Window::close() { + glfwSetWindowShouldClose(m_window, true); +} + +Vector<2> Window::mouse_delta() { + return m_mouse.update(m_window); +} + +bool Window::key(int key, int type) { + return (glfwGetKey(m_window, key) == type); +} + +void Window::start_frame() { + glfwSwapBuffers(m_window); + glfwPollEvents(); +} + +void Window::on_size_change(void (callback)(GLFWwindow*, int, int)) { + glfwSetFramebufferSizeCallback(m_window, static_cast(callback)); +} + +} \ No newline at end of file diff --git a/src/GFX/Window.hpp b/src/GFX/Window.hpp new file mode 100644 index 0000000..63e8446 --- /dev/null +++ b/src/GFX/Window.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include "../Math/Vector.hpp" +#include "Mouse.hpp" + +namespace MC::GFX { + +class Window { +public: + Window(const char* title, uint32_t width, uint32_t height); + ~Window(); + + GLFWwindow* get(); + + void on_size_change(void (* callback)(GLFWwindow*, int, int)); + + void close(); + void start_frame(); + Vector<2> mouse_delta(); + + bool key(int key, int type); + bool should_close(); +private: + GLFWwindow* m_window; + Mouse m_mouse; +}; + +} \ No newline at end of file -- cgit 1.4.1