Major refactor

This commit is contained in:
Nathan Chapman 2025-07-03 18:12:47 -06:00
parent 8978d581d7
commit 890117d3d0
15 changed files with 400 additions and 247 deletions

8
shaders/shader.frag Normal file
View File

@ -0,0 +1,8 @@
#version 330
in vec4 vertex_color;
out vec4 color;
void main() {
color = vertex_color;
}

13
shaders/shader.vert Normal file
View File

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

21
src/file.cpp Normal file
View File

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

7
src/file.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <string>
#include <iostream>
#include <fstream>
std::string read_entire_file(const char *path);

View File

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

View File

@ -1,4 +0,0 @@
#pragma once
#include <GL/glew.h>
void create_triangle(GLuint *VAO, GLuint *VBO);

View File

@ -1,122 +1,88 @@
#include <GL/glew.h> #include "mesh.h"
#include <GLFW/glfw3.h>
#include <cmath>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "shader.h" #include "shader.h"
#include "geometry.h"
#include "math.h"
#include "window.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() { int main() {
GLuint VAO, VBO, shader_program, uniform_model; Mesh *meshes[10] = {nullptr};
bool direction = true; Shader shaders[10];
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;
Window window; Window window;
bool success = setup_window(&window); bool success = setup_window(&window);
Shader vertex_shader; {
vertex_shader.type = VERTEX; // Create a mesh
vertex_shader.raw_code = " \n\ f32 vertices[] = {
#version 330 \n\ -1.0f, -1.0f, 0.0f,
\n\ 0.0f, -1.0f, 1.0f,
layout (location = 0) in vec3 pos; \n\ 1.0f, -1.0f, 0.0f,
\n\ 0.0f, 1.0f, 0.0f
uniform mat4 model; \n\ };
\n\
void main() { \n\
gl_Position = model * vec4(pos, 1.0); \n\
}";
Shader fragment_shader; u32 indices[] = {
fragment_shader.type = FRAGMENT; 0, 3, 1,
fragment_shader.raw_code = " \n\ 1, 3, 2,
#version 330 \n\ 2, 3, 0,
\n\ 0, 1, 2
out vec4 color; \n\ };
\n\
void main() { \n\
color = vec4(1.0, 0.0, 0.0, 1.0); \n\
}";
// Create our triangle Mesh *triangle = new Mesh();
create_triangle(&VAO, &VBO); create_mesh(triangle, vertices, indices, 12, 12);
compile_shaders(&shader_program, &uniform_model, &vertex_shader, &fragment_shader); meshes[0] = triangle;
}
// Loop until window is closed {
while (!glfwWindowShouldClose(window.gl_window)) { // Create a shader
// Get and handle user input events Shader *shader = new Shader();
glfwPollEvents(); create_shader(shader, vertex_shader_code, fragment_shader_code);
shaders[0] = *shader;
}
if (direction) { Matrix4 projection = glm::perspective(
tri_offset += tri_increment; 45.0f, (GLfloat)window.buffer_width / (GLfloat)window.buffer_height, 0.1f,
} else { 100.0f);
tri_offset -= tri_increment;
}
if (std::abs(tri_offset) >= tri_max_offset) { u32 uniform_projection = 0, uniform_model = 0;
direction = !direction; 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 // Clear window
// the program will still run correctly, but if left open too glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// long the number will overflow. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (current_angle >= 360) {
current_angle -= 360;
}
if (size_direction) { glUseProgram(shaders[0].id);
current_size += 0.01f; uniform_model = shaders[0].uniform_model;
} else { uniform_projection = shaders[0].uniform_projection;
current_size -= 0.01f;
}
if (current_size >= max_size || current_size <= min_size) { Matrix4 model(1.0f);
size_direction = !size_direction; 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 current_angle += 0.5f;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
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); render_mesh(meshes[0]);
// 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));
glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model)); glUseProgram(0);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0); // We usually have two buffers, the first is hidden and that's
glUseProgram(0); // 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 return 0;
// 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;
} }

View File

@ -1,11 +1,38 @@
#pragma once #pragma once
#include <cstdint>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// 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 Matrix4 = glm::mat4;
using Vector3 = glm::vec3; using Vector3 = glm::vec3;
const float RADIAN_FACTOR = 3.14159265f / 180.0f; const f32 RADIAN_FACTOR = 3.14159265f / 180.0f;

70
src/mesh.cpp Normal file
View File

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

17
src/mesh.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "math.h"
#include <GL/glew.h>
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);

View File

@ -28,3 +28,9 @@ Creating a Shader program
6. Link program (creates executables from shaders and links them together). 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). 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.

View File

