#include #include #include #include #include #include #include #include #include "Object3D.h" #include "Shader.h" #include "Camera.h" void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow *window); // settings unsigned int SCR_WIDTH = 800; unsigned int SCR_HEIGHT = 600; bool first_mouse = true; bool mouse_lock = true; float last_x = 400, last_y = 300; // Flipped Stuff const float flip_cooldown = 1.0f; // In seconds float last_flip = 0.0f; int flipped = 1; // 1 for normal, -1 for flipped bool flipping = false; glm::vec3 flip_target = glm::vec3(0.0f); // Various other settings const float camera_speed = 0.05f; const float look_sensitivity = 0.1f; const float Z_FAR = 1000.0f; const float Z_NEAR = 0.1f; const bool WIREFRAME_MODE = !true; const float TARGET_FPS = 60.0f; const float FOV = 90.0f; float sleep_time = 15.0f; glm::mat4 projection = glm::mat4(1.0f); float yaw, pitch = 0; // Camera Camera camera = Camera(camera_speed); // Lighting glm::vec3 lightPos(1.2f, 1.0f, 2.0f); glm::vec3 lightColor(0.557, 0.482, 0.6); glm::vec3 objectColor(0.671f, 0.671f, 0.671f); glm::vec3 cubePositions[] = { glm::vec3( 0.0f, 0.0f, 0.0f), glm::vec3( 2.0f, 5.0f, -15.0f), glm::vec3(-1.5f, -2.2f, -2.5f), glm::vec3(-3.8f, -2.0f, -12.3f), glm::vec3 (2.4f, -0.4f, -3.5f), glm::vec3(-1.7f, 3.0f, -7.5f), glm::vec3( 1.3f, -2.0f, -2.5f), glm::vec3( 1.5f, 2.0f, -2.5f), glm::vec3( 1.5f, 0.2f, -1.5f), glm::vec3(-1.3f, 1.0f, -1.5f) }; // Mouse Look void mouse_callback(GLFWwindow * window, double xpos, double ypos) { if (flipping) return; 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 * flipped; pitch += y_offset * flipped; 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); } int main() { // glfw: initialize and configure glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // glfw window creation GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Test", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); // glad: load all OpenGL function pointers if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // ------ Basic Lighting ------ glm::vec3 light_direction(0.0f, 1.0f, 0.0f); // ------ Setup Shader ------ Shader shader("shaders/shader.vert", "shaders/shader.frag"); // ------ World Objects ------ std::vector world_objects; Object3D cube = Object3D("objs/sphere.obj"); world_objects.push_back(cube); // ------ Buffer Setup ------ unsigned int VBO, VAO, EBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); // Move VBO into GPU memory glBindBuffer(GL_ARRAY_BUFFER, VBO); // Get VBO buffer from 3D Object (combine vertices and normals) std::vector object_VBO_buffer = cube.getVBOBuffer(); // for (int i = 0; i < object_VBO_buffer.size(); i++) // std::cout << object_VBO_buffer[i] << std::endl; // std::cout << "VBO buffer" << std::endl; // for (int i = 0; i < cube.VBO_buffer.size(); i++) // std::cout << cube.VBO_buffer[i] << std::endl; // std::cout << "EBO buffer " << cube.EBO_buffer.size() << std::endl; // for (int i = 0; i < cube.EBO_buffer.size(); i++) // std::cout << cube.EBO_buffer[i] + 1 << std::endl; // std::cout << "Faces in cube obj" << std::endl; // for (int i = 0; i < cube.indices.size(); i++) // std::cout << cube.indices[i] + 1 << std::endl; // std::cout << "vertices" << std::endl; // for (int i = 0; i < cube.vertices.size(); i++) // std::cout << i << " " << cube.vertices[i] << std::endl; glBufferData(GL_ARRAY_BUFFER, cube.VBO_buffer.size() * sizeof(float), &cube.VBO_buffer.front(), GL_STATIC_DRAW); glBindVertexArray(VAO); // Tell GPU how to read the memory // Position Attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // Normal Attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 6 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1); // Setup EBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, cube.EBO_buffer.size() * sizeof(unsigned int), &cube.EBO_buffer.front(), GL_STATIC_DRAW); // Color Attribute // glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float))); // glEnableVertexAttribArray(1); // ------ OpenGL Settings ------ if (WIREFRAME_MODE) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glEnable(GL_DEPTH_TEST); // Z-Buffer double start_time = glfwGetTime(); // Setup mouse look glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetCursorPosCallback(window, mouse_callback); int frame_count = 0; 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 // ------ Rendering Loop ------ while (!glfwWindowShouldClose(window)) { // input processInput(window); // ------ SETUP Matrices ------ shader.use(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Z-Buffer // Camera Rotate around origin // const float radius = 10.0f; // camera.position.x = sin(glfwGetTime()) * radius; // camera.position.z = cos(glfwGetTime()) * radius; glm::mat4 view = camera.getView(); shader.setMat4("projection", projection); shader.setMat4("view", view); // Fragment shader things shader.setVec3("lightPos", lightPos); shader.setVec3("viewPos", camera.position); shader.setVec3("lightColor", lightColor); shader.setVec3("objectColor", objectColor); // ------ Render ------ glBindVertexArray(VAO); // glDrawArrays(GL_TRIANGLES, 0, 3); // ---- Rotate Model ---- // glm::mat4 model = glm::mat4(1.0f); // model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f)); // float angle = 20.0f * glfwGetTime(); // model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.5f, 0.0f)); // shader.setMat4("model", model); for (unsigned int i = 0; i < 10; i++) { // calculate the model matrix for each object and pass it to shader before drawing glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, cubePositions[i]); float angle = 20.0f * i; model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); shader.setMat4("model", model); // glDrawArrays(GL_TRIANGLES, 0, 36); glDrawElements(GL_TRIANGLES, cube.EBO_buffer.size(), GL_UNSIGNED_INT, nullptr); } // glDrawElements(GL_TRIANGLES, cube.EBO_buffer.size(), GL_UNSIGNED_INT, nullptr); frame_count++; double end_time = glfwGetTime(); double delta_time = end_time - start_time; // Flip Animation attempt if (flipping && delta_time > 0.1f) { float flip_time = last_flip - end_time; glm::mat4 rotate = glm::mat4(1.0f); float angle = 18.0f * flip_time; rotate = glm::rotate(rotate, glm::radians(angle), glm::vec3(0.0f, 0.0f, 1.0f)); camera.worldUp = glm::vec3(rotate * glm::vec4(camera.worldUp, 1.0f)); if (flip_time > 0.5f) flipped *= -1; if (camera.worldUp.y >= flip_target.y) { flipping = false; camera.worldUp.y = flip_target.y; } } // ------ FPS output ------ if (delta_time >= 1) { const double FPS = frame_count / (delta_time); std::cout << "FPS: " << FPS << std::endl; frame_count = 0; start_time = glfwGetTime(); // ---- Dynamic FPS ---- if (FPS > TARGET_FPS) sleep_time += 5.0f; if (FPS < TARGET_FPS) sleep_time -= 5.0f; } Sleep(sleep_time); // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) glfwSwapBuffers(window); glfwPollEvents(); } // glfw: terminate, clearing all previously allocated GLFW resources. glfwTerminate(); return 0; } // process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly void processInput(GLFWwindow *window) { 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.position += camera.speed * camera.target; if(glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera.position -= camera.speed * camera.target; // Horizontal if(glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera.position -= glm::normalize(glm::cross(camera.target, camera.worldUp)) * camera.speed; if(glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera.position += glm::normalize(glm::cross(camera.target, camera.worldUp)) * camera.speed; // Vertical if(glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) camera.position -= glm::normalize(glm::cross(camera.target, glm::normalize(glm::cross(camera.target, camera.worldUp)))) * camera.speed * 0.5f; if(glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) camera.position += glm::normalize(glm::cross(camera.target, glm::normalize(glm::cross(camera.target, camera.worldUp)))) * camera.speed * 0.5f; // Sprint if(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) camera.speed = camera_speed; if(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_RELEASE) camera.speed = camera_speed * 5; // World Flip if(glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) { float current_time = glfwGetTime(); if (current_time - last_flip > flip_cooldown && !flipping) { // flip_target = camera.worldUp; // flip_target *= -1; camera.worldUp *= -1; last_flip = current_time; flipped *= -1; // flipping = true; } } } // 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); }