From 5f1bf88374c59da59abf72fc7009a0a8e5bb1392 Mon Sep 17 00:00:00 2001 From: JISAUAY Date: Mon, 10 Nov 2025 12:58:30 -0600 Subject: [PATCH] added camera control --- src/main.cpp | 168 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 161 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4944a93..7621046 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,9 +9,15 @@ #include "Object3D.h" // Window dimensions -const unsigned int SCR_WIDTH = 800; -const unsigned int SCR_HEIGHT = 600; +unsigned int SCR_WIDTH = 800; +unsigned int SCR_HEIGHT = 600; +// Jump +const float JUMP_COOLDOWN = 0.0f; +const float JUMP_POWER = 10.0f; // Initial Jump Speed +float last_jump = 0.0f; + +// Camera const float CAMERA_SPEED = 1.0f; const float MAX_CAMERA_SPEED = 2.0f; const float LOOK_SENSITIVITY = 0.1f; @@ -21,12 +27,146 @@ const float Z_NEAR = 0.1f; bool WIREFRAME_MODE = true; const float FOV = 90.0f; +bool W_pressed, S_pressed, A_pressed, D_pressed = false; + glm::mat4 projection = glm::mat4(1.0f); Camera camera = Camera(CAMERA_SPEED, glm::vec3(0.0f, 0.0f, 3.0f)); // Callback function for when the window is resized -void framebuffer_size_callback(GLFWwindow* window, int width, int height) { +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +void framebuffer_size_callback(GLFWwindow* window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); + SCR_WIDTH = width; + SCR_HEIGHT = height; + + // Perspective needs to be recalculated on window size change + projection = glm::perspective(glm::radians(FOV), (float)SCR_WIDTH / (float)SCR_HEIGHT, Z_NEAR, Z_FAR); +} + +float yaw, pitch = 0; +bool first_mouse = true; +bool mouse_lock = true; +float last_x = 400, last_y = 300; + +// Mouse Look +void mouse_callback(GLFWwindow * window, double xpos, double ypos) +{ + float x_offset = xpos - last_x; + float y_offset = ypos - last_y; + last_x = xpos; + last_y = ypos; + + if (first_mouse) + { + first_mouse = false; + return; + } + + x_offset *= LOOK_SENSITIVITY; + y_offset *= LOOK_SENSITIVITY; + + yaw += x_offset; + pitch += y_offset; + + if (pitch > 89.0f) + pitch = 89.0f; + if (pitch < -89.0f) + pitch = -89.0f; + + glm::vec3 direction; + direction.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); + direction.y = -sin(glm::radians(pitch)); + direction.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); + camera.target = glm::normalize(direction); +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +void processInput(GLFWwindow *window) +{ + float current_time = glfwGetTime(); + + if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + // if (mouse_lock) { + // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + // mouse_lock = false; + // } else { + // glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + // mouse_lock = true; + // } + glfwSetWindowShouldClose(window, true); + } + + // ---- Movement ---- + // Forward / Backward + if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + { + camera.forward_velocity = camera.speed * glm::vec3(camera.target.x, 0.0f, camera.target.z); + W_pressed = true; + } + + if(glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + { + camera.forward_velocity = -camera.speed * glm::vec3(camera.target.x, 0.0f, camera.target.z); + S_pressed = true; + } + + + if(glfwGetKey(window, GLFW_KEY_S) == GLFW_RELEASE && S_pressed) + { + camera.forward_velocity = glm::vec3(0.0f); + S_pressed = false; + } + if(glfwGetKey(window, GLFW_KEY_W) == GLFW_RELEASE && W_pressed) + { + camera.forward_velocity = glm::vec3(0.0f); + W_pressed = false; + } + + + // Horizontal + if(glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + { + camera.horizontal_velocity = -glm::normalize(glm::cross(glm::vec3(camera.target.x, 0.0f, camera.target.z), camera.worldUp)) * camera.speed; + A_pressed = true; + } + if(glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + { + camera.horizontal_velocity = glm::normalize(glm::cross(glm::vec3(camera.target.x, 0.0f, camera.target.z), camera.worldUp)) * camera.speed; + D_pressed = true; + } + + + if(glfwGetKey(window, GLFW_KEY_A) == GLFW_RELEASE && A_pressed) + { + camera.horizontal_velocity = glm::vec3(0.0f); + A_pressed = false; + } + if(glfwGetKey(window, GLFW_KEY_D) == GLFW_RELEASE && D_pressed) + { + camera.horizontal_velocity = glm::vec3(0.0f); + D_pressed = false; + } + + + // Jump + if(glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) + // camera.velocity -= glm::normalize(glm::cross(camera.target, glm::normalize(glm::cross(camera.target, camera.worldUp)))) * camera.speed * 0.5f; + { + if (current_time - last_jump > JUMP_COOLDOWN && camera.position.y == 0) + { + camera.vertical_velocity.y = JUMP_POWER; + last_jump = current_time; + } + } + + // Sprint + if(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) + camera.speed = CAMERA_SPEED * 7.5; + if(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_RELEASE) + camera.speed = CAMERA_SPEED * 20; } int main() { @@ -95,27 +235,41 @@ int main() { if (WIREFRAME_MODE) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + // Setup mouse look + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetCursorPosCallback(window, mouse_callback); + // Setup projection matrix projection = glm::perspective(glm::radians(FOV), (float)SCR_WIDTH / (float)SCR_HEIGHT, Z_NEAR, Z_FAR); // This doesn't need to be recalculated every frame - glm::mat4 view = camera.getView(); + glm::mat4 view; + double start_time = glfwGetTime(); + double move_time = glfwGetTime(); // 6. --- The Render Loop --- while (!glfwWindowShouldClose(window)) { // Input (e.g., close window on ESC) - // processInput(window); - if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) - glfwSetWindowShouldClose(window, true); + processInput(window); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Clear screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Z-Buffer + view = camera.getView(); + // Draw the triangle shader.use(); shader.setMat4("u_mvp", projection * view); glBindVertexArray(VAO); // Bind the VAO (our triangle's "recipe") glDrawElements(GL_TRIANGLES, cube.EBO_buffer.size(), GL_UNSIGNED_INT, nullptr); // Draw it! + double end_time = glfwGetTime(); + float time_since_last_move = end_time - move_time; + if (time_since_last_move >= 0.017) + { + camera.move(time_since_last_move); + move_time = end_time; + } + // Swap buffers and poll for events glfwSwapBuffers(window); glfwPollEvents();