diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0dba757..c1c0496 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -11,6 +11,7 @@ "-L${workspaceFolder}/dependencies/library", "-Wall", "${workspaceFolder}/breakout/*.hpp", + "${workspaceFolder}/breakout/*.h", "${workspaceFolder}/breakout/*.cpp", "${workspaceFolder}/breakout/glad.c", "-o", diff --git a/CMakeLists.txt b/CMakeLists.txt index be03a42..83c3ceb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) include_directories(${CMAKE_SOURCE_DIR}/dependencies/include) link_directories(${CMAKE_SOURCE_DIR}/dependencies/library) -file(GLOB SOURCES "${CMAKE_SOURCE_DIR}/breakout/*.cpp" "${CMAKE_SOURCE_DIR}/breakout/*.hpp" "${CMAKE_SOURCE_DIR}/breakout/glad.c") +file(GLOB SOURCES "${CMAKE_SOURCE_DIR}/breakout/*.cpp" "${CMAKE_SOURCE_DIR}/breakout/*.hpp" "${CMAKE_SOURCE_DIR}/breakout/*.h" "${CMAKE_SOURCE_DIR}/breakout/*.c" "${CMAKE_SOURCE_DIR}/breakout/glad.c") add_executable(breakout ${SOURCES}) diff --git a/breakout/breakout b/breakout/breakout old mode 100644 new mode 100755 index 4c9a06c..6e2b440 Binary files a/breakout/breakout and b/breakout/breakout differ diff --git a/breakout/breakout.cpp b/breakout/breakout.cpp deleted file mode 100644 index 3b55456..0000000 --- a/breakout/breakout.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// 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 diff --git a/breakout/constants.hpp b/breakout/constants.hpp deleted file mode 100644 index 0bcbede..0000000 --- a/breakout/constants.hpp +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef BREAKOUT_CONSTANTS_HPP_ -#define BREAKOUT_CONSTANTS_HPP_ - -namespace constants { - constexpr int MAX_KEYS_TRACKED { 1024 }; - constexpr int GAME_WINDOW_SIZE_ALLIGNMENT { 8 }; - constexpr int DEFAULT_INVALID_NUMBER { -1 }; -} - -#endif // BREAKOUT_CONSTANTS_HPP_ diff --git a/breakout/game.cpp b/breakout/game.cpp index dc6db34..14cdf41 100644 --- a/breakout/game.cpp +++ b/breakout/game.cpp @@ -1,21 +1,43 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_GAME_CPP -#define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_GAME_CPP -#include "../breakout/game.hpp" +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#include "game.hpp" + +Game::Game(unsigned int width, unsigned int height) + : State(GAME_ACTIVE), Keys(), Width(width), Height(height) +{ -Game::Game(GameWindowSize size) - : State(GAME_ACTIVE), Keys(), Width(size.width), Height(size.height) { } -void Game::Init() {} +Game::~Game() +{ + +} -void Game::Update(double deltaTime) {} +void Game::Init() +{ + +} -void Game::ProcessInput(double deltaTime) {} +void Game::Update(float dt) +{ + +} -void Game::Render() {} +void Game::ProcessInput(float dt) +{ + +} + +void Game::Render() +{ + +} -#endif -// GAME_CPP diff --git a/breakout/game.hpp b/breakout/game.hpp index 5fcc3f4..34b92b7 100644 --- a/breakout/game.hpp +++ b/breakout/game.hpp @@ -1,44 +1,46 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef BREAKOUT_GAME_HPP_ -#define BREAKOUT_GAME_HPP_ + +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#ifndef GAME_HPP +#define GAME_HPP + +#include #include -#include - -#include "../dependencies/include/glad/glad.h" -#include "./constants.hpp" - -struct GameWindowSize { - unsigned int width; - unsigned int height; -} __attribute__((aligned(constants::GAME_WINDOW_SIZE_ALLIGNMENT))); - // Represents the current state of the game -enum GameState { GAME_ACTIVE, GAME_MENU, GAME_WIN }; - -class Game { - private: - // game state - GameState State; - std::array Keys; - unsigned int Width, Height; - public: - // constructor/destructor - explicit Game(GameWindowSize size); - ~Game() = default; - - // rule of five - Game(const Game& other) = delete; - Game& operator=(const Game& other) = delete; - Game(Game&& other) noexcept = delete; - Game& operator=(Game&& other) noexcept = delete; - // initialize game state (load all shaders/textures/levels) - void Init(); - // game loop - void ProcessInput(double deltaTime); - void Update(double deltaTime); - void Render(); +enum GameState { + GAME_ACTIVE, + GAME_MENU, + GAME_WIN }; -#endif // BREAKOUT_GAME_HPP_ +// Game holds all game-related state and functionality. +// Combines all game-related data into a single class for +// easy access to each of the components and manageability. +class Game +{ +public: + // game state + GameState State; + bool Keys[1024]; + unsigned int Width, Height; + // constructor/destructor + Game(unsigned int width, unsigned int height); + ~Game(); + // initialize game state (load all shaders/textures/levels) + void Init(); + // game loop + void ProcessInput(float dt); + void Update(float dt); + void Render(); +}; + +#endif + diff --git a/breakout/program.cpp b/breakout/program.cpp new file mode 100644 index 0000000..1918dab --- /dev/null +++ b/breakout/program.cpp @@ -0,0 +1,124 @@ + + +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#include +#include + +#include "game.hpp" +#include "resource_manager.h" + +#include + +// 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 +const unsigned int SCREEN_WIDTH = 800; +// The height of the screen +const unsigned int SCREEN_HEIGHT = 600; + +Game Breakout(SCREEN_WIDTH, SCREEN_HEIGHT); + +int main(int argc, char *argv[]) +{ + 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, false); + + GLFWwindow* window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Breakout", nullptr, nullptr); + glfwMakeContextCurrent(window); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + glfwSetKeyCallback(window, key_callback); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + // OpenGL configuration + // -------------------- + glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // initialize game + // --------------- + Breakout.Init(); + + // deltaTime variables + // ------------------- + float deltaTime = 0.0f; + float lastFrame = 0.0f; + + while (!glfwWindowShouldClose(window)) + { + // calculate delta time + // -------------------- + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; + glfwPollEvents(); + + // manage user input + // ----------------- + Breakout.ProcessInput(deltaTime); + + // update game state + // ----------------- + Breakout.Update(deltaTime); + + // render + // ------ + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + Breakout.Render(); + + glfwSwapBuffers(window); + } + + // delete all resources as loaded using the resource manager + // --------------------------------------------------------- + ResourceManager::Clear(); + + glfwTerminate(); + return 0; +} + +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) +{ + // 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, true); + if (key >= 0 && key < 1024) + { + if (action == GLFW_PRESS) + Breakout.Keys[key] = true; + else if (action == GLFW_RELEASE) + Breakout.Keys[key] = false; + } +} + +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); +} + diff --git a/breakout/resourceManager.cpp b/breakout/resourceManager.cpp deleted file mode 100644 index 0659cf1..0000000 --- a/breakout/resourceManager.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_RESOURCEMANAGER_CPP -#define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_RESOURCEMANAGER_CPP - -#include - -#include "../breakout/resourceManager.hpp" -#include "./shader.hpp" -#include "./stb_image.h" -#include "./texture.hpp" - -// Instantiate static variables -std::map ResourceManager::Textures; -std::map ResourceManager::Shaders; - -Shader ResourceManager::LoadShader(const char *vShaderFile, - const char *fShaderFile, - const char *gShaderFile, - const std::string &name) { - Shaders[name] = loadShaderFromFile(vShaderFile, fShaderFile, gShaderFile); - return Shaders[name]; -} - -Shader ResourceManager::GetShader(const std::string &name) { - return Shaders[name]; -} - -Texture2D ResourceManager::LoadTexture(const char *file, bool alpha, - const std::string &name) { - Textures[name] = loadTextureFromFile(file, alpha); - return Textures[name]; -} - -Texture2D ResourceManager::GetTexture(const std::string &name) { - return Textures[name]; -} - -void ResourceManager::Clear() { - // (properly) delete all shaders - for (const auto &iter : Shaders) { - glDeleteProgram(iter.second.ID); - } - // (properly) delete all textures - for (const auto &iter : Textures) { - glDeleteTextures(1, &iter.second.ID); - } -} - -static Shader ResourceManager::createShaderObject( - const std::string& vertexCode, const std::string& fragmentCode, - const char *gShaderFile, const std::string& geometryCode) { - const char *vShaderCode = vertexCode.c_str(); - const char *fShaderCode = fragmentCode.c_str(); - const char *gShaderCode = geometryCode.c_str(); - // 2. now create shader object from source code - Shader shader; - shader.Compile(vShaderCode, fShaderCode, - gShaderFile != nullptr ? gShaderCode : nullptr); - return shader; -} - -static std::string ResourceManager::loadFragmentCode(const char *fShaderFile) { - std::string fragmentCode; - // open files - std::ifstream fragmentShaderFile(fShaderFile); - std::stringstream fShaderStream; - // read file's buffer contents into streams - fShaderStream << fragmentShaderFile.rdbuf(); - // close file handlers - fragmentShaderFile.close(); - // convert stream into string - fragmentCode = fShaderStream.str(); - return fragmentCode; -} - -static std::string ResourceManager::loadVertexCode(const char *vShaderFile) { - std::string vertexCode; - std::ifstream vertexShaderFile(vShaderFile); - std::stringstream vShaderStream; - vShaderStream << vertexShaderFile.rdbuf(); - vertexShaderFile.close(); - vertexCode = vShaderStream.str(); - return vertexCode -} - -static std::string ResourceManager::loadGeometryCode(const char *gShaderFile) { - std::string geometryCode; - std::ifstream geometryShaderFile(gShaderFile); - std::stringstream gShaderStream; - gShaderStream << geometryShaderFile.rdbuf(); - geometryShaderFile.close(); - geometryCode = gShaderStream.str(); - return geometryCode; -} - -static Shader ResourceManager::loadShaderFromFile(const char *vShaderFile, - const char *fShaderFile, - const char *gShaderFile) { - std::string vertexCode; - std::string fragmentCode; - std::string geometryCode; - try { - vertexCode = loadVertexCode(vShaderFile); - fragmentCode = loadFragmentCode(fShaderFile); - // if geometry shader path is present, also load a geometry shader - if (gShaderFile != nullptr) { - geometryCode = loadGeometryCode(gShaderFile); - } - } catch (std::exception const &) { - std::cout << "ERROR::SHADER: Failed to read shader files" << std::endl; - } - return createShaderObject( - vertexCode, fragmentCode, gShaderFile, geometryCode); -} - -static Texture2D ResourceManager::createTextureObject(bool alpha) { - // create texture object - Texture2D texture; - if (alpha) { - texture.Internal_Format = GL_RGBA; - texture.Image_Format = GL_RGBA; - } - return texture; -} - -Texture2D ResourceManager::loadTextureFromFile(const char *file, bool alpha) { - Texture2D texture = createTextureObject(alpha); - // load image - int width = -1; - int height = -1; - int nrChannels = -1; - unsigned char *data = stbi_load(file, &width, &height, &nrChannels, 0); - // now generate texture - texture.Generate(width, height, data); - // and finally free image data - stbi_image_free(data); - return texture; -} - -#endif diff --git a/breakout/resourceManager.hpp b/breakout/resourceManager.hpp deleted file mode 100644 index 8d56132..0000000 --- a/breakout/resourceManager.hpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright [2023] Krzysztof Rudnicki -/******************************************************************* -** This code is part of Breakout. -** -** Breakout is free software: you can redistribute it and/or modify -** it under the terms of the CC BY 4.0 license as published by -** Creative Commons, either version 4 of the License, or (at your -** option) any later version. -******************************************************************/ -#ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_RESOURCEMANAGER_HPP -#define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_RESOURCEMANAGER_HPP - -#include "../dependencies/include/glad/glad.h" - -#include "../breakout/shader.hpp" -#include "../breakout/texture.hpp" - -// A static singleton ResourceManager class that hosts several -// functions to load Textures and Shaders. Each loaded texture -// and/or shader is also stored for future reference by string -// handles. All functions and resources are static and no -// public constructor is defined. -class ResourceManager { -public: - // resource storage - template <> static std::max; - Shaders{}; - template <> static std::max; - Textures{}; - // loads (and generates) a shader program from file loading vertex, - // fragment (and geometry) shader's source code. - // If gShaderFile is not nullptr, it also loads a geometry shader - static auto LoadShader(const char *vShaderFile, const char *fShaderFile, - const char *gShaderFile, const std::string &name) - -> Shader; - // retrieves a stored sader - static auto GetShader(const std::string &name) -> Shader; - // loads (and generates) a texture from file - static auto LoadTexture(const char *file, bool alpha, const std::string &name) - -> Texture2D; - // retrieves a stored texture - static auto GetTexture(const std::string &name) -> Texture2D; - // properly de-allocates all loaded resources - static void Clear(); - -private: - // private constructor, - // that is we do not want any actual resource manager objects. - // Its members and functions should be publicly available (static). - ResourceManager() = default; - // loads and generates a shader from file - static Shader ResourceManager::createShaderObject( - std::string vertexCode, std::string fragmentCode, - const char *gShaderFile, std::string geometryCode); - static std::string ResourceManager::loadFragmentCode(const char *fShaderFile); - static std::string ResourceManager::loadVertexCode(const char *vShaderFile); - static std::string ResourceManager::loadGeometryCode(const char *gShaderFile); - static auto loadShaderFromFile(const char *vShaderFile, - const char *fShaderFile, - const char *gShaderFile) -> Shader; - // loads a single texture from file - static Texture2D ResourceManager::createTextureObject(); - static auto loadTextureFromFile(const char *file, bool alpha) -> Texture2D; -}; - -#endif // HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_RESOURCEMANAGER_HPP diff --git a/breakout/resource_manager.cpp b/breakout/resource_manager.cpp new file mode 100644 index 0000000..ae2ae8c --- /dev/null +++ b/breakout/resource_manager.cpp @@ -0,0 +1,118 @@ + + +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#include "resource_manager.h" + +#include +#include +#include + +#include "stb_image.h" + +// Instantiate static variables +std::map ResourceManager::Textures; +std::map ResourceManager::Shaders; + + +Shader ResourceManager::LoadShader(const char *vShaderFile, const char *fShaderFile, const char *gShaderFile, std::string name) +{ + Shaders[name] = loadShaderFromFile(vShaderFile, fShaderFile, gShaderFile); + return Shaders[name]; +} + +Shader ResourceManager::GetShader(std::string name) +{ + return Shaders[name]; +} + +Texture2D ResourceManager::LoadTexture(const char *file, bool alpha, std::string name) +{ + Textures[name] = loadTextureFromFile(file, alpha); + return Textures[name]; +} + +Texture2D ResourceManager::GetTexture(std::string name) +{ + return Textures[name]; +} + +void ResourceManager::Clear() +{ + // (properly) delete all shaders + for (auto iter : Shaders) + glDeleteProgram(iter.second.ID); + // (properly) delete all textures + for (auto iter : Textures) + glDeleteTextures(1, &iter.second.ID); +} + +Shader ResourceManager::loadShaderFromFile(const char *vShaderFile, const char *fShaderFile, const char *gShaderFile) +{ + // 1. retrieve the vertex/fragment source code from filePath + std::string vertexCode; + std::string fragmentCode; + std::string geometryCode; + try + { + // open files + std::ifstream vertexShaderFile(vShaderFile); + std::ifstream fragmentShaderFile(fShaderFile); + std::stringstream vShaderStream, fShaderStream; + // read file's buffer contents into streams + vShaderStream << vertexShaderFile.rdbuf(); + fShaderStream << fragmentShaderFile.rdbuf(); + // close file handlers + vertexShaderFile.close(); + fragmentShaderFile.close(); + // convert stream into string + vertexCode = vShaderStream.str(); + fragmentCode = fShaderStream.str(); + // if geometry shader path is present, also load a geometry shader + if (gShaderFile != nullptr) + { + std::ifstream geometryShaderFile(gShaderFile); + std::stringstream gShaderStream; + gShaderStream << geometryShaderFile.rdbuf(); + geometryShaderFile.close(); + geometryCode = gShaderStream.str(); + } + } + catch (std::exception e) + { + std::cout << "ERROR::SHADER: Failed to read shader files" << std::endl; + } + const char *vShaderCode = vertexCode.c_str(); + const char *fShaderCode = fragmentCode.c_str(); + const char *gShaderCode = geometryCode.c_str(); + // 2. now create shader object from source code + Shader shader; + shader.Compile(vShaderCode, fShaderCode, gShaderFile != nullptr ? gShaderCode : nullptr); + return shader; +} + +Texture2D ResourceManager::loadTextureFromFile(const char *file, bool alpha) +{ + // create texture object + Texture2D texture; + if (alpha) + { + texture.Internal_Format = GL_RGBA; + texture.Image_Format = GL_RGBA; + } + // load image + int width, height, nrChannels; + unsigned char* data = stbi_load(file, &width, &height, &nrChannels, 0); + // now generate texture + texture.Generate(width, height, data); + // and finally free image data + stbi_image_free(data); + return texture; +} + diff --git a/breakout/resource_manager.h b/breakout/resource_manager.h new file mode 100644 index 0000000..bf4924d --- /dev/null +++ b/breakout/resource_manager.h @@ -0,0 +1,54 @@ + + +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#ifndef RESOURCE_MANAGER_H +#define RESOURCE_MANAGER_H + +#include +#include + +#include + +#include "texture.h" +#include "shader.h" + + +// A static singleton ResourceManager class that hosts several +// functions to load Textures and Shaders. Each loaded texture +// and/or shader is also stored for future reference by string +// handles. All functions and resources are static and no +// public constructor is defined. +class ResourceManager +{ +public: + // resource storage + static std::map Shaders; + static std::map Textures; + // loads (and generates) a shader program from file loading vertex, fragment (and geometry) shader's source code. If gShaderFile is not nullptr, it also loads a geometry shader + static Shader LoadShader(const char *vShaderFile, const char *fShaderFile, const char *gShaderFile, std::string name); + // retrieves a stored sader + static Shader GetShader(std::string name); + // loads (and generates) a texture from file + static Texture2D LoadTexture(const char *file, bool alpha, std::string name); + // retrieves a stored texture + static Texture2D GetTexture(std::string name); + // properly de-allocates all loaded resources + static void Clear(); +private: + // private constructor, that is we do not want any actual resource manager objects. Its members and functions should be publicly available (static). + ResourceManager() { } + // loads and generates a shader from file + static Shader loadShaderFromFile(const char *vShaderFile, const char *fShaderFile, const char *gShaderFile = nullptr); + // loads a single texture from file + static Texture2D loadTextureFromFile(const char *file, bool alpha); +}; + +#endif + diff --git a/breakout/shader.cpp b/breakout/shader.cpp index fb54736..8720554 100644 --- a/breakout/shader.cpp +++ b/breakout/shader.cpp @@ -1,140 +1,140 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_SHADER_CPP -#define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_SHADER_CPP -#include "../breakout/shader.hpp" -auto Shader::Use() -> Shader & { - glUseProgram(this->ID); - return *this; + +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#include "shader.h" + +#include + +Shader &Shader::Use() +{ + glUseProgram(this->ID); + return *this; } -void Shader::Compile(const char *vertexSource, const char *fragmentSource, - const char *geometrySource) { - unsigned int sVertex; - unsigned int sFragment; - unsigned int gShader; - // vertex Shader - sVertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(sVertex, 1, &vertexSource, nullptr); - glCompileShader(sVertex); - checkCompileErrors(sVertex, "VERTEX"); - // fragment Shader - sFragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(sFragment, 1, &fragmentSource, nullptr); - glCompileShader(sFragment); - checkCompileErrors(sFragment, "FRAGMENT"); - // if geometry shader source code is given, also compile geometry shader - if (geometrySource != nullptr) { - gShader = glCreateShader(GL_GEOMETRY_SHADER); - glShaderSource(gShader, 1, &geometrySource, nullptr); - glCompileShader(gShader); - checkCompileErrors(gShader, "GEOMETRY"); - } - // shader program - this->ID = glCreateProgram(); - glAttachShader(this->ID, sVertex); - glAttachShader(this->ID, sFragment); - if (geometrySource != nullptr) { - glAttachShader(this->ID, gShader); - } - glLinkProgram(this->ID); - checkCompileErrors(this->ID, "PROGRAM"); - // delete the shaders as they're linked into our - // program now and no longer necessary - glDeleteShader(sVertex); - glDeleteShader(sFragment); - if (geometrySource != nullptr) { - glDeleteShader(gShader); - } -} - -void Shader::SetFloat(const char *name, float value, bool useShader) { - if (useShader) { - this->Use(); - } - glUniform1f(glGetUniformLocation(this->ID, name), value); -} -void Shader::SetInteger(const char *name, int value, bool useShader) { - if (useShader) { - this->Use(); - } - glUniform1i(glGetUniformLocation(this->ID, name), value); -} -void Shader::SetVector2f(const char *name, float x, float y, bool useShader) { - if (useShader) { - this->Use(); - } - glUniform2f(glGetUniformLocation(this->ID, name), x, y); -} -void Shader::SetVector2f(const char *name, const glm::vec2 &value, - bool useShader) { - if (useShader) { - this->Use(); - } - glUniform2f(glGetUniformLocation(this->ID, name), value.x, value.y); -} -void Shader::SetVector3f(const char *name, float x, float y, float z, - bool useShader) { - if (useShader) { - this->Use(); - } - glUniform3f(glGetUniformLocation(this->ID, name), x, y, z); -} -void Shader::SetVector3f(const char *name, const glm::vec3 &value, - bool useShader) { - if (useShader) { - this->Use(); - } - glUniform3f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z); -} -void Shader::SetVector4f(const char *name, float x, float y, float z, float w, - bool useShader) { - if (useShader) { - this->Use(); - } - glUniform4f(glGetUniformLocation(this->ID, name), x, y, z, w); -} -void Shader::SetVector4f(const char *name, const glm::vec4 &value, - bool useShader) { - if (useShader) { - this->Use(); - } - glUniform4f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z, - value.w); -} -void Shader::SetMatrix4(const char *name, const glm::mat4 &matrix, - bool useShader) { - if (useShader) { - this->Use(); - } - glUniformMatrix4fv(glGetUniformLocation(this->ID, name), 1, 0u, - glm::value_ptr(matrix)); -} - -void Shader::checkCompileErrors(unsigned int object, const std::string &type) { - int success = 0; - char infoLog[1024]; - if (type != "PROGRAM") { - glGetShaderiv(object, GL_COMPILE_STATUS, &success); - if (success == 0) { - glGetShaderInfoLog(object, 1024, nullptr, infoLog); - std::cout - << "| ERROR::SHADER: Compile-time error: Type: " << type << "\n" - << infoLog - << "\n -- --------------------------------------------------- -- " - << std::endl; +void Shader::Compile(const char* vertexSource, const char* fragmentSource, const char* geometrySource) +{ + unsigned int sVertex, sFragment, gShader; + // vertex Shader + sVertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(sVertex, 1, &vertexSource, NULL); + glCompileShader(sVertex); + checkCompileErrors(sVertex, "VERTEX"); + // fragment Shader + sFragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(sFragment, 1, &fragmentSource, NULL); + glCompileShader(sFragment); + checkCompileErrors(sFragment, "FRAGMENT"); + // if geometry shader source code is given, also compile geometry shader + if (geometrySource != nullptr) + { + gShader = glCreateShader(GL_GEOMETRY_SHADER); + glShaderSource(gShader, 1, &geometrySource, NULL); + glCompileShader(gShader); + checkCompileErrors(gShader, "GEOMETRY"); + } + // shader program + this->ID = glCreateProgram(); + glAttachShader(this->ID, sVertex); + glAttachShader(this->ID, sFragment); + if (geometrySource != nullptr) + glAttachShader(this->ID, gShader); + glLinkProgram(this->ID); + checkCompileErrors(this->ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessary + glDeleteShader(sVertex); + glDeleteShader(sFragment); + if (geometrySource != nullptr) + glDeleteShader(gShader); +} + +void Shader::SetFloat(const char *name, float value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform1f(glGetUniformLocation(this->ID, name), value); +} +void Shader::SetInteger(const char *name, int value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform1i(glGetUniformLocation(this->ID, name), value); +} +void Shader::SetVector2f(const char *name, float x, float y, bool useShader) +{ + if (useShader) + this->Use(); + glUniform2f(glGetUniformLocation(this->ID, name), x, y); +} +void Shader::SetVector2f(const char *name, const glm::vec2 &value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform2f(glGetUniformLocation(this->ID, name), value.x, value.y); +} +void Shader::SetVector3f(const char *name, float x, float y, float z, bool useShader) +{ + if (useShader) + this->Use(); + glUniform3f(glGetUniformLocation(this->ID, name), x, y, z); +} +void Shader::SetVector3f(const char *name, const glm::vec3 &value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform3f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z); +} +void Shader::SetVector4f(const char *name, float x, float y, float z, float w, bool useShader) +{ + if (useShader) + this->Use(); + glUniform4f(glGetUniformLocation(this->ID, name), x, y, z, w); +} +void Shader::SetVector4f(const char *name, const glm::vec4 &value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform4f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z, value.w); +} +void Shader::SetMatrix4(const char *name, const glm::mat4 &matrix, bool useShader) +{ + if (useShader) + this->Use(); + glUniformMatrix4fv(glGetUniformLocation(this->ID, name), 1, false, glm::value_ptr(matrix)); +} + + +void Shader::checkCompileErrors(unsigned int object, std::string type) +{ + int success; + char infoLog[1024]; + if (type != "PROGRAM") + { + glGetShaderiv(object, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(object, 1024, NULL, infoLog); + std::cout << "| ERROR::SHADER: Compile-time error: Type: " << type << "\n" + << infoLog << "\n -- --------------------------------------------------- -- " + << std::endl; + } + } + else + { + glGetProgramiv(object, GL_LINK_STATUS, &success); + if (!success) + { + glGetProgramInfoLog(object, 1024, NULL, infoLog); + std::cout << "| ERROR::Shader: Link-time error: Type: " << type << "\n" + << infoLog << "\n -- --------------------------------------------------- -- " + << std::endl; + } } - } else { - glGetProgramiv(object, GL_LINK_STATUS, &success); - if (success == 0) { - glGetProgramInfoLog(object, 1024, nullptr, infoLog); - std::cout - << "| ERROR::Shader: Link-time error: Type: " << type << "\n" - << infoLog - << "\n -- --------------------------------------------------- -- " - << std::endl; - } - } } -#endif diff --git a/breakout/shader.h b/breakout/shader.h new file mode 100644 index 0000000..c8eb7de --- /dev/null +++ b/breakout/shader.h @@ -0,0 +1,51 @@ + + +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#ifndef SHADER_H +#define SHADER_H + +#include + +#include +#include +#include + + +// General purpose shader object. Compiles from file, generates +// compile/link-time error messages and hosts several utility +// functions for easy management. +class Shader +{ +public: + // state + unsigned int ID; + // constructor + Shader() { } + // sets the current shader as active + Shader &Use(); + // compiles the shader from given source code + void Compile(const char *vertexSource, const char *fragmentSource, const char *geometrySource = nullptr); // note: geometry source code is optional + // utility functions + void SetFloat (const char *name, float value, bool useShader = false); + void SetInteger (const char *name, int value, bool useShader = false); + void SetVector2f (const char *name, float x, float y, bool useShader = false); + void SetVector2f (const char *name, const glm::vec2 &value, bool useShader = false); + void SetVector3f (const char *name, float x, float y, float z, bool useShader = false); + void SetVector3f (const char *name, const glm::vec3 &value, bool useShader = false); + void SetVector4f (const char *name, float x, float y, float z, float w, bool useShader = false); + void SetVector4f (const char *name, const glm::vec4 &value, bool useShader = false); + void SetMatrix4 (const char *name, const glm::mat4 &matrix, bool useShader = false); +private: + // checks if compilation or linking failed and if so, print the error logs + void checkCompileErrors(unsigned int object, std::string type); +}; + +#endif + diff --git a/breakout/shader.hpp b/breakout/shader.hpp deleted file mode 100644 index c556474..0000000 --- a/breakout/shader.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_SHADER_HPP -#define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_SHADER_HPP - -#include "../dependencies/include/glad/glad.h" -#include "../dependencies/include/glm/glm/glm.hpp" -#include "../dependencies/include/glm/glm/gtc/type_ptr.hpp" - -// General purpose shader object. Compiles from file, generates -// compile/link-time error messages and hosts several utility -// functions for easy management. -class Shader { -public: - // state - unsigned int ID{}; - // constructor - Shader() = default; - // sets the current shader as active - auto Use() -> Shader &; - // compiles the shader from given source code - void Compile(const char *vertexSource, const char *fragmentSource, - const char *geometrySource); - // note: geometrysource code is optional - // utility functions - void SetFloat(const char *name, float value, bool useShader); - void SetInteger(const char *name, int value, bool useShader); - void SetVector2f(const char *name, float x, float y, bool useShader); - void SetVector2f(const char *name, const glm::vec2 &value, bool useShader); - void SetVector3f(const char *name, float x, float y, float z, bool useShader); - void SetVector3f(const char *name, const glm::vec3 &value, bool useShader); - void SetVector4f(const char *name, float x, float y, float z, float w, - bool useShader); - void SetVector4f(const char *name, const glm::vec4 &value, bool useShader); - void SetMatrix4(const char *name, const glm::mat4 &matrix, bool useShader); - -private: - // checks if compilation or linking failed and if so, print the error logs - static void checkCompileErrors(unsigned int object, const std::string &type); -}; - -#endif // HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_SHADER_HPP diff --git a/breakout/texture.cpp b/breakout/texture.cpp index 5bbc47a..79b2d44 100644 --- a/breakout/texture.cpp +++ b/breakout/texture.cpp @@ -1,35 +1,31 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_TEXTURE_CPP -#define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_TEXTURE_CPP +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#include -#include "../breakout/texture.hpp" +#include "texture.h" Texture2D::Texture2D() - : Width(0), - Height(0), - Internal_Format(GL_RGB), - Image_Format(GL_RGB), - Wrap_S(GL_REPEAT), - Wrap_T(GL_REPEAT), - Filter_Min(GL_LINEAR), - Filter_Max(GL_LINEAR) { + : Width(0), Height(0), Internal_Format(GL_RGB), Image_Format(GL_RGB), Wrap_S(GL_REPEAT), Wrap_T(GL_REPEAT), Filter_Min(GL_LINEAR), Filter_Max(GL_LINEAR) +{ glGenTextures(1, &this->ID); } -void Texture2D::Generate( - unsigned int width, - unsigned int height, - unsigned char* data) { +void Texture2D::Generate(unsigned int width, unsigned int height, unsigned char* data) +{ this->Width = width; this->Height = height; // create Texture glBindTexture(GL_TEXTURE_2D, this->ID); - glTexImage2D(GL_TEXTURE_2D, - 0, this->Internal_Format, width, height, - 0, this->Image_Format, GL_UNSIGNED_BYTE, data); + glTexImage2D(GL_TEXTURE_2D, 0, this->Internal_Format, width, height, 0, this->Image_Format, GL_UNSIGNED_BYTE, data); // set Texture wrap and filter modes glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, this->Wrap_S); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, this->Wrap_T); @@ -39,8 +35,8 @@ void Texture2D::Generate( glBindTexture(GL_TEXTURE_2D, 0); } -void Texture2D::Bind() const { +void Texture2D::Bind() const +{ glBindTexture(GL_TEXTURE_2D, this->ID); } -#endif // HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_TEXTURE_CPP diff --git a/breakout/texture.h b/breakout/texture.h new file mode 100644 index 0000000..8a65954 --- /dev/null +++ b/breakout/texture.h @@ -0,0 +1,42 @@ + + +/******************************************************************* +** This code is part of Breakout. +** +** Breakout is free software: you can redistribute it and/or modify +** it under the terms of the CC BY 4.0 license as published by +** Creative Commons, either version 4 of the License, or (at your +** option) any later version. +******************************************************************/ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include + +// Texture2D is able to store and configure a texture in OpenGL. +// It also hosts utility functions for easy management. +class Texture2D +{ +public: + // holds the ID of the texture object, used for all texture operations to reference to this particular texture + unsigned int ID; + // texture image dimensions + unsigned int Width, Height; // width and height of loaded image in pixels + // texture Format + unsigned int Internal_Format; // format of texture object + unsigned int Image_Format; // format of loaded image + // texture configuration + unsigned int Wrap_S; // wrapping mode on S axis + unsigned int Wrap_T; // wrapping mode on T axis + unsigned int Filter_Min; // filtering mode if texture pixels < screen pixels + unsigned int Filter_Max; // filtering mode if texture pixels > screen pixels + // constructor (sets default texture modes) + Texture2D(); + // generates texture from image data + void Generate(unsigned int width, unsigned int height, unsigned char* data); + // binds the texture as the current active GL_TEXTURE_2D texture object + void Bind() const; +}; + +#endif + diff --git a/breakout/texture.hpp b/breakout/texture.hpp deleted file mode 100644 index 9aeb143..0000000 --- a/breakout/texture.hpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright [2023] Krzysztof Rudnicki -#ifndef HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_TEXTURE_HPP -#define HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_TEXTURE_HPP - -#include "../dependencies/include/glad/glad.h" - -// Texture2D is able to store and configure a texture in OpenGL. -// It also hosts utility functions for easy management. -class Texture2D { -public: - // holds the ID of the texture object, - // used for all texture operations to reference to this particular texture - unsigned int ID{}; - // texture image dimensions - unsigned int Width, Height; - // width and height of loaded image in pixels - // texture Format - unsigned int Internal_Format; - // format of texture object - unsigned int Image_Format; - // format of loaded image - // texture configuration - unsigned int Wrap_S; - // wrapping mode on S axis - unsigned int Wrap_T; - // wrapping mode on T axis - unsigned int Filter_Min; - // filtering mode if texture pixels < screen pixels - unsigned int Filter_Max; - // filtering mode if texture pixels > screen pixels - // constructor (sets default texture modes) - Texture2D(); - // generates texture from image data - void Generate(unsigned int width, unsigned int height, unsigned char *data); - // binds the texture as the current active GL_TEXTURE_2D texture object - void Bind() const; -}; - -#endif // HOME_KUCHY_ENGINEER_THESIS_WUT_BREAKOUT_TEXTURE_HPP