From fbb4cd5101d3dc32756be9b8b6796f1031525bd0 Mon Sep 17 00:00:00 2001 From: Nathan Chapman Date: Fri, 4 Jul 2025 11:28:12 -0600 Subject: [PATCH] Add working camera --- shaders/shader.vert | 3 ++- src/camera.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++++ src/camera.h | 28 ++++++++++++++++++++ src/main.cpp | 64 +++++++++++++++++++++++++++++++++------------ src/shader.cpp | 1 + src/shader.h | 1 + src/window.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++-- src/window.h | 14 +++++++++- 8 files changed, 218 insertions(+), 20 deletions(-) create mode 100644 src/camera.cpp create mode 100644 src/camera.h diff --git a/shaders/shader.vert b/shaders/shader.vert index 71fa1e9..d49e2fe 100644 --- a/shaders/shader.vert +++ b/shaders/shader.vert @@ -6,8 +6,9 @@ out vec4 vertex_color; uniform mat4 projection; uniform mat4 model; +uniform mat4 view; void main() { - gl_Position = projection * model * vec4(pos, 1.0); + gl_Position = projection * view * model * vec4(pos, 1.0); vertex_color = vec4(clamp(pos, 0.0f, 1.0f), 1.0f); } diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 0000000..5717e91 --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,64 @@ +#include "camera.h" + + +Camera::Camera(Vector3 position, Vector3 world_up, f32 yaw, f32 pitch, f32 movement_speed, f32 rotation_speed) : position(position), world_up(world_up), yaw(yaw), pitch(pitch), movement_speed(movement_speed), rotation_speed(rotation_speed) { + update_camera(this); +} + +void update_camera(Camera *camera) { + Vector3 new_front = Vector3( + cos(glm::radians(camera->yaw)) * cos(glm::radians(camera->pitch)), + sin(glm::radians(camera->pitch)), + sin(glm::radians(camera->yaw)) * cos(glm::radians(camera->pitch)) + ); + new_front = glm::normalize(new_front); + camera->front = new_front; + + camera->right = glm::normalize(glm::cross(camera->front, camera->world_up)); + camera->up = glm::normalize(glm::cross(camera->right, camera->front)); +} + +void key_control(Camera *camera, bool *ascii_keys, f32 dt) { + f32 velocity = camera->movement_speed * dt; + + if (ascii_keys[GLFW_KEY_W]) { + camera->position += camera->front * velocity; + } + + if (ascii_keys[GLFW_KEY_S]) { + camera->position -= camera->front * velocity; + } + + if (ascii_keys[GLFW_KEY_D]) { + camera->position += camera->right * velocity; + } + + if (ascii_keys[GLFW_KEY_A]) { + camera->position -= camera->right * velocity; + } +} + +void mouse_control(Camera *camera, f32 x_change, f32 y_change) { + x_change *= camera->rotation_speed; + y_change *= camera->rotation_speed; + + camera->yaw += x_change; + camera->pitch += y_change; + + // Clamp camera pitch + if (camera->pitch > 89.0f) { + camera->pitch = 89.0f; + } + + if (camera->pitch < -89.0f) { + camera->pitch = -89.0f; + } + + update_camera(camera); +} + + +Matrix4 calculate_view_matrix(Camera *camera) { + return glm::lookAt(camera->position, camera->position + camera->front, camera->up); +} + diff --git a/src/camera.h b/src/camera.h new file mode 100644 index 0000000..818424f --- /dev/null +++ b/src/camera.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include +#include "math.h" + +struct Camera { + Vector3 position; + Vector3 front = Vector3(0.0f, 0.0f, -1.0f); + Vector3 up; + Vector3 right; + Vector3 world_up; + + f32 yaw; + f32 pitch; + f32 movement_speed; + f32 rotation_speed; + + Camera(Vector3 position, Vector3 up, f32 yaw, f32 pitch, f32 movement_speed, f32 rotation_speed); + ~Camera() = default; +}; + +void update_camera(Camera *camera); +void key_control(Camera *camera, bool *ascii_keys, f32 dt); +void mouse_control(Camera *camera, f32 x_change, f32 y_change); +Matrix4 calculate_view_matrix(Camera *camera); diff --git a/src/main.cpp b/src/main.cpp index ecfc554..f669ce4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include "mesh.h" #include "shader.h" #include "window.h" +#include "camera.h" static const char *vertex_shader_code = "shaders/shader.vert"; @@ -10,9 +11,13 @@ int main() { Mesh *meshes[10] = {nullptr}; Shader shaders[10]; - Window window; + Window window(1024, 720); bool success = setup_window(&window); + // Delta + f32 dt = 0.0f; + f32 last_dt = 0.f; + { // Create a mesh f32 vertices[] = { @@ -29,9 +34,13 @@ int main() { 0, 1, 2 }; - Mesh *triangle = new Mesh(); - create_mesh(triangle, vertices, indices, 12, 12); - meshes[0] = triangle; + Mesh *pyramid1 = new Mesh(); + create_mesh(pyramid1, vertices, indices, 12, 12); + meshes[0] = pyramid1; + + Mesh *pyramid2 = new Mesh(); + create_mesh(pyramid2, vertices, indices, 12, 12); + meshes[1] = pyramid2; } { @@ -45,33 +54,56 @@ int main() { 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; + Camera camera(Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f), 90.0f, 0.0f, 5.0f, 1.0f); // Loop until window is closed while (!glfwWindowShouldClose(window.gl_window)) { + // Calculate delta + f32 now = glfwGetTime(); + dt = now - last_dt; + last_dt = now; + // Get and handle user input events glfwPollEvents(); + key_control(&camera, window.ascii_keys, dt); + mouse_control(&camera, window.x_change_position, window.y_change_position); + + // This sucks + window.x_change_position = 0.0f; + window.y_change_position = 0.0f; + // Clear window glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(shaders[0].id); - uniform_model = shaders[0].uniform_model; - uniform_projection = shaders[0].uniform_projection; - 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)); + { + 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(shaders[0].uniform_model, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(shaders[0].uniform_projection, 1, GL_FALSE, glm::value_ptr(projection)); + render_mesh(meshes[0]); + } - glUniformMatrix4fv(uniform_model, 1, GL_FALSE, glm::value_ptr(model)); - glUniformMatrix4fv(uniform_projection, 1, GL_FALSE, glm::value_ptr(projection)); + { + Matrix4 model(1.0f); + model = glm::translate(model, Vector3(0.0f, 0.0f, -3.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)); + + glUniformMatrix4fv(shaders[0].uniform_model, 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(shaders[0].uniform_projection, 1, GL_FALSE, glm::value_ptr(projection)); + render_mesh(meshes[1]); + } + + Matrix4 view = calculate_view_matrix(&camera); + glUniformMatrix4fv(shaders[0].uniform_view, 1, GL_FALSE, glm::value_ptr(view)); - render_mesh(meshes[0]); glUseProgram(0); diff --git a/src/shader.cpp b/src/shader.cpp index de10994..298a8bc 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -63,6 +63,7 @@ bool create_shader(Shader *shader, const char *vertex_shader_path, const char *f shader->uniform_projection = glGetUniformLocation(shader->id, "projection"); shader->uniform_model = glGetUniformLocation(shader->id, "model"); + shader->uniform_view = glGetUniformLocation(shader->id, "view"); return true; } diff --git a/src/shader.h b/src/shader.h index 9c01a29..98cc1ba 100644 --- a/src/shader.h +++ b/src/shader.h @@ -14,6 +14,7 @@ struct Shader { u32 id; u32 uniform_projection; u32 uniform_model; + u32 uniform_view; Shader(); ~Shader(); diff --git a/src/window.cpp b/src/window.cpp index 9749724..9bc0fe4 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,5 +1,23 @@ #include "window.h" + + +Window::Window(u32 window_width, u32 window_height) { + width = window_width; + height = window_height; + x_change_position = 0.0f; + y_change_position = 0.0f; + + for (size_t i = 0; i < 1024; i++) { + ascii_keys[i] = 0; + } +} + +Window::~Window() { + glfwDestroyWindow(gl_window); + glfwTerminate(); +} + bool setup_window(Window *window) { // Initialize GLFW glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_WAYLAND); @@ -20,7 +38,7 @@ bool setup_window(Window *window) { window->gl_window = glfwCreateWindow(window->width, window->height, "Test Window", NULL, NULL); - if (!window) { + if (!window->gl_window) { const char *desc; int code = glfwGetError(&desc); printf("GLFW window creation failed!"); @@ -36,7 +54,10 @@ bool setup_window(Window *window) { // Set context for GLEW to use glfwMakeContextCurrent(window->gl_window); - glGetError(); + glfwSetKeyCallback(window->gl_window, handle_keys); + glfwSetCursorPosCallback(window->gl_window, handle_mouse); + // Captures the mouse + glfwSetInputMode(window->gl_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // Allow modern extension features glewExperimental = GL_TRUE; @@ -56,5 +77,43 @@ bool setup_window(Window *window) { // Setup viewport size glViewport(0, 0, window->buffer_width, window->buffer_height); + glfwSetWindowUserPointer(window->gl_window, window); + return true; } + +void handle_keys(GLFWwindow *gl_window, int key, int code, int action, int mode) { + Window *window = static_cast(glfwGetWindowUserPointer(gl_window)); + + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(gl_window, GL_TRUE); + } + + if (key >= 0 && key < 1024) { + if (action == GLFW_PRESS) { + window->ascii_keys[key] = true; + } else if (action == GLFW_RELEASE) { + window->ascii_keys[key] = false; + } + } +} + +void handle_mouse(GLFWwindow *gl_window, f64 x_position, f64 y_position) { + Window *window = static_cast(glfwGetWindowUserPointer(gl_window)); + + if (window->first_mouse_movement) { + window->last_x_position = x_position; + window->last_y_position = y_position; + window->first_mouse_movement = false; + } + + window->x_change_position = x_position - window->last_x_position; + // The order here is to avoid up/down inversion + window->y_change_position = window->last_y_position - y_position; + + window->last_x_position = x_position; + window->last_y_position = y_position; + + // @Todo: reset x/y_change_position back to 0.0f +} + diff --git a/src/window.h b/src/window.h index 46324fe..67fd18e 100644 --- a/src/window.h +++ b/src/window.h @@ -12,7 +12,19 @@ struct Window { u32 width = 800, height = 600; s32 buffer_width, buffer_height; GLFWwindow *gl_window = nullptr; + bool ascii_keys[1024]; + + // Camera coords + f32 last_x_position; + f32 last_y_position; + f32 x_change_position; + f32 y_change_position; + bool first_mouse_movement; + + Window(u32 window_width, u32 window_height); + ~Window(); }; bool setup_window(Window *window); - +void handle_keys(GLFWwindow *gl_window, int key, int code, int action, int mode); +void handle_mouse(GLFWwindow *gl_window, f64 x_position, f64 y_position);