Compare commits
No commits in common. "b4635cdb99a144bf8fdd95c6c6d81706ff44275b" and "eb98beac4327b84ece6228c0d37f10d3df504677" have entirely different histories.
b4635cdb99
...
eb98beac43
18 changed files with 232 additions and 434 deletions
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"texture": "terrain.png",
|
||||
"tile_size": 32,
|
||||
"tiles": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 3,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ defaults:
|
|||
-Wall
|
||||
-Wextra
|
||||
-pedantic
|
||||
-Ivendor/nlohmann_json/include
|
||||
-Ivendor/RmlUi/Include
|
||||
linker_args: >-
|
||||
-lSDL3
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
module;
|
||||
|
||||
export module rutile.core.common;
|
||||
|
||||
import std;
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
// Alias for shared_ptr to be used for shared resource pointers (see ResourceServer)
|
||||
template <typename T>
|
||||
using ResourcePtr = std::shared_ptr<T>;
|
||||
}
|
||||
|
|
@ -5,17 +5,15 @@ module;
|
|||
export module rutile.core.drawing.sprite;
|
||||
|
||||
import std;
|
||||
import rutile.core.common;
|
||||
import rutile.core.render_server;
|
||||
import rutile.core.resources.texture;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
class Sprite
|
||||
{
|
||||
// Shared pointer to a texture (managed by ResourceServer)
|
||||
ResourcePtr<Texture> texture_ptr_;
|
||||
// Texture ID (managed by TextureManager in RenderServer)
|
||||
TextureID texture_id_;
|
||||
|
||||
// Texture source boundaries: which part of the texture to render
|
||||
sdl::FRect texture_boundaries_;
|
||||
|
|
@ -32,13 +30,13 @@ export namespace rutile
|
|||
|
||||
public:
|
||||
explicit Sprite(
|
||||
const ResourcePtr<Texture>& texture_ptr,
|
||||
const TextureID texture_id,
|
||||
const sdl::FRect texture_boundaries,
|
||||
const sdl::FPoint position,
|
||||
const sdl::FPoint texture_offset = {0, 0},
|
||||
const sdl::FPoint texture_scale = {1, 1}
|
||||
)
|
||||
: texture_ptr_{texture_ptr},
|
||||
: texture_id_{texture_id},
|
||||
texture_boundaries_{texture_boundaries},
|
||||
texture_offset_{texture_offset},
|
||||
texture_scale_{texture_scale},
|
||||
|
|
@ -48,16 +46,20 @@ export namespace rutile
|
|||
}
|
||||
|
||||
static Sprite create_from_texture(
|
||||
const ResourcePtr<Texture>& texture_ptr,
|
||||
RenderServer& render_server,
|
||||
const std::string& filename,
|
||||
std::optional<sdl::FRect> texture_boundaries,
|
||||
auto... args
|
||||
)
|
||||
{
|
||||
const TextureID texture_id = render_server.load_texture(filename);
|
||||
|
||||
if (!texture_boundaries.has_value()) {
|
||||
texture_boundaries = texture_ptr->get_boundaries();
|
||||
const sdl::Texture& texture = render_server.get_texture(texture_id);
|
||||
texture_boundaries = texture.get_boundaries();
|
||||
}
|
||||
|
||||
return Sprite(texture_ptr, texture_boundaries.value(), args...);
|
||||
return Sprite(texture_id, texture_boundaries.value(), args...);
|
||||
}
|
||||
|
||||
void set_position(const sdl::FPoint new_position)
|
||||
|
|
@ -74,7 +76,7 @@ export namespace rutile
|
|||
texture_scale_.y * texture_boundaries_.h,
|
||||
};
|
||||
|
||||
render_server.render_texture(*texture_ptr_, &texture_boundaries_, &dest_rect);
|
||||
render_server.render_texture(texture_id_, &texture_boundaries_, &dest_rect);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ module;
|
|||
export module rutile.core.drawing.tile_map;
|
||||
|
||||
import std;
|
||||
import rutile.core.common;
|
||||
import rutile.core.drawing.tile_set;
|
||||
import rutile.core.render_server;
|
||||
import rutile.core.resources.tile_set;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace rutile
|
||||
|
|
@ -17,8 +16,10 @@ export namespace rutile
|
|||
|
||||
class TileMap
|
||||
{
|
||||
// Shared pointer to a tile set (managed by ResourceServer)
|
||||
ResourcePtr<TileSet> tile_set_ptr_;
|
||||
// Tile set ID
|
||||
// TODO: Needed later when we centralize tile set management using a ResourceManager
|
||||
[[maybe_unused]]
|
||||
TileSetID tile_set_id_;
|
||||
|
||||
// Tile size
|
||||
int tile_size_;
|
||||
|
|
@ -35,16 +36,16 @@ export namespace rutile
|
|||
|
||||
public:
|
||||
explicit TileMap(
|
||||
const ResourcePtr<TileSet>& tile_set_ptr,
|
||||
const TileSetID tile_set_id,
|
||||
const int tile_size,
|
||||
const MapCoord width,
|
||||
const MapCoord height,
|
||||
const sdl::FPoint position = {0, 0}
|
||||
)
|
||||
: tile_set_ptr_{tile_set_ptr},
|
||||
tile_size_{tile_size},
|
||||
width_{width},
|
||||
height_{height},
|
||||
: tile_set_id_(tile_set_id),
|
||||
tile_size_(tile_size),
|
||||
width_(width),
|
||||
height_(height),
|
||||
position_{position}
|
||||
{
|
||||
// TODO: This maybe shouldn't be an assert...
|
||||
|
|
@ -71,9 +72,11 @@ export namespace rutile
|
|||
tiles_[map_coords_to_index(x, y)] = tile_id;
|
||||
}
|
||||
|
||||
void draw(const RenderServer& render_server) const
|
||||
// TODO: Should we get the TileSet from the RenderServer, similar to how we get textures?
|
||||
void draw(const RenderServer& render_server, const TileSet& tile_set) const
|
||||
{
|
||||
const TileSet& tile_set = *tile_set_ptr_;
|
||||
// Get tile set texture
|
||||
const sdl::Texture& tile_set_texture = render_server.get_texture(tile_set.get_texture_id());
|
||||
|
||||
// TODO: Implement more efficiently (we could just iterate over tiles_ directly)
|
||||
for (MapCoord y = 0; y < height_; y++) {
|
||||
|
|
@ -94,7 +97,7 @@ export namespace rutile
|
|||
};
|
||||
|
||||
render_server.render_texture(
|
||||
tile_set.get_texture(),
|
||||
tile_set_texture,
|
||||
&tile_atlas_src_rect,
|
||||
&tile_dest_rect
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ module;
|
|||
|
||||
#include <cassert>
|
||||
|
||||
export module rutile.core.resources.tile_set;
|
||||
export module rutile.core.drawing.tile_set;
|
||||
|
||||
import std;
|
||||
import rutile.core.common;
|
||||
import rutile.core.resources.texture;
|
||||
import rutile.core.render_server;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace rutile
|
||||
|
|
@ -21,8 +20,8 @@ export namespace rutile
|
|||
|
||||
class TileSet
|
||||
{
|
||||
// Shared pointer to the tileset atlas texture (managed by ResourceServer)
|
||||
ResourcePtr<Texture> texture_ptr_;
|
||||
// Texture ID of tileset atlas texture
|
||||
TextureID texture_id_;
|
||||
|
||||
// Size of each tile in pixels
|
||||
// TODO: Do we need this?
|
||||
|
|
@ -36,23 +35,27 @@ export namespace rutile
|
|||
TileSet() = delete;
|
||||
|
||||
explicit TileSet(
|
||||
const ResourcePtr<Texture>& texture_ptr,
|
||||
const TextureID texture_id,
|
||||
std::vector<TileDefinition> tile_definitions
|
||||
)
|
||||
: texture_ptr_{texture_ptr},
|
||||
: texture_id_{texture_id},
|
||||
tile_definitions_{std::move(tile_definitions)}
|
||||
{}
|
||||
|
||||
static TileSet create_from_texture(
|
||||
const ResourcePtr<Texture>& texture_ptr,
|
||||
RenderServer& render_server,
|
||||
const std::string& filename,
|
||||
const int tile_size,
|
||||
const std::vector<sdl::Point>& tile_atlas_coords
|
||||
)
|
||||
{
|
||||
const TextureID texture_id = render_server.load_texture(filename);
|
||||
const sdl::Texture& texture = render_server.get_texture(texture_id);
|
||||
|
||||
assert(tile_size > 0);
|
||||
// TODO: These probably shouldn't be asserts...
|
||||
assert(texture_ptr->get_width() % tile_size == 0);
|
||||
assert(texture_ptr->get_height() % tile_size == 0);
|
||||
assert(texture.get_width() % tile_size == 0);
|
||||
assert(texture.get_height() % tile_size == 0);
|
||||
|
||||
std::vector<TileDefinition> tile_definitions;
|
||||
|
||||
|
|
@ -68,17 +71,17 @@ export namespace rutile
|
|||
};
|
||||
|
||||
// TODO: These probably shouldn't be asserts...
|
||||
assert(tile.atlas_src_rect.x + tile.atlas_src_rect.w <= texture_ptr->get_width());
|
||||
assert(tile.atlas_src_rect.y + tile.atlas_src_rect.h <= texture_ptr->get_height());
|
||||
assert(tile.atlas_src_rect.x + tile.atlas_src_rect.w <= texture.get_width());
|
||||
assert(tile.atlas_src_rect.y + tile.atlas_src_rect.h <= texture.get_height());
|
||||
tile_definitions.push_back(tile);
|
||||
}
|
||||
|
||||
return TileSet(texture_ptr, tile_definitions);
|
||||
return TileSet(texture_id, tile_definitions);
|
||||
}
|
||||
|
||||
constexpr const Texture& get_texture() const
|
||||
constexpr TextureID get_texture_id() const
|
||||
{
|
||||
return *texture_ptr_;
|
||||
return texture_id_;
|
||||
}
|
||||
|
||||
constexpr const TileDefinition& get_tile_definition(const TileID tile_id) const
|
||||
|
|
@ -7,7 +7,6 @@ export module rutile.core.engine;
|
|||
import std;
|
||||
import rutile.config;
|
||||
import rutile.core.render_server;
|
||||
import rutile.core.resource_server;
|
||||
import rutile.core.ui.ui_server;
|
||||
import wrappers.sdl;
|
||||
|
||||
|
|
@ -23,14 +22,12 @@ export namespace rutile
|
|||
|
||||
sdl::Window window_;
|
||||
RenderServer render_server_;
|
||||
ResourceServer resource_server_;
|
||||
UIServer ui_server_;
|
||||
|
||||
// Private constructor
|
||||
Engine(sdl::Window&& window, sdl::Renderer&& renderer)
|
||||
: window_{std::move(window)},
|
||||
render_server_{std::move(renderer)},
|
||||
resource_server_{render_server_.get_renderer()},
|
||||
ui_server_{render_server_.get_renderer(), window_}
|
||||
{
|
||||
instantiated_ = true;
|
||||
|
|
@ -87,11 +84,6 @@ export namespace rutile
|
|||
return render_server_;
|
||||
}
|
||||
|
||||
ResourceServer& get_resource_server()
|
||||
{
|
||||
return resource_server_;
|
||||
}
|
||||
|
||||
UIServer& get_ui_server()
|
||||
{
|
||||
return ui_server_;
|
||||
|
|
|
|||
|
|
@ -3,21 +3,28 @@ module;
|
|||
export module rutile.core.render_server;
|
||||
|
||||
import std;
|
||||
import rutile.core.resource_server;
|
||||
import rutile.core.resources.texture;
|
||||
import rutile.core.resource_manager;
|
||||
import rutile.core.texture_loader;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
using TextureID = unsigned int;
|
||||
using TextureManager = ResourceManager<TextureID, sdl::Texture, TextureLoader>;
|
||||
|
||||
class RenderServer
|
||||
{
|
||||
sdl::Renderer renderer_;
|
||||
TextureLoader texture_loader_;
|
||||
TextureManager texture_manager_;
|
||||
|
||||
public:
|
||||
RenderServer() = delete;
|
||||
|
||||
explicit RenderServer(sdl::Renderer&& renderer)
|
||||
: renderer_{std::move(renderer)}
|
||||
: renderer_{std::move(renderer)},
|
||||
texture_loader_{renderer_},
|
||||
texture_manager_{texture_loader_}
|
||||
{
|
||||
renderer_.set_vsync(1);
|
||||
}
|
||||
|
|
@ -35,6 +42,22 @@ export namespace rutile
|
|||
return renderer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a texture from a file (if not loaded yet) and return its texture ID.
|
||||
*/
|
||||
constexpr TextureID load_texture(const std::string& filename)
|
||||
{
|
||||
return texture_manager_.load_resource_by_name(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to a texture by its texture ID.
|
||||
*/
|
||||
constexpr const sdl::Texture& get_texture(const TextureID texture_id) const
|
||||
{
|
||||
return texture_manager_.get_resource(texture_id);
|
||||
}
|
||||
|
||||
void start_frame() const
|
||||
{
|
||||
renderer_.clear();
|
||||
|
|
@ -45,8 +68,17 @@ export namespace rutile
|
|||
renderer_.present();
|
||||
}
|
||||
|
||||
void render_texture(
|
||||
const TextureID texture_id,
|
||||
const sdl::FRect* src_rect,
|
||||
const sdl::FRect* dest_rect
|
||||
) const
|
||||
{
|
||||
render_texture(get_texture(texture_id), src_rect, dest_rect);
|
||||
}
|
||||
|
||||
constexpr void render_texture(
|
||||
const Texture& texture,
|
||||
const sdl::Texture& texture,
|
||||
const sdl::FRect* src_rect,
|
||||
const sdl::FRect* dest_rect
|
||||
) const
|
||||
|
|
|
|||
120
src/rutile/core/resource_manager.cppm
Normal file
120
src/rutile/core/resource_manager.cppm
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
module;
|
||||
|
||||
#include <cassert>
|
||||
|
||||
export module rutile.core.resource_manager;
|
||||
|
||||
import std;
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
template <typename ResourceLoaderType, typename ResourceType>
|
||||
concept IsResourceLoader = requires(ResourceLoaderType loader, const std::string& name)
|
||||
{
|
||||
{ loader.load_resource(name) } -> std::same_as<ResourceType>;
|
||||
};
|
||||
|
||||
template <
|
||||
typename ResourceIDType,
|
||||
typename ResourceType,
|
||||
IsResourceLoader<ResourceType> ResourceLoaderType
|
||||
>
|
||||
class ResourceManager
|
||||
{
|
||||
// Resource loader
|
||||
ResourceLoaderType& resource_loader_;
|
||||
|
||||
// Registry of loaded resources, array index is resource ID
|
||||
std::vector<ResourceType> resource_registry_;
|
||||
|
||||
// Mapping of all loaded resources from (file) name to resource ID
|
||||
std::map<std::string, ResourceIDType> resource_name_map_;
|
||||
|
||||
public:
|
||||
ResourceManager() = delete;
|
||||
|
||||
explicit ResourceManager(ResourceLoaderType& resource_loader)
|
||||
: resource_loader_{resource_loader}
|
||||
{}
|
||||
|
||||
// No copy or move operations
|
||||
ResourceManager(const ResourceManager&) = delete;
|
||||
ResourceManager& operator=(const ResourceManager&) = delete;
|
||||
ResourceManager(ResourceManager&&) = delete;
|
||||
ResourceManager& operator=(ResourceManager&&) = delete;
|
||||
|
||||
~ResourceManager() = default;
|
||||
|
||||
/**
|
||||
* Adds a new resource to the registry and returns its ID.
|
||||
*/
|
||||
ResourceIDType add_resource(ResourceType&& resource)
|
||||
{
|
||||
// Add resource to end of vector
|
||||
resource_registry_.push_back(std::move(resource));
|
||||
|
||||
// Return the index of the newly added resource
|
||||
return static_cast<ResourceIDType>(resource_registry_.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new resource to the registry, associates the name with it and returns its ID.
|
||||
*/
|
||||
ResourceIDType add_resource(ResourceType&& resource, const std::string& name)
|
||||
{
|
||||
// Add resource
|
||||
ResourceIDType resource_id = add_resource(std::move(resource));
|
||||
|
||||
// Associate name with resource ID for future access
|
||||
resource_name_map_.emplace(name, resource_id);
|
||||
|
||||
return resource_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource ID for a given resource name, or `std::nullopt` if the resource was not found.
|
||||
*/
|
||||
std::optional<ResourceIDType> get_resource_id_by_name(const std::string& name) const
|
||||
{
|
||||
// Check if resource is already loaded
|
||||
if (
|
||||
const auto search = resource_name_map_.find(name);
|
||||
search != resource_name_map_.end()
|
||||
) {
|
||||
// Return resource ID
|
||||
return search->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a resource (e.g. from a file) and adds it to the registry if it isn't loaded yet.
|
||||
* Returns the resource ID.
|
||||
*/
|
||||
ResourceIDType load_resource_by_name(const std::string& name)
|
||||
{
|
||||
// Check if resource is already loaded
|
||||
if (
|
||||
auto resource_id = get_resource_id_by_name(name);
|
||||
resource_id.has_value()
|
||||
) {
|
||||
return resource_id.value();
|
||||
}
|
||||
|
||||
// Load resource and add it to the registry
|
||||
return add_resource(resource_loader_.load_resource(name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the resource with the given ID.
|
||||
* The reference is not guaranteed to be valid after adding new resources to the registry.
|
||||
* Assumes that the resource ID is valid.
|
||||
*/
|
||||
const ResourceType& get_resource(const ResourceIDType resource_id) const
|
||||
{
|
||||
assert(resource_id < resource_registry_.size());
|
||||
return resource_registry_[resource_id];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
module;
|
||||
|
||||
export module rutile.core.resource_server;
|
||||
|
||||
import std;
|
||||
import rutile.core.common;
|
||||
import rutile.core.resources.resource_registry;
|
||||
import rutile.core.resources.texture;
|
||||
import rutile.core.resources.tile_set;
|
||||
import rutile.core.resources.loaders.texture_loader;
|
||||
import rutile.core.resources.loaders.tile_set_loader;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
using TextureRegistry = ResourceRegistry<TextureID, Texture>;
|
||||
using TileSetRegistry = ResourceRegistry<TileSetID, TileSet>;
|
||||
|
||||
class ResourceServer
|
||||
{
|
||||
// Resource registries
|
||||
TextureRegistry texture_registry_;
|
||||
TileSetRegistry tile_set_registry_;
|
||||
|
||||
// Resource loaders
|
||||
TextureLoader texture_loader_;
|
||||
TileSetLoader tile_set_loader_;
|
||||
|
||||
public:
|
||||
ResourceServer() = delete;
|
||||
|
||||
explicit ResourceServer(sdl::Renderer& renderer)
|
||||
: texture_loader_{renderer},
|
||||
tile_set_loader_{std::bind(&ResourceServer::load_texture, this, std::placeholders::_1)}
|
||||
{}
|
||||
|
||||
// No copy or move operations
|
||||
ResourceServer(const ResourceServer&) = delete;
|
||||
ResourceServer& operator=(const ResourceServer&) = delete;
|
||||
ResourceServer(ResourceServer&&) = delete;
|
||||
ResourceServer& operator=(ResourceServer&&) = delete;
|
||||
|
||||
~ResourceServer() = default;
|
||||
|
||||
/**
|
||||
* Load a texture from a file (if not loaded yet) and return a reference to a shared Texture pointer.
|
||||
*/
|
||||
const ResourcePtr<Texture>& load_texture(const std::string& filename)
|
||||
{
|
||||
return texture_registry_.load_and_get_resource(filename, texture_loader_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a tile set from a JSON file (if not loaded yet) and return a reference to a shared TileSet pointer.
|
||||
*/
|
||||
const ResourcePtr<TileSet>& load_tile_set(const std::string& filename)
|
||||
{
|
||||
return tile_set_registry_.load_and_get_resource(filename, tile_set_loader_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
module;
|
||||
|
||||
export module rutile.core.resources.loaders.tile_set_loader;
|
||||
|
||||
import std;
|
||||
import rutile.core.common;
|
||||
import rutile.core.resources.texture;
|
||||
import rutile.core.resources.tile_set;
|
||||
import wrappers.sdl;
|
||||
import vendor.nlohmann.json;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace rutile
|
||||
{
|
||||
using TextureLoadCallbackFunc = std::function<
|
||||
const ResourcePtr<Texture>&(const std::string&)
|
||||
>;
|
||||
}
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
class TileSetLoader
|
||||
{
|
||||
TextureLoadCallbackFunc texture_load_callback_;
|
||||
|
||||
public:
|
||||
explicit TileSetLoader(const TextureLoadCallbackFunc& texture_load_callback)
|
||||
: texture_load_callback_{texture_load_callback}
|
||||
{}
|
||||
|
||||
// No copy or move operations (reference)
|
||||
TileSetLoader(const TileSetLoader&) = delete;
|
||||
TileSetLoader& operator=(const TileSetLoader&) = delete;
|
||||
TileSetLoader(TileSetLoader&&) = delete;
|
||||
TileSetLoader& operator=(TileSetLoader&&) = delete;
|
||||
|
||||
~TileSetLoader() = default;
|
||||
|
||||
TileSet load_resource(const std::string& name) const
|
||||
{
|
||||
try {
|
||||
std::ifstream json_file(name);
|
||||
json data = json::parse(json_file);
|
||||
|
||||
// Texture path is relative to JSON file
|
||||
fs::path texture_path = fs::path(name).replace_filename(data.at("texture"));
|
||||
|
||||
std::vector<sdl::Point> tile_atlas_coords;
|
||||
for (auto tile : data.at("tiles")) {
|
||||
tile_atlas_coords.push_back({tile.at("x"), tile.at("y")});
|
||||
}
|
||||
|
||||
return TileSet::create_from_texture(
|
||||
texture_load_callback_(texture_path),
|
||||
data.at("tile_size"),
|
||||
tile_atlas_coords
|
||||
);
|
||||
}
|
||||
catch (const json::exception& e) {
|
||||
throw std::runtime_error(
|
||||
std::format("Error loading tile set from \"{}\": {}", name, e.what())
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
module;
|
||||
|
||||
#include <cassert>
|
||||
|
||||
export module rutile.core.resources.resource_registry;
|
||||
|
||||
import std;
|
||||
import rutile.core.common;
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
template <typename ResourceLoaderType, typename ResourceType>
|
||||
concept IsResourceLoader = requires(ResourceLoaderType loader, const std::string& name)
|
||||
{
|
||||
{ loader.load_resource(name) } -> std::same_as<ResourceType>;
|
||||
};
|
||||
|
||||
template <typename ResourceIDType, typename ResourceType>
|
||||
class ResourceRegistry
|
||||
{
|
||||
// Vector containing all currently loaded resources as shared pointers; array index is resource ID
|
||||
std::vector<ResourcePtr<ResourceType>> resources_;
|
||||
|
||||
// Mapping of all loaded resources from name (e.g. file name) to resource ID
|
||||
std::map<std::string, ResourceIDType> resource_name_map_;
|
||||
|
||||
public:
|
||||
ResourceRegistry() = default;
|
||||
|
||||
// No copy or move operations
|
||||
ResourceRegistry(const ResourceRegistry&) = delete;
|
||||
ResourceRegistry& operator=(const ResourceRegistry&) = delete;
|
||||
ResourceRegistry(ResourceRegistry&&) = delete;
|
||||
ResourceRegistry& operator=(ResourceRegistry&&) = delete;
|
||||
|
||||
~ResourceRegistry() = default;
|
||||
|
||||
/**
|
||||
* Return a reference to a shared pointer of the resource with the given ID.
|
||||
*
|
||||
* The reference is not guaranteed to be valid after adding new resources to the registry. Copy the
|
||||
* reference into a new shared_ptr if you want to keep using it.
|
||||
*
|
||||
* Assumes that the resource ID is valid (debug assertions only).
|
||||
*/
|
||||
const ResourcePtr<ResourceType>& get_resource_by_id(const ResourceIDType resource_id) const
|
||||
{
|
||||
assert(resource_id < resources_.size());
|
||||
assert(resources_[resource_id].use_count() > 0);
|
||||
return resources_[resource_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the resource ID for a given resource name, or return `std::nullopt` if the resource was not found.
|
||||
*/
|
||||
std::optional<ResourceIDType> find_resource_id_by_name(const std::string& name) const
|
||||
{
|
||||
// Check if resource is already loaded
|
||||
const auto search = resource_name_map_.find(name);
|
||||
if (search != resource_name_map_.end()) {
|
||||
// Return resource ID
|
||||
return search->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new resource (without a name) to the registry and return its ID.
|
||||
*/
|
||||
ResourceIDType add_resource(ResourceType&& resource)
|
||||
{
|
||||
// Add resource to end of vector, moving the resource object into a shared_ptr
|
||||
resources_.push_back(
|
||||
std::make_shared<ResourceType>(std::move(resource))
|
||||
);
|
||||
|
||||
// Return the index of the newly added resource
|
||||
return static_cast<ResourceIDType>(resources_.size() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new named resource to the registry, associate the name with it and return its ID.
|
||||
*/
|
||||
ResourceIDType add_resource(ResourceType&& resource, const std::string& name)
|
||||
{
|
||||
// Add resource
|
||||
ResourceIDType resource_id = add_resource(std::move(resource));
|
||||
|
||||
// Associate name with resource ID for future access
|
||||
resource_name_map_.emplace(name, resource_id);
|
||||
|
||||
return resource_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a resource by (file) name using the given resource loader and add it to the registry, unless the
|
||||
* resource is already loaded.
|
||||
* Return the resource ID (in both cases).
|
||||
*/
|
||||
template <IsResourceLoader<ResourceType> ResourceLoaderType>
|
||||
ResourceIDType load_resource(const std::string& name, ResourceLoaderType& resource_loader)
|
||||
{
|
||||
// Check if resource is already loaded
|
||||
auto resource_id = find_resource_id_by_name(name);
|
||||
if (resource_id.has_value()) {
|
||||
return resource_id.value();
|
||||
}
|
||||
|
||||
// Load resource and add it to the registry
|
||||
return add_resource(resource_loader.load_resource(name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a resource if it's not loaded yet (like `load_resource()`), then return a reference to a shared
|
||||
* pointer to the resource (like `get_resource_by_id()`).
|
||||
*/
|
||||
template <IsResourceLoader<ResourceType> ResourceLoaderType>
|
||||
const ResourcePtr<ResourceType>& load_and_get_resource(
|
||||
const std::string& name,
|
||||
ResourceLoaderType& resource_loader
|
||||
)
|
||||
{
|
||||
ResourceIDType resource_id = load_resource(name, resource_loader);
|
||||
return get_resource_by_id(resource_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
module;
|
||||
|
||||
export module rutile.core.resources.texture;
|
||||
|
||||
import std;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace rutile
|
||||
{
|
||||
using TextureID = unsigned int;
|
||||
using Texture = sdl::Texture;
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
module;
|
||||
|
||||
export module rutile.core.resources.loaders.texture_loader;
|
||||
export module rutile.core.texture_loader;
|
||||
|
||||
import std;
|
||||
import rutile.core.resources.texture;
|
||||
import rutile.core.resource_manager;
|
||||
import wrappers.sdl;
|
||||
import wrappers.sdl_image;
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ export namespace rutile
|
|||
|
||||
~TextureLoader() = default;
|
||||
|
||||
Texture load_resource(const std::string& filename) const
|
||||
sdl::Texture load_resource(const std::string& filename) const
|
||||
{
|
||||
return sdl_image::load_texture(renderer_, filename);
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ export module rutile.game.game;
|
|||
import std;
|
||||
import rutile.core.drawing.sprite;
|
||||
import rutile.core.drawing.tile_map;
|
||||
import rutile.core.drawing.tile_set;
|
||||
import rutile.core.engine;
|
||||
import rutile.core.render_server;
|
||||
import wrappers.rmlui.core;
|
||||
|
|
@ -23,9 +24,12 @@ export namespace rutile
|
|||
// Reference to the engine
|
||||
Engine& engine_;
|
||||
|
||||
// Sprites and stuff for testing
|
||||
// Sprites for testing
|
||||
Sprite player_sprite_;
|
||||
std::vector<Sprite> sprites_;
|
||||
|
||||
// Tile set and tile map (TODO: tile set should be moved to resource manager in engine)
|
||||
TileSet tile_set_;
|
||||
TileMap tile_map_;
|
||||
|
||||
// Private constructor
|
||||
|
|
@ -33,16 +37,30 @@ export namespace rutile
|
|||
: engine_(engine),
|
||||
player_sprite_{
|
||||
Sprite::create_from_texture(
|
||||
engine_.get_resource_server().load_texture("assets/sprites/neocat_64.png"),
|
||||
engine_.get_render_server(),
|
||||
"assets/sprites/neocat_64.png",
|
||||
std::nullopt,
|
||||
sdl::FPoint{0, 0},
|
||||
sdl::FPoint{-32, -32}
|
||||
)
|
||||
},
|
||||
tile_map_{
|
||||
engine_.get_resource_server().load_tile_set("assets/tilesets/terrain.json"),
|
||||
32, 16, 12, {50, 50}
|
||||
tile_set_{
|
||||
TileSet::create_from_texture(
|
||||
engine_.get_render_server(),
|
||||
"assets/tilesets/terrain.png",
|
||||
32,
|
||||
{
|
||||
// Tile 0: No tile
|
||||
{0, 0},
|
||||
// Tile 1: Actual first tile in the texture
|
||||
{0, 0},
|
||||
{1, 0},
|
||||
{2, 0},
|
||||
{3, 0},
|
||||
}
|
||||
)
|
||||
},
|
||||
tile_map_(0, 32, 16, 12, {50, 50})
|
||||
{
|
||||
// Initialize UI
|
||||
const auto& ui_server = engine_.get_ui_server();
|
||||
|
|
@ -95,7 +113,8 @@ export namespace rutile
|
|||
if (event.type == sdl::EventTypes::MouseButtonUp) {
|
||||
sprites_.push_back(
|
||||
Sprite::create_from_texture(
|
||||
engine_.get_resource_server().load_texture("assets/sprites/neofox_64.png"),
|
||||
engine_.get_render_server(),
|
||||
"assets/sprites/neofox_64.png",
|
||||
std::nullopt,
|
||||
sdl::FPoint{event.motion.x, event.motion.y},
|
||||
sdl::FPoint{-32, -32}
|
||||
|
|
@ -119,7 +138,7 @@ export namespace rutile
|
|||
render_server.start_frame();
|
||||
|
||||
// Render tilemap
|
||||
tile_map_.draw(render_server);
|
||||
tile_map_.draw(render_server, tile_set_);
|
||||
|
||||
// Render sprites
|
||||
for (const Sprite& sprite : sprites_) {
|
||||
|
|
|
|||
51
src/vendor/nlohmann/json.cppm
vendored
51
src/vendor/nlohmann/json.cppm
vendored
|
|
@ -1,51 +0,0 @@
|
|||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0 (develop branch)
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
module;
|
||||
|
||||
// GCC workaround for C++ modules support.
|
||||
// When using C++20 modules, some compilers (particularly GCC) may have issues
|
||||
// with template instantiations in the module preamble. If you encounter
|
||||
// "redefinition" errors when including nlohmann/json.hpp, try one of:
|
||||
// 1. Include nlohmann/json.hpp in your module preamble BEFORE other #includes
|
||||
// 2. Or use: import nlohmann.json; instead of #include <nlohmann/json.hpp>
|
||||
// 3. Or upgrade to a newer GCC version with better modules support.
|
||||
// See: https://github.com/nlohmann/json/issues/5103
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
// NOTE: Module renamed from nlohmann.json to match directory structure
|
||||
export module vendor.nlohmann.json;
|
||||
|
||||
export NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
using NLOHMANN_JSON_NAMESPACE::adl_serializer;
|
||||
using NLOHMANN_JSON_NAMESPACE::basic_json;
|
||||
using NLOHMANN_JSON_NAMESPACE::json;
|
||||
using NLOHMANN_JSON_NAMESPACE::json_pointer;
|
||||
using NLOHMANN_JSON_NAMESPACE::ordered_json;
|
||||
using NLOHMANN_JSON_NAMESPACE::ordered_map;
|
||||
using NLOHMANN_JSON_NAMESPACE::to_string;
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
inline namespace json_literals
|
||||
{
|
||||
using NLOHMANN_JSON_NAMESPACE::literals::json_literals::operator""_json;
|
||||
using NLOHMANN_JSON_NAMESPACE::literals::json_literals::operator""_json_pointer;
|
||||
} // namespace json_literals
|
||||
} // namespace literals
|
||||
|
||||
// Note: the following nlohmann::detail symbols must be exported due to
|
||||
// an MSVC bug failing to compile without these symbols visible (ticket #3970)
|
||||
namespace detail
|
||||
{
|
||||
using NLOHMANN_JSON_NAMESPACE::detail::json_sax_dom_callback_parser;
|
||||
using NLOHMANN_JSON_NAMESPACE::detail::unknown_size;
|
||||
} // namespace detail
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
|
@ -56,8 +56,7 @@ export namespace sdl
|
|||
*/
|
||||
std::pair<int, int> get_size() const
|
||||
{
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int width, height;
|
||||
|
||||
if (!SDL_GetWindowSize(get_raw(), &width, &height)) {
|
||||
throw SDLException("SDL_GetWindowSize");
|
||||
|
|
|
|||
13
vendor/README.md
vendored
13
vendor/README.md
vendored
|
|
@ -10,19 +10,6 @@ For now, SDL3 and SDL3_image need to be installed on the system. They should be
|
|||
Same for freetype, which is required by RmlUi.
|
||||
|
||||
|
||||
## nlohmann::json
|
||||
|
||||
[JSON for Modern C++](https://github.com/nlohmann/json).
|
||||
|
||||
Within the `vendor` directory, run:
|
||||
|
||||
```shell
|
||||
# We're using the default branch (develop) here because the latest release does not support C++20 modules yet.
|
||||
# (Last commit known working: 484483aca)
|
||||
git clone git@github.com:nlohmann/json.git nlohmann_json
|
||||
```
|
||||
|
||||
|
||||
## RmlUi
|
||||
|
||||
[RmlUi](https://github.com/mikke89/RmlUi) is a UI library.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue