From 890117d3d0198eafadf6b3692a9e3cb3ecb478a4 Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Thu, 3 Jul 2025 18:12:47 -0600 Subject: [PATCH] Major refactor --- shaders/shader.frag | 8 +++ shaders/shader.vert | 13 ++++ src/file.cpp | 21 ++++++ src/file.h | 7 ++ src/geometry.cpp | 23 ------- src/geometry.h | 4 -- src/main.cpp | 164 ++++++++++++++++++-------------------------- src/math.h | 31 ++++++++- src/mesh.cpp | 70 +++++++++++++++++++ src/mesh.h | 17 +++++ src/notes.txt | 6 ++ src/shader.cpp | 160 ++++++++++++++++++++++++++---------------- src/shader.h | 19 +++-- src/window.cpp | 95 ++++++++++++------------- src/window.h | 9 ++- 15 files changed, 400 insertions(+), 247 deletions(-) create mode 100644 shaders/shader.frag create mode 100644 shaders/shader.vert create mode 100644 src/file.cpp create mode 100644 src/file.h delete mode 100644 src/geometry.cpp delete mode 100644 src/geometry.h create mode 100644 src/mesh.cpp create mode 100644 src/mesh.h diff --git a/shaders/shader.frag b/shaders/shader.frag new file mode 100644 index 0000000..cce9d03 --- /dev/null +++ b/shaders/shader.frag @@ -0,0 +1,8 @@ +#version 330 + +in vec4 vertex_color; +out vec4 color; + +void main() { + color = vertex_color; +} diff --git a/shaders/shader.vert b/shaders/shader.vert new file mode 100644 index 0000000..71fa1e9 --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,13 @@ +#version 330 + +layout (location = 0) in vec3 pos; + +out vec4 vertex_color; + +uniform mat4 projection; +uniform mat4 model; + +void main() { + gl_Position = projection * model * vec4(pos, 1.0); + vertex_color = vec4(clamp(pos, 0.0f, 1.0f), 1.0f); +} diff --git a/src/file.cpp b/src/file.cpp new file mode 100644 index 0000000..fcc2ac9 --- /dev/null +++ b/src/file.cpp @@ -0,0 +1,21 @@ +#include "file.h" + +std::string read_entire_file(const char *path) { + std::string content; + std::ifstream file_stream(path, std::ios::in); + + if (!file_stream.is_open()) { + printf("Failed to read %s! File doesn't exist.", path); + return ""; + } + + std::string line = ""; + while (!file_stream.eof()) + { + std::getline(file_stream, line); + content.append(line + "\n"); + } + + file_stream.close(); + return content; +} diff --git a/src/file.h b/src/file.h new file mode 100644 index 0000000..b22bb39 --- /dev/null +++ b/src/file.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include +#include + +std::string read_entire_file(const char *path); diff --git a/src/geometry.cpp b/src/geometry.cpp deleted file mode 100644 index 281e236..0000000 --- a/src/geometry.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "geometry.h" - -void create_triangle(GLuint *VAO, GLuint *VBO) { - GLfloat vertices[] = { - -1.0f, -1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - 0.0f, 1.0f, 0.0f - }; - - glGenVertexArrays(1, VAO); - glBindVertexArray(*VAO); - - glGenBuffers(1, VBO); - glBindBuffer(GL_ARRAY_BUFFER, *VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - glEnableVertexAttribArray(0); - - // Unbinding - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} diff --git a/src/geometry.h b/src/geometry.h deleted file mode 100644 index 9ca6d61..0000000 --- a/src/geometry.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include - -void create_triangle(GLuint *VAO, GLuint *VBO); diff --git a/src/main.cpp b/src/main.cpp index 8eca5f4..ecfc554 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,122 +1,88 @@ -#include -#include -#include -#include -#include -#include - +#include "mesh.h" #include "shader.h" -#include "geometry.h" -#include "math.h" #include "window.h" -// Window dimensions + +static const char *vertex_shader_code = "shaders/shader.vert"; +static const char *fragment_shader_code = "shaders/shader.frag"; int main() { - GLuint VAO, VBO, shader_program, uniform_model; - bool direction = true; - float tri_offset = 0.0f; - float tri_max_offset = 0.7f; - float tri_increment = 0.005f; - float current_angle = 0.0f; - bool size_direction = true; - float current_size = 0.4f; - float max_size = 0.9f; - float min_size = 0.1f; + Mesh *meshes[10] = {nullptr}; + Shader shaders[10]; - Window window; - bool success = setup_window(&window); + Window window; + bool success = setup_window(&window); - Shader vertex_shader; - vertex_shader.type = VERTEX; - vertex_shader.raw_code = " \n\ -#version 330 \n\ - \n\ -layout (location = 0) in vec3 pos; \n\ - \n\ -uniform mat4 model; \n\ - \n\ -void main() { \n\ - gl_Position = model * vec4(pos, 1.0); \n\ -}"; + { + // Create a mesh + f32 vertices[] = { + -1.0f, -1.0f, 0.0f, + 0.0f, -1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f + }; - Shader fragment_shader; - fragment_shader.type = FRAGMENT; - fragment_shader.raw_code = " \n\ -#version 330 \n\ - \n\ -out vec4 color; \n\ - \n\ -void main() { \n\ - color = vec4(1.0, 0.0, 0.0, 1.0); \n\ -}"; + u32 indices[] = { + 0, 3, 1, + 1, 3, 2, + 2, 3, 0, + 0, 1, 2 + }; - // Create our triangle - create_triangle(&VAO, &VBO); - compile_shaders(&shader_program, &uniform_model, &vertex_shader, &fragment_shader); + Mesh *triangle = new Mesh(); + create_mesh(triangle, vertices, indices, 12, 12); + meshes[0] = triangle; + } - // Loop until window is closed - while (!glfwWindowShouldClose(window.gl_window)) { - // Get and handle user input events - glfwPollEvents(); + { + // Create a shader + Shader *shader = new Shader(); + create_shader(shader, vertex_shader_code, fragment_shader_code); + shaders[0] = *shader; + } - if (direction) { - tri_offset += tri_increment; - } else { - tri_offset -= tri_increment; - } + Matrix4 projection = glm::perspective( + 45.0f, (GLfloat)window.buffer_width / (GLfloat)window.buffer_height, 0.1f, + 100.0f); - if (std::abs(tri_offset) >= tri_max_offset) { - direction = !direction; - } + u32 uniform_projection = 0, uniform_model = 0; + f32 current_angle = 0.1f; - current_angle += 0.1f; + // Loop until window is closed + while (!glfwWindowShouldClose(window.gl_window)) { + // Get and handle user input events + glfwPollEvents(); - // This isn't necessary except for safety reasons - // the program will still run correctly, but if left open too - // long the number will overflow. - if (current_angle >= 360) { - current_angle -= 360; - } + // Clear window + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (size_direction) { - current_size += 0.01f; - } else { - current_size -= 0.01f; - } + glUseProgram(shaders[0].id); + uniform_model = shaders[0].uniform_model; + uniform_projection = shaders[0].uniform_projection; - if (current_size >= max_size || current_size <= min_size) { - size_direction = !size_direction; - } + Matrix4 model(1.0f); + model = glm::translate(model, Vector3(0.0f, 0.0f, -2.5f)); + model = glm::rotate(model, current_angle * RADIAN_FACTOR, Vector3(0.0f, 1.0f, 0.0f)); + model = glm::scale(model, Vector3(0.4f, 0.4f, 1.0f)); - // Clear window - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + current_angle += 0.5f; - glUseProgram(shader_program); + glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(uniform_projection, 1, GL_FALSE, glm::value_ptr(projection)); - Matrix4 model = Matrix4(1.0f); - // The order of these matter - model = glm::translate(model, Vector3(tri_offset, 0.0f, 0.0f)); - model = glm::scale(model, Vector3(current_size, 0.4f, 1.0f)); - model = glm::rotate(model, current_angle * RADIAN_FACTOR, Vector3(0.0f, 0.0f, 1.0f)); + render_mesh(meshes[0]); - glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model)); - - glBindVertexArray(VAO); - glDrawArrays(GL_TRIANGLES, 0, 3); + glUseProgram(0); - glBindVertexArray(0); - glUseProgram(0); + // We usually have two buffers, the first is hidden and that's + // the one we draw to. The second is the one we display, so + // when we're done drawing we call this glfwSwapBuffers() to + // swap the buffers to show the one we've been drawing to so + // that it now shows. We then can start drawing on the other + // buffer. + glfwSwapBuffers(window.gl_window); + } - // We usually have two buffers, the first is hidden and that's - // the one we draw to. The second is the one we display, so - // when we're done drawing we call this glfwSwapBuffers() to - // swap the buffers to show the one we've been drawing to so - // that it now shows. We then can start drawing on the other - // buffer. - glfwSwapBuffers(window.gl_window); - } - - return 0; + return 0; } diff --git a/src/math.h b/src/math.h index dbdac1f..f5392a9 100644 --- a/src/math.h +++ b/src/math.h @@ -1,11 +1,38 @@ #pragma once +#include #include #include #include +// using u8 = uint8_t; +// using u16 = uint16_t; +// using u32 = uint32_t; +// using u64 = uint64_t; + +// using i8 = int8_t; +// using i16 = int16_t; +// using i32 = int32_t; +// using i64 = int64_t; + +typedef char unsigned u8; +typedef short unsigned u16; +typedef int unsigned u32; +typedef long long unsigned u64; + +typedef char s8; +typedef short s16; +typedef int s32; +typedef long long s64; + +typedef s32 b32; + +typedef float f32; +typedef double f64; + +#define array_count(Array) (sizeof(Array) / sizeof((Array)[0])) + using Matrix4 = glm::mat4; using Vector3 = glm::vec3; -const float RADIAN_FACTOR = 3.14159265f / 180.0f; - +const f32 RADIAN_FACTOR = 3.14159265f / 180.0f; diff --git a/src/mesh.cpp b/src/mesh.cpp new file mode 100644 index 0000000..e9e1a17 --- /dev/null +++ b/src/mesh.cpp @@ -0,0 +1,70 @@ +#include "mesh.h" + +Mesh::Mesh() { + VAO = 0; + VBO = 0; + IBO = 0; + index_count = 0; +} + +Mesh::~Mesh() { + clear_mesh(this); +} + +void create_mesh( + Mesh *mesh, + f32 *vertices, + u32 *indices, + u32 vertices_count, + u32 indices_count +) { + mesh->index_count = indices_count; + + glGenVertexArrays(1, &mesh->VAO); + glBindVertexArray(mesh->VAO); + + glGenBuffers(1, &mesh->IBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->IBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices_count, indices, GL_STATIC_DRAW); + + glGenBuffers(1, &mesh->VBO); + glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices_count, vertices, GL_STATIC_DRAW); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + + // Unbinding + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +void render_mesh(Mesh *mesh) { + glBindVertexArray(mesh->VAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->IBO); + glDrawElements(GL_TRIANGLES, mesh->index_count, GL_UNSIGNED_INT, 0); + + // Unbinding + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +void clear_mesh(Mesh *mesh) { + if (mesh->IBO != 0) { + glDeleteBuffers(1, &mesh->IBO); + mesh->IBO = 0; + } + + if (mesh->VBO != 0) { + glDeleteBuffers(1, &mesh->VBO); + mesh->VBO = 0; + } + + if (mesh->VAO != 0) { + glDeleteVertexArrays(1, &mesh->VAO); + mesh->VAO = 0; + } + + mesh->index_count = 0; +} diff --git a/src/mesh.h b/src/mesh.h new file mode 100644 index 0000000..74c8159 --- /dev/null +++ b/src/mesh.h @@ -0,0 +1,17 @@ +#pragma once + +#include "math.h" +#include + +struct Mesh { + u32 VAO, VBO, IBO; + u32 index_count; + + Mesh(); + ~Mesh(); +}; + +void create_mesh(Mesh *mesh, f32 *vertices, u32 *indices, u32 vertices_count, u32 indices_count); +void render_mesh(Mesh *mesh); +void clear_mesh(Mesh *mesh); + diff --git a/src/notes.txt b/src/notes.txt index 4a9ac7d..ff4941a 100644 --- a/src/notes.txt +++ b/src/notes.txt @@ -28,3 +28,9 @@ Creating a Shader program 6. Link program (creates executables from shaders and links them together). 7. Validate program (because things run on the GPU it's harder to debug). + + +Projections: Coordinate systems +- Local space: raw position of each vertex draw relative to origin. +- World space: position in the word itself if camery is assumed to be positioned at the origin. + diff --git a/src/shader.cpp b/src/shader.cpp index 6f246d1..de10994 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -1,66 +1,106 @@ -#include -#include #include "shader.h" -bool add_shader(GLuint *program, Shader *shader) { - shader->gl = glCreateShader(shader->type); - const GLchar *code[1]; - code[0] = shader->raw_code; - - GLint code_length[1]; - code_length[0] = strlen(shader->raw_code); - - glShaderSource(shader->gl, 1, code, code_length); - glCompileShader(shader->gl); - - GLint result = 0; - GLchar errors[1024] = { 0 }; - - glGetShaderiv(shader->gl, GL_COMPILE_STATUS, &result); - if (!result) { - glGetShaderInfoLog(shader->gl, sizeof(errors), NULL, errors); - printf("Error compiling the %d shader->gl: '%s'\n", shader->type, errors); - return false; - } - - glAttachShader(*program, shader->gl); - return true; +Shader::Shader() { + id = 0; + uniform_projection = 0; + uniform_model = 0; } -bool compile_shaders(GLuint *program, GLuint *uniform_model, Shader *vertex_shader, Shader *fragment_shader) { - *program = glCreateProgram(); - - if (!program) { - printf("Error creating shader program!\n"); - return false; - } - - add_shader(program, vertex_shader); - add_shader(program, fragment_shader); - - GLint result = 0; - GLchar errors[1024] = { 0 }; - - glLinkProgram(*program); - glGetProgramiv(*program, GL_LINK_STATUS, &result); - - if (!result) { - glGetProgramInfoLog(*program, sizeof(errors), NULL, errors); - printf("Error linking program: '%s'\n", errors); - return false; - } - - glValidateProgram(*program); - glGetProgramiv(*program, GL_VALIDATE_STATUS, &result); - - if (!result) { - glGetProgramInfoLog(*program, sizeof(errors), NULL, errors); - printf("Error validating program: '%s'\n", errors); - return false; - } - - *uniform_model = glGetUniformLocation(*program, "model"); - - return true; +Shader::~Shader() { + clear_shader(this); +} + +bool create_shader(Shader *shader, const char *vertex_shader_path, const char *fragment_shader_path) { + std::string vertex_shader_code = read_entire_file(vertex_shader_path); + std::string fragment_shader_code = read_entire_file(fragment_shader_path); + + + shader->id = glCreateProgram(); + + if (!shader) { + printf("Error creating shader shader!\n"); + return false; + } + + { + bool success = add_shader(shader, vertex_shader_code.c_str(), VERTEX); + + if (!success) { + printf("Error adding vertex shader"); + return false; + } + } + + { + bool success = add_shader(shader, fragment_shader_code.c_str(), FRAGMENT); + + if (!success) { + printf("Error adding fragment shader"); + return false; + } + } + + s32 result = 0; + s8 errors[1024] = {0}; + + glLinkProgram(shader->id); + glGetProgramiv(shader->id, GL_LINK_STATUS, &result); + + if (!result) { + glGetProgramInfoLog(shader->id, sizeof(errors), NULL, errors); + printf("Error linking shader: '%s'\n", errors); + return false; + } + + glValidateProgram(shader->id); + glGetProgramiv(shader->id, GL_VALIDATE_STATUS, &result); + + if (!result) { + glGetProgramInfoLog(shader->id, sizeof(errors), NULL, errors); + printf("Error validating shader: '%s'\n", errors); + return false; + } + + shader->uniform_projection = glGetUniformLocation(shader->id, "projection"); + shader->uniform_model = glGetUniformLocation(shader->id, "model"); + + return true; +} + +bool add_shader(Shader *shader, const char *shader_code, Shader_Type shader_type) { + u32 _shader = glCreateShader(shader_type); + + const char *code[1]; + code[0] = shader_code; + + int code_length[1]; + code_length[0] = strlen(shader_code); + + glShaderSource(_shader, 1, code, code_length); + glCompileShader(_shader); + + int result = 0; + char errors[1024] = {0}; + + glGetShaderiv(_shader, GL_COMPILE_STATUS, &result); + if (!result) { + glGetShaderInfoLog(_shader, sizeof(errors), NULL, errors); + printf("Error compiling the %d shader->id: '%s'\n", shader_type, errors); + return false; + } + + glAttachShader(shader->id, _shader); + + return true; +} + +void clear_shader(Shader *shader) { + if (shader->id != 0) { + glDeleteProgram(shader->id); + shader->id = 0; + } + + shader->uniform_model = 0; + shader->uniform_projection = 0; } diff --git a/src/shader.h b/src/shader.h index ca185fa..9c01a29 100644 --- a/src/shader.h +++ b/src/shader.h @@ -2,18 +2,23 @@ #include #include +#include "math.h" +#include "file.h" -enum Shader_Type : unsigned int { +enum Shader_Type : u32 { VERTEX = GL_VERTEX_SHADER, FRAGMENT = GL_FRAGMENT_SHADER }; struct Shader { - Shader_Type type; - const char *raw_code; - GLuint gl; + u32 id; + u32 uniform_projection; + u32 uniform_model; + + Shader(); + ~Shader(); }; -bool add_shader(GLuint *program, Shader *shader, const char *raw_code); - -bool compile_shaders(GLuint *shader_program, GLuint *uniform_model, Shader *vertex_shader, Shader *fragment_shader); +bool create_shader(Shader *shader, const char *vertex_shader_path, const char *fragment_shader_path); +bool add_shader(Shader *shader, const char *shader_code, Shader_Type type); +void clear_shader(Shader *shader); diff --git a/src/window.cpp b/src/window.cpp index d0de653..9749724 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,67 +1,60 @@ -#include -#include -#include -#include -#include -#include -#include -#include #include "window.h" bool setup_window(Window *window) { // Initialize GLFW - glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); + glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); - if (!glfwInit()) { - printf("GLFW initialization failed!"); - glfwTerminate(); - return false; - } + if (!glfwInit()) { + printf("GLFW initialization failed!"); + glfwTerminate(); + return false; + } - // Setup GLFW window properties - // OpenGL version - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); - // Core profile means it will not be backwards compatible - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + // Setup GLFW window properties + // OpenGL version + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); + // Core profile means it will not be backwards compatible + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - window->gl_window = glfwCreateWindow(window->width, window->height, "Test Window", NULL, NULL); + window->gl_window = glfwCreateWindow(window->width, window->height, "Test Window", NULL, NULL); - if (!window) { - const char *desc; - int code = glfwGetError(&desc); - printf("GLFW window creation failed!"); - printf("GLFW error code: %d, description: %s\n", code, desc ? desc : "No description given"); - glfwTerminate(); - return false; - } + if (!window) { + const char *desc; + int code = glfwGetError(&desc); + printf("GLFW window creation failed!"); + printf("GLFW error code: %d, description: %s\n", code, + desc ? desc : "No description given"); + glfwTerminate(); + return false; + } - // Get Buffer size information - int buffer_width, buffer_height; - glfwGetFramebufferSize(window->gl_window, &buffer_width, &buffer_height); + // Get Buffer size information + glfwGetFramebufferSize(window->gl_window, &window->buffer_width, &window->buffer_height); - // Set context for GLEW to use - glfwMakeContextCurrent(window->gl_window); + // Set context for GLEW to use + glfwMakeContextCurrent(window->gl_window); - glGetError(); + glGetError(); - // Allow modern extension features - glewExperimental = GL_TRUE; + // Allow modern extension features + glewExperimental = GL_TRUE; - GLenum err = glewInit(); - if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) { - printf("OpenGL version: %s\n", glGetString(GL_VERSION)); - fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); - printf("glewInit() returned: %d\n", err); - glfwDestroyWindow(window->gl_window); - glfwTerminate(); - return false; - } + GLenum err = glewInit(); + if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) { + printf("OpenGL version: %s\n", glGetString(GL_VERSION)); + fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); + printf("glewInit() returned: %d\n", err); + glfwDestroyWindow(window->gl_window); + glfwTerminate(); + return false; + } - // Setup viewport size - glViewport(0, 0, buffer_width, buffer_height); + glEnable(GL_DEPTH_TEST); - return true; + // Setup viewport size + glViewport(0, 0, window->buffer_width, window->buffer_height); + + return true; } - diff --git a/src/window.h b/src/window.h index 29e7435..46324fe 100644 --- a/src/window.h +++ b/src/window.h @@ -1,9 +1,16 @@ #pragma once +#include #include +#include +#include +#include +#include +#include "math.h" struct Window { - GLint width = 800, height = 600; + u32 width = 800, height = 600; + s32 buffer_width, buffer_height; GLFWwindow *gl_window = nullptr; };