Add perspective camera and shader-hot-swapping

This commit is contained in:
Nathan Chapman 2025-07-12 21:48:28 -06:00
parent 32a4097a21
commit 67e7d73614
6 changed files with 129 additions and 26 deletions

12
shaders/alt.frag Normal file
View File

@ -0,0 +1,12 @@
#version 460 core
layout (location = 0) in vec4 tex_color;
layout (location = 1) in vec2 tex_coord;
out vec4 frag_color;
uniform sampler2D tex;
void main() {
frag_color = texture(tex, tex_coord) * (vec4(1.0) - tex_color);
}

21
shaders/alt.vert Normal file
View File

@ -0,0 +1,21 @@
#version 460 core
layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec3 a_color;
layout (location = 2) in vec2 a_tex_coord;
layout (std140, binding = 0) uniform Matrices {
mat4 view;
mat4 projection;
};
layout (location = 0) out vec4 tex_color;
layout (location = 1) out vec2 tex_coord;
void main() {
vec3 offset = vec3(0.0, 0.0, -1.0);
gl_Position = projection * view * vec4(a_pos + offset, 1.0);
tex_color = vec4(a_color, 1.0);
tex_coord = a_tex_coord;
}

View File

@ -4,11 +4,16 @@ layout (location = 0) in vec3 a_pos;
layout (location = 1) in vec3 a_color; layout (location = 1) in vec3 a_color;
layout (location = 2) in vec2 a_tex_coord; layout (location = 2) in vec2 a_tex_coord;
layout (std140, binding = 0) uniform Matrices {
mat4 view;
mat4 projection;
};
layout (location = 0) out vec4 tex_color; layout (location = 0) out vec4 tex_color;
layout (location = 1) out vec2 tex_coord; layout (location = 1) out vec2 tex_coord;
void main() { void main() {
gl_Position = vec4(a_pos, 1.0); gl_Position = projection * view * vec4(a_pos, 1.0);
tex_color = vec4(a_color, 1.0); tex_color = vec4(a_color, 1.0);
tex_coord = a_tex_coord; tex_coord = a_tex_coord;
} }

View File

