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,112 +1,78 @@
#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;
}
{
// Create a shader
Shader *shader = new Shader();
create_shader(shader, vertex_shader_code, fragment_shader_code);
shaders[0] = *shader;
}
Matrix4 projection = glm::perspective(
45.0f, (GLfloat)window.buffer_width / (GLfloat)window.buffer_height, 0.1f,
100.0f);
u32 uniform_projection = 0, uniform_model = 0;
f32 current_angle = 0.1f;
// Loop until window is closed // Loop until window is closed
while (!glfwWindowShouldClose(window.gl_window)) { while (!glfwWindowShouldClose(window.gl_window)) {
// Get and handle user input events // Get and handle user input events
glfwPollEvents(); glfwPollEvents();
if (direction) {
tri_offset += tri_increment;
} else {
tri_offset -= tri_increment;
}
if (std::abs(tri_offset) >= tri_max_offset) {
direction = !direction;
}
current_angle += 0.1f;
// 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;
}
if (size_direction) {
current_size += 0.01f;
} else {
current_size -= 0.01f;
}
if (current_size >= max_size || current_size <= min_size) {
size_direction = !size_direction;
}
// Clear window // Clear window
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shader_program); glUseProgram(shaders[0].id);
uniform_model = shaders[0].uniform_model;
uniform_projection = shaders[0].uniform_projection;
Matrix4 model = Matrix4(1.0f); Matrix4 model(1.0f);
// The order of these matter model = glm::translate(model, Vector3(0.0f, 0.0f, -2.5f));
model = glm::translate(model, Vector3(tri_offset, 0.0f, 0.0f)); model = glm::rotate(model, current_angle * RADIAN_FACTOR, Vector3(0.0f, 1.0f, 0.0f));
model = glm::scale(model, Vector3(current_size, 0.4f, 1.0f)); model = glm::scale(model, Vector3(0.4f, 0.4f, 1.0f));
model = glm::rotate(model, current_angle * RADIAN_FACTOR, Vector3(0.0f, 0.0f, 1.0f));
current_angle += 0.5f;
glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(uniform_projection, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO); render_mesh(meshes[0]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glUseProgram(0); glUseProgram(0);
// We usually have two buffers, the first is hidden and that's // We usually have two buffers, the first is hidden and that's

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]; Shader::~Shader() {
code_length[0] = strlen(shader->raw_code); clear_shader(this);
}
glShaderSource(shader->gl, 1, code, code_length); bool create_shader(Shader *shader, const char *vertex_shader_path, const char *fragment_shader_path) {
glCompileShader(shader->gl); std::string vertex_shader_code = read_entire_file(vertex_shader_path);
std::string fragment_shader_code = read_entire_file(fragment_shader_path);
GLint result = 0;
GLchar errors[1024] = { 0 };
glGetShaderiv(shader->gl, GL_COMPILE_STATUS, &result); shader->id = glCreateProgram();
if (!result) {
glGetShaderInfoLog(shader->gl, sizeof(errors), NULL, errors); if (!shader) {
printf("Error compiling the %d shader->gl: '%s'\n", shader->type, errors); printf("Error creating shader shader!\n");
return false; return false;
} }
glAttachShader(*program, shader->gl); {
return true; bool success = add_shader(shader, vertex_shader_code.c_str(), VERTEX);
}
bool compile_shaders(GLuint *program, GLuint *uniform_model, Shader *vertex_shader, Shader *fragment_shader) { if (!success) {
*program = glCreateProgram(); printf("Error adding vertex shader");
if (!program) {
printf("Error creating shader program!\n");
return false; return false;
} }
}
add_shader(program, vertex_shader); {
add_shader(program, fragment_shader); bool success = add_shader(shader, fragment_shader_code.c_str(), FRAGMENT);
GLint result = 0; if (!success) {
GLchar errors[1024] = { 0 }; printf("Error adding fragment shader");
return false;
}
}
glLinkProgram(*program); s32 result = 0;
glGetProgramiv(*program, GL_LINK_STATUS, &result); s8 errors[1024] = {0};
glLinkProgram(shader->id);
glGetProgramiv(shader->id, GL_LINK_STATUS, &result);
if (!result) { if (!result) {
glGetProgramInfoLog(*program, sizeof(errors), NULL, errors); glGetProgramInfoLog(shader->id, sizeof(errors), NULL, errors);
printf("Error linking program: '%s'\n", errors); printf("Error linking shader: '%s'\n", errors);
return false; return false;
} }
glValidateProgram(*program); glValidateProgram(shader->id);
glGetProgramiv(*program, GL_VALIDATE_STATUS, &result); glGetProgramiv(shader->id, GL_VALIDATE_STATUS, &result);
if (!result) { if (!result) {
glGetProgramInfoLog(*program, sizeof(errors), NULL, errors); glGetProgramInfoLog(shader->id, sizeof(errors), NULL, errors);
printf("Error validating program: '%s'\n", errors); printf("Error validating shader: '%s'\n", errors);
return false; return false;
} }
*uniform_model = glGetUniformLocation(*program, "model"); shader->uniform_projection = glGetUniformLocation(shader->id, "projection");
shader->uniform_model = glGetUniformLocation(shader->id, "model");
return true; 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,11 +1,3 @@
#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) {
@ -32,14 +24,14 @@ bool setup_window(Window *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,
desc ? desc : "No description given");
glfwTerminate(); glfwTerminate();
return false; 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);
@ -59,9 +51,10 @@ bool setup_window(Window *window) {
return false; return false;
} }
glEnable(GL_DEPTH_TEST);
// Setup viewport size // Setup viewport size
glViewport(0, 0, buffer_width, buffer_height); glViewport(0, 0, window->buffer_width, window->buffer_height);
return true; 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;
}; };