#include #include #include #include #include #include #include #include "stb/stb_easy_font.h" #include #include #include #include void window_resize_callback(GLFWwindow* window, int width, int height); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void processInput(GLFWwindow *window); const int SCREEN_WIDTH = 1920; const int SCREEN_HEIGHT = 1080; static bool drawWireframe = false; static bool wireframeHeld = false; Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); float lastX = SCREEN_WIDTH / 2.0f; float lastY = SCREEN_HEIGHT / 2.0f; bool firstMouse = true; float deltaTime = 0.0f; // time between current frame and last frame float lastFrame = 0.0f; int main(int argc, char* argv[]) { // Initialize GLFW glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Create GLFW Window GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Renderer", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // Initialize GLAD if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // Initialize Viewport & setup resize callback glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); glfwSetFramebufferSizeCallback(window, window_resize_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // Hide & Lock Cursor glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE); /* Testing */ // Load Shader Shader shaderTest("assets/shaders/basicVertex.vert", "assets/shaders/basicFragment.frag"); std::vector vertices = { // Front face (-z) – normal: (0, 0, -1) { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }, { 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f }, { 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f }, { 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f }, { -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f }, { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }, // Back face (+z) – normal: (0, 0, +1) { -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, { 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f }, { 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }, { 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }, { -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f }, { -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, // Left face (-x) – normal: (-1, 0, 0) { -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, { -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, { -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f }, { -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f }, { -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, // Right face (+x) – normal: (+1, 0, 0) { 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, { 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, { 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, // Bottom face (-y) – normal: (0, -1, 0) { -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f }, { 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f }, { -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f }, { -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f }, // Top face (+y) – normal: (0, +1, 0) { -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }, { 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }, { 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f }, { 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f }, { -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }, { -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f } }; std::vector indices = { // Front (-z) ── outer view CCW 0, 1, 2, 0, 2, 5, // Back (+z) ── outer view CCW 6, 7, 8, 6, 8, 11, // Left (-x) ── outer view CCW 12, 13, 14, 12, 14, 17, // Right (+x) ── outer view CCW 18, 19, 20, 18, 20, 23, // Bottom (-y) ── outer view CCW 24, 25, 26, 24, 26, 29, // Top (+y) ── outer view CCW 30, 31, 32, 30, 32, 35 }; Mesh testMesh(vertices, indices); Texture texture1("assets/wall.jpg"); Texture texture2("assets/awesomeface.png", true); shaderTest.Use(); // don't forget to activate/use the shader before setting uniforms! shaderTest.setInt("ourTexture", 0); shaderTest.setInt("decal", 1); // Render Loop float lastUpdate = 0; while (!glfwWindowShouldClose(window)) { // per-frame time logic // -------------------- float currentFrame = static_cast(glfwGetTime()); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // crappy fps printout if (currentFrame - lastUpdate >= 1.0) { std::cout << 1.0f / deltaTime << std::endl; lastUpdate += 1.0f; } // Input processing processInput(window); // Rendering glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1.ID); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2.ID); shaderTest.Use(); // pass projection matrix to shader (note that in this case it could change every frame) glm::mat4 projection = glm::perspective(glm::radians(camera.zoom), (float)SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.1f, 100.0f); shaderTest.setMat4("projection", projection); // camera/view transformation glm::mat4 view = camera.GetViewMatrix(); shaderTest.setMat4("view", view); glm::mat4 model = glm::mat4(1.0f); shaderTest.setMat4("model", model); testMesh.Draw(); // Call events & swap buffers glfwSwapBuffers(window); glfwPollEvents(); } // Clean up memory glfwTerminate(); return 0; } void window_resize_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } void processInput(GLFWwindow* window) { // Close on Escape if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); // Wireframe toggle if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_PRESS && !wireframeHeld) { wireframeHeld = true; drawWireframe = !drawWireframe; if (drawWireframe) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } if (glfwGetKey(window, GLFW_KEY_F1) == GLFW_RELEASE) wireframeHeld = false; // Camera if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera.processKeyboard(FORWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera.processKeyboard(BACKWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera.processKeyboard(LEFT, deltaTime); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera.processKeyboard(RIGHT, deltaTime); } // glfw: whenever the mouse moves, this callback is called // ------------------------------------------------------- void mouse_callback(GLFWwindow* window, double xposIn, double yposIn) { float xpos = static_cast(xposIn); float ypos = static_cast(yposIn); if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera.processMouseMovement(xoffset, yoffset); } // glfw: whenever the mouse scroll wheel scrolls, this callback is called // ---------------------------------------------------------------------- void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { camera.processMouseScroll(static_cast(yoffset)); }