add abstraction for shaders and camera

This commit is contained in:
hippoz 2023-07-06 16:46:07 +03:00
parent eefee6537a
commit 85f87152ad
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
10 changed files with 307 additions and 128 deletions

View file

@ -9,6 +9,9 @@ incdir = include_directories(['src', 'src/vendor'])
executable( executable(
'game', 'game',
'./src/common.cpp',
'./src/shader.cpp',
'./src/camera.cpp',
'./src/main.cpp', './src/main.cpp',
'./src/vendor/glad/glad.c', './src/vendor/glad/glad.c',
include_directories : incdir, include_directories : incdir,

14
shaders/fragment.glsl Normal file
View file

@ -0,0 +1,14 @@
#version 330 core
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D tex;
void main()
{
FragColor = texture(tex, TexCoord);
}

18
shaders/vertex.glsl Normal file
View file

@ -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;
}

78
src/camera.cpp Normal file
View file

@ -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);
}

33
src/camera.hpp Normal file
View file

@ -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);
};

31
src/common.cpp Normal file
View file

@ -0,0 +1,31 @@
#include "common.hpp"
#include <cstdlib>
#include <cstdio>
#include <cerrno>
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;
}

8
src/common.hpp Normal file
View file

@ -0,0 +1,8 @@
#pragma once
#include <cstdio>
typedef int Errno;
Errno read_entire_file(FILE *f, char **out_data);

View file

@ -1,6 +1,8 @@
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <functional> #include <functional>
#include "camera.hpp"
#include "shader.hpp"
#include "vendor/glad/glad.h" #include "vendor/glad/glad.h"
#include "vendor/glm/glm/ext/matrix_transform.hpp" #include "vendor/glm/glm/ext/matrix_transform.hpp"
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
@ -19,63 +21,6 @@
std::function<void(int width, int height)> framebuffer_size_callback = nullptr; std::function<void(int width, int height)> framebuffer_size_callback = nullptr;
std::function<void(double x, double y)> cursor_position_callback = nullptr; std::function<void(double x, double y)> 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() int main()
{ {
qoi_desc fish_desc; qoi_desc fish_desc;
@ -158,31 +103,7 @@ int main()
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
}; };
static const char *vertex_shader_source = "" unsigned int program = create_program("shaders/vertex.glsl", "shaders/fragment.glsl");
"#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 texture; unsigned int texture;
glGenTextures(1, &texture); glGenTextures(1, &texture);
@ -208,16 +129,7 @@ int main()
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glm::mat4 projection = glm::mat4(1.0f); glm::mat4 projection = glm::mat4(1.0f);
Camera camera;
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;
framebuffer_size_callback = [&projection, program](int width, int height) { framebuffer_size_callback = [&projection, program](int width, int height) {
projection = glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 100.0f); 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); 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) { cursor_position_callback = [&camera](double x, double y) {
if (!mouse_moved_once) { camera.process_mouse(x, y);
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;
}; };
float delta_time = 0.0f; float delta_time = 0.0f;
@ -261,33 +149,30 @@ int main()
delta_time = current_frame_time - last_frame_time; delta_time = current_frame_time - last_frame_time;
last_frame_time = current_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) { 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) { 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) { 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) { 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) { 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) { 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); glClearColor(0.5, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 view = glm::lookAt(camera_position, camera_position + camera_front, camera_up);
glUseProgram(program); 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); glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(vertex_array); glBindVertexArray(vertex_array);

105
src/shader.cpp Normal file
View file

@ -0,0 +1,105 @@
#include "shader.hpp"
#include "common.hpp"
#include "vendor/glad/glad.h"
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <cstdlib>
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;
}

4
src/shader.hpp Normal file
View file

@ -0,0 +1,4 @@
#pragma once
unsigned int create_program(const char *vertex_shader_path, const char *fragment_shader_path);