#include "glad/glad.h" #include "glm/glm.hpp" #include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/type_ptr.hpp" #include #include #include #include #include #include #include #include "camera.hpp" #include "shader.hpp" #include "sphere.hpp" #include "stb_image.h" float deltaTime = 0.0f; // Time between current frame and last frame float lastFrame = 0.0f; // Time of last frame float lastX = 600 / 2.0f; float lastY = 800 / 2.0f; Camera camera(glm::vec3(1.0f, 0.0f, 1.0f)); bool firstMouse = true; const int MAP_WIDTH = 20; const int MAP_HEIGHT = 20; int worldMap[MAP_WIDTH][MAP_HEIGHT] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1}, {1, 0, 2, 2, 2, 0, 1, 0, 2, 2, 2, 2, 0, 1, 0, 2, 2, 2, 0, 1}, {1, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 1}, {1, 0, 2, 2, 2, 0, 1, 0, 2, 2, 2, 2, 0, 1, 0, 2, 2, 2, 0, 1}, {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1}, {1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1}, {1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1}, {1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1}, {1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 2, 2, 2, 2, 2, 2, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 0, 1}, {1, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 1}, {1, 0, 2, 0, 0, 0, 0, 2, 0, 1, 1, 0, 2, 0, 0, 0, 0, 2, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}; bool collision_check(float newX, float newZ) { float playerRadius = 0.2f; // We check the four corners of the player's "hitbox" for (float offset_x = -playerRadius; offset_x <= playerRadius; offset_x += playerRadius * 2) { for (float offset_z = -playerRadius; offset_z <= playerRadius; offset_z += playerRadius * 2) { int gridX = (int)(newX + offset_x); int gridZ = (int)(newZ + offset_z); // 1. Check map boundaries if (gridX < 0 || gridX >= MAP_WIDTH || gridZ < 0 || gridZ >= MAP_HEIGHT) return false; // 2. Check if the tile is a wall if (worldMap[gridX][gridZ] > 0) return false; } } return true; } void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) { (void)window; camera.ProcessMouseScroll(yoffset); } void framebuffer_size_callback(GLFWwindow *window, int width, int height) { (void)window; glViewport(0, 0, width, height); } void mouse_callback(GLFWwindow *window, double xpos, double ypos) { (void)window; if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; lastX = xpos; lastY = ypos; camera.ProcessMouseMovement(xoffset, yoffset); } void updatePhysics(float deltaTime) { // 1. Apply gravity to velocity (Velocity = Acceleration * Time) if (!camera.isGrounded) { camera.verticalVelocity += camera.gravity * deltaTime; } // 2. Apply velocity to position (Position = Velocity * Time) camera.Position.y += camera.verticalVelocity * deltaTime; // 3. Ground Collision (The Floor) // If the floor is at y = 0 if (camera.Position.y <= 0.0f) { camera.Position.y = 0.0f; camera.verticalVelocity = 0.0f; camera.isGrounded = true; } } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, 1); } if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } if (glfwGetKey(window, GLFW_KEY_H) == GLFW_PRESS) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } 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); if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { camera.verticalVelocity = camera.jumpForce; camera.isGrounded = false; } } int main() { float planeVertices[] = { // positions // texture coords -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left }; unsigned int planeIndices[] = { 0, 1, 2, // first triangle 2, 3, 0 // second triangle }; glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); // This makes the window float glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_TRUE); GLFWwindow *window = glfwCreateWindow(800, 600, "testing open gl", NULL, NULL); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); if (window == NULL) { printf("failed to create window"); return -1; } glfwMakeContextCurrent(window); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { printf("failed to initlize glad"); return -1; } glViewport(0, 0, 800, 600); Shader ourshader("../vertexshader.vs", "../fragmentshader.glsl"); float vertices[] = { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // cube one 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // cube one 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // cube one 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // cube one -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // cube one -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // cube one -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // cube one 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // cube one 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // cube one 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // cube one -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // cube one -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // cube one -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // cube one -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // cube one -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // cube one -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // cube one -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // cube one -0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // cube one 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // cube one 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // cube one 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // cube one 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // cube one 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // cube one 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // cube one -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // cube one 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, // cube one 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // cube one 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // cube one -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // cube one -0.5f, -0.5f, -0.5f, 0.0f, 1.0f, // cube one -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // cube one 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // cube one 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // cube one 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // cube one -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, // cube one -0.5f, 0.5f, -0.5f, 0.0f, 1.0f // cube one }; 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) }; unsigned int EBO; glGenBuffers(1, &EBO); unsigned int VBO; glGenBuffers(1, &VBO); unsigned int VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); glEnableVertexAttribArray(0); // texture coord attribute glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float))); glEnableVertexAttribArray(2); unsigned int wallVAO, wallVBO, wallEBO; glGenVertexArrays(1, &wallVAO); glGenBuffers(1, &wallVBO); glGenBuffers(1, &wallEBO); glBindVertexArray(wallVAO); glBindBuffer(GL_ARRAY_BUFFER, wallVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wallEBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); glEnableVertexAttribArray(0); // Texture coord attribute glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float))); glEnableVertexAttribArray(2); // sphere unsigned int sphereVAO, sphereVBO, sphereEBO; std::vector sphereVerts; std::vector sphereIndices; float ballRadius = 0.1f; generateSphere(ballRadius, 36, 18, sphereVerts, sphereIndices); glGenVertexArrays(1, &sphereVAO); glGenBuffers(1, &sphereVBO); glGenBuffers(1, &sphereEBO); glBindVertexArray(sphereVAO); glBindBuffer(GL_ARRAY_BUFFER, sphereVBO); glBufferData(GL_ARRAY_BUFFER, sphereVerts.size() * sizeof(SphereVertex), &sphereVerts[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sphereEBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sphereIndices.size() * sizeof(unsigned int), &sphereIndices[0], GL_STATIC_DRAW); // Position attribute glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(SphereVertex), (void *)0); glEnableVertexAttribArray(0); // Normal attribute glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(SphereVertex), (void *)offsetof(SphereVertex, normal)); glEnableVertexAttribArray(1); // TexCoord attribute glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(SphereVertex), (void *)offsetof(SphereVertex, texCoord)); glEnableVertexAttribArray(2); // loading textures unsigned int texture1, texture2; int width, height, nrChannels; stbi_set_flip_vertically_on_load(true); glGenTextures(1, &texture1); glBindTexture(GL_TEXTURE_2D, texture1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); unsigned char *image = stbi_load("../container.jpg", &width, &height, &nrChannels, 0); if (image) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture" << std::endl; } stbi_image_free(image); glGenTextures(1, &texture2); glBindTexture(GL_TEXTURE_2D, texture2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); image = stbi_load("../awesomeface.png", &width, &height, &nrChannels, 0); if (image) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture" << std::endl; } stbi_image_free(image); ourshader.use(); ourshader.setInt("texture1", 0); ourshader.setInt("texture2", 1); // defines a model matrix which will rotate the plane // ourshader.setMat4("mvp", glm::mat4(1.0f)); glEnable(GL_DEPTH_TEST); glm::vec3 ballVelocity = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 ballPosition = glm::vec3(camera.Position.x, 5.0f, camera.Position.z); float gravity = -9.81f; while (!glfwWindowShouldClose(window)) { float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; updatePhysics(deltaTime); processInput(window); ballVelocity.y += gravity * deltaTime; ballPosition += ballVelocity * deltaTime; float groundlevel = -0.5f; if (ballPosition.y - ballRadius < groundlevel) { ballPosition.y = groundlevel + ballRadius; // Snap to floor ballVelocity.y = -ballVelocity.y * 0.75f; // Reverse and dampen (75% energy kept) // Friction: Slow down X and Z movement slightly on impact ballVelocity.x *= 0.9f; ballVelocity.z *= 0.9f; } printf("ball: \nx:%f\ny:%f\nz:%f\n", ballPosition.x, ballPosition.y, ballPosition.z); printf("camera: \nx:%f\ny:%f\nz:%f\n", camera.Position.x, camera.Position.y, camera.Position.z); // matrix transformations, remember to do them in reverse order to what // you want glm::mat4 trans = glm::mat4(1.0f); trans = // glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f)); trans = // glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, // 0.0f, 1.0f)); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_CULL_FACE); // use our shader program before passing in the uniform ourshader.use(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2); // model = glm::translate( // model, glm::vec3(0.0f, sin(glfwGetTime() * 2) * 10e-4f, 0.0f)); // model = glm::rotate(model, glm::radians(90.0f) * (float)deltaTime, // glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, ballPosition); // Put it somewhere in the map glm::mat4 view; view = camera.GetViewMatrix(); float aspect = (float)width / (float)height; glm::mat4 projection = glm::mat4(1.0f); projection = glm::perspective(glm::radians(camera.Zoom), aspect, 0.1f, 100.0f); ourshader.setMat4("mvp", projection * view * model); glBindVertexArray(sphereVAO); glDrawElements(GL_TRIANGLES, sphereIndices.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(wallVAO); for (int x = 0; x < MAP_WIDTH; x++) { for (int y = 0; y < MAP_HEIGHT; y++) { if (worldMap[x][y] > 0) { // Set Texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, (worldMap[x][y] == 1) ? texture1 : texture2); if (y + 1 < MAP_HEIGHT && worldMap[x][y + 1] == 0) { glm::mat4 model = glm::mat4(1.0f); model = glm::translate( model, glm::vec3(x, 0.0f, y + 0.5f)); // Move to edge // No rotation needed if the plane naturally faces Z ourshader.setMat4("mvp", projection * view * model); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); } // Check East neighbor: if it's empty, draw the East face if (x + 1 < MAP_WIDTH && worldMap[x + 1][y] == 0) { glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(x + 0.5f, 0.0f, y)); model = glm::rotate(model, glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)); ourshader.setMat4("mvp", projection * view * model); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); } if (y - 1 < MAP_HEIGHT && worldMap[x][y - 1] == 0) { glm::mat4 model = glm::mat4(1.0f); model = glm::translate( model, glm::vec3(x, 0.0f, y - 0.5f)); // Move to edge // No rotation needed if the plane naturally faces Z ourshader.setMat4("mvp", projection * view * model); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); } if (x - 1 < MAP_WIDTH && worldMap[x - 1][y] == 0) { glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(x - 0.5f, 0.0f, y)); model = glm::rotate(model, glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)); ourshader.setMat4("mvp", projection * view * model); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); } } else { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); // Draw Floor glm::mat4 floorModel = glm::mat4(1.0f); floorModel = glm::translate(floorModel, glm::vec3((float)x, -0.5f, (float)y)); floorModel = glm::rotate(floorModel, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0)); ourshader.setMat4("mvp", projection * view * floorModel); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // Draw Ceiling glm::mat4 cielModel = glm::mat4(1.0f); cielModel = glm::translate(cielModel, glm::vec3((float)x, 0.5f, (float)y)); cielModel = glm::rotate(cielModel, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0)); ourshader.setMat4("mvp", projection * view * cielModel); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); } } } // for (unsigned int i = 0; i < 10; i++) { // // glm::mat4 model = glm::mat4(1.0f); // model = glm::translate(model, cubePositions[i]); // float angle = 20.0f * i; // // if ((i + 1) % 3 == 0) { // angle = glfwGetTime() * 25.0f; // model = glm::rotate(model, glm::radians(angle), // glm::vec3(0.5f, 1.0f, 0.3f)); // } else { // // model = glm::rotate(model, glm::radians(angle), // glm::vec3(0.5f, 1.0f, 0.3f)); // } // // glm::mat4 mvp = projection * view * model; // // ourshader.setMat4("mvp", mvp); // glDrawArrays(GL_TRIANGLES, 0, 36); // } glBindVertexArray(0); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; }