diff --git a/CMakeLists.txt b/CMakeLists.txt index b23028f..ca4aca6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(ARCADE_BIN_DIR ${CMAKE_CURRENT_LIST_DIR}) set(ARCADE_LIB_DIR ${CMAKE_CURRENT_LIST_DIR}/lib) set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -fno-gnu-unique") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ARCADE_BIN_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${ARCADE_LIB_DIR}) diff --git a/core/src/Core.cpp b/core/src/Core.cpp index 8cf6683..7a9e2b0 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -8,7 +8,6 @@ #include #include -#include #include "Core.hpp" #include "shared/games/components/IComponent.hpp" @@ -25,7 +24,7 @@ Core::Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, c } } -Core::~Core() {} +Core::~Core() = default; std::shared_ptr Core::_getGameProvider(const unsigned char &index) { @@ -112,10 +111,11 @@ void Core::_initWindow() this->_fonts.clear(); this->_sounds.clear(); this->_window = this->_graphicsProvider->createWindow(windowInitProps); + this->_textures.clear(); this->_sceneStage = PLAY; } -std::shared_ptr Core::_getTexture(std::string bin, std::string ascii) +std::shared_ptr Core::_getTexture(const std::string& bin, const std::string& ascii) { for (auto &failedTexture : this->_failedTextures) { if (failedTexture == bin + ascii) @@ -126,7 +126,7 @@ std::shared_ptr Core::_getTexture(std::string bin, std::string ascii) return this->_textures[bin + ascii]; } -std::shared_ptr Core::_getFont(std::string path) +std::shared_ptr Core::_getFont(const std::string& path) { for (auto &failedTexture : this->_failedTextures) { if (failedTexture == path) @@ -137,7 +137,7 @@ std::shared_ptr Core::_getFont(std::string path) return this->_fonts[path]; } -Core::SoundProps Core::_getSound(std::string path) +Core::SoundProps Core::_getSound(const std::string& path) { if (this->_sounds.find(path) == this->_sounds.end()) { SoundProps soundProps { @@ -151,7 +151,7 @@ Core::SoundProps Core::_getSound(std::string path) return this->_sounds[path]; } -void Core::_loadFailed(std::shared_ptr texture) +void Core::_loadFailed(const std::shared_ptr& texture) { if (!texture) return; @@ -159,7 +159,7 @@ void Core::_loadFailed(std::shared_ptr texture) this->_failedTextures.push_back(textureProps.sources.bin + textureProps.sources.ascii); } -void Core::_loadFailed(std::shared_ptr text) +void Core::_loadFailed(const std::shared_ptr& text) { if (!text) return; @@ -167,7 +167,7 @@ void Core::_loadFailed(std::shared_ptr text) this->_failedTextures.push_back(textProps.font.path); } -TextureProps Core::_getTextureEntity(std::shared_ptr texture) +TextureProps Core::_getTextureEntity(const std::shared_ptr& texture) { auto textureProps = texture->getTextureProps(); TextureProps entityTextureProps { @@ -181,7 +181,7 @@ TextureProps Core::_getTextureEntity(std::shared_ptr text) +TextProps Core::_getTextEntity(const std::shared_ptr& text) { auto textProps = text->getTextProps(); TextProps entityTextProps { @@ -296,7 +296,7 @@ components::IKeyboardComponent::KeyData Core::_convertKeyPressData(events::IKeyE return keyCodeData; } -void Core::_preventWindowEvents(std::vector events) +void Core::_preventWindowEvents(const std::vector& events) { for (auto &event : events) { auto type = event->getType(); @@ -359,7 +359,7 @@ void Core::_handleKeyPress(std::shared_ptr &keyEvent, std::sh { auto keyCode = keyEvent->getKeyCode(); auto keyType = keyEvent->getKeyType(); - auto keyCodeData = this->_convertKeyPressData(keyType, keyCode); + auto keyCodeData = Core::_convertKeyPressData(keyType, keyCode); this->_handleFunctionKeys(keyEvent); keyboard->onKeyPress(this->_game, keyCodeData); @@ -369,32 +369,30 @@ void Core::_handleKeyRelease(std::shared_ptr &keyEvent, std:: { auto keyCode = keyEvent->getKeyCode(); auto keyType = keyEvent->getKeyType(); - auto keyCodeData = this->_convertKeyPressData(keyType, keyCode); + auto keyCodeData = Core::_convertKeyPressData(keyType, keyCode); keyboard->onKeyRelease(this->_game, keyCodeData); } void Core::_handleMouseButtonPress(std::shared_ptr &event, std::shared_ptr &component) { - auto button = event->getButton(); auto mousePosition = event->getPosition(); auto entityPosition = component->getPosition(); auto entitySize = component->getSize(); - if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + entitySize.x && - mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + entitySize.y) + if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + static_cast(entitySize.x) && + mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + static_cast(entitySize.y)) component->onMousePress(this->_game); } void Core::_handleMouseButtonRelease(std::shared_ptr &event, std::shared_ptr &component) { - auto button = event->getButton(); auto mousePosition = event->getPosition(); auto entityPosition = component->getPosition(); auto entitySize = component->getSize(); - if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + entitySize.x && - mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + entitySize.y) + if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + static_cast(entitySize.x) && + mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + static_cast(entitySize.y)) component->onMouseRelease(this->_game); } @@ -404,8 +402,8 @@ void Core::_handleMouseMove(std::shared_ptr &event, std::sh auto entityPosition = component->getPosition(); auto entitySize = component->getSize(); - if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + entitySize.x && - mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + entitySize.y) + if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + static_cast(entitySize.x) && + mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + static_cast(entitySize.y)) component->onMouseHover(this->_game); } @@ -421,17 +419,16 @@ void Core::_handleWindowClose() { if (this->_window && this->_window->isOpen()) { this->_stopAllGraphicsSounds(); + this->_textures.clear(); + this->_fonts.clear(); this->_window->close(); + this->_sounds.clear(); this->_menu.updateScore(this->_game); this->_sceneStage = MENU; + this->_window.reset(); } } -void Core::_handleWindowResize() -{ - std::cout << "Window resized" << std::endl; -} - void Core::_handleKeyboardEvents(std::vector &events, std::shared_ptr &component) { for (auto &event : events) { @@ -473,10 +470,10 @@ void Core::_handleCollisions(std::shared_ptr & auto targetPosition = target->getPosition(); auto targetSize = target->getSize(); - if (componentPosition.x < targetPosition.x + targetSize.x && - componentPosition.x + componentSize.x > targetPosition.x && - componentPosition.y < targetPosition.y + targetSize.y && - componentPosition.y + componentSize.y > targetPosition.y) + if (componentPosition.x < targetPosition.x + static_cast(targetSize.x) && + componentPosition.x + static_cast(componentSize.x) > targetPosition.x && + componentPosition.y < targetPosition.y + static_cast(targetSize.y) && + componentPosition.y + static_cast(componentSize.y) > targetPosition.y) component->onCollide(this->_game, target); } @@ -592,13 +589,16 @@ void Core::run() } if (this->_sceneStage == NEWGAME) this->_initGame(); - if (this->_sceneStage == RESUME) + if (this->_sceneStage == RESUME) { this->_initWindow(); + } if (this->_sceneStage == PLAY) { this->_game->compute(deltaTime); this->_gameEntities = this->_game->getEntities(); this->_handleEvents(); - this->_renderEntities(); + if (this->_window && this->_window->isOpen()) { + this->_renderEntities(); + } } } } diff --git a/core/src/Core.hpp b/core/src/Core.hpp index 315907b..9917a8c 100644 --- a/core/src/Core.hpp +++ b/core/src/Core.hpp @@ -45,7 +45,7 @@ class Core { } SoundProps; std::shared_ptr _game; - std::shared_ptr _window; + std::unique_ptr _window; std::shared_ptr _gameProvider; std::shared_ptr _graphicsProvider; std::map> _fonts; @@ -87,15 +87,21 @@ class Core { * * @param texture The texture component */ - void _loadFailed(std::shared_ptr texture); + void _loadFailed(const std::shared_ptr& texture); /** * @brief Load the failed text * * @param text The text component */ - void _loadFailed(std::shared_ptr text); + void _loadFailed(const std::shared_ptr& text); + /** + * @brief Free current resources + * + */ + void _freeResources(); + /** * @brief Get a texture * @@ -103,7 +109,7 @@ class Core { * @param ascii Path to the ascii file * @return The correct texture */ - std::shared_ptr _getTexture(std::string bin, std::string ascii); + std::shared_ptr _getTexture(const std::string& bin, const std::string& ascii); /** * @brief Get a font @@ -111,7 +117,7 @@ class Core { * @param path Path to the font file * @return The correct font */ - std::shared_ptr _getFont(std::string path); + std::shared_ptr _getFont(const std::string& path); /** * @brief Get a sound @@ -119,7 +125,7 @@ class Core { * @param path Path to the sound file * @return The correct sound */ - SoundProps _getSound(std::string path); + SoundProps _getSound(const std::string& path); /** * @brief Get the texture entity @@ -127,7 +133,7 @@ class Core { * @param texture The texture component * @return The texture entity */ - TextureProps _getTextureEntity(std::shared_ptr texture); + TextureProps _getTextureEntity(const std::shared_ptr& texture); /** * @brief Get the text entity @@ -135,7 +141,7 @@ class Core { * @param text The text component * @return The text entity */ - TextProps _getTextEntity(std::shared_ptr text); + TextProps _getTextEntity(const std::shared_ptr& text); /** * @brief Render the props @@ -259,18 +265,12 @@ class Core { */ void _stopAllGraphicsSounds(); - /** - * @brief Handle the window resize event - * - */ - void _handleWindowResize(); - /** * @brief Prevent the window from closing * * @param events The events */ - void _preventWindowEvents(std::vector events); + void _preventWindowEvents(const std::vector& events); /** * @brief Handle the key press event @@ -314,7 +314,7 @@ class Core { * @param code The code of the key * @return The converted key press data */ - components::IKeyboardComponent::KeyData _convertKeyPressData(events::IKeyEvent::KeyType type, events::IKeyEvent::KeyCode code); + static components::IKeyboardComponent::KeyData _convertKeyPressData(events::IKeyEvent::KeyType type, events::IKeyEvent::KeyCode code); /** * @brief Handle the mouse button press event diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index d1f7f1e..8ba2a46 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -10,9 +10,14 @@ #include #include "Menu.hpp" -Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, - std::shared_ptr &gameProvider, std::shared_ptr &graphicsProvider, arcade::core::SceneStage &sceneStage) : - _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), +Menu::Menu( + GameProviders &gameProviders, + GraphicsProviders &graphicsProviders, + std::shared_ptr &gameProvider, + std::shared_ptr &graphicsProvider, + arcade::core::SceneStage &sceneStage +) : + _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), _window(nullptr), _gameProvider(gameProvider), _graphicsProvider(graphicsProvider), _sceneStage(sceneStage) { this->_score.player = ""; @@ -64,17 +69,17 @@ std::string Menu::_truncString(const std::string &str, int size) return newString; } -void Menu::_initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenAuthors(const GameManifest &gameManifest, const std::shared_ptr& checkBox, std::shared_ptr font) { auto authorNames = std::make_shared(font, 35, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 8}); this->_hiddenAuthors[checkBox].push_back(authorNames); auto authors = gameManifest.authors; float index = 10.0; - for (auto author : authors) { - auto authorNameText = std::make_shared(font, 30, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index}); - auto authorMailText = std::make_shared(font, 30, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 1}); - auto authorSiteText = std::make_shared(font, 30, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 2}); + for (const auto& author : authors) { + auto authorNameText = std::make_shared(font, 30, Menu::_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index}); + auto authorMailText = std::make_shared(font, 30, Menu::_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 1}); + auto authorSiteText = std::make_shared(font, 30, Menu::_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 2}); this->_hiddenAuthors[checkBox].push_back(authorNameText); this->_hiddenAuthors[checkBox].push_back(authorMailText); this->_hiddenAuthors[checkBox].push_back(authorSiteText); @@ -82,18 +87,18 @@ void Menu::_initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr< } } -void Menu::_initHiddenScoreHeader(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenScoreHeader(const GameManifest &gameManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font) { - auto truncatName = this->_truncString(gameManifest.name, 23); - auto nameText = std::make_shared(font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); + auto truncatedName = Menu::_truncString(gameManifest.name, 23); + auto nameText = std::make_shared(font, 35, truncatedName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); this->_hiddenTexts[checkBox].push_back(nameText); - auto truncatDesc = this->_truncString(gameManifest.description, 23); - auto descriptionText = std::make_shared(font, 30, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); + auto truncatedDesc = Menu::_truncString(gameManifest.description, 23); + auto descriptionText = std::make_shared(font, 30, truncatedDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); } -void Menu::_initHiddenScoreBoard(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenScoreBoard(const GameManifest &gameManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font) { auto scoreHI = std::make_shared(font, 30, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); this->_hiddenTexts[checkBox].push_back(scoreHI); @@ -117,12 +122,12 @@ void Menu::_initHiddenScoreBoard(const GameManifest &gameManifest, std::shared_p if (count > 7) break; auto playerName = scoreElem.player.empty() ? "Guest" : scoreElem.player; - auto truncatPlayer = this->_truncString(playerName, 17); - auto playerText = std::make_shared(font, 25, truncatPlayer, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{17, 1}, Vector2f{26, index}); - auto scoreString = std::to_string(scoreElem.score).substr(0, 5); + auto truncatedPlayer = Menu::_truncString(playerName, 17); + auto playerText = std::make_shared(font, 25, truncatedPlayer, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{17, 1}, Vector2f{26, index}); + scoreString = std::to_string(scoreElem.score).substr(0, 5); while (scoreString.length() < 5) scoreString = "0" + scoreString; - auto scoreText = std::make_shared(font, 25, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{5, 1}, Vector2f{43, index}); + scoreText = std::make_shared(font, 25, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{5, 1}, Vector2f{43, index}); this->_hiddenTexts[checkBox].push_back(playerText); this->_hiddenTexts[checkBox].push_back(scoreText); index += 1; @@ -131,7 +136,7 @@ void Menu::_initHiddenScoreBoard(const GameManifest &gameManifest, std::shared_p } } -void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenScore(const GameManifest &gameManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font) { this->_initHiddenScoreHeader(gameManifest, checkBox, font); this->_initHiddenScoreBoard(gameManifest, checkBox, font); @@ -159,7 +164,7 @@ void Menu::_initCheckBoxesGames() } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } - for (auto gameProvider : this->_gameProviders) { + for (const auto& gameProvider : this->_gameProviders) { if (count > 5) break; std::string truncatedName = gameProvider.second->getManifest().name.substr(0, 20); @@ -178,25 +183,25 @@ void Menu::_initCheckBoxesGames() this->_initNoGameFound(); } -void Menu::_initHiddenGraphicsHeader(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenGraphicsHeader(const GraphicsManifest &graphicsManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font) { - auto truncatName = this->_truncString(graphicsManifest.name, 23); - auto nameText = std::make_shared(font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); + auto truncatedName = Menu::_truncString(graphicsManifest.name, 23); + auto nameText = std::make_shared(font, 35, truncatedName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); this->_hiddenTexts[checkBox].push_back(nameText); - auto truncatDesc = this->_truncString(graphicsManifest.description, 23); - auto descriptionText = std::make_shared(font, 30, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); + auto truncatedDesc = Menu::_truncString(graphicsManifest.description, 23); + auto descriptionText = std::make_shared(font, 30, truncatedDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); } -void Menu::_initHiddenGraphicsBoard(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenGraphicsBoard(const GraphicsManifest &graphicsManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font) { auto authors = graphicsManifest.authors; float index = 12.0; - for (auto author : authors) { - auto authorNameText = std::make_shared(font, 25, this->_truncString(author.name, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index}); - auto authorMailText = std::make_shared(font, 25, this->_truncString(author.email, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 1}); - auto authorSiteText = std::make_shared(font, 25, this->_truncString(author.website, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 2}); + for (const auto& author : authors) { + auto authorNameText = std::make_shared(font, 25, Menu::_truncString(author.name, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index}); + auto authorMailText = std::make_shared(font, 25, Menu::_truncString(author.email, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 1}); + auto authorSiteText = std::make_shared(font, 25, Menu::_truncString(author.website, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 2}); this->_hiddenTexts[checkBox].push_back(authorNameText); this->_hiddenTexts[checkBox].push_back(authorMailText); this->_hiddenTexts[checkBox].push_back(authorSiteText); @@ -204,7 +209,7 @@ void Menu::_initHiddenGraphicsBoard(const GraphicsManifest &graphicsManifest, st } } -void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font) { this->_initHiddenGraphicsHeader(graphicsManifest, checkBox, font); this->_initHiddenGraphicsBoard(graphicsManifest, checkBox, font); @@ -222,7 +227,7 @@ void Menu::_initCheckBoxesGraphics() } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } - for (auto graphicsProvider : this->_graphicsProviders) { + for (const auto& graphicsProvider : this->_graphicsProviders) { if (count > 5) break; std::string truncatedName = graphicsProvider.second->getManifest().name.substr(0, 20); @@ -255,12 +260,11 @@ void Menu::_initTextures() void Menu::_initTexts() { - auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); + this->_font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); - this->_font = font; - auto games = std::make_shared(font, 40, "Games", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 7}); + auto games = std::make_shared(this->_font, 40, "Games", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 7}); this->_texts.push_back(games); - auto graphics = std::make_shared(font, 40, "Graphics", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 15}); + auto graphics = std::make_shared(this->_font, 40, "Graphics", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 15}); this->_texts.push_back(graphics); } @@ -300,8 +304,8 @@ void Menu::_initWindow() IWindow::WindowInitProps windowInitProps { .size = {50, 25}, .mode = IWindow::WindowMode::WINDOWED, - .fps = 60, - .title = "Menu", + .fps = 1, + .title = "Arcade - Menu", .icon = "assets/menu/img/icon.png" }; @@ -321,7 +325,7 @@ void Menu::_initWindow() void Menu::_handleSelectUpperCheckBox() { - for (auto checkBox : this->_gamesCheckBoxes) { + for (auto &checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) { checkBox->unhover(); auto index = std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox)); @@ -332,7 +336,7 @@ void Menu::_handleSelectUpperCheckBox() break; } } - for (auto checkBox : this->_graphicsCheckBoxes) { + for (const auto& checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered()) { checkBox->unhover(); auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); @@ -353,7 +357,7 @@ void Menu::_handleSelectUpperCheckBox() void Menu::_handleSelectLowerCheckBox() { - for (auto checkBox : this->_graphicsCheckBoxes) { + for (const auto& checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered()) { checkBox->unhover(); auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); @@ -364,7 +368,7 @@ void Menu::_handleSelectLowerCheckBox() break; } } - for (auto checkBox : this->_gamesCheckBoxes) { + for (const auto& checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) { checkBox->unhover(); auto index = std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox)); @@ -379,7 +383,7 @@ void Menu::_handleSelectLowerCheckBox() } } -void Menu::_handleKeyboardEvents(std::shared_ptr key) +void Menu::_handleKeyboardEvents(const std::shared_ptr& key) { if (!key) return; @@ -411,7 +415,7 @@ void Menu::_handleKeyboardEvents(std::shared_ptr key) void Menu::_selectGame() { if (this->_checkBoxType == GAME_CHECKBOX) { - for (auto checkBox : this->_gamesCheckBoxes) { + for (const auto& checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered() && checkBox->isChecked()) return this->_exitWithNewGame(); if (checkBox->isHovered()) @@ -420,7 +424,7 @@ void Menu::_selectGame() checkBox->uncheck(); } } else { - for (auto checkBox : this->_graphicsCheckBoxes) { + for (const auto& checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered() && checkBox->isChecked()) return this->_changeGraphics(checkBox); if (checkBox->isHovered()) @@ -431,13 +435,14 @@ void Menu::_selectGame() } } -void Menu::_changeGraphics(std::shared_ptr checkBox) +void Menu::_changeGraphics(const std::shared_ptr& checkBox) { auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); auto graphicsProvider = this->_getGraphicsProvider(index); if (graphicsProvider != this->_graphicsProvider) { this->_graphicsProvider = graphicsProvider; this->_window->close(); + this->_window.reset(); this->_initWindow(); this->_previousSelectedGame(); this->_previousSelectedGraphics(); @@ -447,22 +452,29 @@ void Menu::_changeGraphics(std::shared_ptr checkBox) void Menu::_exitAndPlayOldGame() { this->_sceneStage = RESUME; - this->_window->close(); + if (this->_window) { + this->_clearLists(); + this->_window.reset(); + } } void Menu::_exitWithNewGame() { - for (auto checkBox : this->_gamesCheckBoxes) { + for (const auto& checkBox : this->_gamesCheckBoxes) { if (checkBox->isChecked()) { this->_gameProvider = this->_getGameProvider(std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox))); break; } } this->_sceneStage = NEWGAME; - this->_window->close(); + if (this->_window) { + this->_window->close(); + this->_clearLists(); + this->_window.reset(); + } } -void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) +void Menu::_handleMouseMoveEvents(const std::shared_ptr& mouse) { if (!mouse) return; @@ -470,15 +482,15 @@ void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) std::shared_ptr lastHoveredCheckBox = nullptr; bool hoveredAtLeastOne = false; - for (auto checkBox : this->_gamesCheckBoxes) { + for (const auto& checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) lastHoveredCheckBox = checkBox; } - for (auto checkBox : this->_graphicsCheckBoxes) { + for (const auto& checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered()) lastHoveredCheckBox = checkBox; } - for (auto checkBox : this->_gamesCheckBoxes) { + for (const auto& checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) checkBox->unhover(); if (checkBox->isHovered(position)) { @@ -487,7 +499,7 @@ void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) hoveredAtLeastOne = true; } } - for (auto checkBox : this->_graphicsCheckBoxes) { + for (const auto& checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered()) checkBox->unhover(); if (checkBox->isHovered(position)) { @@ -500,7 +512,7 @@ void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) lastHoveredCheckBox->hover(); } -void Menu::_handleMouseButtonEvents(std::shared_ptr mouse) +void Menu::_handleMouseButtonEvents(const std::shared_ptr& mouse) { if (!mouse) return; @@ -510,13 +522,13 @@ void Menu::_handleMouseButtonEvents(std::shared_ptr m if (button != events::IMouseButtonEvent::MouseButton::LEFT) return; - this->_handleMouseMouveEvents(move); - for (auto checkBox : this->_gamesCheckBoxes) { + this->_handleMouseMoveEvents(move); + for (const auto& checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered(position)) { this->_selectGame(); } } - for (auto checkBox : this->_graphicsCheckBoxes) { + for (auto &checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered(position)) { this->_selectGame(); } @@ -527,7 +539,7 @@ void Menu::_handleEvents() { auto events = this->_window->getEvents(); - for (auto event : events) { + for (const auto& event : events) { auto type = event->getType(); if (type == events::WINDOW_CLOSE) { this->_window->close(); @@ -539,7 +551,7 @@ void Menu::_handleEvents() } if (type == events::MOUSE_MOVE) { auto mouse = std::dynamic_pointer_cast(event); - this->_handleMouseMouveEvents(mouse); + this->_handleMouseMoveEvents(mouse); } if (type == events::MOUSE_BTN_PRESS) { auto mouse = std::dynamic_pointer_cast(event); @@ -556,8 +568,8 @@ void Menu::_renderField() auto placeholder = std::make_shared(this->_font, 30, "Guest", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); this->_nameField = placeholder; } else { - auto truncatName = this->_truncString(this->_score.player, 17); - auto name = std::make_shared(this->_font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); + auto truncatedName = Menu::_truncString(this->_score.player, 17); + auto name = std::make_shared(this->_font, 35, truncatedName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); this->_nameField = name; } if (this->_nameField) @@ -567,28 +579,28 @@ void Menu::_renderField() void Menu::_render() { this->_window->clear(); - for (auto texture : this->_textures) { + for (auto &texture : this->_textures) { texture->draw(this->_window); } - for (auto text : this->_texts) { + for (auto &text : this->_texts) { text->draw(this->_window); } - for (auto checkBox : this->_gamesCheckBoxes) { + for (auto &checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) { if (this->_textType == GAME) { - for (auto text : this->_hiddenTexts[checkBox]) { + for (auto &text : this->_hiddenTexts[checkBox]) { text->draw(this->_window); } } else { - for (auto text : this->_hiddenAuthors[checkBox]) { + for (auto &text : this->_hiddenAuthors[checkBox]) { text->draw(this->_window); } } } } - for (auto checkBox : this->_graphicsCheckBoxes) { + for (auto &checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered()) { - for (auto text : this->_hiddenTexts[checkBox]) { + for (auto &text : this->_hiddenTexts[checkBox]) { text->draw(this->_window); } } @@ -602,7 +614,7 @@ void Menu::_previousSelectedGame() this->_checkBoxType = GAME_CHECKBOX; if (this->_gamesCheckBoxes.empty()) return; - for (auto gameProvider : this->_gameProviders) { + for (const auto& gameProvider : this->_gameProviders) { if (this->_gameProvider == gameProvider.second) { auto index = std::distance(this->_gameProviders.begin(), std::find(this->_gameProviders.begin(), this->_gameProviders.end(), gameProvider)); auto checkBox = this->_gamesCheckBoxes.at(index); @@ -623,7 +635,7 @@ void Menu::_previousSelectedGraphics() { if (this->_graphicsCheckBoxes.empty()) return; - for (auto graphicsProvider : this->_graphicsProviders) { + for (const auto& graphicsProvider : this->_graphicsProviders) { if (this->_graphicsProvider == graphicsProvider.second) { auto index = std::distance(this->_graphicsProviders.begin(), std::find(this->_graphicsProviders.begin(), this->_graphicsProviders.end(), graphicsProvider)); auto checkBox = this->_graphicsCheckBoxes.at(index); @@ -654,12 +666,14 @@ void Menu::run() this->_previousSelectedGraphics(); if (!this->_window) throw ArcadeError("Can't create window"); - while (this->_window->isOpen()) { - this->_handleEvents(); + while (this->_window && this->_window->isOpen()) { this->_render(); + this->_handleEvents(); } if (this->_music) this->_music->setState(ISound::SoundState::STOP); + this->_clearLists(); + this->_window.reset(); } void Menu::_readScores() @@ -700,7 +714,7 @@ void Menu::_writeScore() scoreFile.close(); } -void Menu::updateScore(std::shared_ptr game) +void Menu::updateScore(const std::shared_ptr& game) { if (!game) return; diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index 8b77dbb..cceae02 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -43,7 +43,7 @@ class Menu { * * @param game Game */ - void updateScore(std::shared_ptr game); + void updateScore(const std::shared_ptr& game); private: @@ -68,7 +68,7 @@ class Menu { Score _score; std::vector _scores; SceneStage &_sceneStage; - std::shared_ptr _window; + std::unique_ptr _window; GameProviders &_gameProviders; GraphicsProviders &_graphicsProviders; std::shared_ptr &_gameProvider; @@ -120,25 +120,25 @@ class Menu { void _handleEvents(); /** - * @brief Handle mouse mouve events + * @brief Handle mouse move events * * @param mouse Mouse event */ - void _handleMouseMouveEvents(std::shared_ptr mouse); + void _handleMouseMoveEvents(const std::shared_ptr& mouse); /** * @brief Handle mouse button events * * @param mouse Mouse event */ - void _handleMouseButtonEvents(std::shared_ptr mouse); + void _handleMouseButtonEvents(const std::shared_ptr& mouse); /** * @brief Handle checkbox events * * @param key Key event */ - void _handleKeyboardEvents(std::shared_ptr key); + void _handleKeyboardEvents(const std::shared_ptr& key); /** * @brief Handle select upper checkbox @@ -174,7 +174,7 @@ class Menu { * @brief Change the text type * */ - void _changeGraphics(std::shared_ptr checkBox); + void _changeGraphics(const std::shared_ptr& checkBox); /** * @brief Initialize checkboxes for games @@ -206,7 +206,7 @@ class Menu { * @param gameManifest GameManifest * @param checkBox CheckBox */ - void _initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenAuthors(const GameManifest &gameManifest, const std::shared_ptr& checkBox, std::shared_ptr font); /** * @brief Initialize hidden texts @@ -215,7 +215,7 @@ class Menu { * @param checkBox CheckBox * @param font IFont */ - void _initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenScore(const GameManifest &gameManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font); /** * @brief Initialize hidden score header @@ -224,7 +224,7 @@ class Menu { * @param checkBox CheckBox * @param font IFont */ - void _initHiddenScoreHeader(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenScoreHeader(const GameManifest &gameManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font); /** * @brief Initialize hidden score board @@ -233,7 +233,7 @@ class Menu { * @param checkBox CheckBox * @param font IFont */ - void _initHiddenScoreBoard(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenScoreBoard(const GameManifest &gameManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font); /** * @brief Initialize When No game found @@ -247,7 +247,7 @@ class Menu { * @param graphicsManifest GraphicsManifest * @param checkBox CheckBox */ - void _initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenGraphics(const GraphicsManifest &graphicsManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font); /** * @brief Initialize hidden graphics header @@ -255,7 +255,7 @@ class Menu { * @param graphicsManifest GraphicsManifest * @param checkBox CheckBox */ - void _initHiddenGraphicsHeader(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenGraphicsHeader(const GraphicsManifest &graphicsManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font); /** * @brief Initialize hidden graphics board @@ -263,7 +263,7 @@ class Menu { * @param graphicsManifest GraphicsManifest * @param checkBox CheckBox */ - void _initHiddenGraphicsBoard(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenGraphicsBoard(const GraphicsManifest &graphicsManifest, const std::shared_ptr& checkBox, const std::shared_ptr& font); /** * @brief Initialize texts @@ -290,7 +290,7 @@ class Menu { * @param size * @return std::string */ - std::string _truncString(const std::string &str, int size); + static std::string _truncString(const std::string &str, int size); /** * @brief Sort the scores diff --git a/core/src/menu/entity/text/Text.cpp b/core/src/menu/entity/text/Text.cpp index ded76d3..ff62a44 100644 --- a/core/src/menu/entity/text/Text.cpp +++ b/core/src/menu/entity/text/Text.cpp @@ -7,15 +7,17 @@ #include "Text.hpp" +#include + Text::Text(std::shared_ptr font, unsigned int fontSize, std::string content, TextAlign align, TextVerticalAlign verticalAlign, Color color, Vector2u size, Vector2f position) : - _font(font), _fontSize(fontSize), _content(content), _align(align), _verticalAlign(verticalAlign), + _font(std::move(font)), _fontSize(fontSize), _content(std::move(content)), _align(align), _verticalAlign(verticalAlign), _color(color), _size(size), _position(position) {} -Text::~Text() {} +Text::~Text() = default; -void Text::draw(std::shared_ptr window) +void Text::draw(std::unique_ptr &window) { TextProps textProps = { .font = this->_font, diff --git a/core/src/menu/entity/text/Text.hpp b/core/src/menu/entity/text/Text.hpp index fa59e3a..d3ee9a7 100644 --- a/core/src/menu/entity/text/Text.hpp +++ b/core/src/menu/entity/text/Text.hpp @@ -35,7 +35,7 @@ class Text { * * @param window Window to draw on */ - void draw(std::shared_ptr window); + void draw(std::unique_ptr &window); /** * @brief Set the Color object diff --git a/core/src/menu/entity/texture/Texture.cpp b/core/src/menu/entity/texture/Texture.cpp index 64d088e..b8fd371 100644 --- a/core/src/menu/entity/texture/Texture.cpp +++ b/core/src/menu/entity/texture/Texture.cpp @@ -7,13 +7,15 @@ #include "Texture.hpp" +#include + Texture::Texture(std::shared_ptr texture, Vector2f binTileSize, Vector2u origin, - Vector2u size, Vector2f position) : _texture(texture), _binTileSize(binTileSize), _origin(origin), + Vector2u size, Vector2f position) : _texture(std::move(texture)), _binTileSize(binTileSize), _origin(origin), _size(size), _position(position) {} -Texture::~Texture() {} +Texture::~Texture() = default; -void Texture::draw(std::shared_ptr window) +void Texture::draw(std::unique_ptr &window) { TextureProps textureProps = { .texture = this->_texture, diff --git a/core/src/menu/entity/texture/Texture.hpp b/core/src/menu/entity/texture/Texture.hpp index 41a03ad..e2885d3 100644 --- a/core/src/menu/entity/texture/Texture.hpp +++ b/core/src/menu/entity/texture/Texture.hpp @@ -39,7 +39,7 @@ class Texture { * * @param window Window to draw on */ - void draw(std::shared_ptr window); + void draw(std::unique_ptr &window); /** * @brief Set the Position object diff --git a/graphics/CMakeLists.txt b/graphics/CMakeLists.txt index 1d54559..57b0c3c 100644 --- a/graphics/CMakeLists.txt +++ b/graphics/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(ncurses) add_subdirectory(sfml) +add_subdirectory(sdl2) diff --git a/graphics/ncurses/src/window/Window.cpp b/graphics/ncurses/src/window/Window.cpp index 2126418..4a03260 100644 --- a/graphics/ncurses/src/window/Window.cpp +++ b/graphics/ncurses/src/window/Window.cpp @@ -31,7 +31,7 @@ Window::Window(const IWindow::WindowInitProps &props): noecho(); keypad(stdscr, TRUE); nodelay(stdscr, TRUE); - mousemask(ALL_MOUSE_EVENTS, NULL); + mousemask(ALL_MOUSE_EVENTS, nullptr); curs_set(0); _window = std::unique_ptr(newwin(_size.y, _size.x, 0, 0), &delwin); } @@ -39,7 +39,7 @@ Window::Window(const IWindow::WindowInitProps &props): Window::~Window() { wclear(stdscr); - close(); + Window::close(); endwin(); } @@ -89,7 +89,7 @@ void Window::render(const shared::graphics::TextProps &props) { } void Window::clear() { - wclear(_window.get()); + werase(_window.get()); } void Window::display() { diff --git a/graphics/sdl2/CMakeLists.txt b/graphics/sdl2/CMakeLists.txt new file mode 100644 index 0000000..d4a4d88 --- /dev/null +++ b/graphics/sdl2/CMakeLists.txt @@ -0,0 +1,32 @@ +project(sdl2) +add_library(sdl2 SHARED + export.cpp + src/GraphicsProvider.cpp + src/GraphicsProvider.hpp + src/window/Window.cpp + src/window/Window.hpp + src/window/EventsHandler.cpp + src/window/EventsHandler.hpp + src/sound/Sound.cpp + src/sound/Sound.hpp + src/texture/Texture.cpp + src/texture/Texture.hpp + src/font/Font.cpp + src/font/Font.hpp + src/window/Renderer.cpp + src/window/Renderer.hpp + src/types/window.hpp + src/types/surface.hpp + src/types/renderer.hpp +) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../common PRIVATE) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/sdl) + +target_include_directories(sdl2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src) +target_include_directories(sdl2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../..) +target_include_directories(sdl2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}/..) +target_include_directories(sdl2 PRIVATE ${CMAKE_CURRENT_LIST_DIR}) + +target_link_libraries(sdl2 + SDL2 SDL2_image SDL2_ttf +) diff --git a/graphics/sdl2/export.cpp b/graphics/sdl2/export.cpp new file mode 100644 index 0000000..911cebc --- /dev/null +++ b/graphics/sdl2/export.cpp @@ -0,0 +1,26 @@ +/* +** EPITECH PROJECT, 2024 +** arcade-shared +** File description: +** export +*/ + +#include "shared/games/IGameProvider.hpp" +#include "shared/types/Libraries.hpp" +#include "src/GraphicsProvider.hpp" + +using namespace arcade::graphics; +using namespace shared::graphics; +using namespace shared::types; + +extern "C" { + LibraryType SHARED_LIBRARY_TYPE_GETTER_NAME(void) + { + return LibraryType::GRAPHIC; + } + + IGraphicsProvider *SHARED_GRAPHICS_PROVIDER_GETTER_NAME(void) + { + return new sdl2::GraphicsProvider(); + } +} diff --git a/graphics/sdl2/sdl/CMakeLists.txt b/graphics/sdl2/sdl/CMakeLists.txt new file mode 100644 index 0000000..2e74222 --- /dev/null +++ b/graphics/sdl2/sdl/CMakeLists.txt @@ -0,0 +1,24 @@ +target_sources(${PROJECT_NAME} PUBLIC + window/Window.cpp + window/Window.hpp + exception/Exception.cpp + exception/Exception.hpp + renderer/Renderer.cpp + renderer/Renderer.hpp + surface/Surface.cpp + surface/Surface.hpp + types/Color.hpp + types/Rect.hpp + text/Font.cpp + text/Font.hpp + text/Text.cpp + text/Text.hpp + texture/Texture.cpp + texture/Texture.hpp + sprite/Sprite.cpp + sprite/Sprite.hpp + types/Event.hpp + initializer/Initializer.cpp + initializer/Initializer.hpp +) + diff --git a/graphics/sdl2/sdl/exception/Exception.cpp b/graphics/sdl2/sdl/exception/Exception.cpp new file mode 100644 index 0000000..fd8f967 --- /dev/null +++ b/graphics/sdl2/sdl/exception/Exception.cpp @@ -0,0 +1,20 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Exception.cpp +*/ + +#include "Exception.hpp" + +#include + +using namespace sdl; + +SDLException::SDLException(std::string message) : _message(std::move(message)) { +} + + +const char *SDLException::what() const noexcept { + return _message.c_str(); +} diff --git a/graphics/sdl2/sdl/exception/Exception.hpp b/graphics/sdl2/sdl/exception/Exception.hpp new file mode 100644 index 0000000..e5770de --- /dev/null +++ b/graphics/sdl2/sdl/exception/Exception.hpp @@ -0,0 +1,29 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Exception.hpp +*/ + +#pragma once +#include +#include + +namespace sdl { + class SDLException; +} + +class sdl::SDLException: public std::exception { +public: + explicit SDLException(std::string message); + ~SDLException() override = default; + + /** + * @brief Get the exception message + * @return Message of the exception + */ + const char *what() const noexcept override; + +private: + const std::string _message; +}; diff --git a/graphics/sdl2/sdl/initializer/Initializer.cpp b/graphics/sdl2/sdl/initializer/Initializer.cpp new file mode 100644 index 0000000..92375d4 --- /dev/null +++ b/graphics/sdl2/sdl/initializer/Initializer.cpp @@ -0,0 +1,57 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Initializer.cpp +*/ + +#include "Initializer.hpp" + +#include +#include +#include +#include "sdl/exception/Exception.hpp" + +using namespace sdl; + +void Initializer::init() { + _initSDL(); + _initIMG(); + _initTTF(); +} + +void Initializer::quit() { + _quitTTF(); + _quitIMG(); + _quitSDL(); +} + +void Initializer::_initSDL() { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + throw SDLException("Failed to initialize SDL2"); +} + +void Initializer::_quitSDL() { + if (SDL_WasInit(SDL_INIT_EVERYTHING)) + SDL_Quit(); +} + +void Initializer::_initIMG() { + auto flags = IMG_INIT_PNG | IMG_INIT_JPG | IMG_INIT_TIF | IMG_INIT_WEBP; + if ((IMG_Init(flags) & flags) != flags) + throw SDLException("Failed to initialize SDL2_image"); +} + +void Initializer::_quitIMG() { + IMG_Quit(); +} + +void Initializer::_initTTF() { + if (TTF_Init() != 0) + throw SDLException("Failed to initialize SDL2_ttf"); +} + +void Initializer::_quitTTF() { + if (TTF_WasInit()) + TTF_Quit(); +} diff --git a/graphics/sdl2/sdl/initializer/Initializer.hpp b/graphics/sdl2/sdl/initializer/Initializer.hpp new file mode 100644 index 0000000..fa7521a --- /dev/null +++ b/graphics/sdl2/sdl/initializer/Initializer.hpp @@ -0,0 +1,59 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Initializer.hpp +*/ + +#pragma once + +namespace sdl { + class Initializer; +} + +class sdl::Initializer { +public: + Initializer() = delete; + ~Initializer() = delete; + + /** + * @brief Initialize all SDL2 modules + */ + static void init(); + + /** + * @brief Quit all SDL2 modules + */ + static void quit(); + +private: + /** + * @brief Initialize SDL2 module + */ + static void _initSDL(); + + /** + * @brief Quit SDL2 module + */ + static void _quitSDL(); + + /** + * @brief Initialize SDL2_image module + */ + static void _initIMG(); + + /** + * @brief Quit SDL2_image module + */ + static void _quitIMG(); + + /** + * @brief Initialize SDL2_ttf module + */ + static void _initTTF(); + + /** + * @brief Quit SDL2_ttf module + */ + static void _quitTTF(); +}; diff --git a/graphics/sdl2/sdl/renderer/Renderer.cpp b/graphics/sdl2/sdl/renderer/Renderer.cpp new file mode 100644 index 0000000..f91a110 --- /dev/null +++ b/graphics/sdl2/sdl/renderer/Renderer.cpp @@ -0,0 +1,105 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Renderer.cpp +*/ + +#include +#include "Renderer.hpp" +#include "sdl/text/Text.hpp" +#include "sdl/types/Color.hpp" +#include "sdl/window/Window.hpp" +#include "sdl/texture/Texture.hpp" +#include "sdl/exception/Exception.hpp" +#include "sdl/sprite/Sprite.hpp" + +using namespace sdl; + +Renderer::Renderer(const Window &window, unsigned int fps) : _window(window), _fps(fps) { + _renderer = nullptr; +} + +SDL_Renderer *Renderer::operator()() const { + return _renderer; +} + +Renderer &Renderer::create() { + reset(); + _renderer = SDL_CreateRenderer(_window(), -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED); + if (!_renderer) + throw SDLException("Failed to create renderer"); + return *this; +} + +void Renderer::reset() { + if (_renderer) { + SDL_DestroyRenderer(_renderer); + _renderer = nullptr; + } +} + +void Renderer::drawColor(Color color) { + if (SDL_SetRenderDrawColor(_safeRenderer(), color.r, color.g, color.b, color.a) < 0) + throw SDLException("Failed to set draw color"); +} + +void Renderer::clear() { + if (SDL_RenderClear(_safeRenderer()) < 0) + throw SDLException("Failed to clear renderer"); +} + +void Renderer::present() { + SDL_RenderPresent(_safeRenderer()); + SDL_Delay(1000 / _fps); +} + +Renderer::~Renderer() { + if (_renderer) + SDL_DestroyRenderer(_renderer); +} + +SDL_Renderer *Renderer::_safeRenderer() { + if (!_renderer) + throw SDLException("Renderer is not created"); + return _renderer; +} + +void Renderer::copy(Text &text) { + SDL_FRect dest = FRect::toSDLRect(text.getGlobalBounds()); + + _copy( + text.toTexture(*this), + nullptr, + &dest + ); +} + +void Renderer::copy(const Sprite &sprite, const Texture &texture) { + SDL_Rect src = Rect::toSDLRect(sprite.getTextureRect()); + SDL_FRect dest = FRect::toSDLRect(sprite.getGlobalBounds()); + + _copy(texture, &src, &dest); +} + +void Renderer::_copy(const Texture &texture, SDL_Rect *srcRect, SDL_FRect *destRect) +{ + auto copy = SDL_RenderCopyF( + _safeRenderer(), + texture(), + srcRect, + destRect + ); + + if (copy < 0) { + throw SDLException("Failed to copy texture: " + std::string(SDL_GetError())); + } +} + +void Renderer::setFramerateLimit(unsigned int fps) { + _fps = fps; +} + +unsigned int Renderer::getFramerateLimit() const { + return _fps; +} diff --git a/graphics/sdl2/sdl/renderer/Renderer.hpp b/graphics/sdl2/sdl/renderer/Renderer.hpp new file mode 100644 index 0000000..24e2054 --- /dev/null +++ b/graphics/sdl2/sdl/renderer/Renderer.hpp @@ -0,0 +1,106 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Renderer.hpp +*/ + +#pragma once + +#include +#include +#include "sdl/types/Color.hpp" +#include "sdl/types/Rect.hpp" +#include "sdl/text/Text.hpp" +#include "sdl/sprite/Sprite.hpp" + +namespace sdl { + class Renderer; + class Window; + class Texture; +} + +class sdl::Renderer { +public: + explicit Renderer(const Window &window, unsigned int fps = 60); + ~Renderer(); + + /** + * @brief Create a renderer for current window + * @param window Window + * @return Renderer + */ + Renderer& create(); + + /** + * @brief Reset the internal renderer + * + */ + void reset(); + + /** + * @brief Get the renderer + * @return SDL_Renderer + */ + SDL_Renderer *operator()() const; + + /** + * @brief Draw a color on the screen + * @param color Color to draw + */ + void drawColor(Color color); + + /** + * @brief Copy a text to the screen + * @param text Text to copy + */ + void copy(Text &text); + + /** + * @brief Copy a sprite to the screen + * @param sprite Sprite to copy + * @param texture Texture to use for the sprite + */ + void copy(const Sprite &sprite, const Texture &texture); + + /** + * @brief Clear the screen + */ + void clear(); + + /** + * @brief Present the screen + */ + void present(); + + /** + * @brief Set the framerate Limit of the window + * @param fps Framerate limit + */ + void setFramerateLimit(unsigned int fps); + + /** + * @brief Get the framerate Limit of the window + * @return Framerate limit + */ + unsigned int getFramerateLimit() const; + +private: + /** + * @brief Get the renderer safely or throw an exception if it's null + * @return Get the renderer + */ + SDL_Renderer *_safeRenderer(); + + /** + * @brief Copy a texture to the screen + * @param texture Texture to copy + * @param srcRect Rect to copy from the texture + * @param destRect Rect to copy to the screen + */ + void _copy(const Texture &texture, SDL_Rect *srcRect, SDL_FRect *destRect); + + SDL_Renderer *_renderer; + unsigned int _fps; + const Window &_window; +}; diff --git a/graphics/sdl2/sdl/sprite/Sprite.cpp b/graphics/sdl2/sdl/sprite/Sprite.cpp new file mode 100644 index 0000000..b0b494c --- /dev/null +++ b/graphics/sdl2/sdl/sprite/Sprite.cpp @@ -0,0 +1,55 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Sprite.cpp +*/ + +#include "Sprite.hpp" + +using namespace sdl; + +Sprite::Sprite(): _position(0, 0), _textureRect(0, 0, 0, 0), _scale(1, 1){ +} + +Sprite::~Sprite() = default; + +void Sprite::setPosition(const Vector2f &position) +{ + _position = position; +} + +const Vector2f &Sprite::getPosition() const +{ + return _position; +} + +void Sprite::setTextureRect(const Rect &textureRect) +{ + _textureRect = textureRect; +} + +const Rect &Sprite::getTextureRect() const +{ + return _textureRect; +} + +const Vector2f &Sprite::getScale() const +{ + return _scale; +} + +void Sprite::setScale(const Vector2f &scale) +{ + _scale = scale; +} + +FRect Sprite::getGlobalBounds() const +{ + return { + _position.x, + _position.y, + static_cast(_textureRect.w) * _scale.x, + static_cast(_textureRect.h) * _scale.y + }; +} diff --git a/graphics/sdl2/sdl/sprite/Sprite.hpp b/graphics/sdl2/sdl/sprite/Sprite.hpp new file mode 100644 index 0000000..cfd7656 --- /dev/null +++ b/graphics/sdl2/sdl/sprite/Sprite.hpp @@ -0,0 +1,69 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Sprite.hpp +*/ + +#pragma once + +#include "sdl/texture/Texture.hpp" +#include "sdl/types/Rect.hpp" + +namespace sdl { + class Sprite; + class Texture; +} + +class sdl::Sprite { +public: + Sprite(); + ~Sprite(); + + /** + * @brief Set the position of the sprite + * @param position Position to set + */ + void setPosition(const Vector2f &position); + + /** + * @brief Get the position of the sprite + * @return Position of the sprite + */ + const Vector2f &getPosition() const; + + /** + * @brief Set the texture rect of the sprite + * @param textureRect Texture rect to set + */ + void setTextureRect(const Rect &textureRect); + + /** + * @brief Get the texture rect of the sprite + * @return Texture rect of the sprite + */ + const Rect &getTextureRect() const; + + /** + * @brief Get the scale of the sprite + * @return Scale of the sprite + */ + const Vector2f &getScale() const; + + /** + * @brief Set the scale of the sprite + * @param scale Scale to set + */ + void setScale(const Vector2f &scale); + + /** + * @brief Get the global bounds of the sprite + * @return Sprite global bounds + */ + FRect getGlobalBounds() const; + +private: + Vector2f _position; + Rect _textureRect; + Vector2f _scale; +}; diff --git a/graphics/sdl2/sdl/surface/Surface.cpp b/graphics/sdl2/sdl/surface/Surface.cpp new file mode 100644 index 0000000..d54cc0e --- /dev/null +++ b/graphics/sdl2/sdl/surface/Surface.cpp @@ -0,0 +1,65 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Image.cpp +*/ + +#include "Surface.hpp" +#include "sdl/exception/Exception.hpp" +#include "sdl/texture/Texture.hpp" +#include "sdl/renderer/Renderer.hpp" + +using namespace sdl; + +Surface::Surface() { + _surface = nullptr; +} + +Surface::Surface(SDL_Surface *surface) { + _surface = surface; +} + +Surface::Surface(const std::string &path): _surface(nullptr) { + if (!load(path)) + throw SDLException("Failed to load image at: " + path); +} + +bool Surface::load(const std::string &path) { + if (_surface) + SDL_FreeSurface(_surface); + _surface = IMG_Load(path.c_str()); + return _surface != nullptr; +} + +Surface::Surface(const Surface &other) { + if (!other._surface) { + _surface = nullptr; + return; + } + _surface = SDL_DuplicateSurface(other._surface); + if (!_surface) + throw SDLException("Failed to duplicate SDL surface"); +} + +Surface::~Surface() { + if (_surface) + SDL_FreeSurface(_surface); +} + +Vector2i Surface::getSize() const { + return {_surface->w, _surface->h }; +} + +SDL_Surface *Surface::operator()() const { + return _surface; +} + +Texture Surface::toTexture(Renderer &renderer) const { + auto raw = SDL_CreateTextureFromSurface(renderer(), _surface); + + if (!raw) + throw SDLException("Failed to create texture from surface"); + SDL_SetTextureScaleMode(raw, SDL_ScaleMode::SDL_ScaleModeLinear); + return Texture(raw); +} diff --git a/graphics/sdl2/sdl/surface/Surface.hpp b/graphics/sdl2/sdl/surface/Surface.hpp new file mode 100644 index 0000000..151ceea --- /dev/null +++ b/graphics/sdl2/sdl/surface/Surface.hpp @@ -0,0 +1,56 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Image.hpp +*/ + +#pragma once + +#include +#include +#include "shared/types/Vector.hpp" + +namespace sdl { + using namespace shared::types; + class Surface; + class Renderer; + class Texture; +} + +class sdl::Surface { +public: + Surface(); + Surface(const Surface &other); + explicit Surface(SDL_Surface *surface); + explicit Surface(const std::string &path); + ~Surface(); + + /** + * @brief Load an image from a file + * @param path Path to the image file + * @return Loading success status + */ + bool load(const std::string &path); + /** + * @brief Get the inner SDL surface + * @return SDL surface pointer + */ + SDL_Surface *operator()() const; + + /** + * @brief Get the size of the surface + * @return Size of the surface + */ + Vector2i getSize() const; + + /** + * @brief Convert the surface to a texture + * @param renderer Renderer to create the texture + * @return Created texture + */ + Texture toTexture(Renderer &renderer) const; + +private: + SDL_Surface *_surface; +}; diff --git a/graphics/sdl2/sdl/text/Font.cpp b/graphics/sdl2/sdl/text/Font.cpp new file mode 100644 index 0000000..fd81df7 --- /dev/null +++ b/graphics/sdl2/sdl/text/Font.cpp @@ -0,0 +1,66 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Font.cpp +*/ + +#include +#include "Font.hpp" +#include "sdl/exception/Exception.hpp" + +using namespace sdl; + +Font::Font() { + _font = nullptr; +} + +Font::Font(const std::string &path, int ptSize): Font() { + if (!load(path, ptSize)) + throw SDLException("Failed to load font"); +} + +bool Font::load(const std::string &path, int ptSize) { + static bool init = false; + if (!init) { + if (TTF_Init() == -1) + throw SDLException("Failed to init TTF"); + init = true; + } + if (_font) + TTF_CloseFont(_font); + _font = TTF_OpenFont(path.c_str(), ptSize); + return _font != nullptr; +} + +Font::~Font() { + if (_font) + TTF_CloseFont(_font); + _font = nullptr; +} + +TTF_Font *Font::_safeFont() const { + if (!_font) + throw SDLException("Font is not loaded"); + return _font; +} + +TTF_Font *Font::operator()() const { + return _font; +} + +void Font::setSize(unsigned int ptSize) { + if (TTF_SetFontSize(_safeFont(), static_cast(ptSize)) == -1) + throw SDLException("Failed to set font size"); +} + +Surface Font::renderText(const std::string &text, unsigned int fontSize, Color color) { + SDL_Surface *surface; + + this->setSize(fontSize); + surface = TTF_RenderText_Blended(_safeFont(), text.c_str(), color()); + + if (!surface) + throw SDLException("Failed to render text"); + return Surface(surface); +} diff --git a/graphics/sdl2/sdl/text/Font.hpp b/graphics/sdl2/sdl/text/Font.hpp new file mode 100644 index 0000000..fdf605b --- /dev/null +++ b/graphics/sdl2/sdl/text/Font.hpp @@ -0,0 +1,64 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Font.hpp +*/ + +#pragma once + +#include +#include +#include +#include "sdl/surface/Surface.hpp" +#include "sdl/types/Color.hpp" + +namespace sdl { + class Font; + typedef std::shared_ptr SharedFont; +} + +class sdl::Font { +public: + Font(); + explicit Font(const std::string &path, int ptSize = 12); + ~Font(); + + /** + * @brief Load a font from a file + * @param path Path to the font file + * @param ptSize Font size + * @return True if the font was loaded successfully + * @throw False if the font could not be loaded + */ + bool load(const std::string &path, int ptSize = 12); + + /** + * @brief Get inner SDL font pointer + * @return SDL Font pointer + */ + TTF_Font *operator()() const; + + /** + * @brief Set the size of the font + * @param ptSize Font size + */ + void setSize(unsigned int ptSize); + + /** + * @brief Create a surface from a string + * @param text Text to render + * @param color Color of the text + * @return Created surface + */ + Surface renderText(const std::string &text, unsigned int fontSize, Color color = ColorWhite); + +private: + TTF_Font *_font; + + /** + * @brief Get the font pointer if is not null or throw an exception + * @return SDL font pointer + */ + TTF_Font *_safeFont() const; +}; diff --git a/graphics/sdl2/sdl/text/Text.cpp b/graphics/sdl2/sdl/text/Text.cpp new file mode 100644 index 0000000..981780f --- /dev/null +++ b/graphics/sdl2/sdl/text/Text.cpp @@ -0,0 +1,101 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Text.cpp +*/ + +#include +#include "Text.hpp" +#include "sdl/renderer/Renderer.hpp" +#include "sdl/exception/Exception.hpp" + +using namespace sdl; + +Text::Text(): _font(nullptr), _position({0, 0}), _color(ColorWhite), _fontSize(12), _rendered(false) +{ +} + +Text::Text(const std::string &content): Text() +{ + _content = content; +} + +void Text::setFont(SharedFont font) +{ + _font = std::move(font); + _rendered = false; +} + +SharedFont Text::getFont() const +{ + return _font; +} + +void Text::setFontSize(unsigned int size) +{ + if (_fontSize != size) + _rendered = false; + _fontSize = size; +} + +unsigned int Text::getFontSize() const +{ + return _fontSize; +} + +void Text::setPosition(const shared::types::Vector2f &position) { + _position = position; +} + +const shared::types::Vector2f &Text::getPosition() const { + return _position; +} + +void Text::setContent(const std::string &content) { + if (_content != content) + _rendered = false; + _content = content; +} + +const std::string &Text::getContent() const { + return _content; +} + +const Color &Text::getColor() const { + return _color; +} + +void Text::setColor(const Color &color) { + if (_color != color) + _rendered = false; + _color = color; +} + +void Text::render(Renderer &renderer) { + if (!_font) + throw SDLException("Unable to render text of which font is not set"); + auto surface = _font->renderText( + _content, + _fontSize, + _color + ); + _texture = surface.toTexture(renderer); + _rendered = true; +} + +Texture &Text::toTexture(Renderer &renderer) { + render(renderer); + return _texture; +} + +FRect Text::getGlobalBounds() const { + if (!_rendered) + throw SDLException("Unable to get global bounds of text that is not rendered"); + return { + _position.x, + _position.y, + static_cast(_texture.getSize().x), + static_cast(_texture.getSize().y) + }; +} diff --git a/graphics/sdl2/sdl/text/Text.hpp b/graphics/sdl2/sdl/text/Text.hpp new file mode 100644 index 0000000..8632109 --- /dev/null +++ b/graphics/sdl2/sdl/text/Text.hpp @@ -0,0 +1,117 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Text.hpp +*/ + +#pragma once + +#include "Font.hpp" +#include +#include "sdl/surface/Surface.hpp" +#include "shared/types/Vector.hpp" +#include "sdl/types/Color.hpp" +#include "sdl/texture/Texture.hpp" +#include "sdl/types/Rect.hpp" + +namespace sdl { + class Text; + class Renderer; +} + +class sdl::Text { +public: + Text(); + + explicit Text(const std::string &content); + + ~Text() = default; + + /** + * @brief Get font of the text + * @return Font of the text + */ + SharedFont getFont() const; + + /** + * @brief Set font of the text + * @param font Font to set + */ + void setFont(SharedFont font); + + /** + * @brief Set content of the text + * @param content Content to set + */ + void setContent(const std::string &content); + + /** + * @brief Get content of the text + * @return Current text content + */ + const std::string &getContent() const; + + /** + * @brief Set position of the text + * @param position Position to set + */ + void setPosition(const shared::types::Vector2f &position); + + /** + * @brief Get position of the text + * @return Current text position + */ + const shared::types::Vector2f &getPosition() const; + + /** + * @brief Set the color of the font + * @param color Color + */ + void setColor(const Color &color); + + /** + * @brief Get the color of the font + * @return Color + */ + const Color &getColor() const; + + /** + * @brief Set the size of the font + * @param size Font size + */ + void setFontSize(unsigned int size); + + /** + * @brief Get the size of the font + * @return Font size + */ + unsigned int getFontSize() const; + + /** + * @brief Render the text + * @param renderer Renderer to use + */ + void render(Renderer &renderer); + + /** + * @brief Get the texture of the text + * @return Texture of the text + */ + Texture &toTexture(Renderer &renderer); + + /** + * @brief Get the texture of the text + * @return Texture of the text + */ + FRect getGlobalBounds() const; + +private: + SharedFont _font; + unsigned int _fontSize; + std::string _content; + shared::types::Vector2f _position; + Color _color; + Texture _texture; + bool _rendered; +}; diff --git a/graphics/sdl2/sdl/texture/Texture.cpp b/graphics/sdl2/sdl/texture/Texture.cpp new file mode 100644 index 0000000..972253e --- /dev/null +++ b/graphics/sdl2/sdl/texture/Texture.cpp @@ -0,0 +1,50 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture.cpp +*/ + +#include "Texture.hpp" +#include "sdl/renderer/Renderer.hpp" +#include "sdl/exception/Exception.hpp" + +using namespace sdl; + +Texture::Texture() { + _texture = nullptr; +} + +Texture::Texture(SDL_Texture *texture) { + _texture = texture; +} + +Texture::Texture(Renderer &renderer, Surface &surface) { + _texture = SDL_CreateTextureFromSurface(renderer(), surface()); + if (!_texture) + throw SDLException("Failed to create texture from surface"); +} + +Texture::~Texture() { + if (_texture) + SDL_DestroyTexture(_texture); +} + +SDL_Texture *Texture::operator()() const { + return _texture; +} + +Texture &Texture::operator=(Texture &&texture) noexcept { + if (_texture) + SDL_DestroyTexture(_texture); + _texture = texture._texture; + texture._texture = nullptr; + return *this; +} + +Vector2i Texture::getSize() const { + Vector2i size(0, 0); + + SDL_QueryTexture(_texture, nullptr, nullptr, &size.x, &size.y); + return size; +} diff --git a/graphics/sdl2/sdl/texture/Texture.hpp b/graphics/sdl2/sdl/texture/Texture.hpp new file mode 100644 index 0000000..f2d46ba --- /dev/null +++ b/graphics/sdl2/sdl/texture/Texture.hpp @@ -0,0 +1,56 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture.hpp +*/ + +#pragma once + +#include +#include "sdl/surface/Surface.hpp" + +namespace sdl { + class Texture; + class Renderer; +} + +class sdl::Texture { +public: + Texture(); + ~Texture(); + + /** + * @brief Construct a new Texture object from an existing SDL2 texture + * @param texture SDL2 texture + */ + explicit Texture(SDL_Texture *texture); + + /** + * @brief Construct a new Texture object from another texture + * @param texture Texture to copy + */ + Texture &operator=(Texture &&texture) noexcept; + + /** + * @brief Construct a new Texture object from a surface + * @param renderer Renderer to create the texture + * @param surface Surface to create the texture + */ + explicit Texture(Renderer &renderer, Surface &surface); + + /** + * @brief Get the inner SDL2 texture + * @return Reference to the inner SDL2 texture + */ + SDL_Texture *operator()() const; + + /** + * @brief Get the size of the texture + * @return Texture size + */ + Vector2i getSize() const; + +private: + SDL_Texture *_texture; +}; diff --git a/graphics/sdl2/sdl/types/Color.hpp b/graphics/sdl2/sdl/types/Color.hpp new file mode 100644 index 0000000..b7efd7c --- /dev/null +++ b/graphics/sdl2/sdl/types/Color.hpp @@ -0,0 +1,42 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Color.hpp +*/ + +#pragma once + +namespace sdl { + typedef struct Color { + Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255) + : r(r), g(g), b(b), a(a) {} + + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + + SDL_Color operator()() { + return SDL_Color{r, g, b, a}; + } + + bool operator==(const Color &color) const { + return r == color.r && g == color.g && b == color.b && a == color.a; + } + + bool operator!=(const Color &color) const { + return !(*this == color); + } + } Color; + + const Color ColorBlack = Color(0, 0, 0); + const Color ColorWhite = Color(255, 255, 255); + const Color ColorRed = Color(255, 0, 0); + const Color ColorGreen = Color(0, 255, 0); + const Color ColorBlue = Color(0, 0, 255); + const Color ColorYellow = Color(255, 255, 0); + const Color ColorMagenta = Color(255, 0, 255); + const Color ColorCyan = Color(0, 255, 255); + const Color ColorTransparent = Color(0, 0, 0, 0); +} diff --git a/graphics/sdl2/sdl/types/Event.hpp b/graphics/sdl2/sdl/types/Event.hpp new file mode 100644 index 0000000..05953b2 --- /dev/null +++ b/graphics/sdl2/sdl/types/Event.hpp @@ -0,0 +1,20 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** events.hpp +*/ + +#pragma once + +#include + +namespace sdl { + typedef SDL_Event Event; + typedef SDL_EventType EventType; + typedef SDL_KeyboardEvent KeyboardEvent; + typedef SDL_MouseButtonEvent MouseButtonEvent; + typedef SDL_MouseMotionEvent MouseMotionEvent; + typedef SDL_QuitEvent QuitEvent; + typedef SDL_Keycode Keycode; +} diff --git a/graphics/sdl2/sdl/types/Rect.hpp b/graphics/sdl2/sdl/types/Rect.hpp new file mode 100644 index 0000000..de4c259 --- /dev/null +++ b/graphics/sdl2/sdl/types/Rect.hpp @@ -0,0 +1,77 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Rect.hpp +*/ + +#pragma once + +#include + +namespace sdl { + typedef struct Rect { + Rect(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) {} + + /** + * @brief X position of the rectangle + */ + int x; + + /** + * @brief Y position of the rectangle + */ + int y; + + /** + * @brief Width of the rectangle + */ + int w; + + /** + * @brief Height of the rectangle + */ + int h; + + /** + * @brief Convert a Rect to SDL_Rect + * @param rect The Rect to convert + * @return The converted SDL_Rect + */ + static SDL_Rect toSDLRect(const Rect &rect) { + return { rect.x, rect.y, rect.w, rect.h }; + } + } Rect; + typedef struct FRect { + FRect(float x, float y, float w, float h) : x(x), y(y), w(w), h(h) {} + + /** + * @brief X position of the rectangle + */ + float x; + + /** + * @brief Y position of the rectangle + */ + float y; + + /** + * @brief Width of the rectangle + */ + float w; + + /** + * @brief Height of the rectangle + */ + float h; + + /** + * @brief Convert a Rect to SDL_Rect + * @param rect The Rect to convert + * @return The converted SDL_Rect + */ + static SDL_FRect toSDLRect(const FRect &rect) { + return { rect.x, rect.y, rect.w, rect.h }; + } + } FRect; +} diff --git a/graphics/sdl2/sdl/window/Window.cpp b/graphics/sdl2/sdl/window/Window.cpp new file mode 100644 index 0000000..e2c3509 --- /dev/null +++ b/graphics/sdl2/sdl/window/Window.cpp @@ -0,0 +1,95 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Window.cpp +*/ + +#include "Window.hpp" +#include "sdl/exception/Exception.hpp" +#include "sdl/initializer/Initializer.hpp" + +using namespace sdl; + +Window::Window(): _renderer(*this) { + _window = nullptr; +} + +Window &Window::create( + const std::string &title, + const Vector2i &position, + const Vector2i &size, + Uint32 flags +) { + Initializer::init(); + _window = SDL_CreateWindow( + title.c_str(), + position.x, + position.y, + size.x, + size.y, + flags + ); + if (!_window) + throw SDLException("Failed to create window"); + _renderer.create(); + return *this; +} + +SDL_Window *Window::operator()() const { + return _window; +} + +Window::~Window() { + close(); +} + +SDL_Window *Window::_safeWindow() const { + if (!_window) + throw SDLException("Window is not created"); + return _window; +} + +void Window::setTitle(const std::string &title) { + SDL_SetWindowTitle(_safeWindow(), title.c_str()); +} + +void Window::setSize(Vector2i size) { + SDL_SetWindowSize(_safeWindow(), size.x, size.y); +} + +Vector2i Window::getSize() const { + Vector2i size(0, 0); + + SDL_GetWindowSize(_safeWindow(), &size.x, &size.y); + return size; +} + +void Window::setFullscreen(Uint32 flags) { + SDL_SetWindowFullscreen(_safeWindow(), flags); +} + +Uint32 Window::getFlags() const { + return SDL_GetWindowFlags(_safeWindow()); +} + +void Window::setIcon(const std::string &path) { + _icon.load(path); + SDL_SetWindowIcon(_safeWindow(), _icon()); +} + +Renderer &Window::getRenderer() { + return _renderer; +} + +void Window::close() +{ + if (_window) { + SDL_DestroyWindow(_window); + } + _window = nullptr; +} + +bool Window::pollEvent(Event &event) { + return SDL_PollEvent(&event); +} diff --git a/graphics/sdl2/sdl/window/Window.hpp b/graphics/sdl2/sdl/window/Window.hpp new file mode 100644 index 0000000..e230b31 --- /dev/null +++ b/graphics/sdl2/sdl/window/Window.hpp @@ -0,0 +1,112 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Window.hpp +*/ + +#pragma once + +#include +#include +#include "shared/types/Vector.hpp" +#include "sdl/renderer/Renderer.hpp" +#include "sdl/surface/Surface.hpp" +#include "sdl/types/Event.hpp" + +namespace sdl { + using namespace shared::types; + + class Window; +} + +class sdl::Window { +public: + Window(); + ~Window(); + + /** + * @brief Create a window + * @param title Title of the window + * @param position Position of the window + * @param size Size of the window + */ + Window &create( + const std::string &title, + const Vector2i &position, + const Vector2i &size, + Uint32 flags = SDL_WINDOW_SHOWN + ); + + /** + * @brief Close the window + * + */ + void close(); + + /** + * @brief Get the window + * @return SDL_Window + */ + SDL_Window *operator()() const; + + /** + * @brief Set the title of the window + * @param title Title + */ + void setTitle(const std::string &title); + + /** + * @brief Set the size of the window + * @param size Size + */ + void setSize(Vector2i size); + + /** + * @brief Get the size of the window + * @return Size + */ + Vector2i getSize() const; + + /** + * @brief Set the fullscreen mode + * @param fullscreen Fullscreen + */ + void setFullscreen(Uint32 flags); + + /** + * @brief Get the flags of the window + * @return Flags + */ + Uint32 getFlags() const; + + /** + * @brief Get the renderer + * @return Renderer + */ + Renderer &getRenderer(); + + /** + * @brief Set the icon of the window + * @param path Path of icon to set + */ + void setIcon(const std::string &path); + + /** + * @brief Poll an event + * @param event Event to fill + * @return Event status + */ + static bool pollEvent(Event &event); + +private: + /** + * @brief Get the window safely and throw an exception if it's not created + * @return Window pointer + */ + SDL_Window *_safeWindow() const; + + SDL_Window *_window; + Surface _icon; + Renderer _renderer; +}; diff --git a/graphics/sdl2/src/GraphicsProvider.cpp b/graphics/sdl2/src/GraphicsProvider.cpp new file mode 100644 index 0000000..a53cd41 --- /dev/null +++ b/graphics/sdl2/src/GraphicsProvider.cpp @@ -0,0 +1,54 @@ +/* +** EPITECH PROJECT, 2024 +** GraphicsProvider.cpp +** File description: +** GraphicsProvider class +*/ + +#include +#include "GraphicsProvider.hpp" +#include "window/Window.hpp" +#include "font/Font.hpp" +#include "sound/Sound.hpp" +#include "texture/Texture.hpp" + +using namespace arcade::graphics::sdl2; + +const GraphicsManifest GraphicsProvider::_manifest = { + .name = "sdl2", + .description = "SDL2 Library", + .version = "1.0", + .authors = { + { + .name = "Flavien Chenu", + .email = "flavien.chenu@epitech.eu", + .website = "https://github.com/flavien-chenu" + } + } +}; + +GraphicsProvider::GraphicsProvider() = default; + +GraphicsProvider::~GraphicsProvider() { + sdl::Initializer::quit(); +} + +const shared::graphics::GraphicsManifest &GraphicsProvider::getManifest() const noexcept { + return GraphicsProvider::_manifest; +} + +std::unique_ptr GraphicsProvider::createWindow(const IWindow::WindowInitProps &props) { + return std::make_unique(props); +} + +std::shared_ptr GraphicsProvider::createSound(const std::string &path) { + return std::make_shared(path); +} + +std::shared_ptrGraphicsProvider::createTexture(const std::string &bin, const std::string &ascii) { + return std::make_shared(bin); +} + +std::shared_ptr GraphicsProvider::createFont(const std::string &path) { + return std::make_shared(path); +} diff --git a/graphics/sdl2/src/GraphicsProvider.hpp b/graphics/sdl2/src/GraphicsProvider.hpp new file mode 100644 index 0000000..2bd3eb9 --- /dev/null +++ b/graphics/sdl2/src/GraphicsProvider.hpp @@ -0,0 +1,69 @@ +/* +** EPITECH PROJECT, 2024 +** GraphicsProvider.hpp +** File description: +** GraphicsProvider class +*/ + +#pragma once + +#include "shared/graphics/ITexture.hpp" +#include "shared/graphics/IGraphicsProvider.hpp" +#include "sdl/initializer/Initializer.hpp" + +namespace arcade::graphics::sdl2 +{ + using namespace shared::graphics; + + class GraphicsProvider; +} + +class arcade::graphics::sdl2::GraphicsProvider : public IGraphicsProvider +{ +public: + GraphicsProvider(); + ~GraphicsProvider() override; + + /** + * @brief Get the manifest of the graphics library + * + * @return Manifest of the graphics library + */ + const GraphicsManifest &getManifest() const noexcept override; + + /** + * @brief Create a renderer object + * + * @param windowProps Properties to use to init the window + * @return Created renderer object + */ + std::unique_ptr createWindow(const IWindow::WindowInitProps &windowProps) override; + + /** + * @brief Create a sound object + * + * @param path Path of the sound file + * @return Created sound object + */ + std::shared_ptr createSound(const std::string &path) override; + + /** + * @brief Create a texture object + * + * @param bin Path of the binary texture file + * @param ascii Path of the ascii texture file + * @return Created texture object + */ + std::shared_ptr createTexture(const std::string &bin, const std::string &ascii) override; + + /** + * @brief Create a font object + * + * @param path Path of the font file + * @return Created font object + */ + std::shared_ptr createFont(const std::string &path) override; + +protected: + static const GraphicsManifest _manifest; +}; diff --git a/graphics/sdl2/src/font/Font.cpp b/graphics/sdl2/src/font/Font.cpp new file mode 100644 index 0000000..0e6f485 --- /dev/null +++ b/graphics/sdl2/src/font/Font.cpp @@ -0,0 +1,29 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Font.cpp +*/ + +#include "Font.hpp" +#include "common/exceptions/FontException.hpp" + +using namespace arcade::graphics::sdl2::font; +using namespace arcade::graphics::common::exceptions; + +Font::Font(const std::string &path) +{ + try { + _font = std::make_shared(path); + } catch (const std::exception &e) { + throw FontException( + "Failed to load font at: " + path, + "Font constructor in SDL2 library" + ); + } +} + +sdl::SharedFont Font::getInnerFont() +{ + return _font; +} diff --git a/graphics/sdl2/src/font/Font.hpp b/graphics/sdl2/src/font/Font.hpp new file mode 100644 index 0000000..d367007 --- /dev/null +++ b/graphics/sdl2/src/font/Font.hpp @@ -0,0 +1,32 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Font.hpp +*/ + +#pragma once + +#include +#include "sdl/text/Font.hpp" +#include "shared/graphics/IFont.hpp" +#include "utils/compiler.hpp" + +namespace arcade::graphics::sdl2::font { + class Font; +} + +class arcade::graphics::sdl2::font::Font : public shared::graphics::IFont { +public: + explicit Font(const std::string &path); + ~Font() override = default; + + /** + * @brief Get the inner SDL2 font + * @return Reference to the inner SDL2 font + */ + sdl::SharedFont getInnerFont(); + +private: + sdl::SharedFont _font; +}; diff --git a/graphics/sdl2/src/sound/Sound.cpp b/graphics/sdl2/src/sound/Sound.cpp new file mode 100644 index 0000000..b7f663a --- /dev/null +++ b/graphics/sdl2/src/sound/Sound.cpp @@ -0,0 +1,65 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Sound.cpp +*/ + +#include "Sound.hpp" +#include "common/exceptions/SoundException.hpp" + +using namespace arcade::graphics::sdl2::sound; +using namespace arcade::graphics::common::exceptions; + +Sound::Sound(const std::string &path, SoundState state) { + /*if(!_buffer.loadFromFile(path)) { + throw SoundException( + "Failed to load sound at: " + path, + "Sound constructor in SDL2 library" + ); + } + _sound.setBuffer(_buffer); + _sound.stop();*/ +} + +Sound::SoundVolume Sound::getVolume() const { + return 45; +} + +void Sound::setVolume(SoundVolume volume) { + +} + +void Sound::setState(SoundState state) { +/* switch (state) { + case PLAY: + return _sound.play(); + case PAUSE: + return _sound.pause(); + case STOP: + return _sound.stop(); + }*/ +} + +Sound::SoundState Sound::getState() const { + /*auto state = _sound.getStatus(); + + switch (state) { + case sf::Sound::Playing: + return PLAY; + case sf::Sound::Paused: + return PAUSE; + default: + return STOP; + }*/ + return PLAY; +} + +void Sound::setLoopState(bool loop) { + //_sound.setLoop(loop); +} + +bool Sound::getLoopState() const { + //return _sound.getLoop(); + return true; +} diff --git a/graphics/sdl2/src/sound/Sound.hpp b/graphics/sdl2/src/sound/Sound.hpp new file mode 100644 index 0000000..c2f20b6 --- /dev/null +++ b/graphics/sdl2/src/sound/Sound.hpp @@ -0,0 +1,34 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Sound.hpp +*/ + +#pragma once + +#include +#include + +#include "shared/graphics/ISound.hpp" + +namespace arcade::graphics::sdl2::sound { + class Sound; +} + +class arcade::graphics::sdl2::sound::Sound : public shared::graphics::ISound { +public: + explicit Sound(const std::string &path, SoundState state = STOP); + ~Sound() override = default; + + SoundVolume getVolume() const override; + SoundState getState() const override; + void setVolume(SoundVolume volume) override; + void setState(SoundState state) override; + void setLoopState(bool loop) override; + bool getLoopState() const override; + +private: +/* sf::SoundBuffer _buffer; + sf::Sound _sound;*/ +}; diff --git a/graphics/sdl2/src/texture/Texture.cpp b/graphics/sdl2/src/texture/Texture.cpp new file mode 100644 index 0000000..23f348b --- /dev/null +++ b/graphics/sdl2/src/texture/Texture.cpp @@ -0,0 +1,33 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture.cpp +*/ + +#include "Texture.hpp" +#include "common/exceptions/TextureException.hpp" + +using namespace arcade::graphics::sdl2::texture; +using namespace arcade::graphics::common::exceptions; + +Texture::Texture(const std::string &path): _textured(false) { + if (!_surface.load(path)) { + throw TextureException( + "Failed to load texture from file: " + path, + "Texture constructor in SDL2 library" + ); + } +} + +const sdl::Texture &Texture::getInnerTexture(sdl::Renderer &renderer) { + if (!_textured) { + _texture = _surface.toTexture(renderer); + _textured = true; + } + return _texture; +} + +shared::types::Vector2i Texture::getSize() const { + return _surface.getSize(); +} diff --git a/graphics/sdl2/src/texture/Texture.hpp b/graphics/sdl2/src/texture/Texture.hpp new file mode 100644 index 0000000..612612c --- /dev/null +++ b/graphics/sdl2/src/texture/Texture.hpp @@ -0,0 +1,40 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture.hpp +*/ + +#pragma once + +#include +#include "shared/graphics/ITexture.hpp" +#include "sdl/texture/Texture.hpp" + +namespace arcade::graphics::sdl2::texture { + class Texture; +} + +class arcade::graphics::sdl2::texture::Texture: public shared::graphics::ITexture { +public: + explicit Texture(const std::string &path); + ~Texture() override = default; + + /** + * @brief Get the inner SDL2 texture + * @param renderer Renderer to create the texture + * @return Rendered texture + */ + const sdl::Texture &getInnerTexture(sdl::Renderer &renderer); + + /** + * @brief Get the size of the texture + * @return Texture size + */ + shared::types::Vector2i getSize() const; + +private: + sdl::Surface _surface; + sdl::Texture _texture; + bool _textured; +}; diff --git a/graphics/sdl2/src/types/renderer.hpp b/graphics/sdl2/src/types/renderer.hpp new file mode 100644 index 0000000..868c11b --- /dev/null +++ b/graphics/sdl2/src/types/renderer.hpp @@ -0,0 +1,18 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** renderer.hpp +*/ + +#pragma once + +#include +#include + +#define SDL_DESTROY_RENDERER &SDL_DestroyRenderer + +namespace arcade::graphics::sdl2::types { + typedef decltype(SDL_DESTROY_RENDERER) SDLDestroyRenderer; + typedef std::unique_ptr SDLRenderer; +} \ No newline at end of file diff --git a/graphics/sdl2/src/types/surface.hpp b/graphics/sdl2/src/types/surface.hpp new file mode 100644 index 0000000..3b24459 --- /dev/null +++ b/graphics/sdl2/src/types/surface.hpp @@ -0,0 +1,18 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** surface.hpp +*/ + +#pragma once + +#include +#include + +#define SDL_DESTROY_SURFACE &SDL_FreeSurface + +namespace arcade::graphics::sdl2::types { + typedef decltype(SDL_DESTROY_SURFACE) SDLDestroySurface; + typedef std::unique_ptr SDLSurface; +} diff --git a/graphics/sdl2/src/types/window.hpp b/graphics/sdl2/src/types/window.hpp new file mode 100644 index 0000000..45dc5e6 --- /dev/null +++ b/graphics/sdl2/src/types/window.hpp @@ -0,0 +1,18 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** window.hpp +*/ + +#pragma once + +#include +#include + +#define SDL_DESTROY_WINDOW &SDL_DestroyWindow + +namespace arcade::graphics::sdl2::types { + typedef decltype(SDL_DESTROY_WINDOW) SDLDestroyWindow; + typedef std::unique_ptr SDLWindow; +} diff --git a/graphics/sdl2/src/window/EventsHandler.cpp b/graphics/sdl2/src/window/EventsHandler.cpp new file mode 100644 index 0000000..ae31923 --- /dev/null +++ b/graphics/sdl2/src/window/EventsHandler.cpp @@ -0,0 +1,229 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** EventHandler.cpp +*/ + +#include +#include +#include "Window.hpp" +#include "EventsHandler.hpp" +#include "utils/compiler.hpp" + +using namespace arcade::graphics::sdl2::window; + +EventsHandler::EventHandler EventsHandler::_getHandler(sdl::EventType type) { + static std::map handlers = { + {SDL_KEYDOWN, _handleKeyPressEvent}, + {SDL_KEYUP, _handleKeyReleaseEvent}, + {SDL_MOUSEBUTTONDOWN, _handleMouseButtonPressEvent}, + {SDL_MOUSEBUTTONUP, _handleMouseBtnReleaseEvent}, + {SDL_MOUSEMOTION, _handleMouseMoveEvent}, + {SDL_WINDOWEVENT, _handleWindowEvents} + }; + auto handler = handlers.find(type); + + return handler != handlers.end() ? handler->second : nullptr; +} + +EventsHandler::EventsHandler(Window &window): _window(window) {} + +std::vector EventsHandler::handleEvents() { + std::vector events; + sdl::Event originalEvent{}; + + while (sdl::Window::pollEvent(originalEvent)) { + auto handler = _getHandler(static_cast(originalEvent.type)); + auto event = handler ? handler(originalEvent, _window) : nullptr; + + if (event) + events.push_back(event); + } + return events; +} + +bool EventsHandler::_handleControlKey( + sdl::KeyboardEvent &event, + IKeyEvent::KeyCode &code +) { + switch (event.keysym.sym) { + case SDLK_LCTRL: + case SDLK_RCTRL: + code.control = IKeyEvent::ControlCode::CTRL; + return true; + + case SDLK_LSHIFT: + case SDLK_RSHIFT: + code.control = IKeyEvent::ControlCode::SHIFT; + return true; + + case SDLK_LALT: + case SDLK_RALT: + code.control = IKeyEvent::ControlCode::ALT; + return true; + + default: + return false; + } +} + +bool EventsHandler::_handleArrowKey( + sdl::KeyboardEvent &event, + IKeyEvent::KeyCode &code +) { + switch (event.keysym.sym) { + case SDLK_LEFT: + code.arrow = IKeyEvent::ArrowCode::LEFT; + return true; + case SDLK_RIGHT: + code.arrow = IKeyEvent::ArrowCode::RIGHT; + return true; + case SDLK_UP: + code.arrow = IKeyEvent::ArrowCode::UP; + return true; + case SDLK_DOWN: + code.arrow = IKeyEvent::ArrowCode::DOWN; + return true; + default: + return false; + } +} + +bool EventsHandler::_handleFunctionKey( + sdl::KeyboardEvent &event, + IKeyEvent::KeyCode &code +) +{ + if (event.keysym.sym >= SDLK_F1 && event.keysym.sym <= SDLK_F12) { + code.func = static_cast(event.keysym.sym - SDLK_F1 + 1); + return true; + } else { + return false; + } +} + +bool EventsHandler::_handleCharKey( + sdl::KeyboardEvent &event, + IKeyEvent::KeyCode &code +) { + static const std::map specials = { + {SDLK_SPACE, ' '}, + {SDLK_LEFTBRACKET, '['}, + {SDLK_RIGHTBRACKET, ']'}, + {SDLK_SEMICOLON, ';'}, + {SDLK_COMMA, ','}, + {SDLK_PERIOD, '.'}, + {SDLK_QUOTE, '\''}, + {SDLK_SLASH, '/'}, + {SDLK_BACKSLASH, '\\'}, + {SDLK_EQUALS, '='}, + {SDLK_RETURN, '\n'}, + {SDLK_BACKSPACE, '\b'}, + {SDLK_TAB, '\t'}, + {SDLK_ESCAPE, 0x1B}, + {SDLK_PLUS, '+'}, + {SDLK_MINUS, '-'}, + {SDLK_ASTERISK, '*'}, + {SDLK_SLASH, '/'} + }; + auto sym = event.keysym.sym; + + if (sym >= SDLK_a && sym <= SDLK_z) { + code.character = static_cast(sym - SDLK_a + 'a'); + } else if (sym >= SDLK_0 && sym <= SDLK_9) { + code.character = static_cast(sym - SDLK_0 + '0'); + } else { + auto special = specials.find(sym); + + if (special != specials.end()) { + code.character = special->second; + } else { + return false; + } + } + return true; +} + +EventPtr EventsHandler::_handleKeyPressEvent(sdl::Event &event, unused Window &window) { + IKeyEvent::KeyType type = IKeyEvent::KeyType::UNKNOWN; + IKeyEvent::KeyCode code; + + if (_handleControlKey(event.key, code)) + type = IKeyEvent::KeyType::CONTROL; + else if (_handleArrowKey(event.key, code)) + type = IKeyEvent::KeyType::ARROW; + else if (_handleFunctionKey(event.key, code)) + type = IKeyEvent::KeyType::FUNC; + else if (_handleCharKey(event.key, code)) + type = IKeyEvent::KeyType::CHAR; + return std::make_shared(type, code); +} + +EventPtr EventsHandler::_handleKeyReleaseEvent( + sdl::Event &event, + unused Window &window +) { + IKeyEvent::KeyType type = IKeyEvent::KeyType::UNKNOWN; + IKeyEvent::KeyCode code; + + if (_handleControlKey(event.key, code)) + type = IKeyEvent::KeyType::CONTROL; + else if (_handleArrowKey(event.key, code)) + type = IKeyEvent::KeyType::ARROW; + else if (_handleFunctionKey(event.key, code)) + type = IKeyEvent::KeyType::FUNC; + else if (_handleCharKey(event.key, code)) + type = IKeyEvent::KeyType::CHAR; + return std::make_shared(type, code); +} + +EventPtr EventsHandler::_handleWindowEvents( + sdl::Event &event, + unused Window &window +) { + if (event.window.event == SDL_WINDOWEVENT_CLOSE) + return std::make_shared(); + if (event.window.event == SDL_WINDOWEVENT_RESIZED) + return std::make_shared(); + return nullptr; + +} + +EventPtr EventsHandler::_handleMouseMoveEvent( + sdl::Event &event, + Window &window +) { + return std::make_shared( + window.pixelsToTiles(Vector2i(event.motion.x, event.motion.y)) + ); +} + +EventPtr EventsHandler::_handleMouseButtonPressEvent( + sdl::Event &event, + Window &window +) { + Vector2f pos = window.pixelsToTiles(Vector2i(event.button.x, event.button.y)); + + if (event.button.button == SDL_BUTTON_LEFT) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::LEFT); + else if (event.button.button == SDL_BUTTON_RIGHT) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::RIGHT); + else + return nullptr; +} + + +EventPtr EventsHandler::_handleMouseBtnReleaseEvent( + sdl::Event &event, + unused Window &window +) { + Vector2f pos = window.pixelsToTiles(Vector2i(event.button.x, event.button.y)); + + if (event.button.button == SDL_BUTTON_LEFT) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::LEFT); + else if (event.button.button == SDL_BUTTON_RIGHT) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::RIGHT); + else + return nullptr; +} diff --git a/graphics/sdl2/src/window/EventsHandler.hpp b/graphics/sdl2/src/window/EventsHandler.hpp new file mode 100644 index 0000000..1f5d06c --- /dev/null +++ b/graphics/sdl2/src/window/EventsHandler.hpp @@ -0,0 +1,121 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** EventHandler.hpp +*/ + +#pragma once + +#include + +#include "sdl/window/Window.hpp" +#include "common/events/window/window.hpp" +#include "common/events/mouse/mouse.hpp" +#include "common/events/key/key.hpp" + +namespace arcade::graphics::sdl2::window { + class EventsHandler; + class Window; +} + +class arcade::graphics::sdl2::window::EventsHandler { +public: + explicit EventsHandler(Window &window); + ~EventsHandler() = default; + + typedef EventPtr (*EventHandler)(sdl::Event &event, Window &window); + + /** + * @brief Handle events from SDL2 + * @param window Window object + * @return Vector of events + */ + std::vector handleEvents(); + +private: + + static EventHandler _getHandler(sdl::EventType type); + + /** + * @brief Handle control key event if it's a control key + * @param event Event from SDL2 + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleControlKey(sdl::KeyboardEvent &event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle control key event if it's an arrow key + * @param event Event from SDL2 + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleArrowKey(sdl::KeyboardEvent &event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle control key event if it's a function key + * @param event Event from SDL2 + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleFunctionKey(sdl::KeyboardEvent &event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle control key event if it's a char key + * @param event Event from SDL2 + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleCharKey(sdl::KeyboardEvent &event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle key press event + * @param event Event from SDL2 + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleKeyPressEvent(sdl::Event &event, Window &window); + + /** + * @brief Handle key release event + * @param event Event from SDL2 + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleKeyReleaseEvent(sdl::Event &event, Window &window); + + /** + * @brief Handle mouse button press event + * @param event Event from SDL2 + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleMouseButtonPressEvent(sdl::Event &event, Window &window); + + /** + * @brief Handle mouse button release event + * @param event Event from SDL2 + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleMouseBtnReleaseEvent(sdl::Event &event, Window &window); + + /** + * @brief Handle mouse move event + * @param event Event from SDL2 + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleMouseMoveEvent(sdl::Event &event, Window &window); + + /** + * @brief Handle window close event + * @param event Event from SDL2 + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleWindowEvents(sdl::Event &event, Window &window); + + window::Window &_window; +}; diff --git a/graphics/sdl2/src/window/Renderer.cpp b/graphics/sdl2/src/window/Renderer.cpp new file mode 100644 index 0000000..9e8c238 --- /dev/null +++ b/graphics/sdl2/src/window/Renderer.cpp @@ -0,0 +1,120 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Renderer.cpp +*/ + +#include +#include "Window.hpp" +#include "Renderer.hpp" +#include "font/Font.hpp" +#include "texture/Texture.hpp" + +using namespace arcade::graphics::sdl2::window;; +using namespace arcade::graphics::common::exceptions; + +Renderer::Renderer(Window &window) : _window(window), _renderer(window.getInnerWindow().getRenderer()) {} + +void Renderer::render(const shared::graphics::TextProps &props) { + auto font = _castOrThrow(props.font); + auto entityPosition = _entityPixelsPosition(props.position); + auto entitySize = _window.tilesToPixels(props.size); + sdl::Texture texture; + + _reset(_text); + _text.setFont(font->getInnerFont()); + _text.setContent(props.content); + _text.setFontSize(props.fontSize); + _text.setColor({ + props.color.r, + props.color.g, + props.color.b, + props.color.a + }); + _text.setPosition(entityPosition); + _text.render(_renderer); + _textAlign(props.align, entitySize); + _textVerticalAlign(props.verticalAlign, entitySize); + _renderer.copy(_text); +} + +void Renderer::_textVerticalAlign(const shared::graphics::TextVerticalAlign &align, + const shared::types::Vector2i &entitySize) +{ + auto bounds = _text.getGlobalBounds(); + auto position = _text.getPosition(); + + if (align == shared::graphics::MIDDLE) { + position.y += (static_cast(entitySize.y) - bounds.h) / 2; + } else if (align == shared::graphics::BOTTOM) { + position.y += static_cast(entitySize.y) - bounds.h; + } + _text.setPosition(position); +} + +void Renderer::_textAlign(const shared::graphics::TextAlign &align, const shared::types::Vector2i &entitySize) { + auto bounds = _text.getGlobalBounds(); + auto position = _text.getPosition(); + + if (align == shared::graphics::CENTER) { + position.x += (static_cast(entitySize.x) - bounds.w) / 2; + } else if (align == shared::graphics::RIGHT) { + position.x += static_cast(entitySize.x) - bounds.w; + } + _text.setPosition(position); +} + +void Renderer::render(const shared::graphics::TextureProps &props) { + auto texture = _castOrThrow(props.texture); + auto entityPosition = _entityPixelsPosition(props.position); + + _reset(_sprite); + _setTextureRect(props); + _sprite.setPosition(entityPosition); + _renderer.copy(_sprite, texture->getInnerTexture(_renderer)); +} + +void Renderer::_setTextureRect(const shared::graphics::TextureProps &props) { + auto size = _window.tilesToPixels(props.size); + float width = static_cast(props.size.x) * props.binTileSize.x; + float height = static_cast(props.size.y) * props.binTileSize.y; + float left = static_cast(props.origin.x) * props.binTileSize.x; + float top = static_cast(props.origin.y) * props.binTileSize.y; + sdl::Rect rectangle = { + static_cast(left), + static_cast(top), + static_cast(width), + static_cast(height) + }; + + _sprite.setTextureRect(rectangle); + _sprite.setScale({ + static_cast(size.x) / width, + static_cast(size.y) / height + }); +} + +void Renderer::_reset(sdl::Text &text) { + text.setContent(""); + text.setFont(nullptr); + text.setPosition({0, 0}); + text.setColor(sdl::ColorWhite); + text.setFontSize(12); +} + +void Renderer::_reset(sdl::Sprite &sprite) { + sprite.setTextureRect(sdl::Rect(0, 0, 0, 0)); + sprite.setScale({1, 1}); + sprite.setPosition({0, 0}); +} + +Vector2f Renderer::_entityPixelsPosition(const Vector2f &position) { + auto pixels = _window.tilesToPixels(position); + + return { + static_cast(pixels.x), + static_cast(pixels.y) + }; +} + diff --git a/graphics/sdl2/src/window/Renderer.hpp b/graphics/sdl2/src/window/Renderer.hpp new file mode 100644 index 0000000..97843f1 --- /dev/null +++ b/graphics/sdl2/src/window/Renderer.hpp @@ -0,0 +1,111 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Renderer.hpp +*/ + +#pragma once + +#include "shared/graphics/ITexture.hpp" +#include "shared/graphics/types/TextureProps.hpp" +#include "shared/graphics/types/TextProps.hpp" +#include "common/exceptions/WindowException.hpp" +#include "types/renderer.hpp" +#include "sdl/text/Text.hpp" +#include "sdl/sprite/Sprite.hpp" + +namespace arcade::graphics::sdl2::window { + using namespace arcade::graphics::sdl2::types; + + class Renderer; + class Window; +} + +class arcade::graphics::sdl2::window::Renderer { +public: + explicit Renderer(Window &window); + + ~Renderer() = default; + + /** + * @brief Render a texture on the window + * @param props Texture properties + */ + void render(const shared::graphics::TextureProps &props); + + /** + * @brief Render a text on the window + * @param props Text properties + */ + void render(const shared::graphics::TextProps &props); + +private: + Window &_window; + sdl::Renderer &_renderer; + sdl::Text _text; + sdl::Sprite _sprite; + + + /** + * @brief Reset the text properties + * @param text Text to reset + */ + static void _reset(sdl::Text &text); + + /** + * @brief Reset the sprite properties + * @param sprite Sprite to reset + */ + static void _reset(sdl::Sprite &sprite); + + /** + * @brief Convert a tile position to pixel position + * @param position Tile position + * @return Pixel position + */ + Vector2f _entityPixelsPosition(const Vector2f &position); + + /** + * @brief Align vertically the text + * @param align Text alignment + * @param entityPos Entity position + * @param entitySize Entity size + */ + void _textVerticalAlign( + const shared::graphics::TextVerticalAlign &align, + const shared::types::Vector2i &entitySize + ); + + /** + * @brief Align the text + * @param align Text alignment + * @param entitySize Entity size + */ + void _textAlign(const shared::graphics::TextAlign &align, const shared::types::Vector2i &entitySize); + + /** + * @brief Set texture rect depending on the texture properties + * @param props Texture properties + */ + void _setTextureRect(const shared::graphics::TextureProps &props); + + /** + * @brief Cast a shared pointer from a type to another + * @tparam From Type from which to cast + * @tparam To Type to which cast + * @param from Value to cast + * @return Casted value + */ + template + static std::shared_ptr _castOrThrow(std::shared_ptr from) { + std::shared_ptr to = std::dynamic_pointer_cast(from); + if (!to) { + throw common::exceptions::WindowException( + "Failed to cast shared pointer of:" + std::string(typeid(from).name()) + " to " + typeid(to).name(), + "SDL2 Library Renderer::_castOrThrow" + ); + } + return to; + }; +}; diff --git a/graphics/sdl2/src/window/Window.cpp b/graphics/sdl2/src/window/Window.cpp new file mode 100644 index 0000000..c3089be --- /dev/null +++ b/graphics/sdl2/src/window/Window.cpp @@ -0,0 +1,177 @@ +/* +** EPITECH PROJECT, 2024 +** Window.cpp +** File description: +** Window class +*/ + +#include +#include "Window.hpp" +#include "EventsHandler.hpp" +#include "graphics/sdl2/sdl/exception/Exception.hpp" +#include "common/events/mouse/mouse.hpp" +#include "common/exceptions/WindowException.hpp" + +using namespace arcade::graphics::sdl2::window; +using namespace arcade::graphics::common::exceptions; + +const Vector2u Window::tileSize = { 35, 35 }; + +Window::Window(const IWindow::WindowInitProps &props): + _size(props.size), + _renderer(*this), + _eventsHandler(*this), + _isOpen(true) +{ + _mode = props.mode; + _fps = props.fps; + _initInnerWindow(props); + Window::setIcon(props.icon); +} + +Window::~Window() = default; + +sdl::Window &Window::getInnerWindow() noexcept { + return _window; +} + +void Window::setTitle(const std::string &title) { + _window.setTitle(title); +} + +void Window::setSize(shared::types::Vector2u size) { + auto real = _getPixelSizeFromTiles(size); + + _size = size; + _window.setSize({ + static_cast(real.x), + static_cast(real.y) + }); +} + +shared::types::Vector2u Window::getSize() const { + return _size; +} + +void Window::setFramerateLimit(unsigned int fps) { + _fps = fps; + _window.getRenderer().setFramerateLimit(_fps); +} + +unsigned int Window::getFramerateLimit() const { + return _fps; +} + +void Window::setMode(IWindow::WindowMode mode) { + auto isFullscreen = _window.getFlags() & SDL_WINDOW_FULLSCREEN; + + this->_mode = mode; + if (mode == FULLSCREEN && !isFullscreen) { + _window.setFullscreen(SDL_WINDOW_FULLSCREEN); + } else { + _window.setFullscreen(0); + } +} + +Window::WindowMode Window::getMode() const { + return _mode; +} + +bool Window::isOpen() const { + return _isOpen; +} + +void Window::setIcon(const std::string &path) { + if (path.empty()) + return; + try { + _window.setIcon(path); + } catch (const sdl::SDLException &e) { + throw WindowException( + "Failed to set icon", + "setIcon in SDL2 library" + ); + } +} + +void Window::render(const shared::graphics::TextureProps &props) { + _renderer.render(props); +} + +void Window::render(const shared::graphics::TextProps &props) { + _renderer.render(props); +} + +void Window::clear() { + _window.getRenderer().drawColor(sdl::ColorBlack); + _window.getRenderer().clear(); +} + +void Window::display() { + _window.getRenderer().present(); +} + +void Window::close() { + _isOpen = false; + _window.close(); +} + +std::vector Window::getEvents() { + return _eventsHandler.handleEvents(); +} + +void Window::_initInnerWindow(const shared::graphics::IWindow::WindowInitProps &props) { + auto size = _getPixelSizeFromTiles(props.size); + + try { + _window.create( + props.title, + { SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED }, + { static_cast(size.x), static_cast(size.y) }, + SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE + ); + } catch (const sdl::SDLException &e) { + throw WindowException( + "Failed to create window", + "Window constructor in SDL2 library" + ); + } +} + +Vector2u Window::_getPixelSizeFromTiles(const Vector2u &size) { + //auto mode = sf::VideoMode::getDesktopMode(); + Vector2u real(1920, 1080); + + if (size.x * static_cast(tileSize.x) < 1920) + real.x = size.x * static_cast(tileSize.x); + if (size.y * static_cast(tileSize.y) < 1080) + real.y = size.y * static_cast(tileSize.y); + return real; +} + +Vector2f Window::pixelsToTiles(const shared::types::Vector2i &position) const { + auto realSize = _window.getSize(); + + return { + static_cast(position.x) * static_cast(_size.x) / static_cast(realSize.x), + static_cast(position.y) * static_cast(_size.y) / static_cast(realSize.y) + }; +} + +Vector2i Window::tilesToPixels(const Vector2f &position) const { + auto realSize = _window.getSize(); + + return { + static_cast(position.x) * realSize.x / static_cast(_size.x), + static_cast(position.y) * realSize.y / static_cast(_size.y) + }; +} + +Vector2i Window::tilesToPixels(const Vector2u &position) const { + auto realSize = _window.getSize(); + + return { + static_cast(position.x * realSize.x / _size.x), + static_cast(position.y * realSize.y / _size.y) + }; +} diff --git a/graphics/sdl2/src/window/Window.hpp b/graphics/sdl2/src/window/Window.hpp new file mode 100644 index 0000000..7b73a25 --- /dev/null +++ b/graphics/sdl2/src/window/Window.hpp @@ -0,0 +1,180 @@ +/* +** EPITECH PROJECT, 2024 +** Window.hpp +** File description: +** Window class +*/ + +#pragma once + +#include +#include +#include "Renderer.hpp" +#include "EventsHandler.hpp" +#include "shared/graphics/IWindow.hpp" +#include "graphics/sdl2/sdl/window/Window.hpp" + +namespace arcade::graphics::sdl2::window { + using namespace arcade::graphics::sdl2::types; + + class Window; +} + +class arcade::graphics::sdl2::window::Window: public shared::graphics::IWindow { +public: + explicit Window(const WindowInitProps &props); + ~Window() override; + + /** + * @brief Set the title of current window + * + * @param title Title of the window + */ + void setTitle(const std::string &title) override; + + /** + * @brief Set the size of the window + * + * @param size Size of the window + */ + void setSize(Vector2u size) override; + + /** + * @brief Get the size of the window + * + * @return Size of the window + */ + Vector2u getSize() const override; + + /** + * @brief Set the framerate Limit of the window + * + * @param fps Frame per seconds + */ + void setFramerateLimit(unsigned int fps) override; + + /** + * @brief Get the framerate Limit of the window + * + * @return Frame per seconds + */ + unsigned int getFramerateLimit() const override; + + /** + * @brief Set the mode of the window + * + * @param mode Mode to apply to the window + */ + void setMode(IWindow::WindowMode mode) override; + + /** + * @brief Get the mode of the window + * + * @return Mode of the window + */ + WindowMode getMode() const override; + + /** + * @brief Set the icon of the window + * + * @param icon Icon to use + */ + void setIcon(const std::string &icon) override; + + /** + * @brief Render the text with given properties + * + * @param props Properties of the entity to render + */ + void render(const shared::graphics::TextProps &props) override; + + /** + * @brief Render the entity with given properties + * + * @param props Properties of the entity to render + */ + void render(const shared::graphics::TextureProps &props) override; + + /** + * @brief Clear the content of the window + * + */ + void clear() override; + + /** + * @brief Display the content of the window + * + */ + void display() override; + + /** + * @brief Close the window + * + */ + void close() override; + + /** + * @brief Check if the window is open + * + * @return Open status of the window + */ + bool isOpen() const override; + + /** + * @brief Get the events object + * + * @return Last events occurred + * @warning Call successively this method will result in losing events + * @note Call `A` return `eventsA` containing 2 events, + * but make another call `B` (directly after call `A`) `eventsB` + * will result to an empty vector + */ + std::vector getEvents() override; + + /** + * @brief Get the window object + * @return Window object + */ + sdl::Window &getInnerWindow() noexcept; + + /** + * @brief Convert a position in pixels to a position in tiles + * @return Converted position + */ + Vector2f pixelsToTiles(const Vector2i &position) const; + + /** + * @brief Convert a position in tiles to a position in pixels + * @return Converted position + */ + Vector2i tilesToPixels(const Vector2f &position) const; + + /** + * @brief Convert a position in tiles to a position in pixels + * @return Converted position + */ + Vector2i tilesToPixels(const Vector2u &position) const; + + /** + * @brief Get the size of a tile + * @return Size of a tile + */ + static const Vector2u tileSize; + +private: + static Vector2u _getPixelSizeFromTiles(const Vector2u &size); + + /** + * @brief Initialize the inner window + * @param props Properties of the window + */ + void _initInnerWindow(const WindowInitProps &props); + + EventsHandler _eventsHandler; + Renderer _renderer; + sdl::Window _window; + unsigned int _fps; + WindowMode _mode; + Vector2u _size; + bool _isOpen; +}; diff --git a/graphics/sfml/CMakeLists.txt b/graphics/sfml/CMakeLists.txt index 9a4ffd1..6bc0fcd 100644 --- a/graphics/sfml/CMakeLists.txt +++ b/graphics/sfml/CMakeLists.txt @@ -18,8 +18,8 @@ add_library(sfml SHARED ) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../common PRIVATE) -target_include_directories(sfml PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src) -target_include_directories(sfml PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../..) -target_include_directories(sfml PUBLIC ${CMAKE_CURRENT_LIST_DIR}/..) +target_include_directories(sfml PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src) +target_include_directories(sfml PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../..) +target_include_directories(sfml PRIVATE ${CMAKE_CURRENT_LIST_DIR}/..) target_link_libraries(sfml sfml-graphics sfml-window sfml-system sfml-audio) diff --git a/graphics/sfml/src/window/EventsHandler.cpp b/graphics/sfml/src/window/EventsHandler.cpp index ccef122..952c563 100644 --- a/graphics/sfml/src/window/EventsHandler.cpp +++ b/graphics/sfml/src/window/EventsHandler.cpp @@ -51,10 +51,17 @@ bool EventsHandler::_handleControlKey( switch (event.code) { case sf::Keyboard::LControl: case sf::Keyboard::RControl: + code.control = IKeyEvent::ControlCode::CTRL; + return true; + case sf::Keyboard::LShift: case sf::Keyboard::RShift: + code.control = IKeyEvent::ControlCode::SHIFT; + return true; + case sf::Keyboard::LAlt: case sf::Keyboard::RAlt: + code.control = IKeyEvent::ControlCode::ALT; return true; default: diff --git a/graphics/sfml/src/window/Renderer.cpp b/graphics/sfml/src/window/Renderer.cpp index c2b78d1..91434a8 100644 --- a/graphics/sfml/src/window/Renderer.cpp +++ b/graphics/sfml/src/window/Renderer.cpp @@ -5,6 +5,7 @@ ** Renderer.cpp */ +#include #include "Window.hpp" #include "Renderer.hpp" #include "font/Font.hpp" diff --git a/graphics/sfml/src/window/Window.cpp b/graphics/sfml/src/window/Window.cpp index 3122d32..dbf9424 100644 --- a/graphics/sfml/src/window/Window.cpp +++ b/graphics/sfml/src/window/Window.cpp @@ -5,6 +5,7 @@ ** Window class */ +#include #include "Window.hpp" #include "EventsHandler.hpp" #include "common/events/mouse/mouse.hpp"