diff --git a/.gitignore b/.gitignore
index 51269c9..e92ae95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,7 @@ __pycache__/
/build
/build.ninja
/shuriken.override.yaml
+
+# Dependencies
+/vendor
+!/vendor/README.md
diff --git a/assets/fonts/LatoLatin-Regular.ttf b/assets/fonts/LatoLatin-Regular.ttf
new file mode 100644
index 0000000..bcc5778
Binary files /dev/null and b/assets/fonts/LatoLatin-Regular.ttf differ
diff --git a/assets/ui/base.rcss b/assets/ui/base.rcss
new file mode 100644
index 0000000..b325039
--- /dev/null
+++ b/assets/ui/base.rcss
@@ -0,0 +1,88 @@
+/* Base style sheet based on: https://mikke89.github.io/RmlUiDoc/pages/rml/html4_style_sheet.html */
+
+body, div, h1, h2, h3, h4, h5, h6, p, hr, pre {
+ display: block;
+}
+
+h1 {
+ font-size: 2em;
+ margin: .67em 0;
+}
+
+h2 {
+ font-size: 1.5em;
+ margin: .75em 0;
+}
+
+h3 {
+ font-size: 1.17em;
+ margin: .83em 0;
+}
+
+h4 {
+ margin: 1.12em 0;
+}
+
+h5 {
+ font-size: .83em;
+ margin: 1.5em 0;
+}
+
+h6 {
+ font-size: .75em;
+ margin: 1.67em 0;
+}
+
+h1, h2, h3, h4, h5, h6, strong {
+ font-weight: bold;
+}
+
+em {
+ font-style: italic;
+}
+
+pre {
+ white-space: pre;
+}
+
+hr {
+ border-width: 1px;
+}
+
+table {
+ box-sizing: border-box;
+ display: table;
+}
+
+tr {
+ box-sizing: border-box;
+ display: table-row;
+}
+
+td {
+ box-sizing: border-box;
+ display: table-cell;
+}
+
+col {
+ box-sizing: border-box;
+ display: table-column;
+}
+
+colgroup {
+ display: table-column-group;
+}
+
+thead, tbody, tfoot {
+ display: table-row-group;
+}
+
+tabset tabs {
+ display: block;
+}
+
+input {
+ background-color: white;
+ color: black;
+ cursor: text;
+}
diff --git a/assets/ui/main_ui.rml b/assets/ui/main_ui.rml
new file mode 100644
index 0000000..9dc12f1
--- /dev/null
+++ b/assets/ui/main_ui.rml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ Meow!
+
+
diff --git a/shuriken.yaml b/shuriken.yaml
index 5983465..0a07b3f 100644
--- a/shuriken.yaml
+++ b/shuriken.yaml
@@ -1,7 +1,18 @@
defaults:
cpp_standard: c++23
- cpp_flags: -Wall -Wextra -Werror -pedantic
- linker_args: -lSDL3 -lSDL3_image
+ cpp_flags: >-
+ -Wall
+ -Wextra
+ -pedantic
+ -Ivendor/RmlUi/Include
+ linker_args: >-
+ -lSDL3
+ -lSDL3_image
+ -lfreetype
+ vendor/RmlUi/Build/librmlui_debugger.a
+ vendor/RmlUi/Build/librmlui.a
+
+enable_import_std: true
default_target: linux
diff --git a/src/main.cpp b/src/main.cpp
index 4a0a4fc..a6e0353 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,30 +1,30 @@
-import app;
+import rutile.app;
#define SDL_MAIN_USE_CALLBACKS
#include
SDL_AppResult SDL_AppInit(void** appstate, const int /*argc*/, char** /*argv*/)
{
- auto* app = new App;
+ auto* app = new rutile::App;
*appstate = app;
return static_cast(app->initialize());
}
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
- auto* app = static_cast(appstate);
- return static_cast(app->handle_event(event));
+ auto* app = static_cast(appstate);
+ return static_cast(app->handle_event(*event));
}
SDL_AppResult SDL_AppIterate(void* appstate)
{
- auto* app = static_cast(appstate);
+ auto* app = static_cast(appstate);
return static_cast(app->iterate());
}
void SDL_AppQuit(void* appstate, const SDL_AppResult /*result*/)
{
- const auto* app = static_cast(appstate);
+ const auto* app = static_cast(appstate);
app->shutdown();
delete app;
}
diff --git a/src/app.cppm b/src/rutile/app.cppm
similarity index 59%
rename from src/app.cppm
rename to src/rutile/app.cppm
index 7b59948..37deff0 100644
--- a/src/app.cppm
+++ b/src/rutile/app.cppm
@@ -1,22 +1,21 @@
module;
-#include
-#include
-#include
+#include
-export module app;
+export module rutile.app;
-import config;
-import core.engine;
-import game.game;
+import std;
+import rutile.config;
+import rutile.core.engine;
+import rutile.game.game;
import wrappers.sdl;
-export
+export namespace rutile
{
class App
{
- std::unique_ptr engine_{nullptr};
- std::unique_ptr game_{nullptr};
+ std::unique_ptr engine_{nullptr};
+ std::unique_ptr game_{nullptr};
public:
App() = default;
@@ -25,20 +24,20 @@ export
{
try {
// Set SDL application metadata
- sdl::SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, config::app_name);
- sdl::SetAppMetadataProperty(SDL_PROP_APP_METADATA_VERSION_STRING, config::app_version);
- sdl::SetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, config::app_identifier);
- sdl::SetAppMetadataProperty(SDL_PROP_APP_METADATA_CREATOR_STRING, config::app_creator);
- sdl::SetAppMetadataProperty(SDL_PROP_APP_METADATA_COPYRIGHT_STRING, config::app_copyright);
- sdl::SetAppMetadataProperty(SDL_PROP_APP_METADATA_URL_STRING, config::app_url);
- sdl::SetAppMetadataProperty(SDL_PROP_APP_METADATA_TYPE_STRING, "game");
+ sdl::set_app_metadata_property(SDL_PROP_APP_METADATA_NAME_STRING, config::app_name);
+ sdl::set_app_metadata_property(SDL_PROP_APP_METADATA_VERSION_STRING, config::app_version);
+ sdl::set_app_metadata_property(SDL_PROP_APP_METADATA_IDENTIFIER_STRING, config::app_identifier);
+ sdl::set_app_metadata_property(SDL_PROP_APP_METADATA_CREATOR_STRING, config::app_creator);
+ sdl::set_app_metadata_property(SDL_PROP_APP_METADATA_COPYRIGHT_STRING, config::app_copyright);
+ sdl::set_app_metadata_property(SDL_PROP_APP_METADATA_URL_STRING, config::app_url);
+ sdl::set_app_metadata_property(SDL_PROP_APP_METADATA_TYPE_STRING, "game");
// Initialize SDL subsystems
- sdl::Init(sdl::InitFlags::Video | sdl::InitFlags::Events);
+ sdl::initialize_sdl(sdl::InitFlags::Video | sdl::InitFlags::Events);
// Create engine (includes window and renderer) and game state
- engine_ = core::Engine::create();
- game_ = game::Game::create(*engine_);
+ engine_ = Engine::create();
+ game_ = Game::create(*engine_);
}
catch (const std::runtime_error& e) {
std::cerr << "Unhandled exception during initialization: " << e.what() << '\n';
@@ -48,7 +47,7 @@ export
return sdl::AppResult::Continue;
}
- sdl::AppResult handle_event(const sdl::Event* event)
+ sdl::AppResult handle_event(const sdl::Event& event)
{
try {
if (!engine_->handle_event(event)) {
diff --git a/src/config.cppm b/src/rutile/config.cppm
similarity index 91%
rename from src/config.cppm
rename to src/rutile/config.cppm
index 0ed9a38..2e36783 100644
--- a/src/config.cppm
+++ b/src/rutile/config.cppm
@@ -1,16 +1,16 @@
module;
-#include
-
#ifdef NDEBUG
#define DEBUG_BOOL false
#else
#define DEBUG_BOOL true
#endif
-export module config;
+export module rutile.config;
-export namespace config
+import std;
+
+export namespace rutile::config
{
constexpr auto debug = DEBUG_BOOL;
diff --git a/src/core/drawing/sprite.cppm b/src/rutile/core/drawing/sprite.cppm
similarity index 95%
rename from src/core/drawing/sprite.cppm
rename to src/rutile/core/drawing/sprite.cppm
index 31224cd..1158bde 100644
--- a/src/core/drawing/sprite.cppm
+++ b/src/rutile/core/drawing/sprite.cppm
@@ -1,15 +1,14 @@
module;
#include
-#include
-#include
-export module core.drawing.sprite;
+export module rutile.core.drawing.sprite;
-import core.render_server;
+import std;
+import rutile.core.render_server;
import wrappers.sdl;
-export namespace core
+export namespace rutile
{
class Sprite
{
diff --git a/src/core/drawing/tile_map.cppm b/src/rutile/core/drawing/tile_map.cppm
similarity index 94%
rename from src/core/drawing/tile_map.cppm
rename to src/rutile/core/drawing/tile_map.cppm
index 31bfbfa..de66b2c 100644
--- a/src/core/drawing/tile_map.cppm
+++ b/src/rutile/core/drawing/tile_map.cppm
@@ -1,19 +1,18 @@
module;
#include
-#include
-#include
-export module core.drawing.tile_map;
+export module rutile.core.drawing.tile_map;
-import core.drawing.tile_set;
-import core.render_server;
+import std;
+import rutile.core.drawing.tile_set;
+import rutile.core.render_server;
import wrappers.sdl;
-export namespace core
+export namespace rutile
{
// Restrict map size to 16 bit per dimension, so that width*height still fits within size_t
- using MapCoord = uint16_t;
+ using MapCoord = std::uint16_t;
class TileMap
{
diff --git a/src/core/drawing/tile_set.cppm b/src/rutile/core/drawing/tile_set.cppm
similarity index 95%
rename from src/core/drawing/tile_set.cppm
rename to src/rutile/core/drawing/tile_set.cppm
index 39ba81d..ddad86c 100644
--- a/src/core/drawing/tile_set.cppm
+++ b/src/rutile/core/drawing/tile_set.cppm
@@ -1,16 +1,14 @@
module;
#include
-#include
-#include
-#include
-export module core.drawing.tile_set;
+export module rutile.core.drawing.tile_set;
-import core.render_server;
+import std;
+import rutile.core.render_server;
import wrappers.sdl;
-export namespace core
+export namespace rutile
{
using TileSetID = unsigned int;
using TileID = unsigned int;
diff --git a/src/core/engine.cppm b/src/rutile/core/engine.cppm
similarity index 73%
rename from src/core/engine.cppm
rename to src/rutile/core/engine.cppm
index d9bd5ad..984f323 100644
--- a/src/core/engine.cppm
+++ b/src/rutile/core/engine.cppm
@@ -1,15 +1,16 @@
module;
#include
-#include
-export module core.engine;
+export module rutile.core.engine;
-import config;
-import core.render_server;
+import std;
+import rutile.config;
+import rutile.core.render_server;
+import rutile.core.ui.ui_server;
import wrappers.sdl;
-export namespace core
+export namespace rutile
{
class Engine
{
@@ -21,11 +22,13 @@ export namespace core
sdl::Window window_;
RenderServer render_server_;
+ UIServer ui_server_;
// Private constructor
Engine(sdl::Window&& window, sdl::Renderer&& renderer)
: window_{std::move(window)},
- render_server_{std::move(renderer)}
+ render_server_{std::move(renderer)},
+ ui_server_{render_server_.get_renderer(), window_}
{
instantiated_ = true;
}
@@ -49,19 +52,21 @@ export namespace core
// Prevent the class from being instantiated multiple times
assert(!instantiated_);
- auto [sdl_window, sdl_renderer] = sdl::CreateWindowAndRenderer(
+ auto [sdl_window, sdl_renderer] = sdl::create_window_and_renderer(
config::get_window_title(),
config::window_width,
config::window_height,
0
);
+ // NOLINTBEGIN: "Allocated memory is leaked"
return std::unique_ptr{
new Engine{
std::move(sdl_window),
std::move(sdl_renderer)
}
};
+ // NOLINTEND
}
bool keep_running() const
@@ -79,15 +84,24 @@ export namespace core
return render_server_;
}
- // Handles an SDL event. Returns true if the event has been handled.
- bool handle_event(const sdl::Event* event)
+ UIServer& get_ui_server()
{
- if (event->type == sdl::EventType::Quit) {
+ return ui_server_;
+ }
+
+ // Handles an SDL event. Returns true if the event has been handled.
+ bool handle_event(const sdl::Event& event)
+ {
+ if (event.type == sdl::EventTypes::Quit) {
// Exit the application
keep_running_ = false;
return true;
}
+ if (ui_server_.handle_event(event)) {
+ return true;
+ }
+
return false;
}
diff --git a/src/core/render_server.cppm b/src/rutile/core/render_server.cppm
similarity index 91%
rename from src/core/render_server.cppm
rename to src/rutile/core/render_server.cppm
index bcb4c9f..7366b13 100644
--- a/src/core/render_server.cppm
+++ b/src/rutile/core/render_server.cppm
@@ -1,15 +1,13 @@
module;
-#include
-#include
+export module rutile.core.render_server;
-export module core.render_server;
-
-import core.resource_manager;
-import core.texture_loader;
+import std;
+import rutile.core.resource_manager;
+import rutile.core.texture_loader;
import wrappers.sdl;
-export namespace core
+export namespace rutile
{
using TextureID = unsigned int;
using TextureManager = ResourceManager;
@@ -27,7 +25,9 @@ export namespace core
: renderer_{std::move(renderer)},
texture_loader_{renderer_},
texture_manager_{texture_loader_}
- {}
+ {
+ renderer_.set_vsync(1);
+ }
// No copy or move operations
RenderServer(const RenderServer&) = delete;
diff --git a/src/core/resource_manager.cppm b/src/rutile/core/resource_manager.cppm
similarity index 96%
rename from src/core/resource_manager.cppm
rename to src/rutile/core/resource_manager.cppm
index 2e947f5..b73f184 100644
--- a/src/core/resource_manager.cppm
+++ b/src/rutile/core/resource_manager.cppm
@@ -1,14 +1,12 @@
module;
#include
-#include