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 <GLFW/glfw3.h>
#include <cmath>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#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);
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;
}
{
// 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
while (!glfwWindowShouldClose(window.gl_window)) {
// Get and handle user input events
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
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);
// 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));
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));
current_angle += 0.5f;
glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(uniform_projection, 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
render_mesh(meshes[0]);
glBindVertexArray(0);
glUseProgram(0);
// We usually have two buffers, the first is hidden and that's

View File

@ -1,11 +1,38 @@
#pragma once
#include <cstdint>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.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 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).
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"
bool add_shader(GLuint *program, Shader *shader) {
shader->gl = glCreateShader(shader->type);
const GLchar *code[1];
code[0] = shader->raw_code;
Shader::Shader() {
id = 0;
uniform_projection = 0;
uniform_model = 0;
}
GLint code_length[1];
code_length[0] = strlen(shader->raw_code);
Shader::~Shader() {
clear_shader(this);
}
glShaderSource(shader->gl, 1, code, code_length);
glCompileShader(shader->gl);
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);
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);
shader->id = glCreateProgram();
if (!shader) {
printf("Error creating shader shader!\n");
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) {
*program = glCreateProgram();
if (!program) {
printf("Error creating shader program!\n");
if (!success) {
printf("Error adding vertex shader");
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;
GLchar errors[1024] = { 0 };
if (!success) {
printf("Error adding fragment shader");
return false;
}
}
glLinkProgram(*program);
glGetProgramiv(*program, GL_LINK_STATUS, &result);
s32 result = 0;
s8 errors[1024] = {0};
glLinkProgram(shader->id);
glGetProgramiv(shader->id, GL_LINK_STATUS, &result);
if (!result) {
glGetProgramInfoLog(*program, sizeof(errors), NULL, errors);
printf("Error linking program: '%s'\n", errors);
glGetProgramInfoLog(shader->id, sizeof(errors), NULL, errors);
printf("Error linking shader: '%s'\n", errors);
return false;
}
glValidateProgram(*program);
glGetProgramiv(*program, GL_VALIDATE_STATUS, &result);
glValidateProgram(shader->id);
glGetProgramiv(shader->id, GL_VALIDATE_STATUS, &result);
if (!result) {
glGetProgramInfoLog(*program, sizeof(errors), NULL, errors);
printf("Error validating program: '%s'\n", errors);
glGetProgramInfoLog(shader->id, sizeof(errors), NULL, errors);
printf("Error validating shader: '%s'\n", errors);
return false;
}
*uniform_model = glGetUniformLocation(*program, "model");
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/gl.h>
#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);

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"
bool setup_window(Window *window) {
@ -32,14 +24,14 @@ bool setup_window(Window *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");
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);
glfwGetFramebufferSize(window->gl_window, &window->buffer_width, &window->buffer_height);
// Set context for GLEW to use
glfwMakeContextCurrent(window->gl_window);
@ -59,9 +51,10 @@ bool setup_window(Window *window) {
return false;
}
glEnable(GL_DEPTH_TEST);
// Setup viewport size
glViewport(0, 0, buffer_width, buffer_height);
glViewport(0, 0, window->buffer_width, window->buffer_height);
return true;
}

View File

@ -1,9 +1,16 @@
#pragma once
#include <GL/glew.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 {
GLint width = 800, height = 600;
u32 width = 800, height = 600;
s32 buffer_width, buffer_height;
GLFWwindow *gl_window = nullptr;
};