aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--readme.md1
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/crepe/api/Button.cpp3
-rw-r--r--src/crepe/api/Button.h12
-rw-r--r--src/crepe/api/CMakeLists.txt2
-rw-r--r--src/crepe/api/Config.h16
-rw-r--r--src/crepe/api/Event.h98
-rw-r--r--src/crepe/api/KeyCodes.h6
-rw-r--r--src/crepe/api/LoopManager.h4
-rw-r--r--src/crepe/api/Script.cpp15
-rw-r--r--src/crepe/api/Script.h18
-rw-r--r--src/crepe/api/Text.cpp12
-rw-r--r--src/crepe/api/Text.h66
-rw-r--r--src/crepe/facade/CMakeLists.txt4
-rw-r--r--src/crepe/facade/EventData.h54
-rw-r--r--src/crepe/facade/Font.cpp21
-rw-r--r--src/crepe/facade/Font.h42
-rw-r--r--src/crepe/facade/FontFacade.cpp43
-rw-r--r--src/crepe/facade/FontFacade.h34
-rw-r--r--src/crepe/facade/SDLContext.cpp268
-rw-r--r--src/crepe/facade/SDLContext.h182
-rw-r--r--src/crepe/system/InputSystem.cpp259
-rw-r--r--src/crepe/system/InputSystem.h40
-rw-r--r--src/crepe/system/RenderSystem.cpp26
-rw-r--r--src/crepe/system/RenderSystem.h10
-rw-r--r--src/example/CMakeLists.txt2
-rw-r--r--src/example/FontExample.cpp55
-rw-r--r--src/example/button.cpp39
-rw-r--r--src/example/loadfont.cpp49
-rw-r--r--src/test/EventTest.cpp51
-rw-r--r--src/test/InputTest.cpp41
31 files changed, 1047 insertions, 430 deletions
diff --git a/readme.md b/readme.md
index d309b30..984a368 100644
--- a/readme.md
+++ b/readme.md
@@ -60,6 +60,7 @@ Then, follow these steps for each library you want to install:
$ cd lib/googletest
$ cd lib/sdl2
$ cd lib/soloud/contrib
+ $ cd lib/sdl_ttf
$ cd lib/sdl_image
$ cd lib/sdl_ttf
$ cd lib/whereami
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 97b21f0..696856c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,10 +9,12 @@ project(crepe C CXX)
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
+find_package(SDL2_ttf REQUIRED)
find_package(SoLoud REQUIRED)
find_package(GTest REQUIRED)
find_package(whereami REQUIRED)
find_library(BERKELEY_DB db)
+find_library(FONTCONFIG_LIB fontconfig)
add_library(crepe SHARED)
add_executable(test_main EXCLUDE_FROM_ALL)
@@ -24,9 +26,11 @@ target_include_directories(crepe
target_link_libraries(crepe
PRIVATE soloud
PUBLIC SDL2
+ PUBLIC SDL2_ttf
PUBLIC SDL2_image
PUBLIC ${BERKELEY_DB}
PUBLIC whereami
+ PUBLIC ${FONTCONFIG_LIB}
)
add_subdirectory(crepe)
diff --git a/src/crepe/api/Button.cpp b/src/crepe/api/Button.cpp
index 76f74f0..305922c 100644
--- a/src/crepe/api/Button.cpp
+++ b/src/crepe/api/Button.cpp
@@ -3,9 +3,8 @@
namespace crepe {
Button::Button(game_object_id_t id, const vec2 & dimensions, const vec2 & offset,
- const std::function<void()> & on_click, bool is_toggle)
+ const std::function<void()> & on_click)
: UIObject(id, dimensions, offset),
- is_toggle(is_toggle),
on_click(on_click) {}
} // namespace crepe
diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h
index 61b18d7..08f5dec 100644
--- a/src/crepe/api/Button.h
+++ b/src/crepe/api/Button.h
@@ -15,19 +15,11 @@ public:
* \param id The unique ID of the game object associated with this button.
* \param dimensions The width and height of the UIObject
* \param offset The offset relative this GameObjects Transform
- * \param is_toggle Optional flag to indicate if the button is a toggle button. Defaults to false.
* \param on_click callback function that will be invoked when the button is clicked.
*/
Button(game_object_id_t id, const vec2 & dimensions, const vec2 & offset,
- const std::function<void()> & on_click, bool is_toggle = false);
+ const std::function<void()> & on_click);
- /**
- * \brief Indicates if the button is a toggle button (can be pressed and released).
- *
- * A toggle button allows for a pressed/released state, whereas a regular button
- * typically only has an on-click state.
- */
- bool is_toggle = false;
// TODO: create separate toggle button class
/**
* \brief The callback function to be executed when the button is clicked.
@@ -56,8 +48,6 @@ public:
private:
//! friend relation for is_pressed and hover variables
friend class InputSystem;
- //! Indicates whether the toggle button is pressed
- bool is_pressed = false;
//! Indicates whether the mouse is currently hovering over the button
bool hover = false;
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index 8f84f06..e8d6f92 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -20,6 +20,7 @@ target_sources(crepe PUBLIC
Button.cpp
UIObject.cpp
AI.cpp
+ Text.cpp
Scene.cpp
)
@@ -51,4 +52,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Button.h
UIObject.h
AI.h
+ Text.h
)
diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h
index ca2d3f1..6b9e3ca 100644
--- a/src/crepe/api/Config.h
+++ b/src/crepe/api/Config.h
@@ -76,6 +76,22 @@ struct Config final {
*/
std::string root_pattern = ".crepe-root";
} asset;
+ //! Default font options
+ struct {
+ /**
+ * \brief Default font size
+ *
+ * Using the SDL_ttf library the font size needs to be set when loading the font.
+ * This config option is the font size at which all fonts will be loaded initially.
+ *
+ */
+ unsigned int size = 16;
+ } font;
+ //! Configuration for click tolerance.
+ struct {
+ //! The maximum number of pixels the mouse can move between MouseDown and MouseUp events to be considered a click.
+ int click_tolerance = 5;
+ } input;
//! Audio system settings
struct {
diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h
index f2f3daf..73bf461 100644
--- a/src/crepe/api/Event.h
+++ b/src/crepe/api/Event.h
@@ -3,7 +3,8 @@
#include <string>
-#include "KeyCodes.h"
+#include "api/KeyCodes.h"
+#include "types.h"
namespace crepe {
@@ -38,11 +39,8 @@ public:
*/
class MousePressEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
+ //! mouse position in world coordinates (game units).
+ vec2 mouse_pos = {0, 0};
//! The mouse button that was pressed.
MouseButton button = MouseButton::NONE;
@@ -53,11 +51,8 @@ public:
*/
class MouseClickEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
+ //! mouse position in world coordinates (game units).
+ vec2 mouse_pos = {0, 0};
//! The mouse button that was clicked.
MouseButton button = MouseButton::NONE;
@@ -68,11 +63,8 @@ public:
*/
class MouseReleaseEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
+ //! mouse position in world coordinates (game units).
+ vec2 mouse_pos = {0, 0};
//! The mouse button that was released.
MouseButton button = MouseButton::NONE;
@@ -83,17 +75,10 @@ public:
*/
class MouseMoveEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
-
- // Movement since last event in x
- int delta_x = 0;
-
- // Movement since last event in y
- int delta_y = 0;
+ //! mouse position in world coordinates (game units).
+ vec2 mouse_pos = {0, 0};
+ //! The change in mouse position relative to the last position (in pixels).
+ ivec2 mouse_delta = {0, 0};
};
/**
@@ -101,12 +86,8 @@ public:
*/
class MouseScrollEvent : public Event {
public:
- //! X-coordinate of the mouse position at the time of the event.
- int mouse_x = 0;
-
- //! Y-coordinate of the mouse position at the time of the event.
- int mouse_y = 0;
-
+ //! mouse position in world coordinates (game units) when the scroll happened.
+ vec2 mouse_pos = {0, 0};
//! scroll direction (-1 = down, 1 = up)
int scroll_direction = 0;
//! scroll amount in y axis (from and away from the person).
@@ -127,4 +108,55 @@ public:
*/
class ShutDownEvent : public Event {};
+/**
+ * \brief Event triggered to indicate the window is overlapped by another window.
+ *
+ * When two windows overlap the bottom window gets distorted and that window has to be redrawn.
+ */
+class WindowExposeEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window is resized.
+ */
+class WindowResizeEvent : public Event {
+public:
+ //! new window dimensions
+ ivec2 dimensions = {0, 0};
+};
+
+/**
+ * \brief Event triggered to indicate the window is moved.
+ */
+class WindowMoveEvent : public Event {
+public:
+ //! The change in position relative to the last position (in pixels).
+ ivec2 delta_move = {0, 0};
+};
+
+/**
+ * \brief Event triggered to indicate the window is minimized.
+ */
+class WindowMinimizeEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window is maximized
+ */
+class WindowMaximizeEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window gained focus
+ *
+ * This event is triggered when the window receives focus, meaning it becomes the active window
+ * for user interaction.
+ */
+class WindowFocusGainEvent : public Event {};
+
+/**
+ * \brief Event triggered to indicate the window lost focus
+ *
+ * This event is triggered when the window loses focus, meaning it is no longer the active window
+ * for user interaction.
+ */
+class WindowFocusLostEvent : public Event {};
+
} // namespace crepe
diff --git a/src/crepe/api/KeyCodes.h b/src/crepe/api/KeyCodes.h
index fcfc080..1b9573a 100644
--- a/src/crepe/api/KeyCodes.h
+++ b/src/crepe/api/KeyCodes.h
@@ -1,5 +1,9 @@
#pragma once
+
+#include <unordered_map>
+
namespace crepe {
+
//! Enumeration for mouse button inputs, including standard and extended buttons.
enum class MouseButton {
NONE = 0, //!< No mouse button input.
@@ -151,4 +155,6 @@ enum class Keycode {
/// \}
MENU = 348, //!< Menu key.
};
+//! Typedef for keyboard state.
+typedef std::unordered_map<Keycode, bool> keyboard_state_t;
} // namespace crepe
diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h
index 40e6b38..1d23cbf 100644
--- a/src/crepe/api/LoopManager.h
+++ b/src/crepe/api/LoopManager.h
@@ -72,6 +72,8 @@ private:
//! Global context
Mediator mediator;
+ //! SDLContext instance
+ SDLContext sdl_context{mediator};
//! Component manager instance
ComponentManager component_manager{mediator};
//! Scene manager instance
@@ -84,8 +86,6 @@ private:
ResourceManager resource_manager{mediator};
//! Save manager instance
SaveManager save_manager{mediator};
- //! SDLContext instance
- SDLContext sdl_context{mediator};
private:
/**
diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp
index 753a9e3..583c04f 100644
--- a/src/crepe/api/Script.cpp
+++ b/src/crepe/api/Script.cpp
@@ -1,7 +1,7 @@
#include <string>
+#include "../facade/SDLContext.h"
#include "../manager/SceneManager.h"
-
#include "Script.h"
using namespace crepe;
@@ -25,3 +25,16 @@ void Script::set_next_scene(const string & name) {
}
SaveManager & Script::get_save_manager() const { return this->mediator->save_manager; }
+
+const keyboard_state_t & Script::get_keyboard_state() const {
+ SDLContext & sdl_context = this->mediator->sdl_context;
+ return sdl_context.get_keyboard_state();
+}
+
+bool Script::get_key_state(Keycode key) const noexcept {
+ try {
+ return this->get_keyboard_state().at(key);
+ } catch (...) {
+ return false;
+ }
+}
diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h
index 668e5d1..65306cd 100644
--- a/src/crepe/api/Script.h
+++ b/src/crepe/api/Script.h
@@ -2,6 +2,7 @@
#include <vector>
+#include "../api/KeyCodes.h"
#include "../manager/EventManager.h"
#include "../manager/Mediator.h"
#include "../system/CollisionSystem.h"
@@ -134,7 +135,22 @@ protected:
//! Retrieve SaveManager reference
SaveManager & get_save_manager() const;
-
+ /**
+ * \brief Utility function to retrieve the keyboard state
+ * \see SDLContext::get_keyboard_state
+ *
+ * \return current keyboard state map with Keycode as key and bool as value(true = pressed, false = not pressed)
+ *
+ */
+ const keyboard_state_t & get_keyboard_state() const;
+ /**
+ * \brief Utility function to retrieve a single key state.
+ * \see SDLContext::get_keyboard_state
+ *
+ * \return Keycode state (true if pressed, false if not pressed).
+ *
+ */
+ bool get_key_state(Keycode key) const noexcept;
//! \}
private:
diff --git a/src/crepe/api/Text.cpp b/src/crepe/api/Text.cpp
new file mode 100644
index 0000000..54a4370
--- /dev/null
+++ b/src/crepe/api/Text.cpp
@@ -0,0 +1,12 @@
+#include "../facade/FontFacade.h"
+
+#include "Text.h"
+
+using namespace crepe;
+
+Text::Text(game_object_id_t id, const vec2 & dimensions, const vec2 & offset,
+ const std::string & font_family, const Data & data, const std::string & text)
+ : UIObject(id, dimensions, offset),
+ text(text),
+ data(data),
+ font_family(font_family) {}
diff --git a/src/crepe/api/Text.h b/src/crepe/api/Text.h
new file mode 100644
index 0000000..c30dc80
--- /dev/null
+++ b/src/crepe/api/Text.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <optional>
+#include <string>
+
+#include "../Component.h"
+
+#include "Asset.h"
+#include "Color.h"
+#include "UIObject.h"
+
+namespace crepe {
+/**
+ * \brief Text UIObject component for displaying text
+ *
+ * This class can be used to display text on screen. By setting the font_family to a font already stored on the current device it will automatically be loaded in.
+ */
+class Text : public UIObject {
+public:
+ //! Text data that does not have to be set in the constructor
+ struct Data {
+ /**
+ * \brief fontsize for text rendering
+ *
+ * \note this is not the actual font size that is loaded in.
+ *
+ * Since SDL_TTF requires the font size when loading in the font it is not possible to switch the font size.
+ * The default font size that is loaded is set in the Config.
+ * Instead this value is used to upscale the font texture which can cause blurring or distorted text when upscaling or downscaling too much.
+ */
+ unsigned int font_size = 16;
+
+ //! Layer sorting level of the text
+ const int sorting_in_layer = 0;
+
+ //! Order within the sorting text
+ const int order_in_layer = 0;
+
+ //! Label text color.
+ Color text_color = Color::BLACK;
+ };
+
+public:
+ /**
+ *
+ * \param dimensions Width and height of the UIObject.
+ * \param offset Offset of the UIObject relative to its transform
+ * \param text The text to be displayed.
+ * \param font_family The font style name to be displayed.
+ * \param data Data struct containing extra text parameters.
+ * \param font Optional font asset that can be passed or left empty.
+ */
+ Text(game_object_id_t id, const vec2 & dimensions, const vec2 & offset,
+ const std::string & font_family, const Data & data, const std::string & text = "");
+
+ //! Label text.
+ std::string text = "";
+ //! font family name
+ std::string font_family = "";
+ //! Font asset variable if this is not set, it will use the font_family to create an asset.
+ std::optional<Asset> font;
+ //! Data instance
+ Data data;
+};
+
+} // namespace crepe
diff --git a/src/crepe/facade/CMakeLists.txt b/src/crepe/facade/CMakeLists.txt
index 0598e16..243ae46 100644
--- a/src/crepe/facade/CMakeLists.txt
+++ b/src/crepe/facade/CMakeLists.txt
@@ -4,6 +4,8 @@ target_sources(crepe PUBLIC
SoundContext.cpp
SDLContext.cpp
DB.cpp
+ FontFacade.cpp
+ Font.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -12,5 +14,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
SoundContext.h
SDLContext.h
DB.h
+ FontFacade.h
+ Font.h
)
diff --git a/src/crepe/facade/EventData.h b/src/crepe/facade/EventData.h
new file mode 100644
index 0000000..a7526b4
--- /dev/null
+++ b/src/crepe/facade/EventData.h
@@ -0,0 +1,54 @@
+#pragma once
+#include "../api/KeyCodes.h"
+#include "../types.h"
+namespace crepe {
+//! EventType enum for passing eventType
+enum EventType {
+ NONE = 0,
+ MOUSE_DOWN,
+ MOUSE_UP,
+ MOUSE_MOVE,
+ MOUSE_WHEEL,
+ KEY_UP,
+ KEY_DOWN,
+ SHUTDOWN,
+ WINDOW_MINIMIZE,
+ WINDOW_MAXIMIZE,
+ WINDOW_FOCUS_GAIN,
+ WINDOW_FOCUS_LOST,
+ WINDOW_MOVE,
+ WINDOW_RESIZE,
+ WINDOW_EXPOSE,
+};
+
+//! Struct for storing key data.
+struct KeyData {
+ Keycode key = Keycode::NONE;
+ bool key_repeat = false;
+};
+
+//! Struct for storing mouse data.
+struct MouseData {
+ MouseButton mouse_button = MouseButton::NONE;
+ ivec2 mouse_position = {-1, -1};
+ int scroll_direction = -1;
+ float scroll_delta = INFINITY;
+ ivec2 rel_mouse_move = {-1, -1};
+};
+
+//! Struct for storing window data.
+struct WindowData {
+ ivec2 move_delta;
+ ivec2 resize_dimension;
+};
+
+//! EventData struct for passing event data from facade
+struct EventData {
+ EventType event_type = EventType::NONE;
+ union {
+ KeyData key_data;
+ MouseData mouse_data;
+ WindowData window_data;
+ } data;
+};
+} // namespace crepe
diff --git a/src/crepe/facade/Font.cpp b/src/crepe/facade/Font.cpp
new file mode 100644
index 0000000..771002f
--- /dev/null
+++ b/src/crepe/facade/Font.cpp
@@ -0,0 +1,21 @@
+#include <SDL2/SDL_ttf.h>
+
+#include "../api/Asset.h"
+#include "../api/Config.h"
+
+#include "Font.h"
+
+using namespace std;
+using namespace crepe;
+
+Font::Font(const Asset & src, Mediator & mediator) : Resource(src, mediator) {
+ const Config & config = Config::get_instance();
+ const std::string FONT_PATH = src.get_path();
+ TTF_Font * loaded_font = TTF_OpenFont(FONT_PATH.c_str(), config.font.size);
+ if (loaded_font == NULL) {
+ throw runtime_error(format("Font: {} (path: {})", TTF_GetError(), FONT_PATH));
+ }
+ this->font = {loaded_font, [](TTF_Font * close_font) { TTF_CloseFont(close_font); }};
+}
+
+TTF_Font * Font::get_font() const { return this->font.get(); }
diff --git a/src/crepe/facade/Font.h b/src/crepe/facade/Font.h
new file mode 100644
index 0000000..b208d96
--- /dev/null
+++ b/src/crepe/facade/Font.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <SDL2/SDL_ttf.h>
+#include <memory>
+
+#include "../Resource.h"
+#include "../api/Config.h"
+
+namespace crepe {
+
+class Asset;
+/**
+ * \brief Resource for managing font creation and destruction
+ *
+ * This class is a wrapper around an SDL_ttf font instance, encapsulating font loading and usage.
+ * It loads a font from an Asset and manages its lifecycle. The font is automatically unloaded
+ * when this object is destroyed.
+ */
+class Font : public Resource {
+
+public:
+ /**
+ * \param src The Asset containing the font file path and metadata to load the font.
+ * \param mediator The Mediator object used for managing the SDL context or related systems.
+ */
+ Font(const Asset & src, Mediator & mediator);
+ /**
+ * \brief Gets the underlying TTF_Font resource.
+ *
+ * This function returns the raw pointer to the SDL_ttf TTF_Font object that represents
+ * the loaded font. This can be used with SDL_ttf functions to render text.
+ *
+ * \return The raw TTF_Font object wrapped in a unique pointer.
+ */
+ TTF_Font * get_font() const;
+
+private:
+ //! The SDL_ttf font object with custom deleter.
+ std::unique_ptr<TTF_Font, std::function<void(TTF_Font *)>> font = nullptr;
+};
+
+} // namespace crepe
diff --git a/src/crepe/facade/FontFacade.cpp b/src/crepe/facade/FontFacade.cpp
new file mode 100644
index 0000000..87f95ab
--- /dev/null
+++ b/src/crepe/facade/FontFacade.cpp
@@ -0,0 +1,43 @@
+#include <fontconfig/fontconfig.h>
+#include <functional>
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+#include "FontFacade.h"
+
+using namespace std;
+using namespace crepe;
+
+FontFacade::FontFacade() {
+ if (!FcInit()) throw runtime_error("Failed to initialize Fontconfig.");
+}
+
+FontFacade::~FontFacade() { FcFini(); }
+
+Asset FontFacade::get_font_asset(const string & font_family) {
+ FcPattern * raw_pattern
+ = FcNameParse(reinterpret_cast<const FcChar8 *>(font_family.c_str()));
+ if (raw_pattern == NULL) throw runtime_error("Failed to create font pattern.");
+
+ unique_ptr<FcPattern, function<void(FcPattern *)>> pattern{
+ raw_pattern, [](FcPattern * p) { FcPatternDestroy(p); }};
+
+ FcConfig * config = FcConfigGetCurrent();
+ if (config == NULL) throw runtime_error("Failed to get current Fontconfig configuration.");
+
+ FcResult result;
+ FcPattern * raw_matched_pattern = FcFontMatch(config, pattern.get(), &result);
+ if (raw_matched_pattern == NULL) throw runtime_error("No matching font found.");
+
+ unique_ptr<FcPattern, function<void(FcPattern *)>> matched_pattern
+ = {raw_matched_pattern, [](FcPattern * p) { FcPatternDestroy(p); }};
+
+ FcChar8 * file_path = nullptr;
+ FcResult res = FcPatternGetString(matched_pattern.get(), FC_FILE, 0, &file_path);
+ if (res != FcResultMatch || file_path == NULL)
+ throw runtime_error("Failed to get font file path.");
+
+ string font_file_path = reinterpret_cast<const char *>(file_path);
+ return Asset(font_file_path);
+}
diff --git a/src/crepe/facade/FontFacade.h b/src/crepe/facade/FontFacade.h
new file mode 100644
index 0000000..9761070
--- /dev/null
+++ b/src/crepe/facade/FontFacade.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <memory>
+
+#include "../api/Asset.h"
+
+namespace crepe {
+
+/**
+ *
+ * \brief Font facade class for converting font family names to absolute file paths
+ *
+ */
+class FontFacade {
+public:
+ FontFacade();
+ ~FontFacade();
+ FontFacade(const FontFacade & other) = delete;
+ FontFacade & operator=(const FontFacade & other) = delete;
+ FontFacade(FontFacade && other) noexcept = delete;
+ FontFacade & operator=(FontFacade && other) noexcept = delete;
+ /**
+ *
+ * \brief Facade function to convert a font_family into an asset.
+ *
+ * This function uses the FontConfig library to convert a font family name (Arial, Inter, Helvetica) and converts it to the font source path.
+ * This function returns a default font path if the font_family name doesnt exist or cant be found
+ * \param font_family Name of the font family name.
+ * \return Asset with filepath to the corresponding font.
+ */
+ Asset get_font_asset(const std::string & font_family);
+};
+
+} // namespace crepe
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index a1a6f97..4818c96 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -6,6 +6,7 @@
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_surface.h>
+#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_video.h>
#include <array>
#include <cmath>
@@ -31,6 +32,9 @@ using namespace std;
SDLContext::SDLContext(Mediator & mediator) {
dbg_trace();
+ if (TTF_Init() == -1) {
+ throw runtime_error(format("SDL_ttf initialization failed: {}", TTF_GetError()));
+ }
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
throw runtime_error(format("SDLContext: SDL_Init error: {}", SDL_GetError()));
}
@@ -72,121 +76,27 @@ SDLContext::~SDLContext() {
// thread that SDL_Init() was called on? This has caused problems for me
// before.
IMG_Quit();
+ TTF_Quit();
SDL_Quit();
}
-Keycode SDLContext::sdl_to_keycode(SDL_Keycode sdl_key) {
- static const std::array<Keycode, SDL_NUM_SCANCODES> LOOKUP_TABLE = [] {
- std::array<Keycode, SDL_NUM_SCANCODES> table{};
- table.fill(Keycode::NONE);
-
- table[SDL_SCANCODE_SPACE] = Keycode::SPACE;
- table[SDL_SCANCODE_APOSTROPHE] = Keycode::APOSTROPHE;
- table[SDL_SCANCODE_COMMA] = Keycode::COMMA;
- table[SDL_SCANCODE_MINUS] = Keycode::MINUS;
- table[SDL_SCANCODE_PERIOD] = Keycode::PERIOD;
- table[SDL_SCANCODE_SLASH] = Keycode::SLASH;
- table[SDL_SCANCODE_0] = Keycode::D0;
- table[SDL_SCANCODE_1] = Keycode::D1;
- table[SDL_SCANCODE_2] = Keycode::D2;
- table[SDL_SCANCODE_3] = Keycode::D3;
- table[SDL_SCANCODE_4] = Keycode::D4;
- table[SDL_SCANCODE_5] = Keycode::D5;
- table[SDL_SCANCODE_6] = Keycode::D6;
- table[SDL_SCANCODE_7] = Keycode::D7;
- table[SDL_SCANCODE_8] = Keycode::D8;
- table[SDL_SCANCODE_9] = Keycode::D9;
- table[SDL_SCANCODE_SEMICOLON] = Keycode::SEMICOLON;
- table[SDL_SCANCODE_EQUALS] = Keycode::EQUAL;
- table[SDL_SCANCODE_A] = Keycode::A;
- table[SDL_SCANCODE_B] = Keycode::B;
- table[SDL_SCANCODE_C] = Keycode::C;
- table[SDL_SCANCODE_D] = Keycode::D;
- table[SDL_SCANCODE_E] = Keycode::E;
- table[SDL_SCANCODE_F] = Keycode::F;
- table[SDL_SCANCODE_G] = Keycode::G;
- table[SDL_SCANCODE_H] = Keycode::H;
- table[SDL_SCANCODE_I] = Keycode::I;
- table[SDL_SCANCODE_J] = Keycode::J;
- table[SDL_SCANCODE_K] = Keycode::K;
- table[SDL_SCANCODE_L] = Keycode::L;
- table[SDL_SCANCODE_M] = Keycode::M;
- table[SDL_SCANCODE_N] = Keycode::N;
- table[SDL_SCANCODE_O] = Keycode::O;
- table[SDL_SCANCODE_P] = Keycode::P;
- table[SDL_SCANCODE_Q] = Keycode::Q;
- table[SDL_SCANCODE_R] = Keycode::R;
- table[SDL_SCANCODE_S] = Keycode::S;
- table[SDL_SCANCODE_T] = Keycode::T;
- table[SDL_SCANCODE_U] = Keycode::U;
- table[SDL_SCANCODE_V] = Keycode::V;
- table[SDL_SCANCODE_W] = Keycode::W;
- table[SDL_SCANCODE_X] = Keycode::X;
- table[SDL_SCANCODE_Y] = Keycode::Y;
- table[SDL_SCANCODE_Z] = Keycode::Z;
- table[SDL_SCANCODE_LEFTBRACKET] = Keycode::LEFT_BRACKET;
- table[SDL_SCANCODE_BACKSLASH] = Keycode::BACKSLASH;
- table[SDL_SCANCODE_RIGHTBRACKET] = Keycode::RIGHT_BRACKET;
- table[SDL_SCANCODE_GRAVE] = Keycode::GRAVE_ACCENT;
- table[SDL_SCANCODE_ESCAPE] = Keycode::ESCAPE;
- table[SDL_SCANCODE_RETURN] = Keycode::ENTER;
- table[SDL_SCANCODE_TAB] = Keycode::TAB;
- table[SDL_SCANCODE_BACKSPACE] = Keycode::BACKSPACE;
- table[SDL_SCANCODE_INSERT] = Keycode::INSERT;
- table[SDL_SCANCODE_DELETE] = Keycode::DELETE;
- table[SDL_SCANCODE_RIGHT] = Keycode::RIGHT;
- table[SDL_SCANCODE_LEFT] = Keycode::LEFT;
- table[SDL_SCANCODE_DOWN] = Keycode::DOWN;
- table[SDL_SCANCODE_UP] = Keycode::UP;
- table[SDL_SCANCODE_PAGEUP] = Keycode::PAGE_UP;
- table[SDL_SCANCODE_PAGEDOWN] = Keycode::PAGE_DOWN;
- table[SDL_SCANCODE_HOME] = Keycode::HOME;
- table[SDL_SCANCODE_END] = Keycode::END;
- table[SDL_SCANCODE_CAPSLOCK] = Keycode::CAPS_LOCK;
- table[SDL_SCANCODE_SCROLLLOCK] = Keycode::SCROLL_LOCK;
- table[SDL_SCANCODE_NUMLOCKCLEAR] = Keycode::NUM_LOCK;
- table[SDL_SCANCODE_PRINTSCREEN] = Keycode::PRINT_SCREEN;
- table[SDL_SCANCODE_PAUSE] = Keycode::PAUSE;
- table[SDL_SCANCODE_F1] = Keycode::F1;
- table[SDL_SCANCODE_F2] = Keycode::F2;
- table[SDL_SCANCODE_F3] = Keycode::F3;
- table[SDL_SCANCODE_F4] = Keycode::F4;
- table[SDL_SCANCODE_F5] = Keycode::F5;
- table[SDL_SCANCODE_F6] = Keycode::F6;
- table[SDL_SCANCODE_F7] = Keycode::F7;
- table[SDL_SCANCODE_F8] = Keycode::F8;
- table[SDL_SCANCODE_F9] = Keycode::F9;
- table[SDL_SCANCODE_F10] = Keycode::F10;
- table[SDL_SCANCODE_F11] = Keycode::F11;
- table[SDL_SCANCODE_F12] = Keycode::F12;
- table[SDL_SCANCODE_KP_0] = Keycode::KP0;
- table[SDL_SCANCODE_KP_1] = Keycode::KP1;
- table[SDL_SCANCODE_KP_2] = Keycode::KP2;
- table[SDL_SCANCODE_KP_3] = Keycode::KP3;
- table[SDL_SCANCODE_KP_4] = Keycode::KP4;
- table[SDL_SCANCODE_KP_5] = Keycode::KP5;
- table[SDL_SCANCODE_KP_6] = Keycode::KP6;
- table[SDL_SCANCODE_KP_7] = Keycode::KP7;
- table[SDL_SCANCODE_KP_8] = Keycode::KP8;
- table[SDL_SCANCODE_KP_9] = Keycode::KP9;
- table[SDL_SCANCODE_LSHIFT] = Keycode::LEFT_SHIFT;
- table[SDL_SCANCODE_LCTRL] = Keycode::LEFT_CONTROL;
- table[SDL_SCANCODE_LALT] = Keycode::LEFT_ALT;
- table[SDL_SCANCODE_LGUI] = Keycode::LEFT_SUPER;
- table[SDL_SCANCODE_RSHIFT] = Keycode::RIGHT_SHIFT;
- table[SDL_SCANCODE_RCTRL] = Keycode::RIGHT_CONTROL;
- table[SDL_SCANCODE_RALT] = Keycode::RIGHT_ALT;
- table[SDL_SCANCODE_RGUI] = Keycode::RIGHT_SUPER;
- table[SDL_SCANCODE_MENU] = Keycode::MENU;
+Keycode SDLContext::sdl_to_keycode(SDL_Scancode sdl_key) {
+ if (!lookup_table.contains(sdl_key)) return Keycode::NONE;
+ return lookup_table.at(sdl_key);
+}
- return table;
- }();
+const keyboard_state_t & SDLContext::get_keyboard_state() {
+ SDL_PumpEvents();
+ const Uint8 * current_state = SDL_GetKeyboardState(nullptr);
- if (sdl_key < 0 || sdl_key >= SDL_NUM_SCANCODES) {
- return Keycode::NONE;
- }
+ for (int i = 0; i < SDL_NUM_SCANCODES; ++i) {
- return LOOKUP_TABLE[sdl_key];
+ Keycode key = sdl_to_keycode(static_cast<SDL_Scancode>(i));
+ if (key != Keycode::NONE) {
+ this->keyboard_state[key] = current_state[i] != 0;
+ }
+ }
+ return this->keyboard_state;
}
MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) {
@@ -364,8 +274,8 @@ ivec2 SDLContext::get_size(const Texture & ctx) {
return size;
}
-std::vector<SDLContext::EventData> SDLContext::get_events() {
- std::vector<SDLContext::EventData> event_list;
+std::vector<EventData> SDLContext::get_events() {
+ std::vector<EventData> event_list;
SDL_Event event;
const CameraAuxiliaryData & cam = this->cam_aux_data;
while (SDL_PollEvent(&event)) {
@@ -374,61 +284,135 @@ std::vector<SDLContext::EventData> SDLContext::get_events() {
mouse_pos.y = (event.button.y - cam.bar_size.y) / cam.render_scale.y;
switch (event.type) {
case SDL_QUIT:
- event_list.push_back(EventData{
- .event_type = SDLContext::EventType::SHUTDOWN,
- });
+ event_list.push_back({.event_type = EventType::SHUTDOWN});
break;
case SDL_KEYDOWN:
event_list.push_back(EventData{
- .event_type = SDLContext::EventType::KEYDOWN,
- .key = sdl_to_keycode(event.key.keysym.scancode),
- .key_repeat = (event.key.repeat != 0),
+ .event_type = EventType::KEY_DOWN,
+ .data = {
+ .key_data = {
+ .key = this->sdl_to_keycode(event.key.keysym.scancode),
+ .key_repeat = event.key.repeat != 0,
+ },
+ },
});
break;
+
case SDL_KEYUP:
event_list.push_back(EventData{
- .event_type = SDLContext::EventType::KEYUP,
- .key = sdl_to_keycode(event.key.keysym.scancode),
+ .event_type = EventType::KEY_UP,
+ .data = {
+ .key_data = {
+ .key = this->sdl_to_keycode(event.key.keysym.scancode),
+ .key_repeat = event.key.repeat != 0,
+ },
+ },
});
break;
+
case SDL_MOUSEBUTTONDOWN:
event_list.push_back(EventData{
- .event_type = SDLContext::EventType::MOUSEDOWN,
- .mouse_button = sdl_to_mousebutton(event.button.button),
- .mouse_position = mouse_pos,
+ .event_type = EventType::MOUSE_DOWN,
+ .data = {
+ .mouse_data = {
+ .mouse_button = this->sdl_to_mousebutton(event.button.button),
+ .mouse_position = mouse_pos,
+ },
+ },
});
break;
- case SDL_MOUSEBUTTONUP: {
- int x, y;
- SDL_GetMouseState(&x, &y);
+ case SDL_MOUSEBUTTONUP:
event_list.push_back(EventData{
- .event_type = SDLContext::EventType::MOUSEUP,
- .mouse_button = sdl_to_mousebutton(event.button.button),
- .mouse_position = mouse_pos,
+ .event_type = EventType::MOUSE_UP,
+ .data = {
+ .mouse_data = {
+ .mouse_button = this->sdl_to_mousebutton(event.button.button),
+ .mouse_position = mouse_pos,
+ },
+ },
});
- } break;
+ break;
- case SDL_MOUSEMOTION: {
- event_list.push_back(
- EventData{.event_type = SDLContext::EventType::MOUSEMOVE,
- .mouse_position = mouse_pos,
- .rel_mouse_move = {event.motion.xrel, event.motion.yrel}});
- } break;
+ case SDL_MOUSEMOTION:
+ event_list.push_back(EventData{
+ .event_type = EventType::MOUSE_MOVE,
+ .data = {
+ .mouse_data = {
+ .mouse_position = mouse_pos,
+ .rel_mouse_move = {event.motion.xrel, event.motion.yrel},
+ },
+ },
+ });
+ break;
- case SDL_MOUSEWHEEL: {
+ case SDL_MOUSEWHEEL:
event_list.push_back(EventData{
- .event_type = SDLContext::EventType::MOUSEWHEEL,
- .mouse_position = mouse_pos,
- // TODO: why is this needed?
- .scroll_direction = event.wheel.y < 0 ? -1 : 1,
- .scroll_delta = event.wheel.preciseY,
+ .event_type = EventType::MOUSE_WHEEL,
+ .data = {
+ .mouse_data = {
+ .mouse_position = mouse_pos,
+ .scroll_direction = event.wheel.y < 0 ? -1 : 1,
+ .scroll_delta = event.wheel.preciseY,
+ },
+ },
});
- } break;
+ break;
+ case SDL_WINDOWEVENT:
+ this->handle_window_event(event.window, event_list);
+ break;
}
}
+
return event_list;
}
+
+void SDLContext::handle_window_event(const SDL_WindowEvent & window_event,
+ std::vector<EventData> & event_list) {
+ switch (window_event.event) {
+ case SDL_WINDOWEVENT_EXPOSED:
+ event_list.push_back(EventData{EventType::WINDOW_EXPOSE});
+ break;
+ case SDL_WINDOWEVENT_RESIZED:
+ event_list.push_back(EventData{
+ .event_type = EventType::WINDOW_RESIZE,
+ .data = {
+ .window_data = {
+ .resize_dimension = {window_event.data1, window_event.data2}
+ },
+ },
+ });
+ break;
+ case SDL_WINDOWEVENT_MOVED:
+ event_list.push_back(EventData{
+ .event_type = EventType::WINDOW_MOVE,
+ .data = {
+ .window_data = {
+ .move_delta = {window_event.data1, window_event.data2}
+ },
+ },
+ });
+ break;
+
+ case SDL_WINDOWEVENT_MINIMIZED:
+ event_list.push_back(EventData{EventType::WINDOW_MINIMIZE});
+ break;
+ case SDL_WINDOWEVENT_MAXIMIZED:
+ event_list.push_back(EventData{EventType::WINDOW_MAXIMIZE});
+ break;
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ event_list.push_back(EventData{EventType::WINDOW_FOCUS_GAIN});
+ break;
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ event_list.push_back(EventData{EventType::WINDOW_FOCUS_LOST});
+ break;
+ }
+}
+
void SDLContext::set_color_texture(const Texture & texture, const Color & color) {
SDL_SetTextureColorMod(texture.get_img(), color.r, color.g, color.b);
SDL_SetTextureAlphaMod(texture.get_img(), color.a);
}
+
+Asset SDLContext::get_font_from_name(const std::string & font_family) {
+ return this->font_facade.get_font_asset(font_family);
+}
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index bcadf87..b687f87 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -9,17 +9,20 @@
#include <functional>
#include <memory>
#include <string>
+#include <unordered_map>
+#include "../types.h"
#include "api/Camera.h"
#include "api/Color.h"
#include "api/KeyCodes.h"
#include "api/Sprite.h"
#include "api/Transform.h"
-
#include "types.h"
-namespace crepe {
+#include "EventData.h"
+#include "FontFacade.h"
+namespace crepe {
class Texture;
class Mediator;
@@ -69,29 +72,11 @@ public:
};
public:
- //! EventType enum for passing eventType
- enum EventType {
- NONE = 0,
- MOUSEDOWN,
- MOUSEUP,
- MOUSEMOVE,
- MOUSEWHEEL,
- KEYUP,
- KEYDOWN,
- SHUTDOWN,
-
- };
- //! EventData struct for passing event data from facade
- struct EventData {
- SDLContext::EventType event_type = SDLContext::EventType::NONE;
- Keycode key = Keycode::NONE;
- bool key_repeat = false;
- MouseButton mouse_button = MouseButton::NONE;
- ivec2 mouse_position = {-1, -1};
- int scroll_direction = -1;
- float scroll_delta = INFINITY;
- ivec2 rel_mouse_move = {-1, -1};
- };
+ /**
+ * \brief Gets the singleton instance of SDLContext.
+ * \return Reference to the SDLContext instance.
+ */
+ static SDLContext & get_instance();
public:
SDLContext(const SDLContext &) = delete;
@@ -122,18 +107,25 @@ public:
*
* \return Events that occurred since last call to `get_events()`
*/
- std::vector<SDLContext::EventData> get_events();
-
+ std::vector<EventData> get_events();
/**
- * \brief Converts an SDL key code to the custom Keycode type.
+ * \brief Fills event_list with triggered window events
*
- * This method maps an SDL key code to the corresponding `Keycode` enum value,
+ * This method checks if any window events are triggered and adds them to the event_list.
+ *
+ */
+ void handle_window_event(const SDL_WindowEvent & window_event,
+ std::vector<EventData> & event_list);
+ /**
+ * \brief Converts an SDL scan code to the custom Keycode type.
+ *
+ * This method maps an SDL scan code to the corresponding `Keycode` enum value,
* which is used internally by the system to identify the keys.
*
- * \param sdl_key The SDL key code to convert.
+ * \param sdl_key The SDL scan code to convert.
* \return The corresponding `Keycode` value or `Keycode::NONE` if the key is unrecognized.
*/
- Keycode sdl_to_keycode(SDL_Keycode sdl_key);
+ Keycode sdl_to_keycode(SDL_Scancode sdl_key);
/**
* \brief Converts an SDL mouse button code to the custom MouseButton type.
@@ -145,6 +137,16 @@ public:
* \return The corresponding `MouseButton` value or `MouseButton::NONE` if the key is unrecognized
*/
MouseButton sdl_to_mousebutton(Uint8 sdl_button);
+ /**
+ * \brief Gets the current state of the keyboard.
+ *
+ * Updates the internal keyboard state by checking the current key states using
+ * SDL's `SDL_GetKeyboardState()`, and returns a reference to the `keyboard_state_t`.
+ *
+ * \return A constant reference to the `keyboard_state_t`, which holds the state
+ * of each key (true = pressed, false = not pressed).
+ */
+ const keyboard_state_t & get_keyboard_state();
public:
/**
@@ -240,6 +242,124 @@ private:
* - this is defined in this class because get_events() needs this information aswell
*/
CameraAuxiliaryData cam_aux_data;
+
+private:
+ //! instance of the font_facade
+ FontFacade font_facade{};
+
+public:
+ /**
+ * \brief Function to Get asset from font_family
+ *
+ * This function uses the FontFacade function to convert a font_family to an asset.
+ *
+ * \param font_family name of the font style that needs to be used (will return an asset with default font path of the font_family doesnt exist)
+ *
+ * \return asset with the font style absolute path
+ */
+ Asset get_font_from_name(const std::string & font_family);
+ //! variable to store the state of each key (true = pressed, false = not pressed)
+ keyboard_state_t keyboard_state;
+ //! lookup table for converting SDL_SCANCODES to Keycodes
+ const std::unordered_map<SDL_Scancode, Keycode> lookup_table
+ = {{SDL_SCANCODE_SPACE, Keycode::SPACE},
+ {SDL_SCANCODE_APOSTROPHE, Keycode::APOSTROPHE},
+ {SDL_SCANCODE_COMMA, Keycode::COMMA},
+ {SDL_SCANCODE_MINUS, Keycode::MINUS},
+ {SDL_SCANCODE_PERIOD, Keycode::PERIOD},
+ {SDL_SCANCODE_SLASH, Keycode::SLASH},
+ {SDL_SCANCODE_0, Keycode::D0},
+ {SDL_SCANCODE_1, Keycode::D1},
+ {SDL_SCANCODE_2, Keycode::D2},
+ {SDL_SCANCODE_3, Keycode::D3},
+ {SDL_SCANCODE_4, Keycode::D4},
+ {SDL_SCANCODE_5, Keycode::D5},
+ {SDL_SCANCODE_6, Keycode::D6},
+ {SDL_SCANCODE_7, Keycode::D7},
+ {SDL_SCANCODE_8, Keycode::D8},
+ {SDL_SCANCODE_9, Keycode::D9},
+ {SDL_SCANCODE_SEMICOLON, Keycode::SEMICOLON},
+ {SDL_SCANCODE_EQUALS, Keycode::EQUAL},
+ {SDL_SCANCODE_A, Keycode::A},
+ {SDL_SCANCODE_B, Keycode::B},
+ {SDL_SCANCODE_C, Keycode::C},
+ {SDL_SCANCODE_D, Keycode::D},
+ {SDL_SCANCODE_E, Keycode::E},
+ {SDL_SCANCODE_F, Keycode::F},
+ {SDL_SCANCODE_G, Keycode::G},
+ {SDL_SCANCODE_H, Keycode::H},
+ {SDL_SCANCODE_I, Keycode::I},
+ {SDL_SCANCODE_J, Keycode::J},
+ {SDL_SCANCODE_K, Keycode::K},
+ {SDL_SCANCODE_L, Keycode::L},
+ {SDL_SCANCODE_M, Keycode::M},
+ {SDL_SCANCODE_N, Keycode::N},
+ {SDL_SCANCODE_O, Keycode::O},
+ {SDL_SCANCODE_P, Keycode::P},
+ {SDL_SCANCODE_Q, Keycode::Q},
+ {SDL_SCANCODE_R, Keycode::R},
+ {SDL_SCANCODE_S, Keycode::S},
+ {SDL_SCANCODE_T, Keycode::T},
+ {SDL_SCANCODE_U, Keycode::U},
+ {SDL_SCANCODE_V, Keycode::V},
+ {SDL_SCANCODE_W, Keycode::W},
+ {SDL_SCANCODE_X, Keycode::X},
+ {SDL_SCANCODE_Y, Keycode::Y},
+ {SDL_SCANCODE_Z, Keycode::Z},
+ {SDL_SCANCODE_LEFTBRACKET, Keycode::LEFT_BRACKET},
+ {SDL_SCANCODE_BACKSLASH, Keycode::BACKSLASH},
+ {SDL_SCANCODE_RIGHTBRACKET, Keycode::RIGHT_BRACKET},
+ {SDL_SCANCODE_GRAVE, Keycode::GRAVE_ACCENT},
+ {SDL_SCANCODE_ESCAPE, Keycode::ESCAPE},
+ {SDL_SCANCODE_RETURN, Keycode::ENTER},
+ {SDL_SCANCODE_TAB, Keycode::TAB},
+ {SDL_SCANCODE_BACKSPACE, Keycode::BACKSPACE},
+ {SDL_SCANCODE_INSERT, Keycode::INSERT},
+ {SDL_SCANCODE_DELETE, Keycode::DELETE},
+ {SDL_SCANCODE_RIGHT, Keycode::RIGHT},
+ {SDL_SCANCODE_LEFT, Keycode::LEFT},
+ {SDL_SCANCODE_DOWN, Keycode::DOWN},
+ {SDL_SCANCODE_UP, Keycode::UP},
+ {SDL_SCANCODE_PAGEUP, Keycode::PAGE_UP},
+ {SDL_SCANCODE_PAGEDOWN, Keycode::PAGE_DOWN},
+ {SDL_SCANCODE_HOME, Keycode::HOME},
+ {SDL_SCANCODE_END, Keycode::END},
+ {SDL_SCANCODE_CAPSLOCK, Keycode::CAPS_LOCK},
+ {SDL_SCANCODE_SCROLLLOCK, Keycode::SCROLL_LOCK},
+ {SDL_SCANCODE_NUMLOCKCLEAR, Keycode::NUM_LOCK},
+ {SDL_SCANCODE_PRINTSCREEN, Keycode::PRINT_SCREEN},
+ {SDL_SCANCODE_PAUSE, Keycode::PAUSE},
+ {SDL_SCANCODE_F1, Keycode::F1},
+ {SDL_SCANCODE_F2, Keycode::F2},
+ {SDL_SCANCODE_F3, Keycode::F3},
+ {SDL_SCANCODE_F4, Keycode::F4},
+ {SDL_SCANCODE_F5, Keycode::F5},
+ {SDL_SCANCODE_F6, Keycode::F6},
+ {SDL_SCANCODE_F7, Keycode::F7},
+ {SDL_SCANCODE_F8, Keycode::F8},
+ {SDL_SCANCODE_F9, Keycode::F9},
+ {SDL_SCANCODE_F10, Keycode::F10},
+ {SDL_SCANCODE_F11, Keycode::F11},
+ {SDL_SCANCODE_F12, Keycode::F12},
+ {SDL_SCANCODE_KP_0, Keycode::KP0},
+ {SDL_SCANCODE_KP_1, Keycode::KP1},
+ {SDL_SCANCODE_KP_2, Keycode::KP2},
+ {SDL_SCANCODE_KP_3, Keycode::KP3},
+ {SDL_SCANCODE_KP_4, Keycode::KP4},
+ {SDL_SCANCODE_KP_5, Keycode::KP5},
+ {SDL_SCANCODE_KP_6, Keycode::KP6},
+ {SDL_SCANCODE_KP_7, Keycode::KP7},
+ {SDL_SCANCODE_KP_8, Keycode::KP8},
+ {SDL_SCANCODE_KP_9, Keycode::KP9},
+ {SDL_SCANCODE_LSHIFT, Keycode::LEFT_SHIFT},
+ {SDL_SCANCODE_LCTRL, Keycode::LEFT_CONTROL},
+ {SDL_SCANCODE_LALT, Keycode::LEFT_ALT},
+ {SDL_SCANCODE_LGUI, Keycode::LEFT_SUPER},
+ {SDL_SCANCODE_RSHIFT, Keycode::RIGHT_SHIFT},
+ {SDL_SCANCODE_RCTRL, Keycode::RIGHT_CONTROL},
+ {SDL_SCANCODE_RALT, Keycode::RIGHT_ALT},
+ {SDL_SCANCODE_RGUI, Keycode::RIGHT_SUPER},
+ {SDL_SCANCODE_MENU, Keycode::MENU}};
};
} // namespace crepe
diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp
index a710ae2..fca540f 100644
--- a/src/crepe/system/InputSystem.cpp
+++ b/src/crepe/system/InputSystem.cpp
@@ -1,7 +1,7 @@
#include "../api/Button.h"
+#include "../facade/SDLContext.h"
#include "../manager/ComponentManager.h"
#include "../manager/EventManager.h"
-#include "facade/SDLContext.h"
#include "util/Log.h"
#include "InputSystem.h"
@@ -10,12 +10,13 @@ using namespace crepe;
void InputSystem::update() {
ComponentManager & mgr = this->mediator.component_manager;
- EventManager & event_mgr = this->mediator.event_manager;
+
SDLContext & context = this->mediator.sdl_context;
- std::vector<SDLContext::EventData> event_list = context.get_events();
+ std::vector<EventData> event_list = context.get_events();
RefVector<Button> buttons = mgr.get_components_by_type<Button>();
RefVector<Camera> cameras = mgr.get_components_by_type<Camera>();
OptionalRef<Camera> curr_cam_ref;
+
// Find the active camera
for (Camera & cam : cameras) {
if (!cam.active) continue;
@@ -23,150 +24,185 @@ void InputSystem::update() {
break;
}
if (!curr_cam_ref) return;
+
Camera & current_cam = curr_cam_ref;
RefVector<Transform> transform_vec
= mgr.get_components_by_id<Transform>(current_cam.game_object_id);
Transform & cam_transform = transform_vec.front().get();
- int camera_origin_x = cam_transform.position.x + current_cam.data.postion_offset.x
- - (current_cam.viewport_size.x / 2);
- int camera_origin_y = cam_transform.position.y + current_cam.data.postion_offset.y
- - (current_cam.viewport_size.y / 2);
-
- for (const SDLContext::EventData & event : event_list) {
- int world_mouse_x = event.mouse_position.x + camera_origin_x;
- int world_mouse_y = event.mouse_position.y + camera_origin_y;
- // check if the mouse is within the viewport
- bool mouse_in_viewport
- = !(world_mouse_x < camera_origin_x
- || world_mouse_x > camera_origin_x + current_cam.viewport_size.x
- || world_mouse_y < camera_origin_y
- || world_mouse_y > camera_origin_y + current_cam.viewport_size.y);
-
- switch (event.event_type) {
- case SDLContext::EventType::KEYDOWN:
- event_mgr.queue_event<KeyPressEvent>(KeyPressEvent{
- .repeat = event.key_repeat,
- .key = event.key,
- });
- break;
- case SDLContext::EventType::KEYUP:
- event_mgr.queue_event<KeyReleaseEvent>(KeyReleaseEvent{
- .key = event.key,
- });
- break;
- case SDLContext::EventType::MOUSEDOWN:
- if (!mouse_in_viewport) {
- break;
- }
- event_mgr.queue_event<MousePressEvent>(MousePressEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .button = event.mouse_button,
- });
- this->last_mouse_down_position = {world_mouse_x, world_mouse_y};
- this->last_mouse_button = event.mouse_button;
- break;
- case SDLContext::EventType::MOUSEUP: {
- if (!mouse_in_viewport) {
- break;
- }
- event_mgr.queue_event<MouseReleaseEvent>(MouseReleaseEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .button = event.mouse_button,
- });
- //check if its a click by checking the last button down
- int delta_x = world_mouse_x - this->last_mouse_down_position.x;
- int delta_y = world_mouse_y - this->last_mouse_down_position.y;
-
- if (this->last_mouse_button == event.mouse_button
- && std::abs(delta_x) <= click_tolerance
- && std::abs(delta_y) <= click_tolerance) {
- event_mgr.queue_event<MouseClickEvent>(MouseClickEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .button = event.mouse_button,
- });
-
- this->handle_click(event.mouse_button, world_mouse_x, world_mouse_y);
- }
- } break;
- case SDLContext::EventType::MOUSEMOVE:
- if (!mouse_in_viewport) {
- break;
- }
- event_mgr.queue_event<MouseMoveEvent>(MouseMoveEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .delta_x = event.rel_mouse_move.x,
- .delta_y = event.rel_mouse_move.y,
- });
- this->handle_move(event, world_mouse_x, world_mouse_y);
- break;
- case SDLContext::EventType::MOUSEWHEEL:
- event_mgr.queue_event<MouseScrollEvent>(MouseScrollEvent{
- .mouse_x = world_mouse_x,
- .mouse_y = world_mouse_y,
- .scroll_direction = event.scroll_direction,
- .scroll_delta = event.scroll_delta,
+
+ vec2 camera_origin = cam_transform.position + current_cam.data.postion_offset
+ - (current_cam.viewport_size / 2);
+
+ for (const EventData & event : event_list) {
+ // Only calculate mouse coordinates for relevant events
+ if (event.event_type == EventType::MOUSE_DOWN
+ || event.event_type == EventType::MOUSE_UP
+ || event.event_type == EventType::MOUSE_MOVE
+ || event.event_type == EventType::MOUSE_WHEEL) {
+ this->handle_mouse_event(event, camera_origin, current_cam);
+
+ } else {
+ this->handle_non_mouse_event(event);
+ }
+ }
+}
+
+void InputSystem::handle_mouse_event(const EventData & event, const vec2 & camera_origin,
+ const Camera & current_cam) {
+ EventManager & event_mgr = this->mediator.event_manager;
+ vec2 adjusted_mouse;
+ adjusted_mouse.x = event.data.mouse_data.mouse_position.x + camera_origin.x;
+ adjusted_mouse.x = event.data.mouse_data.mouse_position.y + camera_origin.y;
+ // Check if the mouse is within the viewport
+ if ((adjusted_mouse.x < camera_origin.x
+ || adjusted_mouse.x > camera_origin.x + current_cam.viewport_size.x
+ || adjusted_mouse.y < camera_origin.y
+ || adjusted_mouse.y > camera_origin.y + current_cam.viewport_size.y))
+ return;
+
+ // Handle mouse-specific events
+ switch (event.event_type) {
+ case EventType::MOUSE_DOWN:
+ event_mgr.queue_event<MousePressEvent>({
+ .mouse_pos = adjusted_mouse,
+ .button = event.data.mouse_data.mouse_button,
+ });
+ this->last_mouse_down_position = adjusted_mouse;
+ this->last_mouse_button = event.data.mouse_data.mouse_button;
+ break;
+
+ case EventType::MOUSE_UP: {
+ event_mgr.queue_event<MouseReleaseEvent>({
+ .mouse_pos = adjusted_mouse,
+ .button = event.data.mouse_data.mouse_button,
+ });
+ vec2 delta_move = adjusted_mouse - this->last_mouse_down_position;
+ int click_tolerance = Config::get_instance().input.click_tolerance;
+ if (this->last_mouse_button == event.data.mouse_data.mouse_button
+ && std::abs(delta_move.x) <= click_tolerance
+ && std::abs(delta_move.y) <= click_tolerance) {
+ event_mgr.queue_event<MouseClickEvent>({
+ .mouse_pos = adjusted_mouse,
+ .button = event.data.mouse_data.mouse_button,
});
- break;
- case SDLContext::EventType::SHUTDOWN:
- event_mgr.queue_event<ShutDownEvent>(ShutDownEvent{});
- break;
- default:
- break;
+ this->handle_click(event.data.mouse_data.mouse_button, adjusted_mouse);
+ }
+ break;
}
+
+ case EventType::MOUSE_MOVE:
+ event_mgr.queue_event<MouseMoveEvent>({
+ .mouse_pos = adjusted_mouse,
+ .mouse_delta = event.data.mouse_data.rel_mouse_move,
+ });
+ this->handle_move(event, adjusted_mouse);
+ break;
+
+ case EventType::MOUSE_WHEEL:
+ event_mgr.queue_event<MouseScrollEvent>({
+ .mouse_pos = adjusted_mouse,
+ .scroll_direction = event.data.mouse_data.scroll_direction,
+ .scroll_delta = event.data.mouse_data.scroll_delta,
+ });
+ break;
+
+ default:
+ break;
+ }
+}
+
+void InputSystem::handle_non_mouse_event(const EventData & event) {
+ EventManager & event_mgr = this->mediator.event_manager;
+ switch (event.event_type) {
+ case EventType::KEY_DOWN:
+
+ event_mgr.queue_event<KeyPressEvent>(
+ {.repeat = event.data.key_data.key_repeat, .key = event.data.key_data.key});
+ break;
+ case EventType::KEY_UP:
+ event_mgr.queue_event<KeyReleaseEvent>({.key = event.data.key_data.key});
+ break;
+ case EventType::SHUTDOWN:
+ event_mgr.queue_event<ShutDownEvent>({});
+ break;
+ case EventType::WINDOW_EXPOSE:
+ event_mgr.queue_event<WindowExposeEvent>({});
+ break;
+ case EventType::WINDOW_RESIZE:
+ event_mgr.queue_event<WindowResizeEvent>(
+ WindowResizeEvent{.dimensions = event.data.window_data.resize_dimension});
+ break;
+ case EventType::WINDOW_MOVE:
+ event_mgr.queue_event<WindowMoveEvent>(
+ {.delta_move = event.data.window_data.move_delta});
+ break;
+ case EventType::WINDOW_MINIMIZE:
+ event_mgr.queue_event<WindowMinimizeEvent>({});
+ break;
+ case EventType::WINDOW_MAXIMIZE:
+ event_mgr.queue_event<WindowMaximizeEvent>({});
+ break;
+ case EventType::WINDOW_FOCUS_GAIN:
+ event_mgr.queue_event<WindowFocusGainEvent>({});
+ break;
+ case EventType::WINDOW_FOCUS_LOST:
+ event_mgr.queue_event<WindowFocusLostEvent>({});
+ break;
+ default:
+ break;
}
}
-void InputSystem::handle_move(const SDLContext::EventData & event_data,
- const int world_mouse_x, const int world_mouse_y) {
+
+void InputSystem::handle_move(const EventData & event_data, const vec2 & mouse_pos) {
ComponentManager & mgr = this->mediator.component_manager;
RefVector<Button> buttons = mgr.get_components_by_type<Button>();
for (Button & button : buttons) {
+ if (!button.active) continue;
RefVector<Transform> transform_vec
= mgr.get_components_by_id<Transform>(button.game_object_id);
Transform & transform(transform_vec.front().get());
bool was_hovering = button.hover;
- if (button.active
- && this->is_mouse_inside_button(world_mouse_x, world_mouse_y, button, transform)) {
+ if (this->is_mouse_inside_button(mouse_pos, button, transform)) {
button.hover = true;
- if (!was_hovering && button.on_mouse_enter) {
+ if (!button.on_mouse_enter) continue;
+ if (!was_hovering) {
button.on_mouse_enter();
}
} else {
button.hover = false;
// Trigger the on_exit callback if the hover state just changed to false
- if (was_hovering && button.on_mouse_exit) {
+ if (!button.on_mouse_exit) continue;
+ if (was_hovering) {
button.on_mouse_exit();
}
}
}
}
-void InputSystem::handle_click(const MouseButton & mouse_button, const int world_mouse_x,
- const int world_mouse_y) {
+void InputSystem::handle_click(const MouseButton & mouse_button, const vec2 & mouse_pos) {
ComponentManager & mgr = this->mediator.component_manager;
RefVector<Button> buttons = mgr.get_components_by_type<Button>();
for (Button & button : buttons) {
+ if (!button.active) continue;
+ if (!button.on_click) continue;
RefVector<Transform> transform_vec
= mgr.get_components_by_id<Transform>(button.game_object_id);
Transform & transform = transform_vec.front().get();
- if (button.active
- && this->is_mouse_inside_button(world_mouse_x, world_mouse_y, button, transform)) {
- this->handle_button_press(button);
+ if (this->is_mouse_inside_button(mouse_pos, button, transform)) {
+
+ button.on_click();
}
}
}
-bool InputSystem::is_mouse_inside_button(const int mouse_x, const int mouse_y,
- const Button & button, const Transform & transform) {
+bool InputSystem::is_mouse_inside_button(const vec2 & mouse_pos, const Button & button,
+ const Transform & transform) {
int actual_x = transform.position.x + button.offset.x;
int actual_y = transform.position.y + button.offset.y;
@@ -174,17 +210,6 @@ bool InputSystem::is_mouse_inside_button(const int mouse_x, const int mouse_y,
int half_height = button.dimensions.y / 2;
// Check if the mouse is within the button's boundaries
- return mouse_x >= actual_x - half_width && mouse_x <= actual_x + half_width
- && mouse_y >= actual_y - half_height && mouse_y <= actual_y + half_height;
-}
-
-void InputSystem::handle_button_press(Button & button) {
- if (button.is_toggle) {
- if (!button.is_pressed && button.on_click) {
- button.on_click();
- }
- button.is_pressed = !button.is_pressed;
- } else if (button.on_click) {
- button.on_click();
- }
+ return mouse_pos.x >= actual_x - half_width && mouse_pos.x <= actual_x + half_width
+ && mouse_pos.y >= actual_y - half_height && mouse_pos.y <= actual_y + half_height;
}
diff --git a/src/crepe/system/InputSystem.h b/src/crepe/system/InputSystem.h
index 87e86f8..eefd9fe 100644
--- a/src/crepe/system/InputSystem.h
+++ b/src/crepe/system/InputSystem.h
@@ -1,6 +1,8 @@
#pragma once
-#include "../facade/SDLContext.h"
+#include "../api/Config.h"
+#include "../facade/EventData.h"
+
#include "../types.h"
#include "../util/OptionalRef.h"
@@ -11,7 +13,6 @@ namespace crepe {
class Camera;
class Button;
class Transform;
-
/**
* \brief Handles the processing of input events created by SDLContext
*
@@ -31,15 +32,30 @@ public:
private:
//! Stores the last position of the mouse when the button was pressed.
- ivec2 last_mouse_down_position;
+ vec2 last_mouse_down_position;
// TODO: specify world/hud space and make regular `vec2`
//! Stores the last mouse button pressed.
MouseButton last_mouse_button = MouseButton::NONE;
-
- //! The maximum allowable distance between mouse down and mouse up to register as a click.
- const int click_tolerance = 5;
-
+ /**
+ * \brief Handles mouse-related events.
+ * \param event The event data for the mouse event.
+ * \param camera_origin The origin position of the camera in world space.
+ * \param current_cam The currently active camera.
+ *
+ * This method processes mouse events, adjusts the mouse position to world coordinates,
+ * and triggers the appropriate mouse-specific event handling logic.
+ */
+ void handle_mouse_event(const EventData & event, const vec2 & camera_origin,
+ const Camera & current_cam);
+ /**
+ * \brief Handles non-mouse-related events.
+ * \param event The event data for the non-mouse event.
+ *
+ * This method processes events that do not involve the mouse, such as keyboard events,
+ * window events, and shutdown events, and triggers the corresponding event actions.
+ */
+ void handle_non_mouse_event(const EventData & event);
/**
* \brief Handles the mouse click event.
* \param mouse_button The mouse button involved in the click.
@@ -48,8 +64,7 @@ private:
*
* This method processes the mouse click event and triggers the corresponding button action.
*/
- void handle_click(const MouseButton & mouse_button, const int world_mouse_x,
- const int world_mouse_y);
+ void handle_click(const MouseButton & mouse_button, const vec2 & mouse_pos);
/**
* \brief Handles the mouse movement event.
@@ -59,8 +74,7 @@ private:
*
* This method processes the mouse movement event and updates the button hover state.
*/
- void handle_move(const SDLContext::EventData & event_data, const int world_mouse_x,
- const int world_mouse_y);
+ void handle_move(const EventData & event_data, const vec2 & mouse_pos);
/**
* \brief Checks if the mouse position is inside the bounds of the button.
@@ -70,8 +84,8 @@ private:
* \param transform The transform component of the button.
* \return True if the mouse is inside the button, false otherwise.
*/
- bool is_mouse_inside_button(const int world_mouse_x, const int world_mouse_y,
- const Button & button, const Transform & transform);
+ bool is_mouse_inside_button(const vec2 & mouse_pos, const Button & button,
+ const Transform & transform);
/**
* \brief Handles the button press event, calling the on_click callback if necessary.
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index c0717fc..88d333e 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -2,13 +2,16 @@
#include <cassert>
#include <cmath>
#include <functional>
+#include <optional>
#include <stdexcept>
#include <vector>
#include "../api/Camera.h"
#include "../api/ParticleEmitter.h"
#include "../api/Sprite.h"
+#include "../api/Text.h"
#include "../api/Transform.h"
+#include "../facade/Font.h"
#include "../facade/SDLContext.h"
#include "../facade/Texture.h"
#include "../manager/ComponentManager.h"
@@ -121,8 +124,14 @@ void RenderSystem::render() {
this->update_camera();
RefVector<Sprite> sprites = mgr.get_components_by_type<Sprite>();
+ ResourceManager & resource_manager = this->mediator.resource_manager;
RefVector<Sprite> sorted_sprites = this->sort(sprites);
-
+ RefVector<Text> text_components = mgr.get_components_by_type<Text>();
+ for (Text & text : text_components) {
+ const Transform & transform
+ = mgr.get_components_by_id<Transform>(text.game_object_id).front().get();
+ this->render_text(text, transform);
+ }
for (const Sprite & sprite : sorted_sprites) {
if (!sprite.active) continue;
const Transform & transform
@@ -135,3 +144,18 @@ void RenderSystem::render() {
this->render_normal(sprite, transform);
}
}
+void RenderSystem::render_text(Text & text, const Transform & tm) {
+ SDLContext & ctx = this->mediator.sdl_context;
+
+ if (!text.font.has_value()) {
+ text.font.emplace(ctx.get_font_from_name(text.font_family));
+ }
+
+ ResourceManager & resource_manager = this->mediator.resource_manager;
+
+ if (!text.font.has_value()) {
+ return;
+ }
+ const Asset & font_asset = text.font.value();
+ const Font & res = resource_manager.get<Font>(font_asset);
+}
diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h
index fc7b46e..56a0553 100644
--- a/src/crepe/system/RenderSystem.h
+++ b/src/crepe/system/RenderSystem.h
@@ -10,7 +10,7 @@ namespace crepe {
class Camera;
class Sprite;
class Transform;
-
+class Text;
/**
* \brief Manages rendering operations for all game objects.
*
@@ -50,7 +50,13 @@ private:
* \return true if particles have been rendered
*/
bool render_particle(const Sprite & sprite, const double & scale);
-
+ /**
+ * \brief Renders all Text components
+ *
+ * \param text The text component to be rendered.
+ * \param tm the Transform component that holds the position,rotation and scale
+ */
+ void render_text(Text & text, const Transform & tm);
/**
* \brief renders a sprite with a Transform component on the screen
*
diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt
index 187ed46..f62414e 100644
--- a/src/example/CMakeLists.txt
+++ b/src/example/CMakeLists.txt
@@ -19,4 +19,6 @@ endfunction()
add_example(rendering_particle)
add_example(game)
add_example(button)
+add_example(loadfont)
+add_example(FontExample)
add_example(AITest)
diff --git a/src/example/FontExample.cpp b/src/example/FontExample.cpp
new file mode 100644
index 0000000..6a334b1
--- /dev/null
+++ b/src/example/FontExample.cpp
@@ -0,0 +1,55 @@
+#include <SDL2/SDL_ttf.h>
+#include <chrono>
+#include <crepe/api/Camera.h>
+#include <crepe/api/Config.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/LoopManager.h>
+#include <crepe/api/Scene.h>
+#include <crepe/api/Script.h>
+#include <crepe/api/Text.h>
+#include <crepe/facade/Font.h>
+#include <crepe/facade/SDLContext.h>
+#include <crepe/manager/EventManager.h>
+#include <crepe/manager/Mediator.h>
+#include <crepe/manager/ResourceManager.h>
+#include <exception>
+#include <iostream>
+#include <memory>
+using namespace crepe;
+using namespace std;
+using namespace std::chrono;
+class TestScript : public Script {
+public:
+ steady_clock::time_point start_time;
+ virtual void init() override { start_time = steady_clock::now(); }
+ virtual void update() override {
+ auto now = steady_clock::now();
+ auto elapsed = duration_cast<seconds>(now - start_time).count();
+
+ if (elapsed >= 5) {
+ Mediator & med = mediator;
+ EventManager & event_mgr = med.event_manager;
+ event_mgr.trigger_event<ShutDownEvent>();
+ }
+ }
+};
+class TestScene : public Scene {
+public:
+ void load_scene() override {
+ GameObject text_object = this->new_object("test", "test", vec2{0, 0}, 0, 1);
+ text_object.add_component<Text>(vec2(100, 100), vec2(0, 0), "OpenSymbol",
+ Text::Data{});
+ text_object.add_component<BehaviorScript>().set_script<TestScript>();
+ text_object.add_component<Camera>(ivec2{300, 300}, vec2{100, 100}, Camera::Data{});
+ }
+ std::string get_name() const override { return "hey"; }
+};
+int main() {
+ // Config& config = Config::get_instance();
+ // config.log.level = Log::Level::TRACE;
+ LoopManager engine;
+ engine.add_scene<TestScene>();
+ engine.start();
+
+ return 0;
+}
diff --git a/src/example/button.cpp b/src/example/button.cpp
index 00bdc28..4220588 100644
--- a/src/example/button.cpp
+++ b/src/example/button.cpp
@@ -1,52 +1,39 @@
#include <SDL2/SDL_timer.h>
#include <chrono>
#include <crepe/Component.h>
-#include <crepe/ComponentManager.h>
#include <crepe/api/Animator.h>
#include <crepe/api/Button.h>
#include <crepe/api/Camera.h>
#include <crepe/api/Color.h>
-#include <crepe/api/EventManager.h>
#include <crepe/api/GameObject.h>
#include <crepe/api/Sprite.h>
#include <crepe/api/Texture.h>
#include <crepe/api/Transform.h>
+#include <crepe/facade/SDLContext.h>
+#include <crepe/manager/ComponentManager.h>
+#include <crepe/manager/EventManager.h>
#include <crepe/system/AnimatorSystem.h>
#include <crepe/system/InputSystem.h>
#include <crepe/system/RenderSystem.h>
#include <crepe/types.h>
-#include <iostream>
using namespace crepe;
using namespace std;
int main(int argc, char * argv[]) {
- ComponentManager mgr;
- RenderSystem sys{mgr};
- EventManager & event_mgr = EventManager::get_instance();
- InputSystem input_sys{mgr};
- AnimatorSystem asys{mgr};
- GameObject camera_obj = mgr.new_object("", "", vec2{1000, 1000}, 0, 1);
- camera_obj.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f);
-
- GameObject button_obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);
- auto s2 = Texture("asset/texture/test_ap43.png");
- bool button_clicked = false;
- auto & sprite2 = button_obj.add_component<Sprite>(
- s2, Color::GREEN, Sprite::FlipSettings{false, false}, 2, 1, 100);
- std::function<void()> on_click = [&]() { std::cout << "button clicked" << std::endl; };
- std::function<void()> on_enter = [&]() { std::cout << "enter" << std::endl; };
- std::function<void()> on_exit = [&]() { std::cout << "exit" << std::endl; };
- auto & button
- = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false);
- button.on_mouse_enter = on_enter;
- button.on_mouse_exit = on_exit;
- button.is_toggle = true;
- button.active = true;
+ Mediator mediator;
+ ComponentManager mgr{mediator};
+ RenderSystem sys{mediator};
+ EventManager event_mgr{mediator};
+ InputSystem input_sys{mediator};
+ SDLContext sdl_context{mediator};
+ GameObject obj = mgr.new_object("camera", "camera", vec2{0, 0}, 0, 1);
+ auto & camera = obj.add_component<Camera>(
+ ivec2{500, 500}, vec2{500, 500}, Camera::Data{.bg_color = Color::WHITE, .zoom = 1.0f});
auto start = std::chrono::steady_clock::now();
while (true) {
+ const keyboard_state_t & keyboard_state = sdl_context.get_keyboard_state();
input_sys.update();
sys.update();
- asys.update();
event_mgr.dispatch_events();
SDL_Delay(30);
}
diff --git a/src/example/loadfont.cpp b/src/example/loadfont.cpp
new file mode 100644
index 0000000..e459332
--- /dev/null
+++ b/src/example/loadfont.cpp
@@ -0,0 +1,49 @@
+#include <SDL2/SDL_ttf.h>
+#include <crepe/api/Asset.h>
+#include <crepe/api/Text.h>
+#include <crepe/facade/Font.h>
+#include <crepe/facade/FontFacade.h>
+#include <crepe/facade/SDLContext.h>
+#include <crepe/manager/Mediator.h>
+#include <crepe/manager/ResourceManager.h>
+#include <exception>
+#include <iostream>
+#include <memory>
+#include <optional>
+using namespace crepe;
+int main() {
+
+ // SDLFontContext font_facade;
+ Mediator mediator;
+ FontFacade font_facade{};
+ SDLContext sdl_context{mediator};
+ // ComponentManager component_manager{mediator};
+ ResourceManager resource_manager{mediator};
+ try {
+ // Correct way to create a unique pointer for Text
+ std::unique_ptr<Text> label = std::make_unique<Text>(
+ 1, vec2(100, 100), vec2(0, 0), "OpenSymbol", Text::Data{}, "test text");
+ // std::cout << "Path: " << label->font.get_path() << std::endl;
+ Asset asset1 = font_facade.get_font_asset("OpenSymbol");
+ std::cout << asset1.get_path() << std::endl;
+ std::unique_ptr<Text> label2 = std::make_unique<Text>(
+ 1, vec2(100, 100), vec2(0, 0), "fsaafdafsdafsdafsdasfdds", Text::Data{});
+ Asset asset = Asset("test test");
+ label->font.emplace(asset);
+ std::cout << label->font.value().get_path() << std::endl;
+ // label2->font = std::make_optional(asset);
+ // std::cout << "Path: " << label2->font.get_path() << std::endl;
+ ResourceManager & resource_mgr = mediator.resource_manager;
+ const Font & res = resource_manager.get<Font>(label->font.value());
+ // TTF_Font * test_font = res.get_font();
+ // if (test_font == NULL) {
+ // std::cout << "error with font" << std::endl;
+ // } else {
+ // std::cout << "correct font retrieved" << std::endl;
+ // }
+ } catch (const std::exception & e) {
+ std::cout << "Standard exception thrown: " << e.what() << std::endl;
+ }
+
+ return 0;
+}
diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp
index 82272b5..f8be3fe 100644
--- a/src/test/EventTest.cpp
+++ b/src/test/EventTest.cpp
@@ -48,15 +48,14 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) {
EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) {
triggered = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false;
};
event_mgr.subscribe<MouseClickEvent>(mouse_handler, EventManager::CHANNEL_ALL);
- MouseClickEvent click_event{
- .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE};
+ MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};
event_mgr.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL);
EXPECT_TRUE(triggered);
@@ -66,15 +65,14 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_one_channel) {
int test_channel = 1;
EventHandler<MouseClickEvent> mouse_handler = [&](const MouseClickEvent & e) {
triggered = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false;
};
event_mgr.subscribe<MouseClickEvent>(mouse_handler, test_channel);
- MouseClickEvent click_event{
- .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE};
+ MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};
event_mgr.trigger_event<MouseClickEvent>(click_event, EventManager::CHANNEL_ALL);
EXPECT_FALSE(triggered);
@@ -90,23 +88,22 @@ TEST_F(EventManagerTest, EventManagerTest_callback_propagation) {
// Handlers
EventHandler<MouseClickEvent> mouse_handler_true = [&](const MouseClickEvent & e) {
triggered_true = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return true; // Stops propagation
};
EventHandler<MouseClickEvent> mouse_handler_false = [&](const MouseClickEvent & e) {
triggered_false = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
// Test event
- MouseClickEvent click_event{
- .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE};
+ MouseClickEvent click_event{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE};
event_mgr.subscribe<MouseClickEvent>(mouse_handler_true, EventManager::CHANNEL_ALL);
event_mgr.subscribe<MouseClickEvent>(mouse_handler_false, EventManager::CHANNEL_ALL);
@@ -138,15 +135,15 @@ TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) {
int test_channel = 1;
EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent & e) {
triggered1 = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent & e) {
triggered2 = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
@@ -154,9 +151,9 @@ TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) {
event_mgr.subscribe<MouseClickEvent>(mouse_handler2, test_channel);
event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE});
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});
event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE},
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE},
test_channel);
event_mgr.dispatch_events();
EXPECT_TRUE(triggered1);
@@ -172,16 +169,16 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
// Define EventHandlers
EventHandler<MouseClickEvent> mouse_handler1 = [&](const MouseClickEvent & e) {
triggered1 = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
EventHandler<MouseClickEvent> mouse_handler2 = [&](const MouseClickEvent & e) {
triggered2 = true;
- EXPECT_EQ(e.mouse_x, 100);
- EXPECT_EQ(e.mouse_y, 200);
+ EXPECT_EQ(e.mouse_pos.x, 100);
+ EXPECT_EQ(e.mouse_pos.y, 200);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false; // Allows propagation
};
@@ -191,7 +188,7 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
// Queue events
event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE});
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});
// Dispatch events - both handlers should be triggered
event_mgr.dispatch_events();
@@ -207,7 +204,7 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
// Queue the same event again
event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE});
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});
// Dispatch events - only handler 2 should be triggered, handler 1 should NOT
event_mgr.dispatch_events();
@@ -222,7 +219,7 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) {
// Queue the event again
event_mgr.queue_event<MouseClickEvent>(
- MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE});
+ MouseClickEvent{.mouse_pos = {100, 200}, .button = MouseButton::LEFT_MOUSE});
// Dispatch events - no handler should be triggered
event_mgr.dispatch_events();
diff --git a/src/test/InputTest.cpp b/src/test/InputTest.cpp
index 8b40cea..2d844d4 100644
--- a/src/test/InputTest.cpp
+++ b/src/test/InputTest.cpp
@@ -1,7 +1,11 @@
-#include "system/RenderSystem.h"
#include <gtest/gtest.h>
+
+#include <crepe/manager/ResourceManager.h>
+#include <crepe/system/RenderSystem.h>
+
#define protected public
#define private public
+
#include "api/KeyCodes.h"
#include "manager/ComponentManager.h"
#include "manager/EventManager.h"
@@ -15,6 +19,7 @@
#include <crepe/api/Metadata.h>
#include <crepe/api/Transform.h>
#include <crepe/api/Vector2.h>
+#include <crepe/facade/SDLContext.h>
#include <gmock/gmock.h>
using namespace std;
@@ -28,6 +33,7 @@ public:
SDLContext sdl_context{mediator};
InputSystem input_system{mediator};
+ ResourceManager resman{mediator};
RenderSystem render{mediator};
EventManager event_manager{mediator};
//GameObject camera;
@@ -43,7 +49,7 @@ protected:
//mediator.component_manager = mgr;
//event_manager.clear();
}
-
+ void TearDown() override {}
void simulate_mouse_click(int mouse_x, int mouse_y, Uint8 mouse_button) {
SDL_Event event;
@@ -70,8 +76,8 @@ TEST_F(InputTest, MouseDown) {
EventHandler<MousePressEvent> on_mouse_down = [&](const MousePressEvent & event) {
mouse_triggered = true;
//middle of the screen = 0,0
- EXPECT_EQ(event.mouse_x, 0);
- EXPECT_EQ(event.mouse_y, 0);
+ EXPECT_EQ(event.mouse_pos.x, 0);
+ EXPECT_EQ(event.mouse_pos.y, 0);
EXPECT_EQ(event.button, MouseButton::LEFT_MOUSE);
return false;
};
@@ -95,8 +101,8 @@ TEST_F(InputTest, MouseUp) {
bool function_triggered = false;
EventHandler<MouseReleaseEvent> on_mouse_release = [&](const MouseReleaseEvent & e) {
function_triggered = true;
- EXPECT_EQ(e.mouse_x, 0);
- EXPECT_EQ(e.mouse_y, 0);
+ EXPECT_EQ(e.mouse_pos.x, 0);
+ EXPECT_EQ(e.mouse_pos.y, 0);
EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE);
return false;
};
@@ -119,10 +125,10 @@ TEST_F(InputTest, MouseMove) {
bool function_triggered = false;
EventHandler<MouseMoveEvent> on_mouse_move = [&](const MouseMoveEvent & e) {
function_triggered = true;
- EXPECT_EQ(e.mouse_x, 0);
- EXPECT_EQ(e.mouse_y, 0);
- EXPECT_EQ(e.delta_x, 10);
- EXPECT_EQ(e.delta_y, 10);
+ EXPECT_EQ(e.mouse_pos.x, 0);
+ EXPECT_EQ(e.mouse_pos.y, 0);
+ EXPECT_EQ(e.mouse_delta.x, 10);
+ EXPECT_EQ(e.mouse_delta.y, 10);
return false;
};
event_manager.subscribe<MouseMoveEvent>(on_mouse_move);
@@ -193,8 +199,8 @@ TEST_F(InputTest, MouseClick) {
EventHandler<MouseClickEvent> on_mouse_click = [&](const MouseClickEvent & event) {
on_click_triggered = true;
EXPECT_EQ(event.button, MouseButton::LEFT_MOUSE);
- EXPECT_EQ(event.mouse_x, 0);
- EXPECT_EQ(event.mouse_y, 0);
+ EXPECT_EQ(event.mouse_pos.x, 0);
+ EXPECT_EQ(event.mouse_pos.y, 0);
return false;
};
event_manager.subscribe<MouseClickEvent>(on_mouse_click);
@@ -209,14 +215,10 @@ TEST_F(InputTest, testButtonClick) {
GameObject button_obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);
bool button_clicked = false;
std::function<void()> on_click = [&]() { button_clicked = true; };
- auto & button
- = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false);
+ auto & button = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click);
bool hover = false;
button.active = true;
-
- button.is_pressed = false;
- button.is_toggle = false;
this->simulate_mouse_click(999, 999, SDL_BUTTON_LEFT);
input_system.update();
event_manager.dispatch_events();
@@ -232,11 +234,8 @@ TEST_F(InputTest, testButtonHover) {
GameObject button_obj = mgr.new_object("body", "person", vec2{0, 0}, 0, 1);
bool button_clicked = false;
std::function<void()> on_click = [&]() { button_clicked = true; };
- auto & button
- = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click, false);
+ auto & button = button_obj.add_component<Button>(vec2{100, 100}, vec2{0, 0}, on_click);
button.active = true;
- button.is_pressed = false;
- button.is_toggle = false;
// Mouse not on button
SDL_Event event;