Add working camera

This commit is contained in:
Nathan Chapman 2025-07-04 11:28:12 -06:00
parent 890117d3d0
commit fbb4cd5101
8 changed files with 218 additions and 20 deletions

View File

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

64
src/camera.cpp Normal file
View File

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

28
src/camera.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <GLFW/glfw3.h>
#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);

View File

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

View File

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

View File

@ -14,6 +14,7 @@ struct Shader {
u32 id;
u32 uniform_projection;
u32 uniform_model;
u32 uniform_view;
Shader();
~Shader();

View File

@ -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<Window *>(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<Window *>(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
}

View File

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