Compare commits
2 Commits
2feb486f20
...
d4c91450d9
| Author | SHA1 | Date |
|---|---|---|
|
|
d4c91450d9 | |
|
|
b8bd56392c |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
|
|
@ -7,13 +7,11 @@ module;
|
|||
export module core.engine;
|
||||
|
||||
import config;
|
||||
import core.renderer;
|
||||
import core.render_server;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace core
|
||||
{
|
||||
using Window = sdl::Window;
|
||||
|
||||
class Engine
|
||||
{
|
||||
// Whether this class is currently instantiated (to prevent multiple instances)
|
||||
|
|
@ -22,13 +20,13 @@ export namespace core
|
|||
// If this is set to false, the application will exit
|
||||
bool keep_running_ = true;
|
||||
|
||||
Window window_;
|
||||
Renderer renderer_;
|
||||
sdl::Window window_;
|
||||
RenderServer render_server_;
|
||||
|
||||
// Private constructor
|
||||
Engine(Window&& window, Renderer&& renderer)
|
||||
Engine(sdl::Window&& window, sdl::Renderer&& renderer)
|
||||
: window_{std::move(window)},
|
||||
renderer_{std::move(renderer)}
|
||||
render_server_{std::move(renderer)}
|
||||
{
|
||||
instantiated_ = true;
|
||||
}
|
||||
|
|
@ -62,7 +60,7 @@ export namespace core
|
|||
return std::unique_ptr<Engine>{
|
||||
new Engine{
|
||||
std::move(sdl_window),
|
||||
Renderer{std::move(sdl_renderer)}
|
||||
std::move(sdl_renderer)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -72,20 +70,20 @@ export namespace core
|
|||
return keep_running_;
|
||||
}
|
||||
|
||||
Window& get_window()
|
||||
sdl::Window& get_window()
|
||||
{
|
||||
return window_;
|
||||
}
|
||||
|
||||
Renderer& get_renderer()
|
||||
RenderServer& get_render_server()
|
||||
{
|
||||
return renderer_;
|
||||
return render_server_;
|
||||
}
|
||||
|
||||
// Handles an SDL event. Returns true if the event has been handled.
|
||||
bool handle_event(const sdl::Event* event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
if (event->type == sdl::EventType::Quit) {
|
||||
// Exit the application
|
||||
keep_running_ = false;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
module;
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
export module core.render_server;
|
||||
|
||||
import core.resource_manager;
|
||||
import core.texture_loader;
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace core
|
||||
{
|
||||
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)},
|
||||
texture_loader_{renderer_},
|
||||
texture_manager_{texture_loader_}
|
||||
{}
|
||||
|
||||
// No copy or move operations
|
||||
RenderServer(const RenderServer&) = delete;
|
||||
RenderServer& operator=(const RenderServer&) = delete;
|
||||
RenderServer(RenderServer&&) = delete;
|
||||
RenderServer& operator=(RenderServer&&) = delete;
|
||||
|
||||
~RenderServer() = default;
|
||||
|
||||
constexpr sdl::Renderer& get_renderer()
|
||||
{
|
||||
return renderer_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a texture from a file (if not loaded yet) and returns its texture ID.
|
||||
*/
|
||||
constexpr TextureID load_texture(const std::string& filename)
|
||||
{
|
||||
return texture_manager_.load_resource_by_name(filename);
|
||||
}
|
||||
|
||||
void start_frame() const
|
||||
{
|
||||
renderer_.clear();
|
||||
}
|
||||
|
||||
void finish_frame() const
|
||||
{
|
||||
renderer_.present();
|
||||
}
|
||||
|
||||
constexpr void render_texture(
|
||||
const TextureID texture_id,
|
||||
const sdl::FRect* src_rect,
|
||||
const sdl::FRect* dest_rect
|
||||
) const
|
||||
{
|
||||
render_texture(texture_manager_.get_resource(texture_id), src_rect, dest_rect);
|
||||
}
|
||||
|
||||
void render_texture(
|
||||
const sdl::Texture& texture,
|
||||
const sdl::FRect* src_rect,
|
||||
const sdl::FRect* dest_rect
|
||||
) const
|
||||
{
|
||||
renderer_.render_texture(texture, src_rect, dest_rect);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
module;
|
||||
|
||||
#include <utility>
|
||||
|
||||
export module core.renderer;
|
||||
|
||||
import wrappers.sdl;
|
||||
|
||||
export namespace core
|
||||
{
|
||||
// TODO: Rename this class to RenderServer or something to distinguish it from sdl::Renderer?
|
||||
class Renderer
|
||||
{
|
||||
sdl::Renderer sdl_renderer_;
|
||||
|
||||
public:
|
||||
Renderer() = delete;
|
||||
|
||||
explicit Renderer(sdl::Renderer&& sdl_renderer)
|
||||
: sdl_renderer_{std::move(sdl_renderer)}
|
||||
{}
|
||||
|
||||
constexpr sdl::Renderer& get_sdl_renderer()
|
||||
{
|
||||
return sdl_renderer_;
|
||||
}
|
||||
|
||||
void start_frame() const
|
||||
{
|
||||
sdl_renderer_.clear();
|
||||
}
|
||||
|
||||
void finish_frame() const
|
||||
{
|
||||
sdl_renderer_.present();
|
||||
}
|
||||
|
||||
void render_texture(
|
||||
const sdl::Texture& texture,
|
||||
const sdl::FRect* src_rect,
|
||||
const sdl::FRect* dest_rect
|
||||
) const
|
||||
{
|
||||
sdl_renderer_.render_texture(texture, src_rect, dest_rect);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
module;
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
export module core.resource_manager;
|
||||
|
||||
export namespace core
|
||||
{
|
||||
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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
module;
|
||||
|
||||
#include <string>
|
||||
|
||||
export module core.texture_loader;
|
||||
|
||||
import core.resource_manager;
|
||||
import wrappers.sdl;
|
||||
import wrappers.sdl_image;
|
||||
|
||||
export namespace core
|
||||
{
|
||||
class TextureLoader
|
||||
{
|
||||
sdl::Renderer& renderer_;
|
||||
|
||||
public:
|
||||
explicit TextureLoader(sdl::Renderer& renderer)
|
||||
: renderer_{renderer}
|
||||
{}
|
||||
|
||||
// No copy or move operations (reference)
|
||||
TextureLoader(const TextureLoader&) = delete;
|
||||
TextureLoader& operator=(const TextureLoader&) = delete;
|
||||
TextureLoader(TextureLoader&&) = delete;
|
||||
TextureLoader& operator=(TextureLoader&&) = delete;
|
||||
|
||||
~TextureLoader() = default;
|
||||
|
||||
sdl::Texture load_resource(const std::string& filename) const
|
||||
{
|
||||
return sdl_image::LoadTexture(renderer_, filename);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -2,12 +2,13 @@ module;
|
|||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
export module game.game;
|
||||
|
||||
import core.engine;
|
||||
import core.renderer;
|
||||
import core.render_server;
|
||||
import game.sprite;
|
||||
import wrappers.sdl;
|
||||
import wrappers.sdl_image;
|
||||
|
|
@ -22,21 +23,18 @@ export namespace game
|
|||
// Reference to the engine
|
||||
core::Engine& engine_;
|
||||
|
||||
// Sprite for testing
|
||||
std::unique_ptr<Sprite> sprite_{nullptr};
|
||||
// Sprites for testing
|
||||
Sprite player_sprite_;
|
||||
std::vector<Sprite> sprites_;
|
||||
|
||||
// Private constructor
|
||||
explicit Game(core::Engine& engine)
|
||||
: engine_(engine)
|
||||
{
|
||||
// TODO: Texture should be a reference/pointer to an object managed by a ResourceManager or similar.
|
||||
auto texture = sdl_image::LoadTexture(
|
||||
engine_.get_renderer().get_sdl_renderer(),
|
||||
"assets/neocat.png"
|
||||
);
|
||||
|
||||
sprite_ = std::make_unique<Sprite>(std::move(texture), 100, 100);
|
||||
: engine_(engine),
|
||||
player_sprite_{
|
||||
engine_.get_render_server().load_texture("assets/neocat.png"),
|
||||
sdl::FRect{0, 0, 100, 100}
|
||||
}
|
||||
{}
|
||||
|
||||
public:
|
||||
Game() = delete;
|
||||
|
|
@ -62,15 +60,28 @@ export namespace game
|
|||
}
|
||||
|
||||
// Handles an SDL event. Returns true if the event has been handled.
|
||||
bool handle_event(const sdl::Event* event) const
|
||||
bool handle_event(const sdl::Event* event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_MOUSE_MOTION) {
|
||||
sprite_->move(
|
||||
if (event->type == sdl::EventType::MouseMotion) {
|
||||
player_sprite_.move(
|
||||
event->motion.x - 50,
|
||||
event->motion.y - 50
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event->type == sdl::EventType::MouseButtonUp) {
|
||||
sprites_.emplace_back(
|
||||
engine_.get_render_server().load_texture("assets/neofox.png"),
|
||||
sdl::FRect{
|
||||
event->motion.x - 50,
|
||||
event->motion.y - 50,
|
||||
100, 100
|
||||
}
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -80,10 +91,15 @@ export namespace game
|
|||
|
||||
void render() const
|
||||
{
|
||||
const auto& renderer = engine_.get_renderer();
|
||||
renderer.start_frame();
|
||||
sprite_->draw(renderer);
|
||||
renderer.finish_frame();
|
||||
const auto& render_server = engine_.get_render_server();
|
||||
render_server.start_frame();
|
||||
|
||||
for (const Sprite& sprite : sprites_) {
|
||||
sprite.draw(render_server);
|
||||
}
|
||||
player_sprite_.draw(render_server);
|
||||
|
||||
render_server.finish_frame();
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
module;
|
||||
|
||||
#include <utility>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
export module game.sprite;
|
||||
|
||||
import core.renderer;
|
||||
import core.render_server;
|
||||
import wrappers.sdl;
|
||||
|
||||
// TODO: Move this to a different namespace (core, drawing, ...?)
|
||||
|
|
@ -13,21 +12,14 @@ export namespace game
|
|||
{
|
||||
class Sprite
|
||||
{
|
||||
// TODO: Texture should be a reference/pointer to an object managed by a ResourceManager or similar.
|
||||
sdl::Texture texture_;
|
||||
core::TextureID texture_id_;
|
||||
sdl::FRect dest_rect_{0, 0, 0, 0};
|
||||
|
||||
public:
|
||||
explicit Sprite(
|
||||
sdl::Texture&& texture,
|
||||
const int width,
|
||||
const int height
|
||||
)
|
||||
: texture_{std::move(texture)}
|
||||
{
|
||||
dest_rect_.w = static_cast<float>(width);
|
||||
dest_rect_.h = static_cast<float>(height);
|
||||
}
|
||||
explicit Sprite(const core::TextureID texture_id, const sdl::FRect dest_rect)
|
||||
: texture_id_{texture_id},
|
||||
dest_rect_{dest_rect}
|
||||
{}
|
||||
|
||||
void move(const float x, const float y)
|
||||
{
|
||||
|
|
@ -35,9 +27,9 @@ export namespace game
|
|||
dest_rect_.y = y;
|
||||
}
|
||||
|
||||
void draw(const core::Renderer& renderer) const
|
||||
void draw(const core::RenderServer& render_server) const
|
||||
{
|
||||
renderer.render_texture(texture_, nullptr, &dest_rect_);
|
||||
render_server.render_texture(texture_id_, nullptr, &dest_rect_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,4 +8,23 @@ export namespace sdl
|
|||
{
|
||||
// Simple alias for SDL_Event union
|
||||
using Event = SDL_Event;
|
||||
|
||||
// Alias for EventType enum
|
||||
using EventType_t = SDL_EventType;
|
||||
|
||||
/**
|
||||
* Wrapper for the SDL_EventType enum.
|
||||
*
|
||||
* We're using a namespace here to emulate an enum-like interface, without having to copy the entire enum.
|
||||
* More constants can be added on demand.
|
||||
*/
|
||||
namespace EventType
|
||||
{
|
||||
constexpr EventType_t Quit = SDL_EVENT_QUIT;
|
||||
constexpr EventType_t KeyDown = SDL_EVENT_KEY_DOWN;
|
||||
constexpr EventType_t KeyUp = SDL_EVENT_KEY_UP;
|
||||
constexpr EventType_t MouseMotion = SDL_EVENT_MOUSE_MOTION;
|
||||
constexpr EventType_t MouseButtonUp = SDL_EVENT_MOUSE_BUTTON_UP;
|
||||
constexpr EventType_t MouseButtonDown = SDL_EVENT_MOUSE_BUTTON_DOWN;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue