Compare commits
2 Commits
e37eb0b03f
...
2feb486f20
| Author | SHA1 | Date |
|---|---|---|
|
|
2feb486f20 | |
|
|
772f4b665a |
|
|
@ -7,13 +7,11 @@ module;
|
||||||
export module core.engine;
|
export module core.engine;
|
||||||
|
|
||||||
import config;
|
import config;
|
||||||
import core.renderer;
|
import core.render_server;
|
||||||
import wrappers.sdl;
|
import wrappers.sdl;
|
||||||
|
|
||||||
export namespace core
|
export namespace core
|
||||||
{
|
{
|
||||||
using Window = sdl::Window;
|
|
||||||
|
|
||||||
class Engine
|
class Engine
|
||||||
{
|
{
|
||||||
// Whether this class is currently instantiated (to prevent multiple instances)
|
// 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
|
// If this is set to false, the application will exit
|
||||||
bool keep_running_ = true;
|
bool keep_running_ = true;
|
||||||
|
|
||||||
Window window_;
|
sdl::Window window_;
|
||||||
Renderer renderer_;
|
RenderServer render_server_;
|
||||||
|
|
||||||
// Private constructor
|
// Private constructor
|
||||||
Engine(Window&& window, Renderer&& renderer)
|
Engine(sdl::Window&& window, sdl::Renderer&& renderer)
|
||||||
: window_{std::move(window)},
|
: window_{std::move(window)},
|
||||||
renderer_{std::move(renderer)}
|
render_server_{std::move(renderer)}
|
||||||
{
|
{
|
||||||
instantiated_ = true;
|
instantiated_ = true;
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +60,7 @@ export namespace core
|
||||||
return std::unique_ptr<Engine>{
|
return std::unique_ptr<Engine>{
|
||||||
new Engine{
|
new Engine{
|
||||||
std::move(sdl_window),
|
std::move(sdl_window),
|
||||||
Renderer{std::move(sdl_renderer)}
|
std::move(sdl_renderer)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -72,20 +70,20 @@ export namespace core
|
||||||
return keep_running_;
|
return keep_running_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Window& get_window()
|
sdl::Window& get_window()
|
||||||
{
|
{
|
||||||
return 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.
|
// Handles an SDL event. Returns true if the event has been handled.
|
||||||
bool handle_event(const sdl::Event* event)
|
bool handle_event(const sdl::Event* event)
|
||||||
{
|
{
|
||||||
if (event->type == SDL_EVENT_QUIT) {
|
if (event->type == sdl::EventType::Quit) {
|
||||||
// Exit the application
|
// Exit the application
|
||||||
keep_running_ = false;
|
keep_running_ = false;
|
||||||
return true;
|
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 <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
export module game.game;
|
export module game.game;
|
||||||
|
|
||||||
import core.engine;
|
import core.engine;
|
||||||
import core.renderer;
|
import core.render_server;
|
||||||
import game.sprite;
|
import game.sprite;
|
||||||
import wrappers.sdl;
|
import wrappers.sdl;
|
||||||
import wrappers.sdl_image;
|
import wrappers.sdl_image;
|
||||||
|
|
@ -22,21 +23,18 @@ export namespace game
|
||||||
// Reference to the engine
|
// Reference to the engine
|
||||||
core::Engine& engine_;
|
core::Engine& engine_;
|
||||||
|
|
||||||
// Sprite for testing
|
// Sprites for testing
|
||||||
std::unique_ptr<Sprite> sprite_{nullptr};
|
Sprite player_sprite_;
|
||||||
|
std::vector<Sprite> sprites_;
|
||||||
|
|
||||||
// Private constructor
|
// Private constructor
|
||||||
explicit Game(core::Engine& engine)
|
explicit Game(core::Engine& engine)
|
||||||
: engine_(engine)
|
: engine_(engine),
|
||||||
{
|
player_sprite_{
|
||||||
// TODO: Texture should be a reference/pointer to an object managed by a ResourceManager or similar.
|
engine_.get_render_server().load_texture("assets/neocat.png"),
|
||||||
auto texture = sdl_image::LoadTexture(
|
sdl::FRect{0, 0, 100, 100}
|
||||||
engine_.get_renderer().get_sdl_renderer(),
|
|
||||||
"assets/neocat.png"
|
|
||||||
);
|
|
||||||
|
|
||||||
sprite_ = std::make_unique<Sprite>(std::move(texture), 100, 100);
|
|
||||||
}
|
}
|
||||||
|
{}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Game() = delete;
|
Game() = delete;
|
||||||
|
|
@ -62,15 +60,28 @@ export namespace game
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles an SDL event. Returns true if the event has been handled.
|
// 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) {
|
if (event->type == sdl::EventType::MouseMotion) {
|
||||||
sprite_->move(
|
player_sprite_.move(
|
||||||
event->motion.x - 50,
|
event->motion.x - 50,
|
||||||
event->motion.y - 50
|
event->motion.y - 50
|
||||||
);
|
);
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,10 +91,15 @@ export namespace game
|
||||||
|
|
||||||
void render() const
|
void render() const
|
||||||
{
|
{
|
||||||
const auto& renderer = engine_.get_renderer();
|
const auto& render_server = engine_.get_render_server();
|
||||||
renderer.start_frame();
|
render_server.start_frame();
|
||||||
sprite_->draw(renderer);
|
|
||||||
renderer.finish_frame();
|
for (const Sprite& sprite : sprites_) {
|
||||||
|
sprite.draw(render_server);
|
||||||
|
}
|
||||||
|
player_sprite_.draw(render_server);
|
||||||
|
|
||||||
|
render_server.finish_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown()
|
void shutdown()
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
module;
|
module;
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
export module game.sprite;
|
export module game.sprite;
|
||||||
|
|
||||||
import core.renderer;
|
import core.render_server;
|
||||||
import wrappers.sdl;
|
import wrappers.sdl;
|
||||||
|
|
||||||
// TODO: Move this to a different namespace (core, drawing, ...?)
|
// TODO: Move this to a different namespace (core, drawing, ...?)
|
||||||
|
|
@ -13,21 +12,14 @@ export namespace game
|
||||||
{
|
{
|
||||||
class Sprite
|
class Sprite
|
||||||
{
|
{
|
||||||
// TODO: Texture should be a reference/pointer to an object managed by a ResourceManager or similar.
|
core::TextureID texture_id_;
|
||||||
sdl::Texture texture_;
|
|
||||||
sdl::FRect dest_rect_{0, 0, 0, 0};
|
sdl::FRect dest_rect_{0, 0, 0, 0};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Sprite(
|
explicit Sprite(const core::TextureID texture_id, const sdl::FRect dest_rect)
|
||||||
sdl::Texture&& texture,
|
: texture_id_{texture_id},
|
||||||
const int width,
|
dest_rect_{dest_rect}
|
||||||
const int height
|
{}
|
||||||
)
|
|
||||||
: texture_{std::move(texture)}
|
|
||||||
{
|
|
||||||
dest_rect_.w = static_cast<float>(width);
|
|
||||||
dest_rect_.h = static_cast<float>(height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void move(const float x, const float y)
|
void move(const float x, const float y)
|
||||||
{
|
{
|
||||||
|
|
@ -35,9 +27,9 @@ export namespace game
|
||||||
dest_rect_.y = y;
|
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
|
// Simple alias for SDL_Event union
|
||||||
using Event = SDL_Event;
|
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