diff --git a/MinecraftYoutube/include/challenges/Cubes.h b/MinecraftYoutube/include/challenges/Cubes.h index 5cf9570..01a305d 100644 --- a/MinecraftYoutube/include/challenges/Cubes.h +++ b/MinecraftYoutube/include/challenges/Cubes.h @@ -4,13 +4,14 @@ namespace MinecraftClone { struct Window; + struct Camera; namespace Cubes { - void init(const Window& window); + void init(); void destroy(); - void update(float dt); + void update(const Camera& camera); } } diff --git a/MinecraftYoutube/include/core.h b/MinecraftYoutube/include/core.h index feed159..6d6010a 100644 --- a/MinecraftYoutube/include/core.h +++ b/MinecraftYoutube/include/core.h @@ -31,6 +31,8 @@ #include #include #include +#include +#include // Use this for hash map and hash sets instead of the crappy std lib #include diff --git a/MinecraftYoutube/include/core/Application.h b/MinecraftYoutube/include/core/Application.h new file mode 100644 index 0000000..8ff7ff6 --- /dev/null +++ b/MinecraftYoutube/include/core/Application.h @@ -0,0 +1,20 @@ +#ifndef MINECRAFT_CLONE_APPLICATION_H +#define MINECRAFT_CLONE_APPLICATION_H + +namespace MinecraftClone +{ + struct Window; + + namespace Application + { + bool init(); + void run(); + void free(); + + const Window& getWindow(); + + extern float deltaTime; + } +} + +#endif \ No newline at end of file diff --git a/MinecraftYoutube/include/core/Input.h b/MinecraftYoutube/include/core/Input.h index 1749159..12eca96 100644 --- a/MinecraftYoutube/include/core/Input.h +++ b/MinecraftYoutube/include/core/Input.h @@ -12,11 +12,14 @@ namespace MinecraftClone extern float mouseY; extern float mouseScrollX; extern float mouseScrollY; + extern float deltaMouseX; + extern float deltaMouseY; void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); void mouseCallback(GLFWwindow* window, double xpos, double ypos); void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods); void mouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset); + void endFrame(); bool isKeyDown(int key); bool isMouseButtonDown(int mouseButton); diff --git a/MinecraftYoutube/include/core/Window.h b/MinecraftYoutube/include/core/Window.h index d8916ca..403c89a 100644 --- a/MinecraftYoutube/include/core/Window.h +++ b/MinecraftYoutube/include/core/Window.h @@ -13,6 +13,8 @@ namespace MinecraftClone void installMainCallbacks(); void close(); + + inline float getAspectRatio() const { return (float)windowWidth / (float)windowHeight; } static Window* createWindow(int width, int height, const char* title, bool fullScreenMode=false); static void freeWindow(Window* window); diff --git a/MinecraftYoutube/include/gameplay/CharacterController.h b/MinecraftYoutube/include/gameplay/CharacterController.h new file mode 100644 index 0000000..e05fe47 --- /dev/null +++ b/MinecraftYoutube/include/gameplay/CharacterController.h @@ -0,0 +1,28 @@ +#ifndef MINECRAFT_CLONE_CHARACTER_CONTROLLER_H +#define MINECRAFT_CLONE_CHARACTER_CONTROLLER_H +#include "core.h" + +namespace MinecraftClone +{ + struct CharacterController + { + float controllerBaseSpeed; + float controllerRunSpeed; + float movementSensitivity; + + glm::vec3 movementAxis; + glm::vec3 viewAxis; + bool isRunning; + bool lockedToCamera; + }; + + // TODO: Move this into physics library once it gets created in the physics episode + struct Rigidbody + { + glm::vec3 velocity; + glm::vec3 acceleration; + float friction; + }; +} + +#endif \ No newline at end of file diff --git a/MinecraftYoutube/include/gameplay/CharacterSystem.h b/MinecraftYoutube/include/gameplay/CharacterSystem.h new file mode 100644 index 0000000..ed32f71 --- /dev/null +++ b/MinecraftYoutube/include/gameplay/CharacterSystem.h @@ -0,0 +1,16 @@ +#ifndef MINECRAFT_CLONE_CHARACTER_SYSTEM_H +#define MINECRAFT_CLONE_CHARACTER_SYSTEM_H + +namespace MinecraftClone +{ + struct Camera; + struct CharacterController; + struct Rigidbody; + + namespace CharacterSystem + { + void update(CharacterController& controller, Camera& camera, Rigidbody& rb); + } +} + +#endif \ No newline at end of file diff --git a/MinecraftYoutube/include/gameplay/PlayerController.h b/MinecraftYoutube/include/gameplay/PlayerController.h new file mode 100644 index 0000000..ef26a0f --- /dev/null +++ b/MinecraftYoutube/include/gameplay/PlayerController.h @@ -0,0 +1,14 @@ +#ifndef MINECRAFT_CLONE_PLAYER_CONTROLLER_H +#define MINECRAFT_CLONE_PLAYER_CONTROLLER_H + +namespace MinecraftClone +{ + struct CharacterController; + + namespace PlayerController + { + void update(CharacterController& controller); + } +} + +#endif \ No newline at end of file diff --git a/MinecraftYoutube/include/renderer/Camera.h b/MinecraftYoutube/include/renderer/Camera.h new file mode 100644 index 0000000..8a94d98 --- /dev/null +++ b/MinecraftYoutube/include/renderer/Camera.h @@ -0,0 +1,34 @@ +#ifndef MINECRAFT_CLONE_CAMERA_H +#define MINECRAFT_CLONE_CAMERA_H +#include "core.h" + +namespace MinecraftClone +{ + struct Camera + { + // TODO: Replace this with an entity representing the + // camera that holds a Transform containing a position + glm::vec3 position; + glm::quat orientation; + // NOTE: Techinally the forward, right and up vectors + // can be obtained from orientation. However, we can + // cache them to avoid recomputing an entire matrix + // every time we need a directional vector. + glm::vec3 forward; + glm::vec3 right; + glm::vec3 up; + glm::mat4 projection; + glm::mat4 view; + float fov; + + // This just calculates the view and then + // returns the member variable view + const glm::mat4& calculateViewMatrix(); + + // This just calculates projection and then + // returns member variable projection + const glm::mat4& calculateProjectionMatrix(); + }; +} + +#endif \ No newline at end of file diff --git a/MinecraftYoutube/src/challenges/Cubes.cpp b/MinecraftYoutube/src/challenges/Cubes.cpp index 043ad4f..21826d1 100644 --- a/MinecraftYoutube/src/challenges/Cubes.cpp +++ b/MinecraftYoutube/src/challenges/Cubes.cpp @@ -2,7 +2,9 @@ #include "core.h" #include "core/Input.h" #include "core/Window.h" +#include "core/Application.h" #include "renderer/ShaderProgram.h" +#include "renderer/Camera.h" namespace MinecraftClone { @@ -98,8 +100,6 @@ namespace MinecraftClone static std::vector cubePositions; static std::vector cubeTextures; - static glm::mat4 projection; - void createDefaultCube() { // Define the 8 unique positions for a cube according to the diagram above @@ -243,7 +243,7 @@ namespace MinecraftClone glDeleteTextures(1, &texture.textureId); } - void init(const Window& window) + void init() { if (!texturedCubeShader.compileAndLink("assets/shaders/vertex/cube.glsl", "assets/shaders/fragment/cube.glsl")) { @@ -253,12 +253,6 @@ namespace MinecraftClone createDefaultCube(); - float windowAspect = ((float)window.windowWidth / (float)window.windowHeight); - float fov = 70.0f; - float zNear = 0.1f; - float zFar = 10'000.0f; - projection = glm::perspective(fov, windowAspect, zNear, zFar); - for (auto& filepath : std::filesystem::directory_iterator("assets/images")) { if (filepath.path().stem().string() != "normal") @@ -299,22 +293,12 @@ namespace MinecraftClone } } - void update(float dt) + void update(const Camera& camera) { texturedCubeShader.bind(); - // Rotate the eye a little bit every frame - static glm::vec3 eye = glm::vec3(); - static float eyeRotation = 45.0f; - if (!Input::isKeyDown(GLFW_KEY_SPACE)) - eyeRotation += 30.0f * dt; - eye = glm::vec3(glm::sin(glm::radians(eyeRotation)) * 7.0f, 5.0f, glm::cos(glm::radians(eyeRotation)) * 7.0f); - - glm::vec3 center = glm::vec3(0.0f, 0.0f, 0.0f); - glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); - glm::mat4 view = glm::lookAt(eye, center, up); - texturedCubeShader.uploadMat4("uView", view); - texturedCubeShader.uploadMat4("uProjection", projection); + texturedCubeShader.uploadMat4("uView", camera.view); + texturedCubeShader.uploadMat4("uProjection", camera.projection); // NOTE: This texture is not required for the challenges glActiveTexture(GL_TEXTURE0 + 1); diff --git a/MinecraftYoutube/src/core/Application.cpp b/MinecraftYoutube/src/core/Application.cpp new file mode 100644 index 0000000..7cb24f0 --- /dev/null +++ b/MinecraftYoutube/src/core/Application.cpp @@ -0,0 +1,175 @@ +#include "core/Application.h" +#include "core.h" +#include "core/Window.h" +#include "core/Input.h" + +// TODO: Temporary includes +#include "challenges/Cubes.h" +#include "gameplay/CharacterController.h" +#include "gameplay/CharacterSystem.h" +#include "gameplay/PlayerController.h" +#include "renderer/Camera.h" + +namespace MinecraftClone +{ + namespace Application + { + // Global variables + // Initialize this to 60FPS so we don't start the first frame with any + // division by 0 errors or something + float deltaTime = 1.0f / 60.0f; + + // Internal variables + static Window* window = nullptr; + static constexpr int windowWidth = 1920; + static constexpr int windowHeight = 1080; + static const char* windowTitle = "Minecraft Clone"; + + // Internal Functions + void GLAPIENTRY errorMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam); + void glfwErrorCallback(int error, const char* description); + + bool init() + { + glfwSetErrorCallback(glfwErrorCallback); + if (!glfwInit()) + { + g_logger_error("GLFW failed to initialize"); + return false; + } + + window = Window::createWindow(windowWidth, windowHeight, windowTitle); + if (window == nullptr) + { + g_logger_error("Failed to create GLFW window"); + glfwTerminate(); + return false; + } + window->installMainCallbacks(); + + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + g_logger_error("Failed to initialize GLAD."); + glfwTerminate(); + return false; + } + + // During init, enable debug output + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(errorMessageCallback, 0); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + glViewport(0, 0, windowWidth, windowHeight); + + // Set the window cursor to be locked + glfwSetInputMode((GLFWwindow*)window->nativeWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + // Initialize our game stuff now + Cubes::init(); + + return true; + } + + void run() + { + float frameStart = 0.0f; + + Camera camera = {}; + // We need to initialize the orientation of the camera + glm::vec3 forward = glm::normalize(glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 right = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), forward); + glm::vec3 up = glm::cross(forward, right); + glm::mat4 rotMatrix = glm::transpose(glm::mat4( + glm::vec4(right, 0.0f), + glm::vec4(up, 0.0f), + glm::vec4(forward, 0.0f), + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f) + )); + camera.orientation = glm::toQuat(rotMatrix); + // The camera projection matrix should only need to be calculated once + // unless the FOV or aspect ratio changes. I'll ignore those for now. + camera.fov = 70.0f; + camera.calculateProjectionMatrix(); + + CharacterController controller = {}; + controller.controllerBaseSpeed = 66.0f; + controller.controllerRunSpeed = controller.controllerBaseSpeed * 2.0f; + controller.movementSensitivity = 0.1f; + + Rigidbody rb = {}; + rb.friction = 0.1f; + + while (!glfwWindowShouldClose(window->nativeWindow)) + { + deltaTime = (float)(glfwGetTime() - (double)frameStart); + frameStart = (float)glfwGetTime(); + glfwPollEvents(); + + glClearColor(39.0f / 255.0f, 40.0f / 255.0f, 34.0f / 255.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Update the player first, so that we get the input settled + PlayerController::update(controller); + // Then update the player data using the inputs we got + CharacterSystem::update(controller, camera, rb); + // Finally calculate our new view matrix and draw our scene + camera.calculateViewMatrix(); + Cubes::update(camera); + + if (Input::isKeyDown(GLFW_KEY_ESCAPE)) + { + glfwSetInputMode((GLFWwindow*)window->nativeWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + else if (Input::isKeyDown(GLFW_KEY_ENTER)) + { + glfwSetInputMode((GLFWwindow*)window->nativeWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + } + + glfwSwapBuffers(window->nativeWindow); + + Input::endFrame(); + } + } + + void free() + { + // Try to destroy things in the reverse order of initialization + // to minimize any weird dependency issues during de-initialization + Cubes::destroy(); + + Window::freeWindow(window); + window = nullptr; + + glfwTerminate(); + } + + const Window& getWindow() + { + return *window; + } + + // ------------ Internal Functions ------------ + void GLAPIENTRY errorMessageCallback( + GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam) + { + if (type == GL_DEBUG_TYPE_ERROR) + { + g_logger_error("GL CALLBACK: **GL ERROR** type = 0x%x, severity = 0x%x, message = %s\n", + type, severity, message); + } + } + + void glfwErrorCallback(int error, const char* description) + { + g_logger_error("GLFW CALLBACK: **GLFW ERROR** Error: %d description: %s\n", error, description); + } + } +} diff --git a/MinecraftYoutube/src/core/Input.cpp b/MinecraftYoutube/src/core/Input.cpp index 7d3f081..5c92443 100644 --- a/MinecraftYoutube/src/core/Input.cpp +++ b/MinecraftYoutube/src/core/Input.cpp @@ -4,12 +4,20 @@ namespace MinecraftClone { namespace Input { + // Global Variables bool keyPressedData[GLFW_KEY_LAST] = {}; bool mouseButtonPressedData[GLFW_MOUSE_BUTTON_LAST] = {}; float mouseX = 0.0f; float mouseY = 0.0f; float mouseScrollX = 0.0f; float mouseScrollY = 0.0f; + float deltaMouseX = 0.0f; + float deltaMouseY = 0.0f; + + // Internal Variables + static float lastMouseX = 0.0f; + static float lastMouseY = 0.0f; + static bool firstFrame = true; void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { @@ -23,6 +31,37 @@ namespace MinecraftClone { mouseX = (float)xpos; mouseY = (float)ypos; + if (firstFrame) + { + // Set these to the mouse position the first frame so that + // we don't get large erratic values the first frame + lastMouseX = (float)xpos; + lastMouseY = (float)ypos; + firstFrame = false; + } + + // NOTE: This stuff is just to prevent the camera from jumping if the mouse cursor + // moves off the window and then back onto the window at a different location + int windowWidth; + int windowHeight; + glfwGetWindowSize(window, &windowWidth, &windowHeight); + bool cursorLocked = glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED; + if (!cursorLocked && + (mouseX >= (float)windowWidth || mouseX <= 0.0f || mouseY >= (float)windowHeight || mouseY <= 0.0f)) + { + // NOTE: If the mouse just came from off the screen and the cursor is not locked + // then don't count that as a real delta movement + deltaMouseX = 0.0f; + deltaMouseY = 0.0f; + } + else + { + deltaMouseX = ((float)xpos - lastMouseX); + deltaMouseY = (lastMouseY - (float)ypos); + } + + lastMouseX = (float)xpos; + lastMouseY = (float)ypos; } void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) @@ -39,6 +78,12 @@ namespace MinecraftClone mouseScrollY = (float)yoffset; } + void endFrame() + { + deltaMouseX = 0.0f; + deltaMouseY = 0.0f; + } + bool isKeyDown(int key) { if (key >= 0 && key < GLFW_KEY_LAST) diff --git a/MinecraftYoutube/src/core/Window.cpp b/MinecraftYoutube/src/core/Window.cpp index 5bcb2e8..ea57824 100644 --- a/MinecraftYoutube/src/core/Window.cpp +++ b/MinecraftYoutube/src/core/Window.cpp @@ -48,6 +48,7 @@ namespace MinecraftClone } glfwMakeContextCurrent(res->nativeWindow); glfwSetWindowUserPointer(res->nativeWindow, (void*)res); + glfwSwapInterval(1); res->windowWidth = width; res->windowHeight = height; diff --git a/MinecraftYoutube/src/gameplay/CharacterSystem.cpp b/MinecraftYoutube/src/gameplay/CharacterSystem.cpp new file mode 100644 index 0000000..7fd68a9 --- /dev/null +++ b/MinecraftYoutube/src/gameplay/CharacterSystem.cpp @@ -0,0 +1,79 @@ +#include "gameplay/CharacterSystem.h" +#include "gameplay/CharacterController.h" +#include "renderer/Camera.h" +#include "core/Application.h" +#include "core/Input.h" + +namespace MinecraftClone +{ + namespace CharacterSystem + { + // Internal Variables + static float terminalVelocity = 8.0f; + + void update(CharacterController& controller, Camera& camera, Rigidbody& rb) + { + float speed = controller.controllerBaseSpeed; + if (controller.isRunning) + { + speed = controller.controllerRunSpeed; + } + + rb.acceleration = camera.forward * controller.movementAxis.x; + rb.acceleration += camera.right * controller.movementAxis.z; + // The y-axis just changes the player's global y position + // instead of using their local up axis + rb.acceleration.y += controller.movementAxis.y; + + // Only normalize the acceleration if it is greater than 0. This + // way we avoid division by 0 errors + float accelerationMagnitudeSquared = glm::length2(rb.acceleration); + if (accelerationMagnitudeSquared > 0) + { + float denominator = glm::inversesqrt(accelerationMagnitudeSquared); + rb.acceleration *= denominator * speed; + } + + rb.velocity += rb.acceleration * Application::deltaTime; + camera.position += rb.velocity * Application::deltaTime; + + // If acceleration is 0, apply friction to decelerate the object + if (glm::all(glm::epsilonEqual(rb.acceleration, glm::vec3(0.0f), 0.001f))) + { + rb.velocity *= rb.friction * Application::deltaTime; + } + + if (glm::length2(rb.velocity) >= terminalVelocity) + { + rb.velocity = glm::normalize(rb.velocity) * terminalVelocity; + } + + // Snap the velocity to 0 when it gets close enough + if (glm::all(glm::epsilonEqual(rb.velocity, glm::vec3(0.0f), 0.001f))) + { + rb.velocity = glm::vec3(0.0f); + } + + // Mouse movements don't need to be smoothed over time. + // They alread represent a change in position + controller.viewAxis *= controller.movementSensitivity; + + // Check out this stack overflow for a deeper explanation of + // why this is necessary + // https://gamedev.stackexchange.com/questions/136174/im-rotating-an-object-on-two-axes-so-why-does-it-keep-twisting-around-the-thir + if (controller.viewAxis.x != 0.0f) + { + // Yaw globally + glm::quat yaw = glm::quat(glm::vec3(0.0f, glm::radians(controller.viewAxis.x), 0.0f)); + camera.orientation = camera.orientation * yaw; + } + + if (controller.viewAxis.y != 0.0f) + { + // Pitch locally (this effects order of operation with quaternion multiplication) + glm::quat pitch = glm::quat(glm::vec3(glm::radians(-controller.viewAxis.y), 0.0f, 0.0f)); + camera.orientation = pitch * camera.orientation; + } + } + } +} \ No newline at end of file diff --git a/MinecraftYoutube/src/gameplay/PlayerController.cpp b/MinecraftYoutube/src/gameplay/PlayerController.cpp new file mode 100644 index 0000000..4158ec6 --- /dev/null +++ b/MinecraftYoutube/src/gameplay/PlayerController.cpp @@ -0,0 +1,34 @@ +#include "gameplay/PlayerController.h" +#include "gameplay/CharacterController.h" +#include "core.h" +#include "core/Input.h" +#include "core/Application.h" +#include "core/Window.h" + +namespace MinecraftClone +{ + namespace PlayerController + { + void update(CharacterController& controller) + { + controller.movementAxis.x = Input::isKeyDown(GLFW_KEY_W) + ? -1.0f + : Input::isKeyDown(GLFW_KEY_S) + ? 1.0f + : 0.0f; + controller.movementAxis.z = Input::isKeyDown(GLFW_KEY_D) + ? 1.0f + : Input::isKeyDown(GLFW_KEY_A) + ? -1.0f + : 0.0f; + controller.movementAxis.y = Input::isKeyDown(GLFW_KEY_SPACE) + ? 1.0f + : Input::isKeyDown(GLFW_KEY_LEFT_SHIFT) + ? -1.0f + : 0.0f; + + controller.viewAxis.x = Input::deltaMouseX; + controller.viewAxis.y = Input::deltaMouseY; + } + } +} \ No newline at end of file diff --git a/MinecraftYoutube/src/main.cpp b/MinecraftYoutube/src/main.cpp index 4b926c2..57ecd66 100644 --- a/MinecraftYoutube/src/main.cpp +++ b/MinecraftYoutube/src/main.cpp @@ -1,95 +1,19 @@ #include "core.h" -#include "core/Window.h" -#include "core/Input.h" -#include "challenges/Cubes.h" -#include "renderer/ShaderProgram.h" +#include "core/Application.h" using namespace MinecraftClone; -const int windowWidth = 1920; -const int windowHeight = 1080; -const char* windowTitle = "OpenGL Template"; - -void GLAPIENTRY errorMessageCallback( - GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* userParam) -{ - if (type == GL_DEBUG_TYPE_ERROR) - { - g_logger_error("GL CALLBACK: **GL ERROR** type = 0x%x, severity = 0x%x, message = %s\n", - type, severity, message); - } -} - -void glfwErrorCallback(int error, const char* description) -{ - g_logger_error("GLFW CALLBACK: **GLFW ERROR** Error: %d description: %s\n", error, description); -} - int main() { - glfwSetErrorCallback(glfwErrorCallback); - if(!glfwInit()){ - g_logger_error("GLFW failed to initialize"); - return -1; - } - - Window* window = Window::createWindow(windowWidth, windowHeight, windowTitle); - if (window == nullptr) + // Try to initialize the app, if it fails exit early + if (!Application::init()) { - g_logger_error("Failed to create GLFW window"); - glfwTerminate(); + g_logger_error("Failed to initialize the game. See the logs above for more details."); return -1; } - window->installMainCallbacks(); - - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) - { - g_logger_error("Failed to initialize GLAD."); - glfwTerminate(); - return -1; - } - - // During init, enable debug output - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(errorMessageCallback, 0); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - glViewport(0, 0, windowWidth, windowHeight); - - float dt = 0.016f; - float frameStart = 0.0f; - - Cubes::init(*window); - - bool showPlayer = false; - bool showTerrain = false; - float keyDebounce = 0.1f; - while (!glfwWindowShouldClose(window->nativeWindow)) - { - dt = glfwGetTime() - frameStart; - frameStart = glfwGetTime(); - - glClearColor(39.0f/255.0f, 40.0f/255.0f, 34.0f/255.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - keyDebounce -= dt; - - Cubes::update(dt); - - glfwSwapBuffers(window->nativeWindow); - glfwPollEvents(); - } - Cubes::destroy(); + Application::run(); + Application::free(); - Window::freeWindow(window); - glfwTerminate(); return 0; } \ No newline at end of file diff --git a/MinecraftYoutube/src/renderer/Camera.cpp b/MinecraftYoutube/src/renderer/Camera.cpp new file mode 100644 index 0000000..9364bca --- /dev/null +++ b/MinecraftYoutube/src/renderer/Camera.cpp @@ -0,0 +1,30 @@ +#include "renderer/Camera.h" +#include "core/Application.h" +#include "core/Window.h" + +namespace MinecraftClone +{ + const glm::mat4& Camera::calculateViewMatrix() + { + glm::mat4 rotationMatrix = glm::toMat4(orientation); + right = glm::row(rotationMatrix, 0); + up = glm::row(rotationMatrix, 1); + forward = glm::row(rotationMatrix, 2); + + glm::mat4 translationMatrix = glm::transpose(glm::mat4( + glm::vec4(1.0f, 0.0f, 0.0f, -position.x), + glm::vec4(0.0f, 1.0f, 0.0f, -position.y), + glm::vec4(0.0f, 0.0f, 1.0f, -position.z), + glm::vec4(0.0f, 0.0f, 0.0f, 1.0f) + )); + + view = rotationMatrix * translationMatrix; + return view; + } + + const glm::mat4& Camera::calculateProjectionMatrix() + { + projection = glm::perspective(fov, Application::getWindow().getAspectRatio(), 0.1f, 100.0f); + return projection; + } +} \ No newline at end of file