// Copyright [2023] Krzysztof Rudnicki #ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_BREAKOUT_CPP #define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_BREAKOUT_CPP #include #include #include #include "../dependencies/include/glad/glad.h" #include "./game.hpp" #include "./resourceManager.hpp" #include "./constants.hpp" // GLFW function declarations void framebuffer_size_callback(GLFWwindow *window, int width, int height); void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode); // The Width of the screen constexpr int SCREEN_WIDTH = 800; // The height of the screen constexpr int SCREEN_HEIGHT = 600; Game &getBreakoutInstance() { static Game Breakout(SCREEN_WIDTH, SCREEN_HEIGHT); return Breakout; } void initGLFW() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif glfwWindowHint(GLFW_RESIZABLE, 0); } int failedGLAD() { // we are forced to use reinterpret_cast since there is no standard-compliant // way to convert a void* (which is what glfwGetProcAddress returns) to a // function pointer in C++ if (gladLoadGLLoader(reinterpret_cast(glfwGetProcAddress)) == 0) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } return 0; } std::pair calculate_delta_time(double deltaTime, double lastFrame) { // calculate delta time // -------------------- double const currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glfwPollEvents(); return std::make_pair(deltaTime, lastFrame); } void main_loop_render(Game Breakout) { // render glClearColor(0.0F, 0.0F, 0.0F, 1.0F); glClear(GL_COLOR_BUFFER_BIT); Breakout.Render(); } void main_loop_inside(GLFWwindow *window, double deltaTime, double lastFrame, Game Breakout) { const std::pair times = calculate_delta_time(deltaTime, lastFrame); deltaTime = times.first; lastFrame = times.second; // manage user input Breakout.ProcessInput(deltaTime); // update game state Breakout.Update(deltaTime); main_loop_render(Breakout); glfwSwapBuffers(window); } void main_loop(GLFWwindow *window, const Game &Breakout) { // deltaTime variables const double deltaTime = 0.0F; const double lastFrame = 0.0F; // We do not comply with altera-unroll-loops // since each loop iteration is dependent on the previous one. while (glfwWindowShouldClose(window) == 0) { main_loop_inside(window, deltaTime, lastFrame, Breakout); } } int delete_resources() { // delete all resources as loaded using the resource manager ResourceManager::Clear(); glfwTerminate(); return 0; } void gl_magic(GLFWwindow *window) { glfwSetKeyCallback(window, key_callback); glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } int main(int /*argc*/, char * /*argv*/[]) { initGLFW(); GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Breakout", nullptr, nullptr); glfwMakeContextCurrent(window); if (failedGLAD() != 0) { return -1; } gl_magic(window); Game Breakout = getBreakoutInstance(); // initialize game Breakout.Init(); main_loop(window, Breakout); return delete_resources(); } void exit_window(GLFWwindow *window, const int key, const int action) { // when a user presses the escape key, we set the // WindowShouldClose property to true, closing the application if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { glfwSetWindowShouldClose(window, 1); } } void key_callback_happy(const std::pair action_key) { Game Breakout = getBreakoutInstance(); if (action_key.first == GLFW_PRESS) { Breakout.Keys.at(action_key.second) = true; } else if (action_key.first == GLFW_RELEASE) { Breakout.Keys.at(action_key.second) = false; } } void key_callback_sad(int key) { std::cerr << "key_callback_sad Error! key is out of range!" << key << std::endl; } // Assume Breakout.Keys is of type KeyArray void key_callback(GLFWwindow *window, int key, int /*scancode*/, int action, int /*mode*/) { // Define the array type for keys const int MAX_KEYS_TRACKED = constants::MAX_KEYS_TRACKED; using KeyArray = std::array; exit_window(window, key, action); if (key >= 0 && key < MAX_KEYS_TRACKED) { try { key_callback_happy(std::pair(action, key)); } catch (const std::out_of_range &e) { key_callback_sad(key); } } } 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); } #endif // BREAKOUT_CPP