@ -1,66 +1,106 @@
#include <stdio.h>
#include <string.h>
#include "shader.h" #include "shader.h"
bool add_shader(GLuint *program, Shader *shader) { Shader::Shader() {
shader->gl = glCreateShader(shader->type); id = 0;
const GLchar *code[1]; uniform_projection = 0;
code[0] = shader->raw_code; uniform_model = 0;
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;
} }
bool compile_shaders(GLuint *program, GLuint *uniform_model, Shader *vertex_shader, Shader *fragment_shader) { Shader::~Shader() {
*program = glCreateProgram(); clear_shader(this);
}
if (!program) {
printf("Error creating shader program!\n"); bool create_shader(Shader *shader, const char *vertex_shader_path, const char *fragment_shader_path) {
return false; std::string vertex_shader_code = read_entire_file(vertex_shader_path);
} std::string fragment_shader_code = read_entire_file(fragment_shader_path);
add_shader(program, vertex_shader);
add_shader(program, fragment_shader); shader->id = glCreateProgram();
GLint result = 0; if (!shader) {
GLchar errors[1024] = { 0 }; printf("Error creating shader shader!\n");
return false;
glLinkProgram(*program); }
glGetProgramiv(*program, GL_LINK_STATUS, &result);
{
if (!result) { bool success = add_shader(shader, vertex_shader_code.c_str(), VERTEX);
glGetProgramInfoLog(*program, sizeof(errors), NULL, errors);
printf("Error linking program: '%s'\n", errors); if (!success) {
return false; printf("Error adding vertex shader");
} return false;
}
glValidateProgram(*program); }
glGetProgramiv(*program, GL_VALIDATE_STATUS, &result);
{
if (!result) { bool success = add_shader(shader, fragment_shader_code.c_str(), FRAGMENT);
glGetProgramInfoLog(*program, sizeof(errors), NULL, errors);
printf("Error validating program: '%s'\n", errors); if (!success) {
return false; printf("Error adding fragment shader");
} return false;
}
*uniform_model = glGetUniformLocation(*program, "model"); }
return true; 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;
} }

View File

@ -2,18 +2,23 @@
#include <GL/glew.h> #include <GL/glew.h>
#include <GL/gl.h> #include <GL/gl.h>
#include "math.h"
#include "file.h"
enum Shader_Type : unsigned int { enum Shader_Type : u32 {
VERTEX = GL_VERTEX_SHADER, VERTEX = GL_VERTEX_SHADER,
FRAGMENT = GL_FRAGMENT_SHADER FRAGMENT = GL_FRAGMENT_SHADER
}; };
struct Shader { struct Shader {
Shader_Type type; u32 id;
const char *raw_code; u32 uniform_projection;
GLuint gl; u32 uniform_model;
Shader();
~Shader();
}; };
bool add_shader(GLuint *program, Shader *shader, const char *raw_code); 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);
bool compile_shaders(GLuint *shader_program, GLuint *uniform_model, Shader *vertex_shader, Shader *fragment_shader); void clear_shader(Shader *shader);

View File

@ -1,67 +1,60 @@
#include <stdio.h>
#include <string.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "window.h" #include "window.h"
bool setup_window(Window *window) { bool setup_window(Window *window) {
// Initialize GLFW // Initialize GLFW
glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND);
if (!glfwInit()) { if (!glfwInit()) {
printf("GLFW initialization failed!"); printf("GLFW initialization failed!");
glfwTerminate(); glfwTerminate();
return false; return false;
} }
// Setup GLFW window properties // Setup GLFW window properties
// OpenGL version // OpenGL version
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
// Core profile means it will not be backwards compatible // Core profile means it will not be backwards compatible
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 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) { if (!window) {
const char *desc; const char *desc;
int code = glfwGetError(&desc); int code = glfwGetError(&desc);
printf("GLFW window creation failed!"); printf("GLFW window creation failed!");
printf("GLFW error code: %d, description: %s\n", code, desc ? desc : "No description given"); printf("GLFW error code: %d, description: %s\n", code,
glfwTerminate(); desc ? desc : "No description given");
return false; glfwTerminate();
} return false;
}
// Get Buffer size information // Get Buffer size information
int buffer_width, buffer_height; glfwGetFramebufferSize(window->gl_window, &window->buffer_width, &window->buffer_height);
glfwGetFramebufferSize(window->gl_window, &buffer_width, &buffer_height);
// Set context for GLEW to use // Set context for GLEW to use
glfwMakeContextCurrent(window->gl_window); glfwMakeContextCurrent(window->gl_window);
glGetError(); glGetError();
// Allow modern extension features // Allow modern extension features
glewExperimental = GL_TRUE; glewExperimental = GL_TRUE;
GLenum err = glewInit(); GLenum err = glewInit();
if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) { if (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) {
printf("OpenGL version: %s\n", glGetString(GL_VERSION)); printf("OpenGL version: %s\n", glGetString(GL_VERSION));
fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
printf("glewInit() returned: %d\n", err); printf("glewInit() returned: %d\n", err);
glfwDestroyWindow(window->gl_window); glfwDestroyWindow(window->gl_window);
glfwTerminate(); glfwTerminate();
return false; return false;
} }
// Setup viewport size glEnable(GL_DEPTH_TEST);
glViewport(0, 0, buffer_width, buffer_height);
return true; // Setup viewport size
glViewport(0, 0, window->buffer_width, window->buffer_height);
return true;
} }

View File

@ -1,9 +1,16 @@
#pragma once #pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <stdio.h>
#include <string.h>
#include "math.h"
struct Window { struct Window {
GLint width = 800, height = 600; u32 width = 800, height = 600;
s32 buffer_width, buffer_height;
GLFWwindow *gl_window = nullptr; GLFWwindow *gl_window = nullptr;
}; };