diff --git a/core/src/loader/Loader.hpp b/core/src/loader/Loader.hpp index 34a4459..8dd8adc 100644 --- a/core/src/loader/Loader.hpp +++ b/core/src/loader/Loader.hpp @@ -13,7 +13,6 @@ class Loader { public: - /** * @brief Construct a new Loader object */ diff --git a/graphics/CMakeLists.txt b/graphics/CMakeLists.txt index c166dc2..2715642 100644 --- a/graphics/CMakeLists.txt +++ b/graphics/CMakeLists.txt @@ -1 +1,2 @@ -add_subdirectory(ncurses) +#add_subdirectory(ncurses) +add_subdirectory(sfml) diff --git a/graphics/common/CMakeLists.txt b/graphics/common/CMakeLists.txt new file mode 100644 index 0000000..a655d16 --- /dev/null +++ b/graphics/common/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(events) +add_subdirectory(exceptions) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../..) diff --git a/graphics/common/events/CMakeLists.txt b/graphics/common/events/CMakeLists.txt new file mode 100644 index 0000000..b6abb48 --- /dev/null +++ b/graphics/common/events/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(mouse) +add_subdirectory(key) +add_subdirectory(window) diff --git a/graphics/common/events/key/AKeyEvent.hpp b/graphics/common/events/key/AKeyEvent.hpp new file mode 100644 index 0000000..b428723 --- /dev/null +++ b/graphics/common/events/key/AKeyEvent.hpp @@ -0,0 +1,46 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** AKeyEvent.hpp +*/ + +#pragma once + +#include "shared/graphics/events/IKeyEvent.hpp" + +using namespace shared::graphics::events; + +namespace arcade::graphics::common::events { + template + concept KeyEventType = T == EventType::KEY_PRESS || T == EventType::KEY_RELEASE; + + template requires KeyEventType + class AKeyEvent; +} + +using namespace arcade::graphics::common::events; + +template requires KeyEventType +class arcade::graphics::common::events::AKeyEvent: public IKeyEvent { +public: + ~AKeyEvent() override = default; + + EventType getType() const noexcept override { + return T; + } + + const KeyCode getKeyCode() const noexcept override { + return _code; + } + + const KeyType getKeyType() const noexcept override { + return _keyType; + } + +protected: + AKeyEvent(const KeyType keyType, const KeyCode code) : _keyType(keyType), _code(code) {}; + + const KeyType _keyType; + const KeyCode _code; +}; diff --git a/graphics/common/events/key/CMakeLists.txt b/graphics/common/events/key/CMakeLists.txt new file mode 100644 index 0000000..ea02f33 --- /dev/null +++ b/graphics/common/events/key/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources(${PROJECT_NAME} PUBLIC + AKeyEvent.hpp + KeyPressEvent.hpp + KeyReleaseEvent.hpp + key.hpp +) diff --git a/graphics/common/events/key/KeyPressEvent.hpp b/graphics/common/events/key/KeyPressEvent.hpp new file mode 100644 index 0000000..f1655a0 --- /dev/null +++ b/graphics/common/events/key/KeyPressEvent.hpp @@ -0,0 +1,21 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** KeyPressEvent.hpp +*/ + +#pragma once + +#include "AKeyEvent.hpp" + +namespace arcade::graphics::common::events { + class KeyPressEvent; +} + +class arcade::graphics::common::events::KeyPressEvent: public AKeyEvent { +public: + explicit KeyPressEvent(const KeyType type, const KeyCode code = { .character = 0 }) + : AKeyEvent(type, code) {}; + ~KeyPressEvent() override = default; +}; diff --git a/graphics/common/events/key/KeyReleaseEvent.hpp b/graphics/common/events/key/KeyReleaseEvent.hpp new file mode 100644 index 0000000..7b868b5 --- /dev/null +++ b/graphics/common/events/key/KeyReleaseEvent.hpp @@ -0,0 +1,20 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** KeyPressEvent.hpp +*/ + +#pragma once + +#include "AKeyEvent.hpp" + +namespace arcade::graphics::common::events { + class KeyReleaseEvent; +} + +class arcade::graphics::common::events::KeyReleaseEvent: public AKeyEvent { +public: + KeyReleaseEvent(const KeyType type, const KeyCode code) : AKeyEvent(type, code) {}; + ~KeyReleaseEvent() override = default; +}; diff --git a/graphics/common/events/key/key.hpp b/graphics/common/events/key/key.hpp new file mode 100644 index 0000000..4702d1c --- /dev/null +++ b/graphics/common/events/key/key.hpp @@ -0,0 +1,11 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** mouse.hpp +*/ + +#pragma once + +#include "KeyPressEvent.hpp" +#include "KeyReleaseEvent.hpp" diff --git a/graphics/common/events/mouse/AMouseButtonEvent.hpp b/graphics/common/events/mouse/AMouseButtonEvent.hpp new file mode 100644 index 0000000..0071cb0 --- /dev/null +++ b/graphics/common/events/mouse/AMouseButtonEvent.hpp @@ -0,0 +1,52 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** AMouseEvent.hpp +*/ + +#pragma once + +#include "AMouseEvent.hpp" +#include "shared/graphics/events/IMouseButtonEvent.hpp" + +using namespace shared::graphics::events; +using namespace shared::types; +using namespace arcade::graphics::common::events; + +namespace arcade::graphics::common::events { + template + concept MouseButtonEventType = T == EventType::MOUSE_BTN_PRESS || T == EventType::MOUSE_BTN_RELEASE; + + template requires MouseButtonEventType + class AMouseButtonEvent; +} + +template requires MouseButtonEventType +class arcade::graphics::common::events::AMouseButtonEvent: public AMouseEvent, public virtual IMouseButtonEvent { +public: + /** + * @brief Construct a new AMouseButtonEvent object + * + * @param pos Position of the mouse + * @param button Targeted button + */ + explicit AMouseButtonEvent( + Vector2i pos, + MouseButton button + ): AMouseEvent(pos), _button(button) {}; + + ~AMouseButtonEvent() override = default; + + /** + * @brief Get the button object + * + * @return Target button type + */ + const MouseButton getButton() const noexcept override { + return _button; + } + +protected: + const MouseButton _button; +}; diff --git a/graphics/common/events/mouse/AMouseEvent.hpp b/graphics/common/events/mouse/AMouseEvent.hpp new file mode 100644 index 0000000..2bf413a --- /dev/null +++ b/graphics/common/events/mouse/AMouseEvent.hpp @@ -0,0 +1,42 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** AMouseEvent.hpp +*/ + +#pragma once + +#include "shared/graphics/events/IMouseEvent.hpp" + +using namespace shared::graphics::events; +using namespace shared::types; + +namespace arcade::graphics::common::events { + template + class AMouseEvent; +} + +template +class arcade::graphics::common::events::AMouseEvent: public virtual IMouseEvent { +public: + ~AMouseEvent() override = default; + + EventType getType() const noexcept override { + return T; + } + + const Vector2i getPosition() const noexcept override { + return _pos; + } + +protected: + /** + * @brief Construct a new AMouseEvent object + * + * @param pos Position of the mouse + */ + explicit AMouseEvent(Vector2i pos): _pos(pos){}; + + Vector2i _pos; +}; diff --git a/graphics/common/events/mouse/CMakeLists.txt b/graphics/common/events/mouse/CMakeLists.txt new file mode 100644 index 0000000..23a780a --- /dev/null +++ b/graphics/common/events/mouse/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${PROJECT_NAME} PUBLIC + AMouseEvent.hpp + MouseButtonPressEvent.hpp + MouseButtonReleaseEvent.hpp + AMouseButtonEvent.hpp + MouseMoveEvent.hpp + mouse.hpp +) diff --git a/graphics/common/events/mouse/MouseButtonPressEvent.hpp b/graphics/common/events/mouse/MouseButtonPressEvent.hpp new file mode 100644 index 0000000..f2865c2 --- /dev/null +++ b/graphics/common/events/mouse/MouseButtonPressEvent.hpp @@ -0,0 +1,24 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** MouseButtonPressEvent.hpp +*/ + +#pragma once + +#include "AMouseButtonEvent.hpp" + +using namespace shared::graphics::events; +using namespace arcade::graphics::common::events; + +namespace arcade::graphics::common::events { + class MouseButtonPressEvent; +}; + +class arcade::graphics::common::events::MouseButtonPressEvent : + public AMouseButtonEvent { +public: + MouseButtonPressEvent(Vector2i pos, MouseButton button) : AMouseButtonEvent(pos, button){}; + ~MouseButtonPressEvent() override = default; +}; diff --git a/graphics/common/events/mouse/MouseButtonReleaseEvent.hpp b/graphics/common/events/mouse/MouseButtonReleaseEvent.hpp new file mode 100644 index 0000000..98638e6 --- /dev/null +++ b/graphics/common/events/mouse/MouseButtonReleaseEvent.hpp @@ -0,0 +1,23 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** MouseButtonPressEvent.hpp +*/ + +#pragma once + +#include "AMouseButtonEvent.hpp" + +using namespace shared::graphics::events; +using namespace arcade::graphics::common::events; + +namespace arcade::graphics::common::events { + class MouseButtonReleaseEvent; +}; + +class arcade::graphics::common::events::MouseButtonReleaseEvent : + public AMouseButtonEvent { +public: + using AMouseButtonEvent::AMouseButtonEvent; +}; diff --git a/graphics/common/events/mouse/MouseMoveEvent.hpp b/graphics/common/events/mouse/MouseMoveEvent.hpp new file mode 100644 index 0000000..76cefef --- /dev/null +++ b/graphics/common/events/mouse/MouseMoveEvent.hpp @@ -0,0 +1,24 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** AMouseEvent.hpp +*/ + +#pragma once + +#include "AMouseEvent.hpp" + +using namespace shared::graphics::events; +using namespace shared::types; + +namespace arcade::graphics::common::events { + class MouseMoveEvent; +} + +class arcade::graphics::common::events::MouseMoveEvent: public AMouseEvent { +public: + explicit MouseMoveEvent(const Vector2i pos): AMouseEvent(pos) {} + + ~MouseMoveEvent() override = default; +}; diff --git a/graphics/common/events/mouse/mouse.hpp b/graphics/common/events/mouse/mouse.hpp new file mode 100644 index 0000000..662df31 --- /dev/null +++ b/graphics/common/events/mouse/mouse.hpp @@ -0,0 +1,12 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** mouse.hpp +*/ + +#pragma once + +#include "MouseButtonPressEvent.hpp" +#include "MouseButtonReleaseEvent.hpp" +#include "MouseMoveEvent.hpp" diff --git a/graphics/common/events/window/CMakeLists.txt b/graphics/common/events/window/CMakeLists.txt new file mode 100644 index 0000000..103c201 --- /dev/null +++ b/graphics/common/events/window/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(${PROJECT_NAME} PUBLIC + WindowCloseEvent.hpp + WindowResizeEvent.hpp + window.hpp +) diff --git a/graphics/common/events/window/WindowCloseEvent.hpp b/graphics/common/events/window/WindowCloseEvent.hpp new file mode 100644 index 0000000..1ad3100 --- /dev/null +++ b/graphics/common/events/window/WindowCloseEvent.hpp @@ -0,0 +1,27 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** WindowCloseEvent.hpp +*/ + +#pragma once + +#include "shared/graphics/events/IEvent.hpp" + +using namespace shared::graphics::events; + +namespace arcade::graphics::common::events { + class WindowCloseEvent; +} + + +class arcade::graphics::common::events::WindowCloseEvent: public IEvent { +public: + WindowCloseEvent() = default; + ~WindowCloseEvent() override = default; + + EventType getType() const noexcept override { + return WINDOW_CLOSE; + } +}; diff --git a/graphics/common/events/window/WindowResizeEvent.hpp b/graphics/common/events/window/WindowResizeEvent.hpp new file mode 100644 index 0000000..da75768 --- /dev/null +++ b/graphics/common/events/window/WindowResizeEvent.hpp @@ -0,0 +1,27 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** WindowCloseEvent.hpp +*/ + +#pragma once + +#include "shared/graphics/events/IEvent.hpp" + +using namespace shared::graphics::events; + +namespace arcade::graphics::common::events { + class WindowResizeEvent; +} + + +class arcade::graphics::common::events::WindowResizeEvent: public IEvent { +public: + WindowResizeEvent() = default; + ~WindowResizeEvent() override = default; + + EventType getType() const noexcept override { + return WINDOW_RESIZE; + } +}; diff --git a/graphics/common/events/window/window.hpp b/graphics/common/events/window/window.hpp new file mode 100644 index 0000000..7edf622 --- /dev/null +++ b/graphics/common/events/window/window.hpp @@ -0,0 +1,11 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** window.hpp +*/ + +#pragma once + +#include "WindowCloseEvent.hpp" +#include "WindowResizeEvent.hpp" diff --git a/graphics/common/exceptions/CMakeLists.txt b/graphics/common/exceptions/CMakeLists.txt new file mode 100644 index 0000000..82dcf6d --- /dev/null +++ b/graphics/common/exceptions/CMakeLists.txt @@ -0,0 +1,8 @@ +target_sources(${PROJECT_NAME} PUBLIC + GraphicsException.cpp + GraphicsException.hpp + SoundException.hpp + TextureException.hpp + WindowException.hpp + FontException.hpp +) diff --git a/graphics/common/exceptions/FontException.hpp b/graphics/common/exceptions/FontException.hpp new file mode 100644 index 0000000..0039eb0 --- /dev/null +++ b/graphics/common/exceptions/FontException.hpp @@ -0,0 +1,22 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** FontException.hpp +*/ + +#pragma once + +#include "GraphicsException.hpp" +#include "shared/graphics/exceptions/IFontException.hpp" + +using namespace shared::graphics::exceptions; + +namespace arcade::graphics::common::exceptions { + class FontException; +} + +class arcade::graphics::common::exceptions::FontException: public GraphicsException, public IFontException { +public: + using GraphicsException::GraphicsException; +}; diff --git a/graphics/common/exceptions/GraphicsException.cpp b/graphics/common/exceptions/GraphicsException.cpp new file mode 100644 index 0000000..5e1da56 --- /dev/null +++ b/graphics/common/exceptions/GraphicsException.cpp @@ -0,0 +1,24 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** GraphicsException.cpp +*/ + +#include "GraphicsException.hpp" + +using namespace arcade::graphics::common::exceptions; + +GraphicsException::GraphicsException(const std::string &message, const std::string &where) +{ + this->_message = message; + this->_where = where; +} + +const char *GraphicsException::what() const noexcept { + return this->_message.c_str(); +} + +const char *GraphicsException::where() const noexcept { + return this->_where.c_str(); +} diff --git a/graphics/common/exceptions/GraphicsException.hpp b/graphics/common/exceptions/GraphicsException.hpp new file mode 100644 index 0000000..5cff65a --- /dev/null +++ b/graphics/common/exceptions/GraphicsException.hpp @@ -0,0 +1,31 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** GraphicsException.hpp +*/ + +#pragma once + +#include +#include "shared/graphics/exceptions/IGraphicsException.hpp" + +using namespace shared::graphics::exceptions; + +namespace arcade::graphics::common::exceptions { + class GraphicsException; +} + +class arcade::graphics::common::exceptions::GraphicsException : public virtual IGraphicsException { +public: + GraphicsException(const std::string &message, const std::string &where); + ~GraphicsException() override = default; + + const char *what() const noexcept override; + + const char *where() const noexcept override; + +protected: + std::string _message; + std::string _where; +}; diff --git a/graphics/common/exceptions/SoundException.hpp b/graphics/common/exceptions/SoundException.hpp new file mode 100644 index 0000000..4518994 --- /dev/null +++ b/graphics/common/exceptions/SoundException.hpp @@ -0,0 +1,22 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** SoundException.hpp +*/ + +#pragma once + +#include "GraphicsException.hpp" +#include "shared/graphics/exceptions/ISoundException.hpp" + +using namespace shared::graphics::exceptions; + +namespace arcade::graphics::common::exceptions { + class SoundException; +} + +class arcade::graphics::common::exceptions::SoundException: public GraphicsException, public ISoundException { +public: + using GraphicsException::GraphicsException; +}; diff --git a/graphics/common/exceptions/TextureException.hpp b/graphics/common/exceptions/TextureException.hpp new file mode 100644 index 0000000..187fe00 --- /dev/null +++ b/graphics/common/exceptions/TextureException.hpp @@ -0,0 +1,22 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** TextureException.hpp +*/ + +#pragma once + +#include "GraphicsException.hpp" +#include "shared/graphics/exceptions/ITextureException.hpp" + +using namespace shared::graphics::exceptions; + +namespace arcade::graphics::common::exceptions { + class TextureException; +} + +class arcade::graphics::common::exceptions::TextureException: public GraphicsException, public ITextureException { +public: + using GraphicsException::GraphicsException; +}; diff --git a/graphics/common/exceptions/WindowException.hpp b/graphics/common/exceptions/WindowException.hpp new file mode 100644 index 0000000..e3ab418 --- /dev/null +++ b/graphics/common/exceptions/WindowException.hpp @@ -0,0 +1,22 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** WindowException.hpp +*/ + +#pragma once + +#include "GraphicsException.hpp" +#include "shared/graphics/exceptions/IWindowException.hpp" + +using namespace shared::graphics::exceptions; + +namespace arcade::graphics::common::exceptions { + class WindowException; +} + +class arcade::graphics::common::exceptions::WindowException: public GraphicsException, public IWindowException { +public: + using GraphicsException::GraphicsException; +}; diff --git a/graphics/sfml/CMakeLists.txt b/graphics/sfml/CMakeLists.txt new file mode 100644 index 0000000..9a4ffd1 --- /dev/null +++ b/graphics/sfml/CMakeLists.txt @@ -0,0 +1,25 @@ +project(sfml) +add_library(sfml 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 +) +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_link_libraries(sfml sfml-graphics sfml-window sfml-system sfml-audio) diff --git a/graphics/sfml/export.cpp b/graphics/sfml/export.cpp new file mode 100644 index 0000000..4373075 --- /dev/null +++ b/graphics/sfml/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 sfml::GraphicsProvider(); + } +} diff --git a/graphics/sfml/src/GraphicsProvider.cpp b/graphics/sfml/src/GraphicsProvider.cpp new file mode 100644 index 0000000..20031d4 --- /dev/null +++ b/graphics/sfml/src/GraphicsProvider.cpp @@ -0,0 +1,57 @@ +/* +** EPITECH PROJECT, 2024 +** GraphicsProvider.cpp +** File description: +** GraphicsProvider class +*/ + +#include +#include "GraphicsProvider.hpp" +#include "utils/compiler.hpp" +#include "window/Window.hpp" +#include "font/Font.hpp" +#include "sound/Sound.hpp" +#include "texture/Texture.hpp" + +using namespace shared::graphics; +using namespace arcade::graphics::sfml; + +const shared::graphics::GraphicsManifest GraphicsProvider::_manifest = { + .name = "sfml", + .description = "SFML Library", + .version = "1.0", + .authors = { + { + .name = "tekmath", + .email = "matheo.coquet@epitech.eu", + .website = "thismath.com" + }, + { + .name = "Flavien Chenu", + .email = "flavien.chenu@epitech.eu", + .website = "https://github.com/flavien-chenu" + } + } +}; + +GraphicsProvider::GraphicsProvider() = default; + +const 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_ptr GraphicsProvider::createTexture(const std::string &bin, unused 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/sfml/src/GraphicsProvider.hpp b/graphics/sfml/src/GraphicsProvider.hpp new file mode 100644 index 0000000..e9ff58d --- /dev/null +++ b/graphics/sfml/src/GraphicsProvider.hpp @@ -0,0 +1,68 @@ +/* +** EPITECH PROJECT, 2024 +** GraphicsProvider.hpp +** File description: +** GraphicsProvider class +*/ + +#pragma once + +#include "shared/graphics/ITexture.hpp" +#include "shared/graphics/IGraphicsProvider.hpp" + +using namespace shared::graphics; + +namespace arcade::graphics::sfml +{ + class GraphicsProvider; +} + +class arcade::graphics::sfml::GraphicsProvider : public shared::graphics::IGraphicsProvider +{ +public: + GraphicsProvider(); + ~GraphicsProvider() override = default; + + /** + * @brief Get the manifest of the graphics library + * + * @return Manifest of the graphics library + */ + const shared::graphics::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 shared::graphics::GraphicsManifest _manifest; +}; diff --git a/graphics/sfml/src/font/Font.cpp b/graphics/sfml/src/font/Font.cpp new file mode 100644 index 0000000..ce8b063 --- /dev/null +++ b/graphics/sfml/src/font/Font.cpp @@ -0,0 +1,26 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Font.cpp +*/ + +#include "Font.hpp" +#include "common/exceptions/FontException.hpp" + +using namespace arcade::graphics::sfml::font; +using namespace arcade::graphics::common::exceptions; + +Font::Font(const std::string &path) +{ + if (!_font.loadFromFile(path)) + throw FontException( + "Failed to load font at: " + path, + "Font constructor in SFML library" + ); +} + +sf::Font &Font::getInnerFont() +{ + return _font; +} diff --git a/graphics/sfml/src/font/Font.hpp b/graphics/sfml/src/font/Font.hpp new file mode 100644 index 0000000..1460376 --- /dev/null +++ b/graphics/sfml/src/font/Font.hpp @@ -0,0 +1,32 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Font.hpp +*/ + +#pragma once + +#include +#include +#include "shared/graphics/IFont.hpp" +#include "utils/compiler.hpp" + +namespace arcade::graphics::sfml::font { + class Font; +} + +class arcade::graphics::sfml::font::Font : public shared::graphics::IFont { +public: + explicit Font(const std::string &path); + ~Font() override = default; + + /** + * @brief Get the inner SFML font + * @return Reference to the inner SFML font + */ + sf::Font &getInnerFont(); + +private: + sf::Font _font; +}; diff --git a/graphics/sfml/src/sound/Sound.cpp b/graphics/sfml/src/sound/Sound.cpp new file mode 100644 index 0000000..c53a4ed --- /dev/null +++ b/graphics/sfml/src/sound/Sound.cpp @@ -0,0 +1,63 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Sound.cpp +*/ + +#include "Sound.hpp" +#include "common/exceptions/SoundException.hpp" + +using namespace arcade::graphics::sfml::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 SFML library" + ); + } + _sound.setBuffer(_buffer); + _sound.stop(); +} + +Sound::SoundVolume Sound::getVolume() const { + return static_cast(_sound.getVolume()); +} + +void Sound::setVolume(SoundVolume volume) { + _sound.setVolume(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; + } +} + +void Sound::setLoopState(bool loop) { + _sound.setLoop(loop); +} + +bool Sound::getLoopState() const { + return _sound.getLoop(); +} diff --git a/graphics/sfml/src/sound/Sound.hpp b/graphics/sfml/src/sound/Sound.hpp new file mode 100644 index 0000000..ed69710 --- /dev/null +++ b/graphics/sfml/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::sfml::sound { + class Sound; +} + +class arcade::graphics::sfml::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/sfml/src/texture/Texture.cpp b/graphics/sfml/src/texture/Texture.cpp new file mode 100644 index 0000000..a1e4c4e --- /dev/null +++ b/graphics/sfml/src/texture/Texture.cpp @@ -0,0 +1,25 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture.cpp +*/ + +#include "Texture.hpp" +#include "common/exceptions/TextureException.hpp" + +using namespace arcade::graphics::sfml::texture; +using namespace arcade::graphics::common::exceptions; + +Texture::Texture(const std::string &path) { + if (!_texture.loadFromFile(path)) + throw TextureException( + "Failed to load texture at: " + path, + "Texture constructor in SFML library" + ); +} + +sf::Texture &Texture::getInnerTexture() +{ + return _texture; +} diff --git a/graphics/sfml/src/texture/Texture.hpp b/graphics/sfml/src/texture/Texture.hpp new file mode 100644 index 0000000..3f51e42 --- /dev/null +++ b/graphics/sfml/src/texture/Texture.hpp @@ -0,0 +1,31 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture.hpp +*/ + +#pragma once + +#include +#include +#include "shared/graphics/ITexture.hpp" + +namespace arcade::graphics::sfml::texture { + class Texture; +} + +class arcade::graphics::sfml::texture::Texture: public shared::graphics::ITexture { +public: + explicit Texture(const std::string &path); + ~Texture() override = default; + + /** + * @brief Get the inner SFML texture + * @return Reference to the inner SFML texture + */ + sf::Texture &getInnerTexture(); + +private: + sf::Texture _texture; +}; diff --git a/graphics/sfml/src/window/EventsHandler.cpp b/graphics/sfml/src/window/EventsHandler.cpp new file mode 100644 index 0000000..877a4d8 --- /dev/null +++ b/graphics/sfml/src/window/EventsHandler.cpp @@ -0,0 +1,227 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** EventHandler.cpp +*/ + +#include + +#include "Window.hpp" +#include "EventsHandler.hpp" +#include "utils/compiler.hpp" + +using namespace arcade::graphics::sfml::window; + +EventsHandler::EventHandler EventsHandler::_getHandler(sf::Event::EventType type) { + static std::map handlers = { + {sf::Event::KeyPressed, _handleKeyPressEvent}, + {sf::Event::KeyReleased, _handleKeyReleaseEvent}, + {sf::Event::MouseButtonPressed, _handleMouseButtonPressEvent}, + {sf::Event::MouseButtonReleased, _handleMouseBtnReleaseEvent}, + {sf::Event::MouseMoved, _handleMouseMoveEvent}, + {sf::Event::Closed, _handleWindowCloseEvent}, + {sf::Event::Resized, _handleWindowResizeEvent} + }; + 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; + sf::Event SFMLEvent{}; + + while (_window.getInnerWindow().pollEvent(SFMLEvent)) { + auto handler = _getHandler(SFMLEvent.type); + auto event = handler ? handler(SFMLEvent, _window) : nullptr; + + if (event) + events.push_back(event); + } + return events; +} + +bool EventsHandler::_handleControlKey( + sf::Event::KeyEvent event, + IKeyEvent::KeyCode &code +) { + switch (event.code) { + case sf::Keyboard::LControl: + case sf::Keyboard::RControl: + case sf::Keyboard::LShift: + case sf::Keyboard::RShift: + case sf::Keyboard::LAlt: + case sf::Keyboard::RAlt: + return true; + + default: + return false; + } +} + +bool EventsHandler::_handleArrowKey( + sf::Event::KeyEvent event, + IKeyEvent::KeyCode &code +) { + switch (event.code) { + case sf::Keyboard::Left: + code.arrow = IKeyEvent::ArrowCode::LEFT; + return true; + case sf::Keyboard::Right: + code.arrow = IKeyEvent::ArrowCode::RIGHT; + return true; + case sf::Keyboard::Up: + code.arrow = IKeyEvent::ArrowCode::UP; + return true; + case sf::Keyboard::Down: + code.arrow = IKeyEvent::ArrowCode::DOWN; + return true; + default: + return false; + } +} + +bool EventsHandler::_handleFunctionKey( + sf::Event::KeyEvent event, + IKeyEvent::KeyCode &code +) +{ + if (event.code >= sf::Keyboard::F1 && event.code <= sf::Keyboard::F12) { + code.func = event.code - sf::Keyboard::F1 + 1; + return true; + } else { + return false; + } +} + +bool EventsHandler::_handleCharKey( + sf::Event::KeyEvent event, + IKeyEvent::KeyCode &code +) { + static const std::map specials = { + {sf::Keyboard::Space, ' '}, + {sf::Keyboard::LBracket, '['}, + {sf::Keyboard::RBracket, ']'}, + {sf::Keyboard::Semicolon, ';'}, + {sf::Keyboard::Comma, ','}, + {sf::Keyboard::Period, '.'}, + {sf::Keyboard::Quote, '\''}, + {sf::Keyboard::Slash, '/'}, + {sf::Keyboard::Backslash, '\\'}, + {sf::Keyboard::Tilde, '~'}, + {sf::Keyboard::Equal, '='}, + {sf::Keyboard::Hyphen, '-'}, + {sf::Keyboard::Enter, '\n'}, + {sf::Keyboard::Backspace, '\b'}, + {sf::Keyboard::Tab, '\t'}, + {sf::Keyboard::Escape, 0x1B}, + {sf::Keyboard::Add, '+'}, + {sf::Keyboard::Subtract, '-'}, + {sf::Keyboard::Multiply, '*'}, + {sf::Keyboard::Divide, '/'} + }; + + if (event.code >= sf::Keyboard::A && event.code <= sf::Keyboard::Z) { + code.character = static_cast(event.code - sf::Keyboard::A + 'a'); + } else if (event.code >= sf::Keyboard::Num0 && event.code <= sf::Keyboard::Num9) { + code.character = static_cast(event.code - sf::Keyboard::Num0 + '0'); + } else if (event.code >= sf::Keyboard::Numpad0 && event.code <= sf::Keyboard::Numpad9) { + code.character = static_cast(event.code - sf::Keyboard::Numpad0 + '0'); + } else { + auto special = specials.find(event.code); + + if (special != specials.end()) { + code.character = special->second; + } else { + return false; + } + } + return true; +} + +EventPtr EventsHandler::_handleKeyPressEvent(sf::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( + sf::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::_handleWindowCloseEvent( + unused sf::Event &event, + unused Window &window +) { + return std::make_shared(); +} + +EventPtr EventsHandler::_handleWindowResizeEvent( + unused sf::Event &event, + Window &window +) { + return std::make_shared(); +} + +EventPtr EventsHandler::_handleMouseMoveEvent( + sf::Event &event, + Window &window +) { + return std::make_shared( + window.pixelsToTiles(Vector2i(event.mouseMove.x, event.mouseMove.y)) + ); +} + +EventPtr EventsHandler::_handleMouseButtonPressEvent( + sf::Event &event, + Window &window +) { + Vector2i pos = window.pixelsToTiles(Vector2i(event.mouseButton.x, event.mouseButton.y)); + + if (event.mouseButton.button == sf::Mouse::Button::Left) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::LEFT); + else if (event.mouseButton.button == sf::Mouse::Button::Right) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::RIGHT); + else + return nullptr; +} + +EventPtr EventsHandler::_handleMouseBtnReleaseEvent( + sf::Event &event, + unused Window &window +) { + Vector2i pos = window.pixelsToTiles(Vector2i(event.mouseButton.x, event.mouseButton.y)); + + if (event.mouseButton.button == sf::Mouse::Button::Left) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::LEFT); + else if (event.mouseButton.button == sf::Mouse::Button::Right) + return std::make_shared(pos, IMouseButtonEvent::MouseButton::RIGHT); + else + return nullptr; +} diff --git a/graphics/sfml/src/window/EventsHandler.hpp b/graphics/sfml/src/window/EventsHandler.hpp new file mode 100644 index 0000000..e78132b --- /dev/null +++ b/graphics/sfml/src/window/EventsHandler.hpp @@ -0,0 +1,137 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** EventHandler.hpp +*/ + +#pragma once + +#include +#include + +#include "common/events/window/window.hpp" +#include "common/events/mouse/mouse.hpp" +#include "common/events/key/key.hpp" + +namespace arcade::graphics::sfml::window { + class EventsHandler; + class Window; +} + +class arcade::graphics::sfml::window::EventsHandler { +public: + explicit EventsHandler(Window &window); + ~EventsHandler() = default; + + typedef EventPtr (*EventHandler)(sf::Event &event, Window &window); + + /** + * @brief Handle events from SFML + * @param window Window object + * @return Vector of events + */ + std::vector handleEvents(); + +private: + + static EventHandler _getHandler(sf::Event::EventType type); + + /** + * @brief Handle control key event if it's a control key + * @param event Event from SFML + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleControlKey(sf::Event::KeyEvent event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle control key event if it's an arrow key + * @param event Event from SFML + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleArrowKey(sf::Event::KeyEvent event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle control key event if it's a function key + * @param event Event from SFML + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleFunctionKey(sf::Event::KeyEvent event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle control key event if it's a char key + * @param event Event from SFML + * @param code Code of the key to set + * @return Status of handling + */ + static bool _handleCharKey(sf::Event::KeyEvent event, IKeyEvent::KeyCode &code); + + /** + * @brief Handle key press event + * @param event Event from SFML + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleKeyPressEvent(sf::Event &event, Window &window); + + /** + * @brief Handle key release event + * @param event Event from SFML + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleKeyReleaseEvent(sf::Event &event, Window &window); + + /** + * @brief Handle mouse button press event + * @param event Event from SFML + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleMouseButtonPressEvent(sf::Event &event, Window &window); + + /** + * @brief Handle mouse button release event + * @param event Event from SFML + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleMouseBtnReleaseEvent(sf::Event &event, Window &window); + + /** + * @brief Handle mouse move event + * @param event Event from SFML + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleMouseMoveEvent(sf::Event &event, Window &window); + + /** + * @brief Handle window close event + * @param event Event from SFML + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleWindowCloseEvent(sf::Event &event, Window &window); + + /** + * @brief Handle window resize event + * @param event Event from SFML + * @param window Window object + * @return Pointer to created event or null if not handled + */ + static EventPtr _handleWindowResizeEvent(sf::Event &event, Window &window); + + /** + * @brief Resolve position of the event to convert it in tiles unit + * @param position Position to resolve + * @param window Window object of which relate the position + * @return Resolved position + */ + static Vector2i _resolvePosition(Vector2i position, Window &window); + + window::Window &_window; +}; diff --git a/graphics/sfml/src/window/Renderer.cpp b/graphics/sfml/src/window/Renderer.cpp new file mode 100644 index 0000000..3ba9489 --- /dev/null +++ b/graphics/sfml/src/window/Renderer.cpp @@ -0,0 +1,135 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Renderer.cpp +*/ + +#include "Window.hpp" +#include "Renderer.hpp" +#include "font/Font.hpp" +#include "texture/Texture.hpp" +#include "common/exceptions/WindowException.hpp" + +using namespace arcade::graphics::sfml::window; +using namespace arcade::graphics::common::exceptions; + +Renderer::Renderer(Window &window) : _window(window), _layer(_window.getInnerWindow()) { + _text.setFont(sf::Font()); + _sprite.setTexture(sf::Texture()); +} + +void Renderer::render(const shared::graphics::TextProps &props) { + auto font = _castOrThrow(props.font); + auto entityPosition = _entityPixelsPosition(props.position); + auto entitySize = _window.tilesToPixels(props.size); + + _reset(_text); + _text.setFont(font->getInnerFont()); + _text.setString(props.content); + _text.setCharacterSize(props.fontSize); + _text.setFillColor(sf::Color( + props.color.r, + props.color.g, + props.color.b, + props.color.a) + ); + _text.setPosition(entityPosition.x, entityPosition.y); + _textAlign(props.align, entitySize); + _textVerticalAlign(props.verticalAlign, entitySize); + _textAdjustPosition(); + _layer.draw(_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.height) / 2; + } else if (align == shared::graphics::BOTTOM) { + position.y += static_cast(entitySize.y) - bounds.height; + } + _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.width) / 2; + } else if (align == shared::graphics::RIGHT) { + position.x += static_cast(entitySize.x) - bounds.width; + } + _text.setPosition(position); +} + +void Renderer::_textAdjustPosition() { + auto actual = _text.getPosition(); + sf::FloatRect bounds; + + _text.setPosition(0, 0); + bounds = _text.getGlobalBounds(); + _text.setPosition(actual.x - bounds.left, actual.y - bounds.top); +} + +void Renderer::render(const shared::graphics::TextureProps &props) { + auto texture = _castOrThrow(props.texture); + auto entityPosition = _entityPixelsPosition(props.position); + + _reset(_sprite); + _sprite.setTexture(texture->getInnerTexture()); + _sprite.setPosition(entityPosition.x, entityPosition.y); + _setTextureRectAndScale(props); + _layer.draw(_sprite); +} + +void Renderer::_setTextureRectAndScale(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; + sf::IntRect 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(sf::Text &text) { + text.setString(""); + text.setCharacterSize(0); + text.setFillColor(sf::Color::White); + text.setStyle(sf::Text::Regular); + text.setPosition(0, 0); + text.setScale(1, 1); + text.setOrigin(0, 0); +} + +void Renderer::_reset(sf::Sprite &sprite) { + sprite.setTextureRect(sf::IntRect(0, 0, 0, 0)); + sprite.setColor(sf::Color::White); + sprite.setScale(1, 1); + sprite.setPosition(0, 0); + sprite.setOrigin(0, 0); +} + +Vector2f Renderer::_entityPixelsPosition(const Vector2i &position) { + auto pixels = _window.tilesToPixels(position); + + return { + static_cast(pixels.x), + static_cast(pixels.y) + }; +} diff --git a/graphics/sfml/src/window/Renderer.hpp b/graphics/sfml/src/window/Renderer.hpp new file mode 100644 index 0000000..21c4998 --- /dev/null +++ b/graphics/sfml/src/window/Renderer.hpp @@ -0,0 +1,112 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Renderer.hpp +*/ + +#pragma once + +#include +#include "shared/graphics/ITexture.hpp" +#include "shared/graphics/types/TextureProps.hpp" +#include "shared/graphics/types/TextProps.hpp" +#include "common/exceptions/WindowException.hpp" + +namespace arcade::graphics::sfml::window { + class Renderer; + + class Window; +} + +class arcade::graphics::sfml::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; + sf::RenderWindow &_layer; + sf::Text _text; + sf::Sprite _sprite; + + /** + * @brief Reset the text properties + * @param text Text to reset + */ + static void _reset(sf::Text &text); + + /** + * @brief Reset the sprite properties + * @param sprite Sprite to reset + */ + static void _reset(sf::Sprite &sprite); + + /** + * @brief Convert a tile position to pixel position + * @param position Tile position + * @return Pixel position + */ + Vector2f _entityPixelsPosition(const Vector2i &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 Adjust the text position + */ + void _textAdjustPosition(); + + /** + * @brief Set texture rect depending on the texture properties + * @param props Texture properties + */ + void _setTextureRectAndScale(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(), + "SFML Library Renderer::_castOrThrow" + ); + } + return to; + }; +}; diff --git a/graphics/sfml/src/window/Window.cpp b/graphics/sfml/src/window/Window.cpp new file mode 100644 index 0000000..c63269e --- /dev/null +++ b/graphics/sfml/src/window/Window.cpp @@ -0,0 +1,171 @@ +/* +** EPITECH PROJECT, 2024 +** Window.cpp +** File description: +** Window class +*/ + +#include "Window.hpp" +#include "EventsHandler.hpp" +#include "common/events/mouse/mouse.hpp" +#include "common/exceptions/WindowException.hpp" + +using namespace arcade::graphics::sfml::window; +using namespace arcade::graphics::common::exceptions; + +const Vector2u Window::tileSize = { 12, 12 }; + +Window::Window(const IWindow::WindowInitProps &props): + _size(props.size), + _renderer(*this), + _eventsHandler(*this) +{ + auto size = _getPixelSizeFromTiles(props.size); + + _mode = props.mode; + _fps = props.fps; + _window.create( + sf::VideoMode(size.x, size.y), + props.title + ); + Window::setIcon(props.icon); +} + +Window::~Window() +{ + _window.close(); +} + +sf::RenderWindow &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(sf::Vector2u(real.x, real.y)); +} + +shared::types::Vector2u Window::getSize() const { + return _size; +} + +void Window::setFramerateLimit(unsigned int fps) { + _window.setFramerateLimit(fps); + _fps = fps; +} + +unsigned int Window::getFramerateLimit() const { + return _fps; +} + +void Window::setMode(IWindow::WindowMode mode) { + auto size = _window.getSize(); + + this->_mode = mode; + if (mode == FULLSCREEN) { + _window.create( + sf::VideoMode(size.x, size.y), + this->_title, + sf::Style::Fullscreen + ); + } else { + _window.create( + sf::VideoMode(size.x, size.y), + this->_title, + sf::Style::Default + ); + } +} + +Window::WindowMode Window::getMode() const { + return _mode; +} + +bool Window::isOpen() const { + return _window.isOpen(); +} + +void Window::setIcon(const std::string &path) { + if (path.empty()) + return; + if (!_icon.loadFromFile(path)) { + throw WindowException( + "Failed to load icon at: " + path, + "Window.setIcon in SFML library" + ); + } + _window.setIcon( + _icon.getSize().x, + _icon.getSize().y, + _icon.getPixelsPtr() + ); +} + +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.clear(); +} + +void Window::display() { + _window.display(); +} + +void Window::close() { + _window.close(); +} + +std::vector Window::getEvents() { + return _eventsHandler.handleEvents(); +} + +Vector2u Window::_getPixelSizeFromTiles(const Vector2u &size) { + auto mode = sf::VideoMode::getDesktopMode(); + Vector2u real(mode.width, mode.height); + + if (size.x * static_cast(tileSize.x) < mode.width) + real.x = size.x * static_cast(tileSize.x); + if (size.y * static_cast(tileSize.y) < mode.height) + real.y = size.y * static_cast(tileSize.y); + return real; +} + +Vector2i Window::pixelsToTiles(const shared::types::Vector2i &position) const { + auto realSize = _window.getSize(); + + return { + static_cast(position.x * _size.x / realSize.x), + static_cast(position.y * _size.y / realSize.y) + }; +} + +Vector2i Window::tilesToPixels(const Vector2i &position) const { + auto realSize = _window.getSize(); + + return { + static_cast(position.x * realSize.x / _size.x), + static_cast(position.y * realSize.y / _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/sfml/src/window/Window.hpp b/graphics/sfml/src/window/Window.hpp new file mode 100644 index 0000000..5ff6fdd --- /dev/null +++ b/graphics/sfml/src/window/Window.hpp @@ -0,0 +1,171 @@ +/* +** EPITECH PROJECT, 2024 +** Window.hpp +** File description: +** Window class +*/ + +#pragma once + +#include +#include "Renderer.hpp" +#include "shared/graphics/IWindow.hpp" +#include "EventsHandler.hpp" + +namespace arcade::graphics::sfml::window { + class Window; +} + +class arcade::graphics::sfml::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 + */ + sf::RenderWindow &getInnerWindow() noexcept; + + /** + * @brief Convert a position in pixels to a position in tiles + * @return Converted position + */ + Vector2i pixelsToTiles(const Vector2i &position) const; + + /** + * @brief Convert a position in tiles to a position in pixels + * @return Converted position + */ + Vector2i tilesToPixels(const Vector2i &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); + + EventsHandler _eventsHandler; + Renderer _renderer; + sf::RenderWindow _window; + std::string _title; + unsigned int _fps; + WindowMode _mode; + sf::Image _icon; + Vector2u _size; +}; diff --git a/shared/games/IGame.hpp b/shared/games/IGame.hpp index bc8353d..bd684c8 100644 --- a/shared/games/IGame.hpp +++ b/shared/games/IGame.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include #include "IEntity.hpp" #include "../types/Vector.hpp" #include "types/GameManifest.hpp" @@ -18,7 +19,7 @@ namespace shared::games { class IGame; - typedef unsigned long DeltaTime; + typedef std::chrono::duration DeltaTime; } class shared::games::IGame diff --git a/shared/games/components/ICollidableComponent.hpp b/shared/games/components/ICollidableComponent.hpp index f6ce1c3..ba65ba0 100644 --- a/shared/games/components/ICollidableComponent.hpp +++ b/shared/games/components/ICollidableComponent.hpp @@ -8,14 +8,14 @@ #pragma once #include "../IGame.hpp" -#include "IPositionComponent.hpp" +#include "IPositionableComponent.hpp" #include "../../types/Vector.hpp" namespace shared::games::components { class ICollidableComponent; } -class shared::games::components::ICollidableComponent: public virtual IPositionComponent +class shared::games::components::ICollidableComponent: public virtual IPositionableComponent { public: virtual ~ICollidableComponent() = default; diff --git a/shared/games/components/IComponent.hpp b/shared/games/components/IComponent.hpp index e03cc51..db6c260 100644 --- a/shared/games/components/IComponent.hpp +++ b/shared/games/components/IComponent.hpp @@ -13,9 +13,10 @@ namespace shared::games::components { typedef enum { TEXTURE, TEXT, + DISPLAYABLE, SOUND, COLLIDABLE, - POSITION, + POSITIONABLE, KEYBOARD } ComponentType; diff --git a/shared/games/components/IDisplayableComponent.hpp b/shared/games/components/IDisplayableComponent.hpp index 0a60cec..8732895 100644 --- a/shared/games/components/IDisplayableComponent.hpp +++ b/shared/games/components/IDisplayableComponent.hpp @@ -7,7 +7,7 @@ #pragma once -#include "IPositionComponent.hpp" +#include "IPositionableComponent.hpp" #include "../IGame.hpp" #include "../../types/Vector.hpp" @@ -15,16 +15,10 @@ namespace shared::games::components { class IDisplayableComponent; } -class shared::games::components::IDisplayableComponent : public virtual IPositionComponent { +class shared::games::components::IDisplayableComponent : public virtual IPositionableComponent { public: virtual ~IDisplayableComponent() = default; - /** - * @brief Get size of the entity (tiles) - * - */ - virtual Vector2u &getSize() noexcept = 0; - /** * @brief Get Z index that is usefull for display prioroty * diff --git a/shared/games/components/IKeyboardComponent.hpp b/shared/games/components/IKeyboardComponent.hpp index 097b293..f2f474a 100644 --- a/shared/games/components/IKeyboardComponent.hpp +++ b/shared/games/components/IKeyboardComponent.hpp @@ -12,7 +12,11 @@ namespace shared::games::components { class IKeyboardComponent; +} +class shared::games::components::IKeyboardComponent: public virtual IComponent +{ +public: typedef enum { CONTROL, // Control key (`Ctrl`, `Shift`, `Alt`) @@ -50,11 +54,7 @@ namespace shared::games::components { KeyCode code; // Key code. Interpretation depends on the type KeyType type; // Type of the key } KeyData; -} -class shared::games::components::IKeyboardComponent: public virtual IComponent -{ -public: virtual ~IKeyboardComponent() = default; /** diff --git a/shared/games/components/IPositionComponent.hpp b/shared/games/components/IPositionableComponent.hpp similarity index 51% rename from shared/games/components/IPositionComponent.hpp rename to shared/games/components/IPositionableComponent.hpp index 4e508df..bc51501 100644 --- a/shared/games/components/IPositionComponent.hpp +++ b/shared/games/components/IPositionableComponent.hpp @@ -2,7 +2,7 @@ ** EPITECH PROJECT, 2024 ** arcade-shared ** File description: -** IPositionComponent +** IPositionableComponent */ #pragma once @@ -11,17 +11,23 @@ #include "../../types/Vector.hpp" namespace shared::games::components { - class IPositionComponent; + class IPositionableComponent; } -class shared::games::components::IPositionComponent: public virtual IComponent +class shared::games::components::IPositionableComponent: public virtual IComponent { public: - virtual ~IPositionComponent() = default; + virtual ~IPositionableComponent() = default; /** * @brief Get position of the entity (tiles) * */ virtual types::Vector2i &getPosition(void) noexcept = 0; + + /** + * @brief Get size of the entity (tiles) + * + */ + virtual types::Vector2u &getSize(void) noexcept = 0; }; diff --git a/shared/games/components/ITextComponent.hpp b/shared/games/components/ITextComponent.hpp index 655d45e..64dd5cf 100644 --- a/shared/games/components/ITextComponent.hpp +++ b/shared/games/components/ITextComponent.hpp @@ -13,7 +13,10 @@ namespace shared::games::components { class ITextComponent; +} +class shared::games::components::ITextComponent : public virtual IDisplayableComponent { +public: typedef enum { LEFT, CENTER, @@ -38,10 +41,7 @@ namespace shared::games::components { TextFontProps font; // Font of the text types::Color color; // Color of the text } TextProps; -} -class shared::games::components::ITextComponent : public virtual IDisplayableComponent { -public: virtual ~ITextComponent() = default; /** diff --git a/shared/graphics/events/IKeyEvent.hpp b/shared/graphics/events/IKeyEvent.hpp index db6cab4..81fe453 100644 --- a/shared/graphics/events/IKeyEvent.hpp +++ b/shared/graphics/events/IKeyEvent.hpp @@ -13,7 +13,7 @@ namespace shared::graphics::events { class IKeyEvent; } -class shared::graphics::events::IKeyEvent : public IEvent { +class shared::graphics::events::IKeyEvent : public virtual IEvent { public: virtual ~IKeyEvent() = default; diff --git a/shared/graphics/events/IMouseButtonEvent.hpp b/shared/graphics/events/IMouseButtonEvent.hpp index b70ab17..bac5eba 100644 --- a/shared/graphics/events/IMouseButtonEvent.hpp +++ b/shared/graphics/events/IMouseButtonEvent.hpp @@ -13,7 +13,7 @@ namespace shared::graphics::events{ class IMouseButtonEvent; } -class shared::graphics::events::IMouseButtonEvent : public IMouseEvent { +class shared::graphics::events::IMouseButtonEvent : public virtual IMouseEvent { public: virtual ~IMouseButtonEvent() = default; diff --git a/shared/graphics/events/IMouseEvent.hpp b/shared/graphics/events/IMouseEvent.hpp index a85ae4b..618e5fe 100644 --- a/shared/graphics/events/IMouseEvent.hpp +++ b/shared/graphics/events/IMouseEvent.hpp @@ -14,7 +14,7 @@ namespace shared::graphics::events { class IMouseEvent; } -class shared::graphics::events::IMouseEvent : public IEvent { +class shared::graphics::events::IMouseEvent : public virtual IEvent { public: virtual ~IMouseEvent() = default; diff --git a/shared/graphics/exceptions/IFontException.hpp b/shared/graphics/exceptions/IFontException.hpp new file mode 100644 index 0000000..7b875e6 --- /dev/null +++ b/shared/graphics/exceptions/IFontException.hpp @@ -0,0 +1,19 @@ +/* +** EPITECH PROJECT, 2024 +** arcade-shared +** File description: +** IFontException.hpp +*/ + +#pragma once + +#include "IGraphicsException.hpp" + +namespace shared::graphics::exceptions { + class IFontException; +} + +class shared::graphics::exceptions::IFontException : public virtual IGraphicsException { +public: + virtual ~IFontException() = default; +}; diff --git a/shared/graphics/exceptions/IGraphicsException.hpp b/shared/graphics/exceptions/IGraphicsException.hpp new file mode 100644 index 0000000..a899775 --- /dev/null +++ b/shared/graphics/exceptions/IGraphicsException.hpp @@ -0,0 +1,23 @@ +/* +** EPITECH PROJECT, 2024 +** arcade-shared +** File description: +** IGraphicsException.hpp +*/ + +#pragma once + +#include + +namespace shared::graphics::exceptions { + class IGraphicsException; +} + +class shared::graphics::exceptions::IGraphicsException: public std::exception { +public: + /** + * @brief Get error location + * @return String containing error location + */ + virtual const char *where() const noexcept = 0; +}; diff --git a/shared/graphics/exceptions/ISoundException.hpp b/shared/graphics/exceptions/ISoundException.hpp new file mode 100644 index 0000000..2a2e534 --- /dev/null +++ b/shared/graphics/exceptions/ISoundException.hpp @@ -0,0 +1,19 @@ +/* +** EPITECH PROJECT, 2024 +** arcade-shared +** File description: +** ISoundException.hpp +*/ + +#pragma once + +#include "IGraphicsException.hpp" + +namespace shared::graphics::exceptions { + class ISoundException; +} + +class shared::graphics::exceptions::ISoundException : public virtual IGraphicsException { +public: + virtual ~ISoundException() = default; +}; diff --git a/shared/graphics/exceptions/ITextureException.hpp b/shared/graphics/exceptions/ITextureException.hpp new file mode 100644 index 0000000..e894b71 --- /dev/null +++ b/shared/graphics/exceptions/ITextureException.hpp @@ -0,0 +1,19 @@ +/* +** EPITECH PROJECT, 2024 +** arcade-shared +** File description: +** ITextureException.hpp +*/ + +#pragma once + +#include "IGraphicsException.hpp" + +namespace shared::graphics::exceptions { + class ITextureException; +} + +class shared::graphics::exceptions::ITextureException : public virtual IGraphicsException { +public: + virtual ~ITextureException() = default; +}; diff --git a/shared/graphics/exceptions/IWindowException.hpp b/shared/graphics/exceptions/IWindowException.hpp new file mode 100644 index 0000000..ae030f3 --- /dev/null +++ b/shared/graphics/exceptions/IWindowException.hpp @@ -0,0 +1,19 @@ +/* +** EPITECH PROJECT, 2024 +** arcade-shared +** File description: +** IWindowException.hpp +*/ + +#pragma once + +#include "IGraphicsException.hpp" + +namespace shared::graphics::exceptions { + class IWindowException; +} + +class shared::graphics::exceptions::IWindowException : public virtual IGraphicsException { +public: + virtual ~IWindowException() = default; +}; diff --git a/utils/compiler.hpp b/utils/compiler.hpp new file mode 100644 index 0000000..5a59f81 --- /dev/null +++ b/utils/compiler.hpp @@ -0,0 +1,10 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** compiler.hpp +*/ + +#pragma once + +#define unused __attribute__((unused))