diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index d73eb7e..b977ef7 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -45,9 +45,9 @@ jobs: if [ -f "CMakeLists.txt" ]; then mkdir build && cd build cmake .. - make + make -k || true else - make && make clean + make -k || true && make clean fi - name: Check Compilation diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fca7e2..fbef4db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,8 @@ target_link_libraries(arcade_ncurses PRIVATE ncurses) add_arcade_library(arcade_sdl2 "src/graphicals/Sdl2/Sdl2Module.cpp") target_link_libraries(arcade_sdl2 PRIVATE SDL2 SDL2_ttf) -#add_arcade_library(arcade_sfml "src/graphicals/Sfml/SfmlModule.cpp") -#target_link_libraries(arcade_sfml sfml-graphics sfml-window sfml-system) +add_arcade_library(arcade_sfml "src/graphicals/Sfml/SfmlModule.cpp") +target_link_libraries(arcade_sfml sfml-graphics sfml-window sfml-system) add_arcade_library(arcade_snake "src/games/Snake/SnakeModule.cpp") add_arcade_library(arcade_pacman "src/games/Pacman/PacmanModule.cpp") diff --git a/Makefile b/Makefile index dc04f46..2a10212 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,8 @@ GRAPH_DIR = graphicals/ CORE_FILES = main.cpp \ - Core.cpp + Core.cpp \ + MenuSelector.cpp CORE = $(addprefix $(SRC_DIR), $(CORE_FILES)) CORE_OBJ = $(CORE:%.cpp=$(DIR_OBJ)%.o) BINARY = arcade @@ -38,6 +39,11 @@ SDL2_OBJ = $(SDL2:%.cpp=$(DIR_OBJ)%.o) SDL2_LIB = $(LIB_DIR)arcade_sdl2.so SDL2_FLAGS = -lSDL2 -lSDL2_ttf +SFML = $(SRC_DIR)$(GRAPH_DIR)Sfml/SfmlModule.cpp +SFML_OBJ = $(SFML:%.cpp=$(DIR_OBJ)%.o) +SFML_LIB = $(LIB_DIR)arcade_sfml.so +SFML_FLAGS = -lsfml-graphics -lsfml-window -lsfml-system + CPPFLAGS = -std=c++20 -Iinclude -fPIC -g -Wall -Wextra -Werror LDFLAGS_CORE = -ldl -rdynamic LDFLAGS_LIB = -shared @@ -49,7 +55,7 @@ core: $(BINARY) games: $(SNAKE_LIB) $(PACMAN_LIB) -graphicals: $(NCURSES_LIB) $(SDL2_LIB) +graphicals: $(NCURSES_LIB) $(SDL2_LIB) $(SFML_LIB) $(BINARY): $(CORE_OBJ) @$(CC) $^ -o $@ $(LDFLAGS_CORE) @@ -75,6 +81,10 @@ $(SDL2_LIB): $(SDL2_OBJ) @$(CC) $^ -o $@ $(LDFLAGS_LIB) $(SDL2_FLAGS) @echo -e "\x1b[32m[OK] Library $@\x1b[0m" +$(SFML_LIB): $(SFML_OBJ) + @mkdir -p $(dir $(LIB_DIR)) + @$(CC) $^ -o $@ $(LDFLAGS_LIB) $(SFML_FLAGS) + @echo -e "\x1b[32m[OK] Library $@\x1b[0m" $(DIR_OBJ)%.o: %.cpp @mkdir -p $(dir $@) diff --git a/src/graphicals/Sfml/SfmlModule.cpp b/src/graphicals/Sfml/SfmlModule.cpp new file mode 100644 index 0000000..8cb16d6 --- /dev/null +++ b/src/graphicals/Sfml/SfmlModule.cpp @@ -0,0 +1,177 @@ +#include "IGraphic.hpp" +#include +#include +#include +#include +#include +#include +#include +#ifdef __APPLE__ + #define FONT "/System/Library/Fonts/Monaco.ttf" +#else + #define FONT "/usr/share/fonts/TTF/JetBrainsMonoNerdFontMono-Medium.ttf" +#endif + +static sf::Color toSFMLColor(std::uint8_t colorIndex) { + switch (colorIndex) { + case 1: return sf::Color::White; + case 2: return sf::Color::Red; + case 3: return sf::Color::Green; + case 4: return sf::Color::Yellow; + case 5: return sf::Color::Blue; + case 6: return sf::Color::Magenta; + case 7: return sf::Color::Cyan; + default: return sf::Color(20, 20, 20); + } +} + +class SFMLModule : public Arcade::IGraphics { +private: + sf::RenderWindow* _window; + sf::Font _font; + std::map _keyMapping; + bool _initialized; + int _cellSize; + float _windowWidth; + float _windowHeight; + + void initKeyMapping() { + _keyMapping[Arcade::InputAction::Up] = sf::Keyboard::Key::Up; + _keyMapping[Arcade::InputAction::Down] = sf::Keyboard::Key::Down; + _keyMapping[Arcade::InputAction::Left] = sf::Keyboard::Key::Left; + _keyMapping[Arcade::InputAction::Right] = sf::Keyboard::Key::Right; + _keyMapping[Arcade::InputAction::Quit] = sf::Keyboard::Key::Q; + _keyMapping[Arcade::InputAction::Menu] = sf::Keyboard::Key::M; + _keyMapping[Arcade::InputAction::Restart] = sf::Keyboard::Key::R; + _keyMapping[Arcade::InputAction::NextGraphics] = sf::Keyboard::Key::G; + _keyMapping[Arcade::InputAction::PrevGraphics] = sf::Keyboard::Key::H; + _keyMapping[Arcade::InputAction::NextGame] = sf::Keyboard::Key::N; + _keyMapping[Arcade::InputAction::PrevGame] = sf::Keyboard::Key::B; + _keyMapping[Arcade::InputAction::Action] = sf::Keyboard::Key::Enter; + } + + Arcade::InputAction convertKeyToAction(sf::Keyboard::Key key) { + for (const auto& [action, mappedKey] : _keyMapping) { + if (mappedKey == key) return action; + } + return Arcade::InputAction::None; + } + +public: + SFMLModule() : _window(nullptr), _initialized(false), _cellSize(25), _windowWidth(800), _windowHeight(600) { + initKeyMapping(); + } + + ~SFMLModule() { + if (_initialized) shutdown(); + } + + void init() override { + if (_initialized) return; + + _window = new sf::RenderWindow(sf::VideoMode({1280, 720}, 24), "Arcade - SFML", + sf::Style::Titlebar | sf::Style::Close | sf::Style::Resize); + + if (!_window) { + std::cerr << "SFML Window creation failed" << std::endl; + return; + } + + _window->setFramerateLimit(60); + + if (!_font.openFromFile(FONT)) { + std::cerr << "Warning: Could not load font" << std::endl; + } + + _initialized = true; + } + + void shutdown() override { + if (!_initialized) return; + + if (_window) { + _window->close(); + delete _window; + _window = nullptr; + } + _initialized = false; + } + + void clear() override { + if (_window) { + _window->clear(sf::Color::Black); + } + } + + void draw(const std::vector& cells) override { + if (!_window) return; + + sf::Vector2u windowSize = _window->getSize(); + float scaleX = windowSize.x / _windowWidth; + float scaleY = windowSize.y / _windowHeight; + + for (const auto& cell : cells) { + float x = cell.x * _cellSize * scaleX; + float y = cell.y * _cellSize * scaleY; + float width = _cellSize * scaleX; + float height = _cellSize * scaleY; + + sf::RectangleShape rect(sf::Vector2f(width - 1, height - 1)); + rect.setPosition({x, y}); + rect.setFillColor(toSFMLColor(cell.color)); + + if (cell.color == 0) { + rect.setOutlineThickness(1); + rect.setOutlineColor(sf::Color(40, 40, 40)); + } + + _window->draw(rect); + + if (cell.character != ' ') { + sf::Text text(_font, cell.character, 1); + text.setCharacterSize(static_cast(_cellSize * 0.7f * scaleY)); + text.setFillColor(toSFMLColor(cell.textColor)); + + sf::FloatRect textBounds = text.getLocalBounds(); + text.setPosition({ + x + (width - textBounds.size.x) / 2.0f, + y + (height - textBounds.size.y) / 2.0f - textBounds.position.y + }); + + _window->draw(text); + } + } + } + + void display() override { + if (_window) { + _window->display(); + } + } + + Arcade::InputAction pollEvent() override { + if (!_window) return Arcade::InputAction::None; + + while (auto event = _window->pollEvent()) { + if (event->is()) { + return Arcade::InputAction::Quit; + } + if (event->is()) { + return convertKeyToAction(event->getIf()->code); + } + if (event->is()) { + sf::FloatRect visibleArea({0, 0}, {static_cast(event->getIf()->size.x), static_cast(event->getIf()->size.y)}); + _window->setView(sf::View(visibleArea)); + } + } + return Arcade::InputAction::None; + } + + std::string getName() const override { + return "SFML"; + } +}; + +extern "C" Arcade::IGraphics* createGraphics() { + return new SFMLModule(); +}