@ -3,6 +3,10 @@
bool init_renderer(Renderer *renderer, u32 width, u32 height) { bool init_renderer(Renderer *renderer, u32 width, u32 height) {
renderer->m_width = width;
renderer->m_height = height;
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
log(1, "%s error: failed to initialize GLAD\n", __FUNCTION__); log(1, "%s error: failed to initialize GLAD\n", __FUNCTION__);
return false; return false;
@ -40,12 +44,29 @@ bool init_renderer(Renderer *renderer, u32 width, u32 height) {
} }
{ {
bool success = load_shaders(&renderer->shader, "shaders/basic.vert", "shaders/basic.frag"); bool success = init_uniform_buffer(&renderer->uniform_buffer);
if (!success) { if (!success) {
log(1, "%s: shader loading failed\n", __FUNCTION__); log(1, "%s: uniform buffer successfully created\n", __FUNCTION__);
return false; return false;
} }
log(1, "%s: shaders succesfully loaded\n", __FUNCTION__); }
{
bool success = load_shaders(&renderer->shader, "shaders/basic.vert", "shaders/basic.frag");
if (!success) {
log(1, "%s: basic shader loading failed\n", __FUNCTION__);
return false;
}
log(1, "%s: basic shaders succesfully loaded\n", __FUNCTION__);
}
{
bool success = load_shaders(&renderer->alt_shader, "shaders/alt.vert", "shaders/alt.frag");
if (!success) {
log(1, "%s: alt shader loading failed\n", __FUNCTION__);
return false;
}
log(1, "%s: alt shaders succesfully loaded\n", __FUNCTION__);
} }
return true; return true;
@ -66,13 +87,30 @@ void draw_renderer(Renderer *renderer) {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
use_shader(&renderer->shader); Vector3 camera_position = Vector3(0.4f, 0.3f, 1.0f);
Vector3 camera_look_at_position = Vector3(0.0f, 0.0f, 0.0f);
Vector3 camera_up_vector = Vector3(0.0f, 1.0f, 0.0f);
renderer->projection_matrix = glm::perspective(glm::radians(90.0f), static_cast<f32>(renderer->m_width) / static_cast<f32>(renderer->m_height), 0.1f, 100.0f);
f32 dt = glfwGetTime();
Matrix4 model = Matrix4(1.0);
if (!renderer->use_alt_shader) {
use_shader(&renderer->shader);
model = glm::rotate(Matrix4(1.0f), dt, Vector3(0.0f, 0.0f, 1.0f));
} else {
use_shader(&renderer->alt_shader);
model = glm::rotate(Matrix4(1.0f), -dt, Vector3(0.0f, 0.0f, 1.0f));
}
renderer->view_matrix = glm::lookAt(camera_position, camera_look_at_position, camera_up_vector) * model;
upload_uniform_buffer_data(&renderer->uniform_buffer, renderer->view_matrix, renderer->projection_matrix);
bind_texture(&renderer->texture); bind_texture(&renderer->texture);
bind_vertex_buffer(&renderer->vertex_buffer); bind_vertex_buffer(&renderer->vertex_buffer);
draw_vertex_buffer(GL_TRIANGLES, 0, renderer->triangle_count * 3); draw_vertex_buffer(GL_TRIANGLES, 0, renderer->triangle_count * 3);
unbind_vertex_buffer(); unbind_vertex_buffer();
@ -89,6 +127,7 @@ void upload_renderer_data(Renderer *renderer, Mesh *vertex_data) {
void cleanup_renderer(Renderer *renderer) { void cleanup_renderer(Renderer *renderer) {
cleanup_shader(&renderer->shader); cleanup_shader(&renderer->shader);
cleanup_shader(&renderer->alt_shader);
cleanup_texture(&renderer->texture); cleanup_texture(&renderer->texture);
cleanup_vertex_buffer(&renderer->vertex_buffer); cleanup_vertex_buffer(&renderer->vertex_buffer);
cleanup_frame_buffer(&renderer->frame_buffer); cleanup_frame_buffer(&renderer->frame_buffer);
@ -231,6 +270,30 @@ void draw_vertex_buffer(u32 mode, u32 start, u32 num) {
glDrawArrays(mode, start, num); glDrawArrays(mode, start, num);
} }
/*
* Uniform buffer
*/
bool init_uniform_buffer(Uniform_Buffer *uniform_buffer) {
glGenBuffers(1, &uniform_buffer->ubo_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer->ubo_buffer);
glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(Matrix4), nullptr, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
return true;
}
void upload_uniform_buffer_data(Uniform_Buffer *uniform_buffer, Matrix4 view_matrix, Matrix4 projection_matrix) {
glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer->ubo_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), glm::value_ptr(view_matrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(Matrix4), sizeof(Matrix4), glm::value_ptr(projection_matrix));
glBindBufferRange(GL_UNIFORM_BUFFER, 0, uniform_buffer->ubo_buffer, 0, 2 * sizeof(Matrix4));
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
void cleanup(Uniform_Buffer *uniform_buffer) {
glDeleteBuffers(1, &uniform_buffer->ubo_buffer);
}
/* /*
* Texture * Texture
@ -304,6 +367,9 @@ bool load_shaders(Shader *shader, string vertex_shader_filepath, string fragment
return false; return false;
} }
s32 ubo_index = glGetUniformBlockIndex(shader->program, "Matrices");
glUniformBlockBinding(shader->program, ubo_index, 0);
glDeleteShader(vertex_shader); glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader); glDeleteShader(fragment_shader);

View File

@ -7,6 +7,7 @@
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <stb_image.h> #include <stb_image.h>
#include <glm/gtc/type_ptr.hpp>
struct Vertex { struct Vertex {
@ -32,6 +33,10 @@ struct Vertex_Buffer {
u32 vbo = 0; u32 vbo = 0;
}; };
struct Uniform_Buffer {
u32 ubo_buffer = 0;
};
struct Texture { struct Texture {
u32 texture = 0; u32 texture = 0;
s32 width = 0; s32 width = 0;
@ -44,14 +49,20 @@ struct Shader {
u32 program = 0; u32 program = 0;
}; };
struct Renderer { struct Renderer {
Shader shader; Shader shader;
Shader alt_shader;
Frame_Buffer frame_buffer; Frame_Buffer frame_buffer;
Vertex_Buffer vertex_buffer; Vertex_Buffer vertex_buffer;
Uniform_Buffer uniform_buffer;
Texture texture; Texture texture;
Mesh mesh; Mesh mesh;
s32 triangle_count = 0; s32 triangle_count = 0;
bool use_alt_shader = false;
Matrix4 view_matrix = Matrix4(1.0f);
Matrix4 projection_matrix = Matrix4(1.0f);
u32 m_width = 0;
u32 m_height = 0;
}; };
@ -76,6 +87,10 @@ void bind_vertex_buffer(Vertex_Buffer *vertex_buffer);
void unbind_vertex_buffer(); void unbind_vertex_buffer();
void draw_vertex_buffer(u32 mode, u32 start, u32 num); void draw_vertex_buffer(u32 mode, u32 start, u32 num);
bool init_uniform_buffer(Uniform_Buffer *uniform_buffer);
void upload_uniform_buffer_data(Uniform_Buffer *uniform_buffer, Matrix4 view_matrix, Matrix4 projection_matrix);
void cleanup(Uniform_Buffer *uniform_buffer);
bool load_texture(Texture *texture, string filepath); bool load_texture(Texture *texture, string filepath);
void bind_texture(Texture *texture); void bind_texture(Texture *texture);
void unbind_texture(); void unbind_texture();

View File

@ -82,25 +82,9 @@ void handle_close(GLFWwindow *gl_window) {
void handle_key_events(GLFWwindow *gl_window, s32 key, s32 scancode, s32 action, s32 mods) { void handle_key_events(GLFWwindow *gl_window, s32 key, s32 scancode, s32 action, s32 mods) {
Window *window = static_cast<Window *>(glfwGetWindowUserPointer(gl_window)); Window *window = static_cast<Window *>(glfwGetWindowUserPointer(gl_window));
string action_name; if (glfwGetKey(window->glfw_window, GLFW_KEY_SPACE) == GLFW_PRESS) {
window->renderer->use_alt_shader = !window->renderer->use_alt_shader;
switch(action) {
case GLFW_PRESS:
action_name = "pressed";
break;
case GLFW_RELEASE:
action_name = "released";
break;
case GLFW_REPEAT:
action_name = "repeated";
break;
default:
action_name = "invalid";
break;
} }
const char *key_name = glfwGetKeyName(key, 0);
log(1, "%s: key %s (key %i, scancode %i) %s\n", __FUNCTION__, key_name, key, scancode, action_name.c_str());
} }
void handle_mouse_position_events(GLFWwindow *gl_window, f64 x_pos, f64 y_pos) { void handle_mouse_position_events(GLFWwindow *gl_window, f64 x_pos, f64 y_pos) {