From 85f87152ad920edc71550b39d06398a52bf6c65a Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Thu, 6 Jul 2023 16:46:07 +0300 Subject: [PATCH] add abstraction for shaders and camera --- meson.build | 3 + shaders/fragment.glsl | 14 +++++ shaders/vertex.glsl | 18 ++++++ src/camera.cpp | 78 +++++++++++++++++++++++ src/camera.hpp | 33 ++++++++++ src/common.cpp | 31 ++++++++++ src/common.hpp | 8 +++ src/main.cpp | 141 ++++-------------------------------------- src/shader.cpp | 105 +++++++++++++++++++++++++++++++ src/shader.hpp | 4 ++ 10 files changed, 307 insertions(+), 128 deletions(-) create mode 100644 shaders/fragment.glsl create mode 100644 shaders/vertex.glsl create mode 100644 src/camera.cpp create mode 100644 src/camera.hpp create mode 100644 src/common.cpp create mode 100644 src/common.hpp create mode 100644 src/shader.cpp create mode 100644 src/shader.hpp diff --git a/meson.build b/meson.build index 362daf1..4623b5c 100644 --- a/meson.build +++ b/meson.build @@ -9,6 +9,9 @@ incdir = include_directories(['src', 'src/vendor']) executable( 'game', + './src/common.cpp', + './src/shader.cpp', + './src/camera.cpp', './src/main.cpp', './src/vendor/glad/glad.c', include_directories : incdir, diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl new file mode 100644 index 0000000..1f16171 --- /dev/null +++ b/shaders/fragment.glsl @@ -0,0 +1,14 @@ +#version 330 core + + +in vec2 TexCoord; + +out vec4 FragColor; + +uniform sampler2D tex; + + +void main() +{ + FragColor = texture(tex, TexCoord); +} diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl new file mode 100644 index 0000000..ab99072 --- /dev/null +++ b/shaders/vertex.glsl @@ -0,0 +1,18 @@ +#version 330 core + + +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoord; + +out vec2 TexCoord; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + TexCoord = aTexCoord; +} diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..6752016 --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,78 @@ +#include "camera.hpp" + +#include "vendor/glm/glm/mat4x4.hpp" +#include "vendor/glm/glm/geometric.hpp" +#include "vendor/glm/glm/gtc/type_ptr.hpp" + + + +void Camera::process_mouse(double x, double y) +{ + bool dirty = last_mouse_x != x || last_mouse_y != y; + + if (!mouse_moved_once) { + mouse_moved_once = true; + last_mouse_x = x; + last_mouse_y = y; + dirty = true; + } + + if (!dirty) { + return; + } + + double x_offset = (x - last_mouse_x) * turn_speed; + double y_offset = (last_mouse_y - y) * turn_speed; + yaw += x_offset; + pitch += y_offset; + + if (pitch > 89.0f) + pitch = 89.0f; + if (pitch < -89.0f) + pitch = -89.0f; + + double pitch_factor = cos(glm::radians(pitch)); + front = (glm::vec3){ + cos(glm::radians(yaw)) * pitch_factor, + sin(glm::radians(pitch)), + sin(glm::radians(yaw)) * pitch_factor + }; + + last_mouse_x = x; + last_mouse_y = y; + + view = compute_view(); +} + +void Camera::movement(float delta_time, CameraMovement movement) +{ + const float factor = movement_speed * delta_time; + + switch (movement) { + case MovementUp: + position += factor * up; + break; + case MovementDown: + position += factor * down; + break; + case MovementLeft: + position -= factor * glm::normalize(glm::cross(front, up)); + break; + case MovementRight: + position += factor * glm::normalize(glm::cross(front, up)); + break; + case MovementBack: + position -= factor * front; + break; + case MovementForward: + position += factor * front; + break; + } + + view = compute_view(); +} + +const glm::mat4 Camera::compute_view(void) +{ + return glm::lookAt(position, position + front, up); +} diff --git a/src/camera.hpp b/src/camera.hpp new file mode 100644 index 0000000..c3a7946 --- /dev/null +++ b/src/camera.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "vendor/glm/glm/mat4x4.hpp" +#include "vendor/glm/glm/vec3.hpp" + + +struct Camera { + enum CameraMovement { + MovementUp, + MovementDown, + MovementLeft, + MovementRight, + MovementBack, + MovementForward, + }; + + double yaw = -90.0f; + double pitch = 0.0f; + double movement_speed = 2.0f; + double turn_speed = 0.1f; + double last_mouse_x, last_mouse_y = 0.0f; + bool mouse_moved_once = false; + glm::vec3 position { 0.0f, 0.0f, 3.0f }; + glm::vec3 front { 0.0f, 0.0f, -1.0f }; + glm::vec3 up { 0.0f, 1.0f, 0.0f }; + glm::vec3 down = { 0.0f, -1.0f, 0.0f }; + glm::mat4 view { 1.0f }; + + void process_mouse(double x, double y); + void movement(float delta_time, CameraMovement movement); + const glm::mat4 compute_view(void); +}; + diff --git a/src/common.cpp b/src/common.cpp new file mode 100644 index 0000000..3c3fa07 --- /dev/null +++ b/src/common.cpp @@ -0,0 +1,31 @@ +#include "common.hpp" +#include +#include +#include + + +Errno read_entire_file(FILE *f, char **out_data) +{ + long saved = ftell(f); + if (saved < 0) return errno; + if (fseek(f, 0, SEEK_END) < 0) return errno; + long size = ftell(f); + if (size < 0) return errno; + if (fseek(f, saved, SEEK_SET) < 0) return errno; + + char *data = (char*)malloc(size + 1); + if (!data) { + return errno; + } + + fread(data, 1, size, f); + if (ferror(f)) { + free(data); + return errno; + } + + data[size] = 0; + *out_data = data; + + return 0; +} diff --git a/src/common.hpp b/src/common.hpp new file mode 100644 index 0000000..0e744b8 --- /dev/null +++ b/src/common.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +typedef int Errno; + + +Errno read_entire_file(FILE *f, char **out_data); diff --git a/src/main.cpp b/src/main.cpp index c4c0321..bef521a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ #include #include #include +#include "camera.hpp" +#include "shader.hpp" #include "vendor/glad/glad.h" #include "vendor/glm/glm/ext/matrix_transform.hpp" #define GLFW_INCLUDE_NONE @@ -19,63 +21,6 @@ std::function framebuffer_size_callback = nullptr; std::function cursor_position_callback = nullptr; -unsigned int create_shader(unsigned int type, const char **source) -{ - unsigned int shader = glCreateShader(type); - if (!shader) { - printf("err: create_shader: glCreateShader returned 0\n"); - return 0; - } - glShaderSource(shader, 1, source, NULL); - glCompileShader(shader); - - int success; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (!success) { - char log[512]; - glGetShaderInfoLog(shader, 512, NULL, log); - printf("err: create_shader: compilation failed, log: %s\n", log); - return 0; - } - - return shader; -} - -unsigned int create_program(const char *vertex_shader_source, const char *fragment_shader_source) -{ - unsigned int program = glCreateProgram(); - if (!program) { - printf("err: create_program: glCreateProgram returned 0\n"); - return 0; - } - - unsigned int vertex_shader = create_shader(GL_VERTEX_SHADER, &vertex_shader_source); - if (!vertex_shader) { - printf("err: create_program: create_shader failed returned 0 (vertex_shader)\n"); - return 0; - } - unsigned int fragment_shader = create_shader(GL_FRAGMENT_SHADER, &fragment_shader_source); - if (!fragment_shader) { - printf("err: create_program: create_shader failed returned 0 (fragment_shader)\n"); - return 0; - } - - glAttachShader(program, vertex_shader); - glAttachShader(program, fragment_shader); - glLinkProgram(program); - - int success; - glGetProgramiv(program, GL_LINK_STATUS, &success); - if (!success) { - char log[512]; - glGetProgramInfoLog(program, 512, NULL, log); - printf("err: create_program: link failed, log: %s\n", log); - return 0; - } - - return program; -} - int main() { qoi_desc fish_desc; @@ -158,31 +103,7 @@ int main() -0.5f, 0.5f, -0.5f, 0.0f, 1.0f }; - static const char *vertex_shader_source = "" - "#version 330 core\n" - "layout (location = 0) in vec3 aPos;\n" - "layout (location = 1) in vec2 aTexCoord;\n" - "out vec2 TexCoord;\n" - "uniform mat4 model;\n" - "uniform mat4 view;\n" - "uniform mat4 projection;\n" - "void main()\n" - "{\n" - " gl_Position = projection * view * model * vec4(aPos, 1.0);\n" - " TexCoord = aTexCoord;\n" - "}\0"; - - static const char *fragment_shader_source = "" - "#version 330 core\n" - "in vec2 TexCoord;\n" - "out vec4 FragColor;\n" - "uniform sampler2D tex;\n" - "void main()\n" - "{\n" - " FragColor = texture(tex, TexCoord);\n" - "}\0"; - - unsigned int program = create_program(vertex_shader_source, fragment_shader_source); + unsigned int program = create_program("shaders/vertex.glsl", "shaders/fragment.glsl"); unsigned int texture; glGenTextures(1, &texture); @@ -208,16 +129,7 @@ int main() glEnableVertexAttribArray(1); glm::mat4 projection = glm::mat4(1.0f); - - glm::vec3 camera_position = glm::vec3(0.0f, 0.0f, 3.0f); - glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f); - glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f); - glm::vec3 camera_down = glm::vec3(0.0f, -1.0f, 0.0f); - - double camera_pitch = 0.0f; - double camera_yaw = 0.0f; - double last_mouse_x, last_mouse_y = 0.0f; - bool mouse_moved_once = false; + Camera camera; framebuffer_size_callback = [&projection, program](int width, int height) { projection = glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 100.0f); @@ -225,32 +137,8 @@ int main() glViewport(0, 0, width, height); }; - cursor_position_callback = [&mouse_moved_once, &last_mouse_x, &last_mouse_y, &camera_pitch, &camera_yaw, &camera_front](double x, double y) { - if (!mouse_moved_once) { - mouse_moved_once = true; - last_mouse_x = x; - last_mouse_y = y; - } - - double x_offset = (x - last_mouse_x) * 0.15; - double y_offset = (last_mouse_y - y) * 0.15; - camera_yaw += x_offset; - camera_pitch += y_offset; - - if (camera_pitch > 89.0f) - camera_pitch = 89.0f; - if (camera_pitch < -89.0f) - camera_pitch = -89.0f; - - double pitch_factor = cos(glm::radians(camera_pitch)); - camera_front = (glm::vec3){ - cos(glm::radians(camera_yaw)) * pitch_factor, - sin(glm::radians(camera_pitch)), - sin(glm::radians(camera_yaw)) * pitch_factor - }; - - last_mouse_x = x; - last_mouse_y = y; + cursor_position_callback = [&camera](double x, double y) { + camera.process_mouse(x, y); }; float delta_time = 0.0f; @@ -261,33 +149,30 @@ int main() delta_time = current_frame_time - last_frame_time; last_frame_time = current_frame_time; - const float camera_speed = 2.0f * delta_time; // adjust accordingly if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { - camera_position += camera_speed * camera_front; + camera.movement(delta_time, Camera::MovementForward); } if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { - camera_position -= camera_speed * camera_front; + camera.movement(delta_time, Camera::MovementBack); } if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { - camera_position -= glm::normalize(glm::cross(camera_front, camera_up)) * camera_speed; + camera.movement(delta_time, Camera::MovementLeft); } if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { - camera_position += glm::normalize(glm::cross(camera_front, camera_up)) * camera_speed; + camera.movement(delta_time, Camera::MovementRight); } if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) { - camera_position += camera_speed * camera_up; + camera.movement(delta_time, Camera::MovementUp); } if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) { - camera_position += camera_speed * camera_down; + camera.movement(delta_time, Camera::MovementDown); } glClearColor(0.5, 0.5, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glm::mat4 view = glm::lookAt(camera_position, camera_position + camera_front, camera_up); - glUseProgram(program); - glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, glm::value_ptr(view)); + glUniformMatrix4fv(glGetUniformLocation(program, "view"), 1, GL_FALSE, glm::value_ptr(camera.view)); glBindTexture(GL_TEXTURE_2D, texture); glBindVertexArray(vertex_array); diff --git a/src/shader.cpp b/src/shader.cpp new file mode 100644 index 0000000..7f28f37 --- /dev/null +++ b/src/shader.cpp @@ -0,0 +1,105 @@ +#include "shader.hpp" +#include "common.hpp" +#include "vendor/glad/glad.h" +#include +#include +#include +#include + + +unsigned int create_shader(unsigned int type, const char **source) +{ + unsigned int shader = glCreateShader(type); + if (!shader) { + printf("err: create_shader: glCreateShader returned 0\n"); + return 0; + } + glShaderSource(shader, 1, source, NULL); + glCompileShader(shader); + + int success; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) { + char log[512]; + glGetShaderInfoLog(shader, 512, NULL, log); + printf("err: create_shader: compilation failed, log: %s\n", log); + return 0; + } + + return shader; +} + +unsigned int create_program_source(const char *vertex_shader_source, const char *fragment_shader_source) +{ + unsigned int program = glCreateProgram(); + if (!program) { + printf("err: create_program: glCreateProgram returned 0\n"); + return 0; + } + + unsigned int vertex_shader = create_shader(GL_VERTEX_SHADER, &vertex_shader_source); + if (!vertex_shader) { + printf("err: create_program: create_shader failed returned 0 (vertex_shader)\n"); + return 0; + } + unsigned int fragment_shader = create_shader(GL_FRAGMENT_SHADER, &fragment_shader_source); + if (!fragment_shader) { + printf("err: create_program: create_shader failed returned 0 (fragment_shader)\n"); + return 0; + } + + glAttachShader(program, vertex_shader); + glAttachShader(program, fragment_shader); + glLinkProgram(program); + + int success; + glGetProgramiv(program, GL_LINK_STATUS, &success); + if (!success) { + char log[512]; + glGetProgramInfoLog(program, 512, NULL, log); + printf("err: create_program: link failed, log: %s\n", log); + return 0; + } + + return program; +} + +unsigned int create_program(const char *vertex_shader_path, const char *fragment_shader_path) +{ + FILE *vertex_shader_file, *fragment_shader_file = NULL; + char *vertex_shader_source = NULL; + char *fragment_shader_source = NULL; + Errno err = 0; + unsigned int ret = 0; + + vertex_shader_file = fopen(vertex_shader_path, "r"); + if (!vertex_shader_file) { + fprintf(stderr, "create_program: failed to open vertex shader file (%s): %s\n", vertex_shader_path, strerror(errno)); + goto done; + } + err = read_entire_file(vertex_shader_file, &vertex_shader_source); + if (err) { + fprintf(stderr, "create_program: failed to read vertex shader file (%s): %s\n", vertex_shader_path, strerror(err)); + goto done; + } + + fragment_shader_file = fopen(fragment_shader_path, "r"); + if (!fragment_shader_file) { + fprintf(stderr, "create_program: failed to open fragment shader file (%s): %s\n", fragment_shader_path, strerror(errno)); + goto done; + } + err = read_entire_file(fragment_shader_file, &fragment_shader_source); + if (err) { + fprintf(stderr, "create_program: failed to read fragment shader file (%s): %s\n", fragment_shader_path, strerror(err)); + goto done; + } + + ret = create_program_source(vertex_shader_source, fragment_shader_source); + +done: + if (vertex_shader_file) fclose(vertex_shader_file); + if (fragment_shader_file) fclose(fragment_shader_file); + if (vertex_shader_source) free(vertex_shader_source); + if (fragment_shader_source) free(fragment_shader_source); + return ret; +} diff --git a/src/shader.hpp b/src/shader.hpp new file mode 100644 index 0000000..8028e06 --- /dev/null +++ b/src/shader.hpp @@ -0,0 +1,4 @@ +#pragma once + + +unsigned int create_program(const char *vertex_shader_path, const char *fragment_shader_path);