From 07adbf48e0781cd8c95983c1871a84b6160ee5bf Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Thu, 14 Nov 2024 13:57:13 +0100 Subject: implement asset + more WIP audio system --- src/crepe/api/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/crepe/api/CMakeLists.txt') diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 85696c4..93a1fac 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -1,5 +1,5 @@ target_sources(crepe PUBLIC - # AudioSource.cpp + AudioSource.cpp BehaviorScript.cpp Script.cpp GameObject.cpp @@ -23,7 +23,7 @@ target_sources(crepe PUBLIC ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES - # AudioSource.h + AudioSource.h BehaviorScript.h Config.h Script.h -- cgit v1.2.3 From 431b0bd7c6c502b42bb5be5488371d8c475e7024 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Thu, 14 Nov 2024 14:06:18 +0100 Subject: move some shit around --- src/crepe/Asset.cpp | 50 ------------------------------ src/crepe/Asset.h | 43 -------------------------- src/crepe/CMakeLists.txt | 2 -- src/crepe/api/Asset.cpp | 50 ++++++++++++++++++++++++++++++ src/crepe/api/Asset.h | 43 ++++++++++++++++++++++++++ src/crepe/api/AssetManager.cpp | 17 ---------- src/crepe/api/AssetManager.h | 65 --------------------------------------- src/crepe/api/AssetManager.hpp | 24 --------------- src/crepe/api/AudioSource.h | 5 ++- src/crepe/api/CMakeLists.txt | 8 +++-- src/crepe/api/ResourceManager.cpp | 17 ++++++++++ src/crepe/api/ResourceManager.h | 65 +++++++++++++++++++++++++++++++++++++++ src/crepe/api/ResourceManager.hpp | 24 +++++++++++++++ src/crepe/facade/Sound.cpp | 2 +- src/test/AssetTest.cpp | 2 +- 15 files changed, 208 insertions(+), 209 deletions(-) delete mode 100644 src/crepe/Asset.cpp delete mode 100644 src/crepe/Asset.h create mode 100644 src/crepe/api/Asset.cpp create mode 100644 src/crepe/api/Asset.h delete mode 100644 src/crepe/api/AssetManager.cpp delete mode 100644 src/crepe/api/AssetManager.h delete mode 100644 src/crepe/api/AssetManager.hpp create mode 100644 src/crepe/api/ResourceManager.cpp create mode 100644 src/crepe/api/ResourceManager.h create mode 100644 src/crepe/api/ResourceManager.hpp (limited to 'src/crepe/api/CMakeLists.txt') diff --git a/src/crepe/Asset.cpp b/src/crepe/Asset.cpp deleted file mode 100644 index 8692c6c..0000000 --- a/src/crepe/Asset.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include - -#include "Asset.h" -#include "api/Config.h" - -using namespace crepe; -using namespace std; - -Asset::Asset(const string & src) : src(find_asset(src)) { } -Asset::Asset(const char * src) : src(find_asset(src)) { } - -const string & Asset::get_path() const noexcept { return this->src; } - -string Asset::find_asset(const string & src) const { - auto & cfg = Config::get_instance(); - auto & root_pattern = cfg.asset.root_pattern; - - // if root_pattern is empty, find_asset must return all paths as-is - if (root_pattern.empty()) return src; - - // absolute paths do not need to be resolved, only canonicalized - filesystem::path path = src; - if (path.is_absolute()) - return filesystem::canonical(path); - - // find directory matching root_pattern - filesystem::path root = this->whereami(); - while (1) { - if (filesystem::exists(root / root_pattern)) - break; - if (!root.has_parent_path()) - throw runtime_error(format("Asset: Cannot find root pattern ({})", root_pattern)); - root = root.parent_path(); - } - - // join path to root (base directory) and canonicalize - return filesystem::canonical(root / path); -} - -string Asset::whereami() const noexcept { - string path; - size_t path_length = wai_getExecutablePath(NULL, 0, NULL); - path.resize(path_length + 1); // wai writes null byte - wai_getExecutablePath(path.data(), path_length, NULL); - path.resize(path_length); - return path; -} - diff --git a/src/crepe/Asset.h b/src/crepe/Asset.h deleted file mode 100644 index f6e6782..0000000 --- a/src/crepe/Asset.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -namespace crepe { - -/** - * \brief Asset location helper - * - * This class is used to locate game asset files, and should *always* be used - * instead of reading file paths directly. - */ -class Asset { -public: - /** - * \param src Unique identifier to asset - */ - Asset(const std::string & src); - /** - * \param src Unique identifier to asset - */ - Asset(const char * src); - -public: - /** - * \brief Get the path to this asset - * \return path to this asset - */ - const std::string & get_path() const noexcept; - -private: - //! path to asset - const std::string src; - -private: - std::string find_asset(const std::string & src) const; - /** - * \returns The path to the current executable - */ - std::string whereami() const noexcept; -}; - -} // namespace crepe diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index 52a781e..05f86d7 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -1,5 +1,4 @@ target_sources(crepe PUBLIC - Asset.cpp Particle.cpp ComponentManager.cpp Component.cpp @@ -8,7 +7,6 @@ target_sources(crepe PUBLIC ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES - Asset.h ComponentManager.h ComponentManager.hpp Component.h diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp new file mode 100644 index 0000000..8692c6c --- /dev/null +++ b/src/crepe/api/Asset.cpp @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "Asset.h" +#include "api/Config.h" + +using namespace crepe; +using namespace std; + +Asset::Asset(const string & src) : src(find_asset(src)) { } +Asset::Asset(const char * src) : src(find_asset(src)) { } + +const string & Asset::get_path() const noexcept { return this->src; } + +string Asset::find_asset(const string & src) const { + auto & cfg = Config::get_instance(); + auto & root_pattern = cfg.asset.root_pattern; + + // if root_pattern is empty, find_asset must return all paths as-is + if (root_pattern.empty()) return src; + + // absolute paths do not need to be resolved, only canonicalized + filesystem::path path = src; + if (path.is_absolute()) + return filesystem::canonical(path); + + // find directory matching root_pattern + filesystem::path root = this->whereami(); + while (1) { + if (filesystem::exists(root / root_pattern)) + break; + if (!root.has_parent_path()) + throw runtime_error(format("Asset: Cannot find root pattern ({})", root_pattern)); + root = root.parent_path(); + } + + // join path to root (base directory) and canonicalize + return filesystem::canonical(root / path); +} + +string Asset::whereami() const noexcept { + string path; + size_t path_length = wai_getExecutablePath(NULL, 0, NULL); + path.resize(path_length + 1); // wai writes null byte + wai_getExecutablePath(path.data(), path_length, NULL); + path.resize(path_length); + return path; +} + diff --git a/src/crepe/api/Asset.h b/src/crepe/api/Asset.h new file mode 100644 index 0000000..f6e6782 --- /dev/null +++ b/src/crepe/api/Asset.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace crepe { + +/** + * \brief Asset location helper + * + * This class is used to locate game asset files, and should *always* be used + * instead of reading file paths directly. + */ +class Asset { +public: + /** + * \param src Unique identifier to asset + */ + Asset(const std::string & src); + /** + * \param src Unique identifier to asset + */ + Asset(const char * src); + +public: + /** + * \brief Get the path to this asset + * \return path to this asset + */ + const std::string & get_path() const noexcept; + +private: + //! path to asset + const std::string src; + +private: + std::string find_asset(const std::string & src) const; + /** + * \returns The path to the current executable + */ + std::string whereami() const noexcept; +}; + +} // namespace crepe diff --git a/src/crepe/api/AssetManager.cpp b/src/crepe/api/AssetManager.cpp deleted file mode 100644 index 3925758..0000000 --- a/src/crepe/api/AssetManager.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "util/Log.h" - -#include "AssetManager.h" - -using namespace crepe; - -AssetManager & AssetManager::get_instance() { - static AssetManager instance; - return instance; -} - -AssetManager::~AssetManager() { - dbg_trace(); - this->asset_cache.clear(); -} - -AssetManager::AssetManager() { dbg_trace(); } diff --git a/src/crepe/api/AssetManager.h b/src/crepe/api/AssetManager.h deleted file mode 100644 index 86a9902..0000000 --- a/src/crepe/api/AssetManager.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace crepe { - -/** - * \brief The AssetManager is responsible for storing and managing assets over - * multiple scenes. - * - * The AssetManager ensures that assets are loaded once and can be accessed - * across different scenes. It caches assets to avoid reloading them every time - * a scene is loaded. Assets are retained in memory until the AssetManager is - * destroyed, at which point the cached assets are cleared. - */ -class AssetManager { - -private: - //! A cache that holds all the assets, accessible by their file path, over multiple scenes. - std::unordered_map asset_cache; - -private: - AssetManager(); - virtual ~AssetManager(); - -public: - AssetManager(const AssetManager &) = delete; - AssetManager(AssetManager &&) = delete; - AssetManager & operator=(const AssetManager &) = delete; - AssetManager & operator=(AssetManager &&) = delete; - - /** - * \brief Retrieves the singleton instance of the AssetManager. - * - * \return A reference to the single instance of the AssetManager. - */ - static AssetManager & get_instance(); - -public: - /** - * \brief Caches an asset by loading it from the given file path. - * - * \param file_path The path to the asset file to load. - * \param reload If true, the asset will be reloaded from the file, even if - * it is already cached. - * \tparam T The type of asset to cache (e.g., texture, sound, etc.). - * - * \return A shared pointer to the cached asset. - * - * This template function caches the asset at the given file path. If the - * asset is already cached and `reload` is false, the existing cached version - * will be returned. Otherwise, the asset will be reloaded and added to the - * cache. - */ - template - std::shared_ptr cache(const std::string & file_path, - bool reload = false); -}; - -} // namespace crepe - -#include "AssetManager.hpp" diff --git a/src/crepe/api/AssetManager.hpp b/src/crepe/api/AssetManager.hpp deleted file mode 100644 index 977b4e1..0000000 --- a/src/crepe/api/AssetManager.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "AssetManager.h" - -namespace crepe { - -template -std::shared_ptr AssetManager::cache(const std::string & file_path, - bool reload) { - auto it = asset_cache.find(file_path); - - if (!reload && it != asset_cache.end()) { - return std::any_cast>(it->second); - } - - std::shared_ptr new_asset - = std::make_shared(file_path.c_str()); - - asset_cache[file_path] = new_asset; - - return new_asset; -} - -} // namespace crepe diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h index 0748267..8a78927 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -1,11 +1,10 @@ #pragma once -#include - -#include "../Asset.h" #include "../Component.h" #include "../types.h" +#include "Asset.h" + namespace crepe { //! Audio source component diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 93a1fac..70f1527 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -8,7 +8,7 @@ target_sources(crepe PUBLIC Transform.cpp Color.cpp Texture.cpp - AssetManager.cpp + ResourceManager.cpp Sprite.cpp SaveManager.cpp Config.cpp @@ -20,6 +20,7 @@ target_sources(crepe PUBLIC Animator.cpp LoopManager.cpp LoopTimer.cpp + Asset.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -35,8 +36,8 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Vector2.h Color.h Texture.h - AssetManager.h - AssetManager.hpp + ResourceManager.h + ResourceManager.hpp SaveManager.h Scene.h Metadata.h @@ -46,4 +47,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Animator.h LoopManager.h LoopTimer.h + Asset.h ) diff --git a/src/crepe/api/ResourceManager.cpp b/src/crepe/api/ResourceManager.cpp new file mode 100644 index 0000000..470e511 --- /dev/null +++ b/src/crepe/api/ResourceManager.cpp @@ -0,0 +1,17 @@ +#include "util/Log.h" + +#include "ResourceManager.h" + +using namespace crepe; + +ResourceManager & ResourceManager::get_instance() { + static ResourceManager instance; + return instance; +} + +ResourceManager::~ResourceManager() { + dbg_trace(); + this->asset_cache.clear(); +} + +ResourceManager::ResourceManager() { dbg_trace(); } diff --git a/src/crepe/api/ResourceManager.h b/src/crepe/api/ResourceManager.h new file mode 100644 index 0000000..7a45493 --- /dev/null +++ b/src/crepe/api/ResourceManager.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include +#include + +namespace crepe { + +/** + * \brief The ResourceManager is responsible for storing and managing assets over + * multiple scenes. + * + * The ResourceManager ensures that assets are loaded once and can be accessed + * across different scenes. It caches assets to avoid reloading them every time + * a scene is loaded. Assets are retained in memory until the ResourceManager is + * destroyed, at which point the cached assets are cleared. + */ +class ResourceManager { + +private: + //! A cache that holds all the assets, accessible by their file path, over multiple scenes. + std::unordered_map asset_cache; + +private: + ResourceManager(); + virtual ~ResourceManager(); + +public: + ResourceManager(const ResourceManager &) = delete; + ResourceManager(ResourceManager &&) = delete; + ResourceManager & operator=(const ResourceManager &) = delete; + ResourceManager & operator=(ResourceManager &&) = delete; + + /** + * \brief Retrieves the singleton instance of the ResourceManager. + * + * \return A reference to the single instance of the ResourceManager. + */ + static ResourceManager & get_instance(); + +public: + /** + * \brief Caches an asset by loading it from the given file path. + * + * \param file_path The path to the asset file to load. + * \param reload If true, the asset will be reloaded from the file, even if + * it is already cached. + * \tparam T The type of asset to cache (e.g., texture, sound, etc.). + * + * \return A shared pointer to the cached asset. + * + * This template function caches the asset at the given file path. If the + * asset is already cached and `reload` is false, the existing cached version + * will be returned. Otherwise, the asset will be reloaded and added to the + * cache. + */ + template + std::shared_ptr cache(const std::string & file_path, + bool reload = false); +}; + +} // namespace crepe + +#include "ResourceManager.hpp" diff --git a/src/crepe/api/ResourceManager.hpp b/src/crepe/api/ResourceManager.hpp new file mode 100644 index 0000000..9cd4bcb --- /dev/null +++ b/src/crepe/api/ResourceManager.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "ResourceManager.h" + +namespace crepe { + +template +std::shared_ptr ResourceManager::cache(const std::string & file_path, + bool reload) { + auto it = asset_cache.find(file_path); + + if (!reload && it != asset_cache.end()) { + return std::any_cast>(it->second); + } + + std::shared_ptr new_asset + = std::make_shared(file_path.c_str()); + + asset_cache[file_path] = new_asset; + + return new_asset; +} + +} // namespace crepe diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index b7bfeab..726f11f 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -1,6 +1,6 @@ #include -#include "../Asset.h" +#include "../api/Asset.h" #include "../util/Log.h" #include "Sound.h" diff --git a/src/test/AssetTest.cpp b/src/test/AssetTest.cpp index c3ff158..324a3f1 100644 --- a/src/test/AssetTest.cpp +++ b/src/test/AssetTest.cpp @@ -1,7 +1,7 @@ #include "api/Config.h" #include -#include +#include using namespace std; using namespace crepe; -- cgit v1.2.3 From add8724446fdeae1aaec9b07544cf7a5475a9bfe Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Thu, 14 Nov 2024 19:57:45 +0100 Subject: ResourceManager working + tested --- src/crepe/Resource.h | 3 +-- src/crepe/api/Asset.cpp | 4 ++++ src/crepe/api/Asset.h | 7 +++++++ src/crepe/api/CMakeLists.txt | 1 - src/crepe/api/ResourceManager.cpp | 27 +++++++++++++++++++++------ src/crepe/api/ResourceManager.h | 4 ---- src/crepe/api/ResourceManager.hpp | 27 --------------------------- src/crepe/facade/Sound.cpp | 5 +++++ src/crepe/facade/Sound.h | 2 +- src/crepe/util/OptionalRef.hpp | 2 +- src/test/OptionalRefTest.cpp | 24 +++++++++++++++++++++++- src/test/ResourceManagerTest.cpp | 36 +++++++++++++++++++++++++++++++++--- src/test/main.cpp | 15 +++++++++++++-- 13 files changed, 109 insertions(+), 48 deletions(-) delete mode 100644 src/crepe/api/ResourceManager.hpp (limited to 'src/crepe/api/CMakeLists.txt') diff --git a/src/crepe/Resource.h b/src/crepe/Resource.h index 95b4d06..a0c8859 100644 --- a/src/crepe/Resource.h +++ b/src/crepe/Resource.h @@ -1,7 +1,5 @@ #pragma once -#include - namespace crepe { class ResourceManager; @@ -14,6 +12,7 @@ class Asset; class Resource { public: Resource(const Asset & src); + virtual ~Resource() = default; private: /** diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp index 1887814..5271cf7 100644 --- a/src/crepe/api/Asset.cpp +++ b/src/crepe/api/Asset.cpp @@ -48,6 +48,10 @@ string Asset::whereami() const noexcept { return path; } +bool Asset::operator==(const Asset & other) const noexcept { + return this->src == other.src; +} + size_t std::hash::operator()(const Asset & asset) const noexcept { return std::hash{}(asset.get_path()); }; diff --git a/src/crepe/api/Asset.h b/src/crepe/api/Asset.h index 0f6b0b3..05dccba 100644 --- a/src/crepe/api/Asset.h +++ b/src/crepe/api/Asset.h @@ -29,6 +29,13 @@ public: */ const std::string & get_path() const noexcept; + /** + * \brief Comparison operator + * \param other Possibly different instance of \c Asset to test equality against + * \return True if \c this and \c other are equal + */ + bool operator == (const Asset & other) const noexcept; + private: //! path to asset const std::string src; diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 70f1527..b452f37 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -37,7 +37,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Color.h Texture.h ResourceManager.h - ResourceManager.hpp SaveManager.h Scene.h Metadata.h diff --git a/src/crepe/api/ResourceManager.cpp b/src/crepe/api/ResourceManager.cpp index 6eb4afd..7877ed9 100644 --- a/src/crepe/api/ResourceManager.cpp +++ b/src/crepe/api/ResourceManager.cpp @@ -1,11 +1,11 @@ +#include + #include "util/Log.h" #include "ResourceManager.h" -// default resource cache functions -#include "../facade/Sound.h" - using namespace crepe; +using namespace std; ResourceManager & ResourceManager::get_instance() { static ResourceManager instance; @@ -19,8 +19,23 @@ void ResourceManager::clear() { this->resources.clear(); } -template <> -Sound & ResourceManager::cache(const Asset & asset) { - return this->cache(asset); +template +T & ResourceManager::cache(const Asset & asset) { + dbg_trace(); + static_assert(is_base_of::value, "cache must recieve a derivative class of Resource"); + + if (!this->resources.contains(asset)) + this->resources[asset] = make_unique(asset); + + Resource * resource = this->resources.at(asset).get(); + T * concrete_resource = dynamic_cast(resource); + + if (concrete_resource == nullptr) + throw runtime_error(format("ResourceManager: mismatch between requested type and actual type of resource ({})", asset.get_path())); + + return *concrete_resource; } +#include "../facade/Sound.h" +template Sound & ResourceManager::cache(const Asset &); + diff --git a/src/crepe/api/ResourceManager.h b/src/crepe/api/ResourceManager.h index 468af16..efdd5c5 100644 --- a/src/crepe/api/ResourceManager.h +++ b/src/crepe/api/ResourceManager.h @@ -65,9 +65,5 @@ public: void clear(); }; -template <> -Sound & ResourceManager::cache(const Asset & asset); - } // namespace crepe -#include "ResourceManager.hpp" diff --git a/src/crepe/api/ResourceManager.hpp b/src/crepe/api/ResourceManager.hpp deleted file mode 100644 index 62cac20..0000000 --- a/src/crepe/api/ResourceManager.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - -#include "ResourceManager.h" - -namespace crepe { - -template -T & ResourceManager::cache(const Asset & asset) { - using namespace std; - static_assert(is_base_of::value, "cache must recieve a derivative class of Resource"); - - if (!this->resources.contains(asset)) - this->resources[asset] = make_unique(asset); - - Resource * resource = this->resources.at(asset).get(); - T * concrete_resource = dynamic_cast(resource); - - if (concrete_resource == nullptr) - throw runtime_error(format("ResourceManager: mismatch between requested type and actual type of resource ({})", asset.get_path())); - - return *concrete_resource; -} - -} // namespace crepe diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 4eefcda..b589759 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -11,6 +11,7 @@ Sound::Sound(const Asset & src) : Resource(src) { this->sample.load(src.get_path().c_str()); dbg_trace(); } +Sound::~Sound() { dbg_trace(); } void Sound::play() { SoundContext & ctx = this->context.get(); @@ -52,3 +53,7 @@ void Sound::set_looping(bool looping) { ctx.engine.setLooping(this->handle, this->looping); } +void Sound::set_context(SoundContext & ctx) { + this->context = ctx; +} + diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h index 6f8462a..94b1996 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -20,6 +19,7 @@ class SoundContext; class Sound : public Resource { public: Sound(const Asset & src); + ~Sound(); // dbg_trace /** * \brief Pause this sample * diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp index e603a25..7b201b0 100644 --- a/src/crepe/util/OptionalRef.hpp +++ b/src/crepe/util/OptionalRef.hpp @@ -60,7 +60,7 @@ OptionalRef & OptionalRef::operator=(T & ref) { template OptionalRef::operator bool() const noexcept { - return this->ref == nullptr; + return this->ref != nullptr; } } diff --git a/src/test/OptionalRefTest.cpp b/src/test/OptionalRefTest.cpp index 65bd816..219ccca 100644 --- a/src/test/OptionalRefTest.cpp +++ b/src/test/OptionalRefTest.cpp @@ -9,8 +9,30 @@ using namespace testing; TEST(OptionalRefTest, Explicit) { string value = "foo"; OptionalRef ref; + EXPECT_FALSE(ref); + ASSERT_THROW(ref.get(), runtime_error); + + ref.set(value); + EXPECT_TRUE(ref); + ASSERT_NO_THROW(ref.get()); + + ref.clear(); + EXPECT_FALSE(ref); + ASSERT_THROW(ref.get(), runtime_error); +} + +TEST(OptionalRefTest, Implicit) { + string value = "foo"; + OptionalRef ref = value; + EXPECT_TRUE(ref); + ASSERT_NO_THROW(ref.get()); - EXPECT_FALSE(bool(ref)); + ref.clear(); + EXPECT_FALSE(ref); ASSERT_THROW(ref.get(), runtime_error); + + ref = value; + EXPECT_TRUE(ref); + ASSERT_NO_THROW(ref.get()); } diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp index 42b6b5d..5d1ae7a 100644 --- a/src/test/ResourceManagerTest.cpp +++ b/src/test/ResourceManagerTest.cpp @@ -1,5 +1,7 @@ #include +#include +#include #include using namespace std; @@ -8,14 +10,42 @@ using namespace testing; class ResourceManagerTest : public Test { public: - ResourceManager & manager = ResourceManager::get_instance(); + ResourceManager & resman = ResourceManager::get_instance(); + Config & cfg = Config::get_instance(); void SetUp() override { - this->manager.clear(); + cfg.log.level = Log::Level::TRACE; + resman.clear(); } }; TEST_F(ResourceManagerTest, Main) { - Sound & sound = this->manager.cache("mwe/audio/sfx1.wav"); + Asset path1 = "mwe/audio/sfx1.wav"; + Asset path2 = "mwe/audio/sfx1.wav"; + ASSERT_EQ(path1, path2); + + Sound * ptr1 = nullptr; + Sound * ptr2 = nullptr; + { + Log::logf(Log::Level::DEBUG, "Get first sound (constructor call)"); + Sound & sound = resman.cache(path1); + ptr1 = &sound; + } + { + Log::logf(Log::Level::DEBUG, "Get same sound (NO constructor call)"); + Sound & sound = resman.cache(path2); + ptr2 = &sound; + } + EXPECT_EQ(ptr1, ptr2); + + Log::logf(Log::Level::DEBUG, "Clear cache (destructor call)"); + resman.clear(); + + Log::logf(Log::Level::DEBUG, "Get first sound again (constructor call)"); + Sound & sound = resman.cache(path1); + + // NOTE: there is no way (that I know of) to ensure the above statement + // allocates the new Sound instance in a different location than the first, + // so this test was verified using the above print statements. } diff --git a/src/test/main.cpp b/src/test/main.cpp index 241015d..19a8d6e 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -5,11 +5,22 @@ using namespace crepe; using namespace testing; +class GlobalConfigReset : public EmptyTestEventListener { +public: + Config & cfg = Config::get_instance(); + + // This function is called before each test + void OnTestStart(const TestInfo &) override { + cfg.log.level = Log::Level::WARNING; + } +}; + int main(int argc, char ** argv) { InitGoogleTest(&argc, argv); - auto & cfg = Config::get_instance(); - cfg.log.level = Log::Level::ERROR; + UnitTest & ut = *UnitTest::GetInstance(); + ut.listeners().Append(new GlobalConfigReset); return RUN_ALL_TESTS(); } + -- cgit v1.2.3 From a685e5f743786cc6499e7ce8973bb78a83d101f7 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 26 Nov 2024 20:03:41 +0100 Subject: big WIP --- src/crepe/CMakeLists.txt | 2 + src/crepe/ResourceManager.cpp | 36 ++++++++++++ src/crepe/ResourceManager.h | 76 +++++++++++++++++++++++++ src/crepe/api/AudioSource.h | 1 + src/crepe/api/CMakeLists.txt | 2 - src/crepe/api/Config.h | 27 +-------- src/crepe/api/ResourceManager.cpp | 41 -------------- src/crepe/api/ResourceManager.h | 69 ----------------------- src/crepe/system/AudioSystem.cpp | 2 +- src/crepe/system/AudioSystem.h | 4 +- src/crepe/util/Log.cpp | 2 +- src/crepe/util/Log.h | 16 ++++++ src/test/EventTest.cpp | 1 - src/test/ResourceManagerTest.cpp | 115 +++++++++++++++++++++++++++----------- src/test/main.cpp | 12 ++-- 15 files changed, 224 insertions(+), 182 deletions(-) create mode 100644 src/crepe/ResourceManager.cpp create mode 100644 src/crepe/ResourceManager.h delete mode 100644 src/crepe/api/ResourceManager.cpp delete mode 100644 src/crepe/api/ResourceManager.h (limited to 'src/crepe/api/CMakeLists.txt') diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index df15b8f..0313dfa 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -3,6 +3,7 @@ target_sources(crepe PUBLIC ComponentManager.cpp Component.cpp Collider.cpp + ResourceManager.cpp Resource.cpp ) @@ -13,6 +14,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Collider.h ValueBroker.h ValueBroker.hpp + ResourceManager.h Resource.h ) diff --git a/src/crepe/ResourceManager.cpp b/src/crepe/ResourceManager.cpp new file mode 100644 index 0000000..111b9e0 --- /dev/null +++ b/src/crepe/ResourceManager.cpp @@ -0,0 +1,36 @@ +#include + +#include "util/Log.h" + +#include "ResourceManager.h" + +using namespace crepe; +using namespace std; + +ResourceManager::~ResourceManager() { dbg_trace(); } +ResourceManager::ResourceManager() { dbg_trace(); } + +void ResourceManager::clear() { + this->resources.clear(); +} + +// template +// T & ResourceManager::cache(const Asset & asset) { +// dbg_trace(); +// static_assert(is_base_of::value, "cache must recieve a derivative class of Resource"); +// +// if (!this->resources.contains(asset)) +// this->resources[asset] = make_unique(asset); +// +// Resource * resource = this->resources.at(asset).get(); +// T * concrete_resource = dynamic_cast(resource); +// +// if (concrete_resource == nullptr) +// throw runtime_error(format("ResourceManager: mismatch between requested type and actual type of resource ({})", asset.get_path())); +// +// return *concrete_resource; +// } +// +// #include "facade/Sound.h" +// template Sound & ResourceManager::cache(const Asset &); + diff --git a/src/crepe/ResourceManager.h b/src/crepe/ResourceManager.h new file mode 100644 index 0000000..26a86a8 --- /dev/null +++ b/src/crepe/ResourceManager.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +#include "api/Asset.h" + +#include "Component.h" +#include "Resource.h" + +namespace crepe { + + +/** + * \brief The ResourceManager is responsible for storing and managing assets over + * multiple scenes. + * + * The ResourceManager ensures that assets are loaded once and can be accessed + * across different scenes. It caches assets to avoid reloading them every time + * a scene is loaded. Assets are retained in memory until the ResourceManager is + * destroyed, at which point the cached assets are cleared. + */ +class ResourceManager { +public: + ResourceManager(); // dbg_trace + virtual ~ResourceManager(); // dbg_trace + +private: + template + Resource & get_internal(const Component & component, const Asset & asset); + + template + const Asset & get_source(const Component & component) const; + + //! A cache that holds all the assets, accessible by their file path, over multiple scenes. + std::unordered_map> resources; + +public: + /** + * \brief Caches an asset by loading it from the given file path. + * + * \param file_path The path to the asset file to load. + * \param reload If true, the asset will be reloaded from the file, even if + * it is already cached. + * \tparam T The type of asset to cache (e.g., texture, sound, etc.). + * + * \return A reference to the resource + * + * This template function caches the asset at the given file path. If the + * asset is already cached, the existing instance will be returned. + * Otherwise, the concrete resource will be instantiated and added to the + * cache. + */ + template + void cache(const Asset & asset, bool persistent = false); + + template + void cache(const Component & component, bool persistent = false); + + // void resman.cache(Asset, Lifetime); + // void resman.cache(Component, Asset, Lifetime); + + template + Resource & get(const Component & component); + + //! Clear the resource cache + void clear(); +}; + +class Sound; +class AudioSource; +template <> +Sound & ResourceManager::get(const AudioSource & component); + +} // namespace crepe + diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h index 1264790..0950129 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -3,6 +3,7 @@ #include "../Component.h" #include "../types.h" +#include "GameObject.h" #include "Asset.h" namespace crepe { diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index a2e21fa..ad82924 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -7,7 +7,6 @@ target_sources(crepe PUBLIC Transform.cpp Color.cpp Texture.cpp - ResourceManager.cpp Sprite.cpp SaveManager.cpp Config.cpp @@ -39,7 +38,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Vector2.hpp Color.h Texture.h - ResourceManager.h SaveManager.h Scene.h Metadata.h diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 0c9d116..5bd6913 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -11,35 +11,12 @@ namespace crepe { * modified *before* execution is handed over from the game programmer to the engine (i.e. the * main loop is started). */ -class Config final { -public: +struct Config final { //! Retrieve handle to global Config instance static Config & get_instance(); -private: - Config() = default; - ~Config() = default; - Config(const Config &) = default; - Config(Config &&) = default; - Config & operator=(const Config &) = default; - Config & operator=(Config &&) = default; - -public: //! Logging-related settings - struct { - /** - * \brief Log level - * - * Only messages with equal or higher priority than this value will be logged. - */ - Log::Level level = Log::Level::INFO; - /** - * \brief Colored log output - * - * Enables log coloring using ANSI escape codes. - */ - bool color = true; - } log; + Log::Config log; //! Save manager struct { diff --git a/src/crepe/api/ResourceManager.cpp b/src/crepe/api/ResourceManager.cpp deleted file mode 100644 index 7877ed9..0000000 --- a/src/crepe/api/ResourceManager.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#include "util/Log.h" - -#include "ResourceManager.h" - -using namespace crepe; -using namespace std; - -ResourceManager & ResourceManager::get_instance() { - static ResourceManager instance; - return instance; -} - -ResourceManager::~ResourceManager() { dbg_trace(); } -ResourceManager::ResourceManager() { dbg_trace(); } - -void ResourceManager::clear() { - this->resources.clear(); -} - -template -T & ResourceManager::cache(const Asset & asset) { - dbg_trace(); - static_assert(is_base_of::value, "cache must recieve a derivative class of Resource"); - - if (!this->resources.contains(asset)) - this->resources[asset] = make_unique(asset); - - Resource * resource = this->resources.at(asset).get(); - T * concrete_resource = dynamic_cast(resource); - - if (concrete_resource == nullptr) - throw runtime_error(format("ResourceManager: mismatch between requested type and actual type of resource ({})", asset.get_path())); - - return *concrete_resource; -} - -#include "../facade/Sound.h" -template Sound & ResourceManager::cache(const Asset &); - diff --git a/src/crepe/api/ResourceManager.h b/src/crepe/api/ResourceManager.h deleted file mode 100644 index efdd5c5..0000000 --- a/src/crepe/api/ResourceManager.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include -#include - -#include "Asset.h" -#include "Resource.h" - -namespace crepe { - -class Sound; - -/** - * \brief The ResourceManager is responsible for storing and managing assets over - * multiple scenes. - * - * The ResourceManager ensures that assets are loaded once and can be accessed - * across different scenes. It caches assets to avoid reloading them every time - * a scene is loaded. Assets are retained in memory until the ResourceManager is - * destroyed, at which point the cached assets are cleared. - */ -class ResourceManager { - -private: - //! A cache that holds all the assets, accessible by their file path, over multiple scenes. - std::unordered_map> resources; - -private: - ResourceManager(); // dbg_trace - virtual ~ResourceManager(); // dbg_trace - - ResourceManager(const ResourceManager &) = delete; - ResourceManager(ResourceManager &&) = delete; - ResourceManager & operator=(const ResourceManager &) = delete; - ResourceManager & operator=(ResourceManager &&) = delete; - -public: - /** - * \brief Retrieves the singleton instance of the ResourceManager. - * - * \return A reference to the single instance of the ResourceManager. - */ - static ResourceManager & get_instance(); - -public: - /** - * \brief Caches an asset by loading it from the given file path. - * - * \param file_path The path to the asset file to load. - * \param reload If true, the asset will be reloaded from the file, even if - * it is already cached. - * \tparam T The type of asset to cache (e.g., texture, sound, etc.). - * - * \return A reference to the resource - * - * This template function caches the asset at the given file path. If the - * asset is already cached, the existing instance will be returned. - * Otherwise, the concrete resource will be instantiated and added to the - * cache. - */ - template - T & cache(const Asset & asset); - - //! Clear the resource cache - void clear(); -}; - -} // namespace crepe - diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index b7ac1f2..6c30b85 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -47,7 +47,7 @@ void AudioSystem::update() { * using the same underlying instance of Sound (esp. w/ * play/pause/retrigger behavior). */ - Sound & sound = this->resman.cache(component.source); + // Sound & sound = this->resource_manager.get(component); // TODO: lots of state diffing } diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h index d0b4f9a..d3d5aeb 100644 --- a/src/crepe/system/AudioSystem.h +++ b/src/crepe/system/AudioSystem.h @@ -1,7 +1,7 @@ #pragma once #include "../facade/SoundContext.h" -#include "../api/ResourceManager.h" +#include "../ResourceManager.h" #include "System.h" @@ -14,7 +14,7 @@ public: private: SoundContext context {}; - ResourceManager & resman = ResourceManager::get_instance(); + ResourceManager resource_manager {}; }; } // namespace crepe diff --git a/src/crepe/util/Log.cpp b/src/crepe/util/Log.cpp index 84d80a8..bc86c7e 100644 --- a/src/crepe/util/Log.cpp +++ b/src/crepe/util/Log.cpp @@ -25,7 +25,7 @@ string Log::prefix(const Level & level) { } void Log::log(const Level & level, const string & msg) { - auto & cfg = Config::get_instance(); + auto & cfg = crepe::Config::get_instance(); if (level < cfg.log.level) return; string out = Log::prefix(level) + msg; diff --git a/src/crepe/util/Log.h b/src/crepe/util/Log.h index fc0bb3a..914145a 100644 --- a/src/crepe/util/Log.h +++ b/src/crepe/util/Log.h @@ -77,6 +77,22 @@ private: * \return Colored message severity prefix string */ static std::string prefix(const Level & level); + +public: + struct Config { + /** + * \brief Log level + * + * Only messages with equal or higher priority than this value will be logged. + */ + Level level = INFO; + /** + * \brief Colored log output + * + * Enables log coloring using ANSI escape codes. + */ + bool color = true; + }; }; } // namespace crepe diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp index b0e6c9c..a21a851 100644 --- a/src/test/EventTest.cpp +++ b/src/test/EventTest.cpp @@ -37,7 +37,6 @@ public: TEST_F(EventManagerTest, EventSubscription) { EventHandler key_handler = [](const KeyPressEvent & e) { - std::cout << "Key Event Triggered" << std::endl; return true; }; diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp index 3fc9ebd..f57c419 100644 --- a/src/test/ResourceManagerTest.cpp +++ b/src/test/ResourceManagerTest.cpp @@ -1,52 +1,101 @@ #include +#define private public +#define protected public + #include -#include -#include +#include +#include +#include +#include using namespace std; using namespace crepe; using namespace testing; +class TestComponent : public Component { +public: + TestComponent(game_object_id_t id, const Asset & asset) + : Component(id), + source(asset) {} + const Asset source; +}; + +class TestResource : public Resource { +public: + static unsigned instances; + +public: + const unsigned instance; + TestResource(const Asset & src) + : Resource(src), + instance(this->instances++) { } +}; +unsigned TestResource::instances = 0; + +template <> +TestResource & ResourceManager::get(const TestComponent & component) { + return this->get_internal(component, component.source); +} + class ResourceManagerTest : public Test { public: - ResourceManager & resman = ResourceManager::get_instance(); - Config & cfg = Config::get_instance(); + ResourceManager resource_manager{}; + + static constexpr const char * ASSET_LOCATION = "asset/texture/img.png"; + + TestComponent a{0, ASSET_LOCATION}; + TestComponent b{1, ASSET_LOCATION}; +private: void SetUp() override { - resman.clear(); + TestResource::instances = 0; } }; -TEST_F(ResourceManagerTest, Main) { - // NOTE: there is no way (that I know of) to ensure the last cache call - // allocates the new Sound instance in a different location than the first, - // so this test should be verified manually using these print statements and - // debug trace messages. - cfg.log.level = Log::Level::TRACE; - - Asset path1 = "mwe/audio/sfx1.wav"; - Asset path2 = "mwe/audio/sfx1.wav"; - ASSERT_EQ(path1, path2); - - Sound * ptr1 = nullptr; - Sound * ptr2 = nullptr; - { - Log::logf(Log::Level::DEBUG, "Get first sound (constructor call)"); - Sound & sound = resman.cache(path1); - ptr1 = &sound; - } - { - Log::logf(Log::Level::DEBUG, "Get same sound (NO constructor call)"); - Sound & sound = resman.cache(path2); - ptr2 = &sound; - } - EXPECT_EQ(ptr1, ptr2); +TEST_F(ResourceManagerTest, Uncached) { + TestResource & res_1 = resource_manager.get(a); // 1 + TestResource & res_2 = resource_manager.get(a); // 1 + TestResource & res_3 = resource_manager.get(b); // 2 + TestResource & res_4 = resource_manager.get(b); // 2 + + ASSERT_EQ(res_1, res_2); + ASSERT_EQ(res_3, res_4); + EXPECT_NE(res_1, res_3); + + EXPECT_EQ(TestResource::instances, 2); +} + +// TODO: per GameObject / Component +TEST_F(ResourceManagerTest, PerComponent) { + resource_manager.cache(a); + resource_manager.cache(b); + + TestResource & res_1 = resource_manager.get(a); // 1 + TestResource & res_2 = resource_manager.get(a); // 1 + TestResource & res_3 = resource_manager.get(b); // 2 + TestResource & res_4 = resource_manager.get(b); // 2 + + ASSERT_EQ(res_1, res_2); + ASSERT_EQ(res_3, res_4); + EXPECT_NE(res_1, res_3); + + EXPECT_EQ(TestResource::instances, 2); +} + +TEST_F(ResourceManagerTest, PerAsset) { + resource_manager.cache(ASSET_LOCATION); + EXPECT_EQ(TestResource::instances, 1); + + TestResource & res_1 = resource_manager.get(a); // 1 + TestResource & res_2 = resource_manager.get(a); // 1 + TestResource & res_3 = resource_manager.get(b); // 1 + TestResource & res_4 = resource_manager.get(b); // 1 - Log::logf(Log::Level::DEBUG, "Clear cache (destructor call)"); - resman.clear(); + EXPECT_EQ(res_1, res_2); + EXPECT_EQ(res_2, res_3); + EXPECT_EQ(res_3, res_4); - Log::logf(Log::Level::DEBUG, "Get first sound again (constructor call)"); - Sound & sound = resman.cache(path1); + EXPECT_EQ(TestResource::instances, 1); } diff --git a/src/test/main.cpp b/src/test/main.cpp index e03a989..54f74fd 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -1,8 +1,4 @@ #include - -#define protected public -#define private public - #include using namespace crepe; @@ -11,12 +7,14 @@ using namespace testing; class GlobalConfigReset : public EmptyTestEventListener { public: Config & cfg = Config::get_instance(); - Config cfg_default = Config(); // This function is called before each test void OnTestStart(const TestInfo &) override { - cfg = cfg_default; - cfg.log.level = Log::Level::WARNING; + cfg = { + .log = { + .level = Log::Level::WARNING, + }, + }; } }; -- cgit v1.2.3 From a73ff31b67faa7e6a922cfb5598f56f80bc01d62 Mon Sep 17 00:00:00 2001 From: WBoerenkamps Date: Sat, 7 Dec 2024 14:19:16 +0100 Subject: added loopTimer and eventManager to mediator and removed the singletons --- src/crepe/api/CMakeLists.txt | 6 -- src/crepe/api/IKeyListener.cpp | 19 ----- src/crepe/api/IKeyListener.h | 50 ------------- src/crepe/api/IMouseListener.cpp | 29 ------- src/crepe/api/IMouseListener.h | 73 ------------------ src/crepe/api/LoopManager.cpp | 18 ++--- src/crepe/api/LoopManager.h | 9 ++- src/crepe/api/LoopTimer.cpp | 75 ------------------- src/crepe/api/LoopTimer.h | 133 --------------------------------- src/crepe/manager/CMakeLists.txt | 2 + src/crepe/manager/EventManager.cpp | 6 +- src/crepe/manager/EventManager.h | 24 ++---- src/crepe/manager/LoopTimerManager.cpp | 77 +++++++++++++++++++ src/crepe/manager/LoopTimerManager.h | 133 +++++++++++++++++++++++++++++++++ src/crepe/manager/Mediator.h | 8 +- src/test/EventTest.cpp | 88 +++++++++------------- src/test/LoopManagerTest.cpp | 29 ++++--- src/test/LoopTimerTest.cpp | 17 ++--- src/test/ScriptTest.h | 4 +- 19 files changed, 303 insertions(+), 497 deletions(-) delete mode 100644 src/crepe/api/IKeyListener.cpp delete mode 100644 src/crepe/api/IKeyListener.h delete mode 100644 src/crepe/api/IMouseListener.cpp delete mode 100644 src/crepe/api/IMouseListener.h delete mode 100644 src/crepe/api/LoopTimer.cpp delete mode 100644 src/crepe/api/LoopTimer.h create mode 100644 src/crepe/manager/LoopTimerManager.cpp create mode 100644 src/crepe/manager/LoopTimerManager.h (limited to 'src/crepe/api/CMakeLists.txt') diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 7da9dca..60d9dc5 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -13,10 +13,7 @@ target_sources(crepe PUBLIC Metadata.cpp Camera.cpp Animator.cpp - IKeyListener.cpp - IMouseListener.cpp LoopManager.cpp - LoopTimer.cpp Asset.cpp EventHandler.cpp Script.cpp @@ -45,9 +42,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES EventHandler.h EventHandler.hpp Event.h - IKeyListener.h - IMouseListener.h LoopManager.h - LoopTimer.h Asset.h ) diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp deleted file mode 100644 index 8642655..0000000 --- a/src/crepe/api/IKeyListener.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "IKeyListener.h" - -using namespace crepe; - -// Constructor with specified channel -IKeyListener::IKeyListener(event_channel_t channel) - : event_manager(EventManager::get_instance()) { - this->press_id = event_manager.subscribe( - [this](const KeyPressEvent & event) { return this->on_key_pressed(event); }, channel); - this->release_id = event_manager.subscribe( - [this](const KeyReleaseEvent & event) { return this->on_key_released(event); }, - channel); -} - -// Destructor, unsubscribe events -IKeyListener::~IKeyListener() { - event_manager.unsubscribe(this->press_id); - event_manager.unsubscribe(this->release_id); -} diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h deleted file mode 100644 index 6ded107..0000000 --- a/src/crepe/api/IKeyListener.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "../manager/EventManager.h" - -#include "Event.h" -#include "EventHandler.h" - -namespace crepe { - -/** - * \class IKeyListener - * \brief Interface for keyboard event handling in the application. - */ -class IKeyListener { -public: - /** - * \brief Constructs an IKeyListener with a specified channel. - * \param channel The channel ID for event handling. - */ - IKeyListener(event_channel_t channel = EventManager::CHANNEL_ALL); - virtual ~IKeyListener(); - IKeyListener(const IKeyListener &) = delete; - IKeyListener & operator=(const IKeyListener &) = delete; - IKeyListener & operator=(IKeyListener &&) = delete; - IKeyListener(IKeyListener &&) = delete; - - /** - * \brief Pure virtual function to handle key press events. - * \param event The key press event to handle. - * \return True if the event was handled, false otherwise. - */ - virtual bool on_key_pressed(const KeyPressEvent & event) = 0; - - /** - * \brief Pure virtual function to handle key release events. - * \param event The key release event to handle. - * \return True if the event was handled, false otherwise. - */ - virtual bool on_key_released(const KeyReleaseEvent & event) = 0; - -private: - //! Key press event id - subscription_t press_id = -1; - //! Key release event id - subscription_t release_id = -1; - //! EventManager reference - EventManager & event_manager; -}; - -} // namespace crepe diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp deleted file mode 100644 index 989aeb3..0000000 --- a/src/crepe/api/IMouseListener.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "IMouseListener.h" - -using namespace crepe; - -IMouseListener::IMouseListener(event_channel_t channel) - : event_manager(EventManager::get_instance()) { - this->click_id = event_manager.subscribe( - [this](const MouseClickEvent & event) { return this->on_mouse_clicked(event); }, - channel); - - this->press_id = event_manager.subscribe( - [this](const MousePressEvent & event) { return this->on_mouse_pressed(event); }, - channel); - - this->release_id = event_manager.subscribe( - [this](const MouseReleaseEvent & event) { return this->on_mouse_released(event); }, - channel); - - this->move_id = event_manager.subscribe( - [this](const MouseMoveEvent & event) { return this->on_mouse_moved(event); }, channel); -} - -IMouseListener::~IMouseListener() { - // Unsubscribe event handlers - event_manager.unsubscribe(this->click_id); - event_manager.unsubscribe(this->press_id); - event_manager.unsubscribe(this->release_id); - event_manager.unsubscribe(this->move_id); -} diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h deleted file mode 100644 index 9e4fdf7..0000000 --- a/src/crepe/api/IMouseListener.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include "../manager/EventManager.h" - -#include "Event.h" -#include "EventHandler.h" - -namespace crepe { - -/** - * \class IMouseListener - * \brief Interface for mouse event handling in the application. - */ -class IMouseListener { -public: - /** - * \brief Constructs an IMouseListener with a specified channel. - * \param channel The channel ID for event handling. - */ - IMouseListener(event_channel_t channel = EventManager::CHANNEL_ALL); - virtual ~IMouseListener(); - IMouseListener & operator=(const IMouseListener &) = delete; - IMouseListener(const IMouseListener &) = delete; - IMouseListener & operator=(const IMouseListener &&) = delete; - IMouseListener(IMouseListener &&) = delete; - - /** - * \brief Move assignment operator (deleted). - */ - IMouseListener & operator=(IMouseListener &&) = delete; - - /** - * \brief Handles a mouse click event. - * \param event The mouse click event to handle. - * \return True if the event was handled, false otherwise. - */ - virtual bool on_mouse_clicked(const MouseClickEvent & event) = 0; - - /** - * \brief Handles a mouse press event. - * \param event The mouse press event to handle. - * \return True if the event was handled, false otherwise. - */ - virtual bool on_mouse_pressed(const MousePressEvent & event) = 0; - - /** - * \brief Handles a mouse release event. - * \param event The mouse release event to handle. - * \return True if the event was handled, false otherwise. - */ - virtual bool on_mouse_released(const MouseReleaseEvent & event) = 0; - - /** - * \brief Handles a mouse move event. - * \param event The mouse move event to handle. - * \return True if the event was handled, false otherwise. - */ - virtual bool on_mouse_moved(const MouseMoveEvent & event) = 0; - -private: - //! Mouse click event id - subscription_t click_id = -1; - //! Mouse press event id - subscription_t press_id = -1; - //! Mouse release event id - subscription_t release_id = -1; - //! Mouse move event id - subscription_t move_id = -1; - //! EventManager reference - EventManager & event_manager; -}; - -} //namespace crepe diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 454afe8..69cbfaf 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,3 +1,4 @@ +#include #include "../facade/SDLContext.h" #include "../manager/EventManager.h" @@ -20,10 +21,8 @@ LoopManager::LoopManager() { this->load_system(); this->load_system(); this->load_system(); - EventManager::get_instance().subscribe( + this->event_manager.subscribe( [this](const ShutDownEvent & event) { return this->on_shutdown(event); }); - this->loop_timer = make_unique(); - this->mediator.loop_timer = *loop_timer; } void LoopManager::process_input() { @@ -38,27 +37,28 @@ void LoopManager::start() { void LoopManager::fixed_update() {} void LoopManager::loop() { - this->loop_timer->start(); + while (game_running) { - this->loop_timer->update(); + this->loop_timer.update(); - while (this->loop_timer->get_lag() >= this->loop_timer->get_fixed_delta_time()) { + while (this->loop_timer.get_lag() >= this->loop_timer.get_fixed_delta_time()) { this->process_input(); + event_manager.dispatch_events(); this->fixed_update(); - this->loop_timer->advance_fixed_update(); + this->loop_timer.advance_fixed_update(); } this->update(); this->render(); - this->loop_timer->enforce_frame_rate(); + this->loop_timer.enforce_frame_rate(); } } void LoopManager::setup() { this->game_running = true; - this->loop_timer->start(); + this->loop_timer.start(); } void LoopManager::render() { diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index 2161dff..00f5409 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -5,10 +5,11 @@ #include "../facade/SDLContext.h" #include "../manager/ComponentManager.h" #include "../manager/SceneManager.h" +#include "../manager/EventManager.h" +#include "../manager/LoopTimerManager.h" #include "../system/System.h" #include "api/Event.h" -#include "api/LoopTimer.h" namespace crepe { /** @@ -96,8 +97,10 @@ private: //! SDL context \todo no more singletons! SDLContext & sdl_context = SDLContext::get_instance(); - //! loop timer instance - std::unique_ptr loop_timer; + //! LoopTimer instance + LoopTimerManager loop_timer{mediator}; + //! EventManager instance + EventManager event_manager{mediator}; private: /** diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp deleted file mode 100644 index 8fb7ce8..0000000 --- a/src/crepe/api/LoopTimer.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include - -#include "../facade/SDLContext.h" -#include "../util/Log.h" - -#include "LoopTimer.h" - -using namespace crepe; - -LoopTimer::LoopTimer() { dbg_trace(); } - -void LoopTimer::start() { - this->last_frame_time = std::chrono::steady_clock::now(); - - this->elapsed_time = std::chrono::milliseconds(0); - // by starting the elapsed_fixed_time at (0 - fixed_delta_time) in milliseconds it calls a fixed update at the start of the loop. - this->elapsed_fixed_time - = -std::chrono::duration_cast(fixed_delta_time); - this->delta_time = std::chrono::milliseconds(0); -} - -void LoopTimer::update() { - auto current_frame_time = std::chrono::steady_clock::now(); - // Convert to duration in seconds for delta time - this->delta_time = std::chrono::duration_cast>( - current_frame_time - last_frame_time); - - if (this->delta_time > this->maximum_delta_time) { - this->delta_time = this->maximum_delta_time; - } - this->actual_fps = 1.0 / this->delta_time.count(); - - this->delta_time *= this->game_scale; - this->elapsed_time += this->delta_time; - this->last_frame_time = current_frame_time; -} - -double LoopTimer::get_delta_time() const { return this->delta_time.count(); } - -double LoopTimer::get_current_time() const { return this->elapsed_time.count(); } - -void LoopTimer::advance_fixed_update() { this->elapsed_fixed_time += this->fixed_delta_time; } - -double LoopTimer::get_fixed_delta_time() const { return this->fixed_delta_time.count(); } - -void LoopTimer::set_target_fps(int fps) { - this->target_fps = fps; - // target time per frame in seconds - this->frame_target_time = std::chrono::duration(1.0) / this->target_fps; -} - -int LoopTimer::get_fps() const { return this->actual_fps; } - -void LoopTimer::set_game_scale(double value) { this->game_scale = value; } - -double LoopTimer::get_game_scale() const { return this->game_scale; } -void LoopTimer::enforce_frame_rate() { - auto current_frame_time = std::chrono::steady_clock::now(); - auto frame_duration = current_frame_time - this->last_frame_time; - - // Check if frame duration is less than the target frame time - if (frame_duration < this->frame_target_time) { - auto delay_time = std::chrono::duration_cast( - this->frame_target_time - frame_duration); - - if (delay_time.count() > 0) { - std::this_thread::sleep_for(delay_time); - } - } -} - -double LoopTimer::get_lag() const { - return (this->elapsed_time - this->elapsed_fixed_time).count(); -} diff --git a/src/crepe/api/LoopTimer.h b/src/crepe/api/LoopTimer.h deleted file mode 100644 index c4294d7..0000000 --- a/src/crepe/api/LoopTimer.h +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include - -namespace crepe { - -class LoopTimer { -public: - LoopTimer(); - /** - * \brief Get the current delta time for the current frame. - * - * \return Delta time in seconds since the last frame. - */ - double get_delta_time() const; - - /** - * \brief Get the current game time. - * - * \note The current game time may vary from real-world elapsed time. It is the cumulative - * sum of each frame's delta time. - * - * \return Elapsed game time in seconds. - */ - double get_current_time() const; - - /** - * \brief Set the target frames per second (FPS). - * - * \param fps The desired frames rendered per second. - */ - void set_target_fps(int fps); - - /** - * \brief Get the current frames per second (FPS). - * - * \return Current FPS. - */ - int get_fps() const; - - /** - * \brief Get the current game scale. - * - * \return The current game scale, where 0 = paused, 1 = normal speed, and values > 1 speed - * up the game. - */ - double get_game_scale() const; - - /** - * \brief Set the game scale. - * - * \param game_scale The desired game scale (0 = pause, 1 = normal speed, > 1 = speed up). - */ - void set_game_scale(double game_scale); - -private: - friend class LoopManager; - - /** - * \brief Start the loop timer. - * - * Initializes the timer to begin tracking frame times. - */ - void start(); - /** - * \brief Enforce the frame rate limit. - * - * Ensures that the game loop does not exceed the target FPS by delaying frame updates as - * necessary. - */ - void enforce_frame_rate(); - - /** - * \brief Get the fixed delta time for consistent updates. - * - * Fixed delta time is used for operations that require uniform time steps, such as physics - * calculations. - * - * \return Fixed delta time in seconds. - */ - double get_fixed_delta_time() const; - - /** - * \brief Get the accumulated lag in the game loop. - * - * Lag represents the difference between the target frame time and the actual frame time, - * useful for managing fixed update intervals. - * - * \return Accumulated lag in seconds. - */ - double get_lag() const; - - /** - * \brief Update the timer to the current frame. - * - * Calculates and updates the delta time for the current frame and adds it to the cumulative - * game time. - */ - void update(); - - /** - * \brief Advance the game loop by a fixed update interval. - * - * This method progresses the game state by a consistent, fixed time step, allowing for - * stable updates independent of frame rate fluctuations. - */ - void advance_fixed_update(); - -private: - //! Target frames per second - int target_fps = 50; - //! Actual frames per second - int actual_fps = 0; - //! Current game scale - double game_scale = 1; - //! Maximum delta time in seconds to avoid large jumps - std::chrono::duration maximum_delta_time{0.25}; - //! Delta time for the current frame in seconds - std::chrono::duration delta_time{0.0}; - //! Target time per frame in seconds - std::chrono::duration frame_target_time - = std::chrono::duration(1.0) / target_fps; - //! Fixed delta time for fixed updates in seconds - std::chrono::duration fixed_delta_time = std::chrono::duration(1.0) / 50.0; - //! Total elapsed game time in seconds - std::chrono::duration elapsed_time{0.0}; - //! Total elapsed time for fixed updates in seconds - std::chrono::duration elapsed_fixed_time{0.0}; - //! Time of the last frame - std::chrono::steady_clock::time_point last_frame_time; -}; - -} // namespace crepe diff --git a/src/crepe/manager/CMakeLists.txt b/src/crepe/manager/CMakeLists.txt index 517b8a2..29d6df0 100644 --- a/src/crepe/manager/CMakeLists.txt +++ b/src/crepe/manager/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(crepe PUBLIC Manager.cpp SaveManager.cpp SceneManager.cpp + LoopTimerManager.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -16,5 +17,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES SaveManager.h SceneManager.h SceneManager.hpp + LoopTimerManager.h ) diff --git a/src/crepe/manager/EventManager.cpp b/src/crepe/manager/EventManager.cpp index 20f0dd3..9b0fa95 100644 --- a/src/crepe/manager/EventManager.cpp +++ b/src/crepe/manager/EventManager.cpp @@ -3,11 +3,9 @@ using namespace crepe; using namespace std; -EventManager & EventManager::get_instance() { - static EventManager instance; - return instance; +EventManager::EventManager(Mediator & mediator) : Manager(mediator){ + this->mediator.event_manager = *this; } - void EventManager::dispatch_events() { for (auto & event : this->events_queue) { this->handle_event(event.type, event.channel, *event.event.get()); diff --git a/src/crepe/manager/EventManager.h b/src/crepe/manager/EventManager.h index d634f54..5f8b107 100644 --- a/src/crepe/manager/EventManager.h +++ b/src/crepe/manager/EventManager.h @@ -8,6 +8,8 @@ #include "../api/Event.h" #include "../api/EventHandler.h" +#include "Manager.h" + namespace crepe { //! Event listener unique ID @@ -22,27 +24,16 @@ typedef size_t subscription_t; typedef size_t event_channel_t; /** - * \class EventManager * \brief Manages event subscriptions, triggers, and queues, enabling decoupled event handling. * * The `EventManager` acts as a centralized event system. It allows for registering callbacks * for specific event types, triggering events synchronously, queueing events for later * processing, and managing subscriptions via unique identifiers. */ -class EventManager { +class EventManager : public Manager { public: static constexpr const event_channel_t CHANNEL_ALL = -1; - - /** - * \brief Get the singleton instance of the EventManager. - * - * This method returns the unique instance of the EventManager, creating it if it - * doesn't already exist. Ensures only one instance is active in the program. - * - * \return Reference to the singleton instance of the EventManager. - */ - static EventManager & get_instance(); - + EventManager(Mediator & mediator); /** * \brief Subscribe to a specific event type. * @@ -107,12 +98,7 @@ public: void clear(); private: - /** - * \brief Default constructor for the EventManager. - * - * Constructor is private to enforce the singleton pattern. - */ - EventManager() = default; + /** * \struct QueueEntry diff --git a/src/crepe/manager/LoopTimerManager.cpp b/src/crepe/manager/LoopTimerManager.cpp new file mode 100644 index 0000000..8156c6d --- /dev/null +++ b/src/crepe/manager/LoopTimerManager.cpp @@ -0,0 +1,77 @@ +#include +#include + +#include "../facade/SDLContext.h" +#include "../util/Log.h" + +#include "LoopTimerManager.h" + +using namespace crepe; + +LoopTimerManager::LoopTimerManager(Mediator & mediator) : Manager(mediator) { + this->mediator.loop_timer = *this; + dbg_trace(); + } + +void LoopTimerManager::start() { + this->last_frame_time = std::chrono::steady_clock::now(); + + this->elapsed_time = std::chrono::milliseconds(0); + // by starting the elapsed_fixed_time at (0 - fixed_delta_time) in milliseconds it calls a fixed update at the start of the loop. + this->elapsed_fixed_time + = -std::chrono::duration_cast(fixed_delta_time); + this->delta_time = std::chrono::milliseconds(0); +} + +void LoopTimerManager::update() { + auto current_frame_time = std::chrono::steady_clock::now(); + // Convert to duration in seconds for delta time + this->delta_time = std::chrono::duration_cast>( + current_frame_time - last_frame_time); + + if (this->delta_time > this->maximum_delta_time) { + this->delta_time = this->maximum_delta_time; + } + this->actual_fps = 1.0 / this->delta_time.count(); + + this->elapsed_time += this->delta_time; + this->last_frame_time = current_frame_time; +} + +double LoopTimerManager::get_delta_time() const { return this->delta_time.count() * this->game_scale; } + +double LoopTimerManager::get_current_time() const { return this->elapsed_time.count(); } + +void LoopTimerManager::advance_fixed_update() { this->elapsed_fixed_time += this->fixed_delta_time; } + +double LoopTimerManager::get_fixed_delta_time() const { return this->fixed_delta_time.count(); } + +void LoopTimerManager::set_target_fps(int fps) { + this->target_fps = fps; + // target time per frame in seconds + this->frame_target_time = std::chrono::duration(1.0) / this->target_fps; +} + +int LoopTimerManager::get_fps() const { return this->actual_fps; } + +void LoopTimerManager::set_time_scale(double value) { this->game_scale = value; } + +double LoopTimerManager::get_time_scale() const { return this->game_scale; } +void LoopTimerManager::enforce_frame_rate() { + auto current_frame_time = std::chrono::steady_clock::now(); + auto frame_duration = current_frame_time - this->last_frame_time; + + // Check if frame duration is less than the target frame time + if (frame_duration < this->frame_target_time) { + auto delay_time = std::chrono::duration_cast( + this->frame_target_time - frame_duration); + + if (delay_time.count() > 0) { + std::this_thread::sleep_for(delay_time); + } + } +} + +double LoopTimerManager::get_lag() const { + return (this->elapsed_time - this->elapsed_fixed_time).count(); +} diff --git a/src/crepe/manager/LoopTimerManager.h b/src/crepe/manager/LoopTimerManager.h new file mode 100644 index 0000000..dba0f66 --- /dev/null +++ b/src/crepe/manager/LoopTimerManager.h @@ -0,0 +1,133 @@ +#pragma once + +#include +#include "../manager/Manager.h" +namespace crepe { + +class LoopTimerManager : public Manager { +public: + LoopTimerManager(Mediator & mediator); + /** + * \brief Get the current delta time for the current frame. + * + * \return Delta time in seconds since the last frame. + */ + double get_delta_time() const; + + /** + * \brief Get the current game time. + * + * \note The current game time may vary from real-world elapsed time. It is the cumulative + * sum of each frame's delta time. + * + * \return Elapsed game time in seconds. + */ + double get_current_time() const; + + /** + * \brief Set the target frames per second (FPS). + * + * \param fps The desired frames rendered per second. + */ + void set_target_fps(int fps); + + /** + * \brief Get the current frames per second (FPS). + * + * \return Current FPS. + */ + int get_fps() const; + + /** + * \brief Get the current time scale. + * + * \return The current time scale, where 0 = paused, 1 = normal speed, and values > 1 speed + * up the game. + */ + double get_time_scale() const; + + /** + * \brief Set the time scale. + * + * \param game_scale The desired time scale (0 = pause, 1 = normal speed, > 1 = speed up). + */ + void set_time_scale(double game_scale); + +private: + friend class LoopManager; + + /** + * \brief Start the loop timer. + * + * Initializes the timer to begin tracking frame times. + */ + void start(); + /** + * \brief Enforce the frame rate limit. + * + * Ensures that the game loop does not exceed the target FPS by delaying frame updates as + * necessary. + */ + void enforce_frame_rate(); + + /** + * \brief Get the fixed delta time for consistent updates. + * + * Fixed delta time is used for operations that require uniform time steps, such as physics + * calculations. + * + * \return Fixed delta time in seconds. + */ + double get_fixed_delta_time() const; + + /** + * \brief Get the accumulated lag in the game loop. + * + * Lag represents the difference between the target frame time and the actual frame time, + * useful for managing fixed update intervals. + * + * \return Accumulated lag in seconds. + */ + double get_lag() const; + + /** + * \brief Update the timer to the current frame. + * + * Calculates and updates the delta time for the current frame and adds it to the cumulative + * game time. + */ + void update(); + + /** + * \brief Advance the game loop by a fixed update interval. + * + * This method progresses the game state by a consistent, fixed time step, allowing for + * stable updates independent of frame rate fluctuations. + */ + void advance_fixed_update(); + +private: + //! Target frames per second + int target_fps = 50; + //! Actual frames per second + int actual_fps = 0; + //! Current game scale + double game_scale = 1; + //! Maximum delta time in seconds to avoid large jumps + std::chrono::duration maximum_delta_time{0.25}; + //! Delta time for the current frame in seconds + std::chrono::duration delta_time{0.0}; + //! Target time per frame in seconds + std::chrono::duration frame_target_time + = std::chrono::duration(1.0) / target_fps; + //! Fixed delta time for fixed updates in seconds + std::chrono::duration fixed_delta_time = std::chrono::duration(1.0) / 50.0; + //! Total elapsed game time in seconds + std::chrono::duration elapsed_time{0.0}; + //! Total elapsed time for fixed updates in seconds + std::chrono::duration elapsed_fixed_time{0.0}; + //! Time of the last frame + std::chrono::steady_clock::time_point last_frame_time; +}; + +} // namespace crepe diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h index cd96614..c72af8e 100644 --- a/src/crepe/manager/Mediator.h +++ b/src/crepe/manager/Mediator.h @@ -3,14 +3,14 @@ #include "../util/OptionalRef.h" // TODO: remove these singletons: -#include "EventManager.h" #include "SaveManager.h" namespace crepe { class ComponentManager; class SceneManager; -class LoopTimer; +class LoopTimerManager; +class EventManager; /** * Struct to pass references to classes that would otherwise need to be singletons down to * other classes within the engine hierarchy. Made to prevent constant changes to subclasses to @@ -27,8 +27,8 @@ struct Mediator { OptionalRef component_manager; OptionalRef scene_manager; OptionalRef save_manager = SaveManager::get_instance(); - OptionalRef event_manager = EventManager::get_instance(); - OptionalRef loop_timer; + OptionalRef event_manager; + OptionalRef loop_timer; }; } // namespace crepe diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp index dccd554..8479998 100644 --- a/src/test/EventTest.cpp +++ b/src/test/EventTest.cpp @@ -1,56 +1,41 @@ #include #include - #include -#include -#include #include - +#include using namespace std; using namespace std::chrono_literals; using namespace crepe; class EventManagerTest : public ::testing::Test { protected: + Mediator mediator; + EventManager event_mgr{mediator}; void SetUp() override { // Clear any existing subscriptions or events before each test - EventManager::get_instance().clear(); + event_mgr.clear(); } void TearDown() override { // Ensure cleanup after each test - EventManager::get_instance().clear(); + event_mgr.clear(); } }; -class MockKeyListener : public IKeyListener { -public: - MOCK_METHOD(bool, on_key_pressed, (const KeyPressEvent & event), (override)); - MOCK_METHOD(bool, on_key_released, (const KeyReleaseEvent & event), (override)); -}; - -class MockMouseListener : public IMouseListener { -public: - MOCK_METHOD(bool, on_mouse_clicked, (const MouseClickEvent & event), (override)); - MOCK_METHOD(bool, on_mouse_pressed, (const MousePressEvent & event), (override)); - MOCK_METHOD(bool, on_mouse_released, (const MouseReleaseEvent & event), (override)); - MOCK_METHOD(bool, on_mouse_moved, (const MouseMoveEvent & event), (override)); -}; - TEST_F(EventManagerTest, EventSubscription) { EventHandler key_handler = [](const KeyPressEvent & e) { return true; }; // Subscribe to KeyPressEvent - EventManager::get_instance().subscribe(key_handler, 1); + event_mgr.subscribe(key_handler, 1); // Verify subscription (not directly verifiable; test by triggering event) - EventManager::get_instance().trigger_event( + event_mgr.trigger_event( KeyPressEvent{ .repeat = true, .key = Keycode::A, }, 1); - EventManager::get_instance().trigger_event( + event_mgr.trigger_event( KeyPressEvent{ .repeat = true, .key = Keycode::A, @@ -68,12 +53,12 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) { EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); return false; }; - EventManager::get_instance().subscribe(mouse_handler, + event_mgr.subscribe(mouse_handler, EventManager::CHANNEL_ALL); MouseClickEvent click_event{ .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; - EventManager::get_instance().trigger_event(click_event, + event_mgr.trigger_event(click_event, EventManager::CHANNEL_ALL); EXPECT_TRUE(triggered); @@ -88,19 +73,18 @@ TEST_F(EventManagerTest, EventManagerTest_trigger_one_channel) { EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); return false; }; - EventManager::get_instance().subscribe(mouse_handler, test_channel); + event_mgr.subscribe(mouse_handler, test_channel); MouseClickEvent click_event{ .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; - EventManager::get_instance().trigger_event(click_event, + event_mgr.trigger_event(click_event, EventManager::CHANNEL_ALL); EXPECT_FALSE(triggered); - EventManager::get_instance().trigger_event(click_event, test_channel); + event_mgr.trigger_event(click_event, test_channel); } TEST_F(EventManagerTest, EventManagerTest_callback_propagation) { - EventManager & event_manager = EventManager::get_instance(); // Flags to track handler calls bool triggered_true = false; @@ -126,11 +110,11 @@ TEST_F(EventManagerTest, EventManagerTest_callback_propagation) { // Test event MouseClickEvent click_event{ .mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}; - event_manager.subscribe(mouse_handler_true, EventManager::CHANNEL_ALL); - event_manager.subscribe(mouse_handler_false, EventManager::CHANNEL_ALL); + event_mgr.subscribe(mouse_handler_true, EventManager::CHANNEL_ALL); + event_mgr.subscribe(mouse_handler_false, EventManager::CHANNEL_ALL); // Trigger event - event_manager.trigger_event(click_event, EventManager::CHANNEL_ALL); + event_mgr.trigger_event(click_event, EventManager::CHANNEL_ALL); // Check that only the true handler was triggered EXPECT_TRUE(triggered_true); @@ -139,12 +123,12 @@ TEST_F(EventManagerTest, EventManagerTest_callback_propagation) { // Reset and clear triggered_true = false; triggered_false = false; - event_manager.clear(); - event_manager.subscribe(mouse_handler_false, EventManager::CHANNEL_ALL); - event_manager.subscribe(mouse_handler_true, EventManager::CHANNEL_ALL); + event_mgr.clear(); + event_mgr.subscribe(mouse_handler_false, EventManager::CHANNEL_ALL); + event_mgr.subscribe(mouse_handler_true, EventManager::CHANNEL_ALL); // Trigger event again - event_manager.trigger_event(click_event, EventManager::CHANNEL_ALL); + event_mgr.trigger_event(click_event, EventManager::CHANNEL_ALL); // Check that both handlers were triggered EXPECT_TRUE(triggered_true); @@ -152,7 +136,6 @@ TEST_F(EventManagerTest, EventManagerTest_callback_propagation) { } TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) { - EventManager & event_manager = EventManager::get_instance(); bool triggered1 = false; bool triggered2 = false; int test_channel = 1; @@ -170,21 +153,20 @@ TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) { EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); return false; // Allows propagation }; - event_manager.subscribe(mouse_handler1); - event_manager.subscribe(mouse_handler2, test_channel); + event_mgr.subscribe(mouse_handler1); + event_mgr.subscribe(mouse_handler2, test_channel); - event_manager.queue_event( + event_mgr.queue_event( MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); - event_manager.queue_event( + event_mgr.queue_event( MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}, test_channel); - event_manager.dispatch_events(); + event_mgr.dispatch_events(); EXPECT_TRUE(triggered1); EXPECT_TRUE(triggered2); } TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { - EventManager & event_manager = EventManager::get_instance(); // Flags to track if handlers are triggered bool triggered1 = false; @@ -207,15 +189,15 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { return false; // Allows propagation }; // Subscribe handlers - subscription_t handler1_id = event_manager.subscribe(mouse_handler1); - subscription_t handler2_id = event_manager.subscribe(mouse_handler2); + subscription_t handler1_id = event_mgr.subscribe(mouse_handler1); + subscription_t handler2_id = event_mgr.subscribe(mouse_handler2); // Queue events - event_manager.queue_event( + event_mgr.queue_event( MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); // Dispatch events - both handlers should be triggered - event_manager.dispatch_events(); + event_mgr.dispatch_events(); EXPECT_TRUE(triggered1); // Handler 1 should be triggered EXPECT_TRUE(triggered2); // Handler 2 should be triggered @@ -224,14 +206,14 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { triggered2 = false; // Unsubscribe handler1 - event_manager.unsubscribe(handler1_id); + event_mgr.unsubscribe(handler1_id); // Queue the same event again - event_manager.queue_event( + event_mgr.queue_event( MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); // Dispatch events - only handler 2 should be triggered, handler 1 should NOT - event_manager.dispatch_events(); + event_mgr.dispatch_events(); EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered EXPECT_TRUE(triggered2); // Handler 2 should be triggered @@ -239,14 +221,14 @@ TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { triggered2 = false; // Unsubscribe handler2 - event_manager.unsubscribe(handler2_id); + event_mgr.unsubscribe(handler2_id); // Queue the event again - event_manager.queue_event( + event_mgr.queue_event( MouseClickEvent{.mouse_x = 100, .mouse_y = 200, .button = MouseButton::LEFT_MOUSE}); // Dispatch events - no handler should be triggered - event_manager.dispatch_events(); + event_mgr.dispatch_events(); EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered EXPECT_FALSE(triggered2); // Handler 2 should NOT be triggered } diff --git a/src/test/LoopManagerTest.cpp b/src/test/LoopManagerTest.cpp index 503eb1f..57f7a2e 100644 --- a/src/test/LoopManagerTest.cpp +++ b/src/test/LoopManagerTest.cpp @@ -2,13 +2,11 @@ #include #include #include -#include #define private public #define protected public -#include "api/LoopManager.h" -#include "api/LoopTimer.h" -#include "manager/EventManager.h" -#include "api/Event.h" +#include +#include +#include using namespace std::chrono; using namespace crepe; @@ -24,19 +22,18 @@ protected: TestGameLoop test_loop; // LoopManager test_loop; void SetUp() override { - test_loop.loop_timer->set_target_fps(10); } }; TEST_F(LoopManagerTest, FixedUpdate) { // Arrange - test_loop.loop_timer->set_target_fps(60); + test_loop.loop_timer.set_target_fps(60); // Set expectations for the mock calls EXPECT_CALL(test_loop, render).Times(::testing::Exactly(60)); EXPECT_CALL(test_loop, update).Times(::testing::Exactly(60)); - EXPECT_CALL(test_loop, fixed_update).Times(::testing::AtLeast(50)); + EXPECT_CALL(test_loop, fixed_update).Times(::testing::Exactly(50)); // Start the loop in a separate thread std::thread loop_thread([&]() { test_loop.start(); }); @@ -46,12 +43,26 @@ TEST_F(LoopManagerTest, FixedUpdate) { // Stop the game loop test_loop.game_running = false; - // Wait for the loop thread to finish loop_thread.join(); // Test finished } +TEST_F(LoopManagerTest, ShutDown) { + // Arrange + test_loop.loop_timer.set_target_fps(60); + EXPECT_CALL(test_loop, render).Times(::testing::AtLeast(1)); + EXPECT_CALL(test_loop, update).Times(::testing::AtLeast(1)); + EXPECT_CALL(test_loop, fixed_update).Times(::testing::AtLeast(1)); + // Start the loop in a separate thread + std::thread loop_thread([&]() { test_loop.start(); }); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + test_loop.event_manager.trigger_event(ShutDownEvent{}); + // Wait for the loop thread to finish + loop_thread.join(); + + // Test finished +} diff --git a/src/test/LoopTimerTest.cpp b/src/test/LoopTimerTest.cpp index 7652093..09b4e00 100644 --- a/src/test/LoopTimerTest.cpp +++ b/src/test/LoopTimerTest.cpp @@ -1,16 +1,17 @@ #include -#include #include +#include #define private public #define protected public -#include "api/LoopTimer.h" - +#include +#include using namespace std::chrono; using namespace crepe; class LoopTimerTest : public ::testing::Test { protected: - LoopTimer loop_timer; + Mediator mediator; + LoopTimerManager loop_timer{mediator}; void SetUp() override { loop_timer.start(); } }; @@ -25,8 +26,7 @@ TEST_F(LoopTimerTest, EnforcesTargetFrameRate) { auto elapsed_ms = duration_cast(elapsed_time).count(); // For 60 FPS, the target frame time is around 16.67ms - ASSERT_GE(elapsed_ms, 16); // Make sure it's at least 16 ms (could be slightly more) - ASSERT_LE(elapsed_ms, 18); // Ensure it's not too much longer + ASSERT_NEAR(elapsed_ms,16.7,1); } TEST_F(LoopTimerTest, SetTargetFps) { // Set the target FPS to 120 @@ -48,11 +48,10 @@ TEST_F(LoopTimerTest, DeltaTimeCalculation) { // Check the delta time double delta_time = loop_timer.get_delta_time(); - auto elapsed_time = duration_cast(end_time - start_time).count(); + auto elapsed_time = duration_cast(end_time - start_time).count(); // Assert that delta_time is close to the elapsed time - ASSERT_GE(delta_time, elapsed_time / 1000.0); - ASSERT_LE(delta_time, (elapsed_time + 2) / 1000.0); + ASSERT_NEAR(delta_time, elapsed_time, 1); } TEST_F(LoopTimerTest, getCurrentTime) { diff --git a/src/test/ScriptTest.h b/src/test/ScriptTest.h index 1bbfdd3..ee68c23 100644 --- a/src/test/ScriptTest.h +++ b/src/test/ScriptTest.h @@ -7,7 +7,7 @@ #include #include #include - +#include class ScriptTest : public testing::Test { protected: crepe::Mediator mediator; @@ -15,7 +15,7 @@ protected: public: crepe::ComponentManager component_manager{mediator}; crepe::ScriptSystem system{mediator}; - + crepe::EventManager event_mgr{mediator}; class MyScript : public crepe::Script { // NOTE: explicitly stating `public:` is not required on actual scripts -- cgit v1.2.3 From 7b8de90699aea153e73b5f2cee05c69b966b81be Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Tue, 10 Dec 2024 16:21:05 +0100 Subject: implemented feedback wouter, improved animator. however if spritesheet aspect_ratio is not the same as the single frame then the scaling is wrong --- src/crepe/api/Animator.cpp | 18 +++++----- src/crepe/api/Animator.h | 12 +++---- src/crepe/api/CMakeLists.txt | 2 -- src/crepe/api/LoopManager.cpp | 1 - src/crepe/api/Texture.cpp | 35 ------------------ src/crepe/api/Texture.h | 71 ------------------------------------ src/crepe/facade/CMakeLists.txt | 2 ++ src/crepe/facade/SDLContext.cpp | 4 +-- src/crepe/facade/Texture.cpp | 34 ++++++++++++++++++ src/crepe/facade/Texture.h | 72 +++++++++++++++++++++++++++++++++++++ src/crepe/system/AnimatorSystem.cpp | 2 +- src/crepe/system/RenderSystem.cpp | 5 +-- src/example/rendering_particle.cpp | 16 ++------- 13 files changed, 130 insertions(+), 144 deletions(-) delete mode 100644 src/crepe/api/Texture.cpp delete mode 100644 src/crepe/api/Texture.h create mode 100644 src/crepe/facade/Texture.cpp create mode 100644 src/crepe/facade/Texture.h (limited to 'src/crepe/api/CMakeLists.txt') diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index ad1778d..4c72cc0 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -7,20 +7,18 @@ using namespace crepe; -Animator::Animator(game_object_id_t id, Sprite & spritesheet, unsigned int pixel_frame_x, - unsigned int pixel_frame_y, unsigned int max_row, unsigned int max_col, - const Animator::Data & data) +Animator::Animator(game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size, + const uvec2 & max_cell_size, const Animator::Data & data) : Component(id), spritesheet(spritesheet), - max_rows(max_row), - max_columns(max_col), + max_cell_size(max_cell_size), data(data) { dbg_trace(); - this->spritesheet.mask.h = this->max_columns * pixel_frame_y; - this->spritesheet.mask.w /= this->max_rows * pixel_frame_x; - this->spritesheet.mask.x = this->data.row * this->spritesheet.mask.w; - this->spritesheet.mask.y = this->data.col * this->spritesheet.mask.h; + this->spritesheet.mask.w = single_frame_size.x; + this->spritesheet.mask.h = single_frame_size.y; + this->spritesheet.mask.x = 0; + this->spritesheet.mask.y = 0; } Animator::~Animator() { dbg_trace(); } @@ -51,6 +49,6 @@ void Animator::set_anim(int col) { void Animator::next_anim() { Animator::Data & ctx = this->data; - ctx.row = ctx.row++ % this->max_rows; + ctx.row = ctx.row++ % this->max_cell_size.x; this->spritesheet.mask.x = ctx.row * this->spritesheet.mask.w; } diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h index 8ceddad..9a26bf0 100644 --- a/src/crepe/api/Animator.h +++ b/src/crepe/api/Animator.h @@ -82,16 +82,14 @@ public: * This constructor sets up the Animator with the given parameters, and initializes the * animation system. */ - Animator(game_object_id_t id, Sprite & spritesheet, unsigned int pixel_frame_x, - unsigned int pixel_frame_y, unsigned int max_row, unsigned int max_col, - const Animator::Data & data); + Animator(game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size, + const uvec2 & max_cell_size, const Animator::Data & data); ~Animator(); // dbg_trace public: - //! The maximum number of columns in the sprite sheet. - const unsigned int max_columns; - //! The maximum number of rows in the sprite sheet. - const unsigned int max_rows; + //! The maximum number of rows and columns size + const uvec2 max_cell_size; + Animator::Data data; private: diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index a163faf..718e497 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -6,7 +6,6 @@ target_sources(crepe PUBLIC ParticleEmitter.cpp Transform.cpp Color.cpp - Texture.cpp Sprite.cpp Config.cpp Metadata.cpp @@ -38,7 +37,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Vector2.h Vector2.hpp Color.h - Texture.h Scene.h Metadata.h Camera.h diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 044f096..88243c4 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -65,7 +65,6 @@ void LoopManager::setup() { this->scene_manager.load_next_scene(); timer.start(); timer.set_fps(200); - this->scene_manager.load_next_scene(); } void LoopManager::render() { diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp deleted file mode 100644 index b0863cb..0000000 --- a/src/crepe/api/Texture.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "../util/Log.h" -#include "manager/Mediator.h" -#include "facade/SDLContext.h" - -#include "Asset.h" -#include "Resource.h" -#include "Texture.h" -#include "types.h" - -using namespace crepe; -using namespace std; - -Texture::Texture(const Asset & src, Mediator & mediator) : Resource(src, mediator){ - dbg_trace(); - SDLContext & ctx = mediator.sdl_context; - this->texture = ctx.texture_from_path(src.get_path()); - this->size = ctx.get_size(*this); - this->aspect_ratio = static_cast(this->size.x) / this->size.y; -} - -Texture::~Texture() { - dbg_trace(); - this->texture.reset(); -} - -const ivec2 & Texture::get_size() const noexcept{ - return this->size; -} -const float & Texture::get_ratio() const noexcept{ - return this->aspect_ratio; -} - -SDL_Texture * Texture::get_img() const noexcept{ - return this->texture.get(); -} diff --git a/src/crepe/api/Texture.h b/src/crepe/api/Texture.h deleted file mode 100644 index c33d9e5..0000000 --- a/src/crepe/api/Texture.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -// FIXME: this header can't be included because this is an API header, and SDL2 development -// headers won't be bundled with crepe. Why is this facade in the API namespace? - -#include -#include - -#include "Asset.h" -#include "Resource.h" -#include "types.h" - -namespace crepe { - -class Mediator; - -/** - * \class Texture - * \brief Manages texture loading and properties. - * - * The Texture class is responsible for loading an image from a source and providing access to - * its dimensions. Textures can be used for rendering. - */ -class Texture : public Resource { - -public: - /** - * \brief Constructs a Texture from an Asset resource. - * \param src Asset with texture data to load. - * \param mediator use the SDLContext reference to load the image - */ - Texture(const Asset & src, Mediator & mediator); - - /** - * \brief Destroys the Texture instance - */ - ~Texture(); - - /** - * \brief get width and height of image in pixels - * \return pixel size width and height - * - */ - const ivec2 & get_size() const noexcept; - - /** - * \brief aspect_ratio of image - * \return ratio - * - */ - const float & get_ratio() const noexcept; - - /** - * \brief get the image texture - * \return SDL_Texture - * - */ - SDL_Texture * get_img() const noexcept; - -private: - //! The texture of the class from the library - std::unique_ptr> texture; - - // texture size in pixel - ivec2 size; - - //! ratio of image - float aspect_ratio; -}; - -} // namespace crepe diff --git a/src/crepe/facade/CMakeLists.txt b/src/crepe/facade/CMakeLists.txt index 4cc53bc..0598e16 100644 --- a/src/crepe/facade/CMakeLists.txt +++ b/src/crepe/facade/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(crepe PUBLIC Sound.cpp + Texture.cpp SoundContext.cpp SDLContext.cpp DB.cpp @@ -7,6 +8,7 @@ target_sources(crepe PUBLIC target_sources(crepe PUBLIC FILE_SET HEADERS FILES Sound.h + Texture.h SoundContext.h SDLContext.h DB.h diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index ac21d15..a92ec8b 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -19,12 +19,12 @@ #include "../api/Color.h" #include "../api/Config.h" #include "../api/Sprite.h" -#include "../api/Texture.h" #include "../util/Log.h" #include "manager/Manager.h" #include "manager/Mediator.h" #include "SDLContext.h" +#include "Texture.h" #include "types.h" using namespace crepe; @@ -273,7 +273,7 @@ void SDLContext::draw(const RenderContext & ctx) { .img_scale = ctx.scale, }); - cout << dstrect.w << " " << dstrect.h << " " << dstrect.x << " " << dstrect.y << endl; + cout << srcrect->w << " " << srcrect->h << " " << srcrect->x << " " << srcrect->y << endl; double angle = ctx.angle + data.angle_offset; this->set_color_texture(ctx.texture, ctx.sprite.data.color); diff --git a/src/crepe/facade/Texture.cpp b/src/crepe/facade/Texture.cpp new file mode 100644 index 0000000..7224cb8 --- /dev/null +++ b/src/crepe/facade/Texture.cpp @@ -0,0 +1,34 @@ +#include "../util/Log.h" +#include "manager/Mediator.h" +#include "facade/SDLContext.h" + +#include "Resource.h" +#include "Texture.h" +#include "types.h" + +using namespace crepe; +using namespace std; + +Texture::Texture(const Asset & src, Mediator & mediator) : Resource(src, mediator){ + dbg_trace(); + SDLContext & ctx = mediator.sdl_context; + this->texture = ctx.texture_from_path(src.get_path()); + this->size = ctx.get_size(*this); + this->aspect_ratio = static_cast(this->size.x) / this->size.y; +} + +Texture::~Texture() { + dbg_trace(); + this->texture.reset(); +} + +const ivec2 & Texture::get_size() const noexcept{ + return this->size; +} +const float & Texture::get_ratio() const noexcept{ + return this->aspect_ratio; +} + +SDL_Texture * Texture::get_img() const noexcept{ + return this->texture.get(); +} diff --git a/src/crepe/facade/Texture.h b/src/crepe/facade/Texture.h new file mode 100644 index 0000000..255e14b --- /dev/null +++ b/src/crepe/facade/Texture.h @@ -0,0 +1,72 @@ +#pragma once + +// FIXME: this header can't be included because this is an API header, and SDL2 development +// headers won't be bundled with crepe. Why is this facade in the API namespace? + +#include +#include + +#include "../Resource.h" + +#include "types.h" + +namespace crepe { + +class Mediator; +class Asset; + +/** + * \class Texture + * \brief Manages texture loading and properties. + * + * The Texture class is responsible for loading an image from a source and providing access to + * its dimensions. Textures can be used for rendering. + */ +class Texture : public Resource { + +public: + /** + * \brief Constructs a Texture from an Asset resource. + * \param src Asset with texture data to load. + * \param mediator use the SDLContext reference to load the image + */ + Texture(const Asset & src, Mediator & mediator); + + /** + * \brief Destroys the Texture instance + */ + ~Texture(); + + /** + * \brief get width and height of image in pixels + * \return pixel size width and height + * + */ + const ivec2 & get_size() const noexcept; + + /** + * \brief aspect_ratio of image + * \return ratio + * + */ + const float & get_ratio() const noexcept; + + /** + * \brief get the image texture + * \return SDL_Texture + * + */ + SDL_Texture * get_img() const noexcept; + +private: + //! The texture of the class from the library + std::unique_ptr> texture; + + // texture size in pixel + ivec2 size; + + //! ratio of image + float aspect_ratio; +}; + +} // namespace crepe diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp index 549c35d..bb22b62 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -23,7 +23,7 @@ void AnimatorSystem::update() { int last_frame = ctx.row; - int cycle_end = (ctx.cycle_end == -1) ? a.max_rows : ctx.cycle_end; + int cycle_end = (ctx.cycle_end == -1) ? a.max_cell_size.x : ctx.cycle_end; int total_frames = cycle_end - ctx.cycle_start; int curr_frame = static_cast(elapsed_time / frame_duration) % total_frames; diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index daf71c5..51340fb 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -10,9 +10,10 @@ #include "../api/Sprite.h" #include "../api/Transform.h" #include "../facade/SDLContext.h" +#include "../facade/Texture.h" #include "../manager/ComponentManager.h" -#include "api/Texture.h" -#include "manager/ResourceManager.h" +#include "../manager/ResourceManager.h" + #include "RenderSystem.h" using namespace crepe; diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index cfc5a84..44bd96a 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -1,5 +1,4 @@ #include "api/Asset.h" -#include "manager/ResourceManager.h" #include #include #include @@ -9,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -52,7 +50,7 @@ public: Color color(255, 255, 255, 255); - Asset img{"asset/texture/test_ap43.png"}; + Asset img{"asset/spritesheet/spritesheet_test.png"}; Sprite & test_sprite = game_object.add_component( img, Sprite::Data{ @@ -65,16 +63,8 @@ public: .position_offset = {0, 0}, }); - /* - - auto & anim = game_object.add_component(test_sprite, 4, 4, - Animator::Data{ - .fps = 1, - .looping = false, - }); - anim.set_anim(2); - anim.active = false; - */ + auto & anim = game_object.add_component(test_sprite,ivec2{32, 64}, uvec2{4,1}, Animator::Data{}); + anim.set_anim(0); auto & cam = game_object.add_component(ivec2{1280, 720}, vec2{400, 400}, Camera::Data{ -- cgit v1.2.3