diff options
30 files changed, 448 insertions, 196 deletions
diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index da9d492..6cbb9fe 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources(crepe PUBLIC Particle.cpp Component.cpp Collider.cpp + Resource.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -9,6 +10,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Collider.h ValueBroker.h ValueBroker.hpp + Resource.h ) add_subdirectory(api) diff --git a/src/crepe/Component.h b/src/crepe/Component.h index dc17721..67bcc68 100644 --- a/src/crepe/Component.h +++ b/src/crepe/Component.h @@ -16,7 +16,12 @@ class Component { public: //! Whether the component is active bool active = true; - //! The id of the GameObject this component belongs to + /** + * \brief The id of the GameObject this component belongs to + * + * \note Only systems are supposed to use this member, but since friend + * relations aren't inherited this needs to be public. + */ const game_object_id_t game_object_id; protected: @@ -24,7 +29,7 @@ protected: * \param id The id of the GameObject this component belongs to */ Component(game_object_id_t id); - //! Only the ComponentManager can create components + //! Only ComponentManager can create components friend class ComponentManager; Component(const Component &) = delete; @@ -45,6 +50,8 @@ public: * \return The maximum number of instances for this component */ virtual int get_instances_max() const { return -1; } + //! Only ComponentManager needs to know the max instance count + friend class ComponentManager; }; } // namespace crepe diff --git a/src/crepe/Resource.cpp b/src/crepe/Resource.cpp new file mode 100644 index 0000000..e254695 --- /dev/null +++ b/src/crepe/Resource.cpp @@ -0,0 +1,6 @@ +#include "Resource.h" + +using namespace crepe; + +Resource::Resource(const Asset & asset) { } + diff --git a/src/crepe/Resource.h b/src/crepe/Resource.h new file mode 100644 index 0000000..a0c8859 --- /dev/null +++ b/src/crepe/Resource.h @@ -0,0 +1,26 @@ +#pragma once + +namespace crepe { + +class ResourceManager; +class Asset; + +/** + * Resource is an interface class used to represent a (deserialized) game + * resource (e.g. textures, sounds). + */ +class Resource { +public: + Resource(const Asset & src); + virtual ~Resource() = default; + +private: + /** + * The resource manager uses \c clone to create new instances of the concrete + * resource class. This may be used to inherit references to classes that + * would otherwise need to be implemented as singletons. + */ + friend class ResourceManager; +}; + +} // 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 fee6780..0000000 --- a/src/crepe/api/AssetManager.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include <any> -#include <memory> -#include <string> -#include <unordered_map> - -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<std::string, std::any> 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 <typename T> - std::shared_ptr<T> 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 1c0e978..0000000 --- a/src/crepe/api/AssetManager.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "AssetManager.h" - -namespace crepe { - -template <typename asset> -std::shared_ptr<asset> 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<std::shared_ptr<asset>>(it->second); - } - - std::shared_ptr<asset> new_asset = std::make_shared<asset>(file_path.c_str()); - - asset_cache[file_path] = new_asset; - - return new_asset; -} - -} // namespace crepe diff --git a/src/crepe/api/AudioSource.cpp b/src/crepe/api/AudioSource.cpp new file mode 100644 index 0000000..4baac9a --- /dev/null +++ b/src/crepe/api/AudioSource.cpp @@ -0,0 +1,20 @@ +#include "AudioSource.h" + +using namespace crepe; +using namespace std; + +AudioSource::AudioSource(game_object_id_t id, const Asset & src) : + Component(id), + source(src) +{ } + +void AudioSource::play(bool looping) { + this->loop = looping; + this->playing = true; +} + +void AudioSource::stop() { + this->playing = false; + this->rewind = true; +} + diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h new file mode 100644 index 0000000..0950129 --- /dev/null +++ b/src/crepe/api/AudioSource.h @@ -0,0 +1,61 @@ +#pragma once + +#include "../Component.h" +#include "../types.h" + +#include "GameObject.h" +#include "Asset.h" + +namespace crepe { + +class AudioSystem; + +//! Audio source component +class AudioSource : public Component { + //! AudioSource components are handled by AudioSystem + friend class AudioSystem; + +protected: + AudioSource(game_object_id_t id, const Asset & source); + //! Only ComponentManager can create components + friend class ComponentManager; +public: + // But std::unique_ptr needs to be able to destoy this component again + virtual ~AudioSource() = default; + +public: + //! Start or resume this audio source + void play(bool looping = false); + //! Stop this audio source + void stop(); + +public: + //! Play when this component becomes active + bool play_on_awake = false; + //! Repeat the current audio clip during playback + bool loop = false; + //! Normalized volume (0.0 - 1.0) + float volume = 1.0; + +private: + //! This audio source's clip + const Asset source; + + //! If this source is playing audio + bool playing = false; + //! Rewind the sample location + bool rewind = false; + +private: + //! Value of \c active after last system update + bool last_active = false; + //! Value of \c playing after last system update + bool last_playing = false; + //! Value of \c volume after last system update + float last_volume = 1.0; + //! Value of \c loop after last system update + bool last_loop = false; +}; + +} // namespace crepe + diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 7da9dca..0808612 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 GameObject.cpp Rigidbody.cpp @@ -7,7 +7,6 @@ target_sources(crepe PUBLIC Transform.cpp Color.cpp Texture.cpp - AssetManager.cpp Sprite.cpp Config.cpp Metadata.cpp @@ -23,7 +22,7 @@ target_sources(crepe PUBLIC ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES - # AudioSource.h + AudioSource.h BehaviorScript.h Config.h Script.h @@ -36,8 +35,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Vector2.hpp Color.h Texture.h - AssetManager.h - AssetManager.hpp Scene.h Metadata.h Camera.h diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 225e9b9..693400a 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -13,35 +13,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/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 4d3abf5..52496af 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -1,3 +1,4 @@ +#include "../api/Asset.h" #include "../util/Log.h" #include "Sound.h" @@ -6,20 +7,13 @@ using namespace crepe; using namespace std; -Sound::Sound(unique_ptr<Asset> res) { +Sound::Sound(const Asset & src) : Resource(src) { + this->sample.load(src.get_path().c_str()); dbg_trace(); - this->load(std::move(res)); } +Sound::~Sound() { dbg_trace(); } -Sound::Sound(const char * src) { - dbg_trace(); - this->load(make_unique<Asset>(src)); -} - -void Sound::load(unique_ptr<Asset> res) { this->sample.load(res->get_path().c_str()); } - -void Sound::play() { - SoundContext & ctx = SoundContext::get_instance(); +void Sound::play(SoundContext & ctx) { if (ctx.engine.getPause(this->handle)) { // resume if paused ctx.engine.setPause(this->handle, false); @@ -30,30 +24,25 @@ void Sound::play() { } } -void Sound::pause() { - SoundContext & ctx = SoundContext::get_instance(); +void Sound::pause(SoundContext & ctx) { if (ctx.engine.getPause(this->handle)) return; ctx.engine.setPause(this->handle, true); } -void Sound::rewind() { - SoundContext & ctx = SoundContext::get_instance(); +void Sound::rewind(SoundContext & ctx) { if (!ctx.engine.isValidVoiceHandle(this->handle)) return; ctx.engine.seek(this->handle, 0); } -void Sound::set_volume(float volume) { +void Sound::set_volume(SoundContext & ctx, float volume) { this->volume = volume; - - SoundContext & ctx = SoundContext::get_instance(); if (!ctx.engine.isValidVoiceHandle(this->handle)) return; ctx.engine.setVolume(this->handle, this->volume); } -void Sound::set_looping(bool looping) { +void Sound::set_looping(SoundContext & ctx, bool looping) { this->looping = looping; - - SoundContext & ctx = SoundContext::get_instance(); if (!ctx.engine.isValidVoiceHandle(this->handle)) return; ctx.engine.setLooping(this->handle, this->looping); } + diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h index 4c68f32..b0b80f8 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -1,28 +1,31 @@ #pragma once -#include <memory> #include <soloud/soloud.h> #include <soloud/soloud_wav.h> -#include "../api/Asset.h" +#include "../Resource.h" namespace crepe { +class SoundContext; + /** * \brief Sound resource facade * * This class is a wrapper around a \c SoLoud::Wav instance, which holds a * single sample. It is part of the sound facade. */ -class Sound { +class Sound : public Resource { public: + Sound(const Asset & src); + ~Sound(); // dbg_trace /** * \brief Pause this sample * * Pauses this sound if it is playing, or does nothing if it is already paused. The playhead * position is saved, such that calling \c play() after this function makes the sound resume. */ - void pause(); + void pause(SoundContext & ctx); /** * \brief Play this sample * @@ -32,7 +35,7 @@ public: * \c play() while the sound is already playing causes multiple instances of the sample to * play simultaniously. The sample started last is the one that is controlled afterwards. */ - void play(); + void play(SoundContext & ctx); /** * \brief Reset playhead position * @@ -40,13 +43,13 @@ public: * from the start of the sample. If the sound is not paused before calling this function, * this function will stop playback. */ - void rewind(); + void rewind(SoundContext & ctx); /** * \brief Set playback volume / gain * * \param volume Volume (0 = muted, 1 = full volume) */ - void set_volume(float volume); + void set_volume(SoundContext & ctx, float volume); /** * \brief Get playback volume / gain * @@ -58,7 +61,7 @@ public: * * \param looping Looping behavior (false = one-shot, true = loop) */ - void set_looping(bool looping); + void set_looping(SoundContext & ctx, bool looping); /** * \brief Get looping behavior * @@ -66,13 +69,6 @@ public: */ bool get_looping() const { return this->looping; } -public: - Sound(const char * src); - Sound(std::unique_ptr<Asset> res); - -private: - void load(std::unique_ptr<Asset> res); - private: SoLoud::Wav sample; SoLoud::handle handle; diff --git a/src/crepe/facade/SoundContext.cpp b/src/crepe/facade/SoundContext.cpp index deb2b62..b65dfb2 100644 --- a/src/crepe/facade/SoundContext.cpp +++ b/src/crepe/facade/SoundContext.cpp @@ -4,11 +4,6 @@ using namespace crepe; -SoundContext & SoundContext::get_instance() { - static SoundContext instance; - return instance; -} - SoundContext::SoundContext() { dbg_trace(); engine.init(); diff --git a/src/crepe/facade/SoundContext.h b/src/crepe/facade/SoundContext.h index d703c16..d22ff7a 100644 --- a/src/crepe/facade/SoundContext.h +++ b/src/crepe/facade/SoundContext.h @@ -13,18 +13,18 @@ namespace crepe { * the methods for playing \c Sound instances. It is part of the sound facade. */ class SoundContext { -private: - // singleton +public: SoundContext(); virtual ~SoundContext(); + SoundContext(const SoundContext &) = delete; SoundContext(SoundContext &&) = delete; SoundContext & operator=(const SoundContext &) = delete; SoundContext & operator=(SoundContext &&) = delete; private: - static SoundContext & get_instance(); SoLoud::Soloud engine; + //! Sound directly calls methods on \c engine friend class Sound; }; diff --git a/src/crepe/manager/CMakeLists.txt b/src/crepe/manager/CMakeLists.txt index 517b8a2..480c8ee 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 + ResourceManager.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -16,5 +17,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES SaveManager.h SceneManager.h SceneManager.hpp + ResourceManager.h + ResourceManager.hpp ) diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h index a91509e..475aed9 100644 --- a/src/crepe/manager/Mediator.h +++ b/src/crepe/manager/Mediator.h @@ -10,6 +10,7 @@ namespace crepe { class ComponentManager; class SceneManager; +class ResourceManager; /** * Struct to pass references to classes that would otherwise need to be singletons down to @@ -28,6 +29,7 @@ struct Mediator { OptionalRef<SceneManager> scene_manager; OptionalRef<SaveManager> save_manager = SaveManager::get_instance(); OptionalRef<EventManager> event_manager = EventManager::get_instance(); + OptionalRef<ResourceManager> resource_manager; }; } diff --git a/src/crepe/manager/ResourceManager.cpp b/src/crepe/manager/ResourceManager.cpp new file mode 100644 index 0000000..87585ad --- /dev/null +++ b/src/crepe/manager/ResourceManager.cpp @@ -0,0 +1,34 @@ +#include "util/Log.h" + +#include "ResourceManager.h" + +using namespace crepe; +using namespace std; + +ResourceManager::ResourceManager(Mediator & mediator) : Manager(mediator) { + mediator.resource_manager = *this; + dbg_trace(); +} +ResourceManager::~ResourceManager() { dbg_trace(); } + +void ResourceManager::clear() { + std::erase_if(this->resources, [](const pair<const Asset, CacheEntry> & pair) { + const CacheEntry & entry = pair.second; + return entry.persistent == false; + }); +} + +void ResourceManager::clear_all() { + this->resources.clear(); +} + +void ResourceManager::set_persistent(const Asset & asset, bool persistent) { + this->get_entry(asset).persistent = persistent; +} + +ResourceManager::CacheEntry & ResourceManager::get_entry(const Asset & asset) { + if (!this->resources.contains(asset)) + this->resources[asset] = {}; + return this->resources.at(asset); +} + diff --git a/src/crepe/manager/ResourceManager.h b/src/crepe/manager/ResourceManager.h new file mode 100644 index 0000000..e7e6abc --- /dev/null +++ b/src/crepe/manager/ResourceManager.h @@ -0,0 +1,48 @@ +#pragma once + +#include <memory> +#include <unordered_map> + +#include "../Resource.h" +#include "../api/Asset.h" + +#include "Manager.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 Manager { +public: + ResourceManager(Mediator & mediator); + virtual ~ResourceManager(); // dbg_trace + +private: + struct CacheEntry { + std::unique_ptr<Resource> resource = nullptr; + bool persistent = false; + }; + //! A cache that holds all the assets, accessible by their file path, over multiple scenes. + std::unordered_map<const Asset, CacheEntry> resources; + CacheEntry & get_entry(const Asset & asset); + +public: + void set_persistent(const Asset & asset, bool persistent); + + template <typename Resource> + Resource & get(const Asset & asset); + + void clear(); + void clear_all(); +}; + +} // namespace crepe + +#include "ResourceManager.hpp" diff --git a/src/crepe/manager/ResourceManager.hpp b/src/crepe/manager/ResourceManager.hpp new file mode 100644 index 0000000..8270bc5 --- /dev/null +++ b/src/crepe/manager/ResourceManager.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include <format> + +#include "ResourceManager.h" + +namespace crepe { + +template <typename T> +T & ResourceManager::get(const Asset & asset) { + using namespace std; + static_assert(is_base_of<Resource, T>::value, "cache must recieve a derivative class of Resource"); + + CacheEntry & entry = this->get_entry(asset); + if (entry.resource == nullptr) + entry.resource = make_unique<T>(asset); + + T * concrete_resource = dynamic_cast<T *>(entry.resource.get()); + if (concrete_resource == nullptr) + throw runtime_error(format("ResourceManager: mismatch between requested type and actual type of resource ({})", asset.get_path())); + + return *concrete_resource; +} + +} + diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp new file mode 100644 index 0000000..97cf966 --- /dev/null +++ b/src/crepe/system/AudioSystem.cpp @@ -0,0 +1,24 @@ +#include "AudioSystem.h" + +#include "../api/AudioSource.h" +#include "../manager/ComponentManager.h" +#include "../manager/ResourceManager.h" +#include "../types.h" + +using namespace crepe; +using namespace std; + +void AudioSystem::update() { + ComponentManager & component_manager = this->mediator.component_manager; + ResourceManager & resource_manager = this->mediator.resource_manager; + RefVector<AudioSource> components = component_manager.get_components_by_type<AudioSource>(); + + for (auto component_ref : components) { + AudioSource & component = component_ref.get(); + if (!component.active) continue; + + Sound & sound = resource_manager.get<Sound>(component.source); + // TODO: lots of state diffing + } +} + diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h new file mode 100644 index 0000000..e037f51 --- /dev/null +++ b/src/crepe/system/AudioSystem.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../facade/SoundContext.h" + +#include "System.h" + +namespace crepe { + +class AudioSystem : public System { +public: + using System::System; + void update() override; + +private: + SoundContext context {}; +}; + +} // namespace crepe + diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt index d658b25..f507b90 100644 --- a/src/crepe/system/CMakeLists.txt +++ b/src/crepe/system/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources(crepe PUBLIC PhysicsSystem.cpp CollisionSystem.cpp RenderSystem.cpp + AudioSystem.cpp AnimatorSystem.cpp ) @@ -14,5 +15,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES PhysicsSystem.h CollisionSystem.h RenderSystem.h + AudioSystem.h AnimatorSystem.h ) 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/example/asset_manager.cpp b/src/example/asset_manager.cpp index 917b547..660b318 100644 --- a/src/example/asset_manager.cpp +++ b/src/example/asset_manager.cpp @@ -8,7 +8,7 @@ int main() { // this needs to be called before the asset manager otherwise the destructor of sdl is not in // the right order - { Texture test("../asset/texture/img.png"); } + { Texture test("asset/texture/img.png"); } // FIXME: make it so the issue described by the above comment is not possible (i.e. the order // in which internal classes are instantiated should not impact the way the engine works). @@ -17,20 +17,20 @@ int main() { { // TODO: [design] the Sound class can't be directly included by the user as it includes // SoLoud headers. - auto bgm = mgr.cache<Sound>("../mwe/audio/bgm.ogg"); - auto sfx1 = mgr.cache<Sound>("../mwe/audio/sfx1.wav"); - auto sfx2 = mgr.cache<Sound>("../mwe/audio/sfx2.wav"); + auto bgm = mgr.cache<Sound>("mwe/audio/bgm.ogg"); + auto sfx1 = mgr.cache<Sound>("mwe/audio/sfx1.wav"); + auto sfx2 = mgr.cache<Sound>("mwe/audio/sfx2.wav"); - auto img = mgr.cache<Texture>("../asset/texture/img.png"); - auto img1 = mgr.cache<Texture>("../asset/texture/second.png"); + auto img = mgr.cache<Texture>("asset/texture/img.png"); + auto img1 = mgr.cache<Texture>("asset/texture/second.png"); } { - auto bgm = mgr.cache<Sound>("../mwe/audio/bgm.ogg"); - auto sfx1 = mgr.cache<Sound>("../mwe/audio/sfx1.wav"); - auto sfx2 = mgr.cache<Sound>("../mwe/audio/sfx2.wav"); + auto bgm = mgr.cache<Sound>("mwe/audio/bgm.ogg"); + auto sfx1 = mgr.cache<Sound>("mwe/audio/sfx1.wav"); + auto sfx2 = mgr.cache<Sound>("mwe/audio/sfx2.wav"); - auto img = mgr.cache<Texture>("../asset/texture/img.png"); - auto img1 = mgr.cache<Texture>("../asset/texture/second.png"); + auto img = mgr.cache<Texture>("asset/texture/img.png"); + auto img1 = mgr.cache<Texture>("asset/texture/second.png"); } } diff --git a/src/test/AudioTest.cpp b/src/test/AudioTest.cpp new file mode 100644 index 0000000..afd2672 --- /dev/null +++ b/src/test/AudioTest.cpp @@ -0,0 +1,27 @@ +#include <gtest/gtest.h> + +#include <crepe/manager/ComponentManager.h> +#include <crepe/api/AudioSource.h> +#include <crepe/api/GameObject.h> +#include <crepe/system/AudioSystem.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class AudioTest : public Test { + Mediator mediator; +public: + ComponentManager component_manager{mediator}; + AudioSystem system {mediator}; + + void SetUp() override { + auto & mgr = this->component_manager; + GameObject entity = mgr.new_object("name"); + entity.add_component<AudioSource>("mwe/audio/sfx1.wav"); + } +}; + +TEST_F(AudioTest, Default) { +} + diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index d3e27b0..4174926 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -3,7 +3,9 @@ target_sources(test_main PUBLIC PhysicsTest.cpp ScriptTest.cpp ParticleTest.cpp + AudioTest.cpp AssetTest.cpp + ResourceManagerTest.cpp OptionalRefTest.cpp RenderSystemTest.cpp EventTest.cpp diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp new file mode 100644 index 0000000..1f56e23 --- /dev/null +++ b/src/test/ResourceManagerTest.cpp @@ -0,0 +1,75 @@ +#include <gtest/gtest.h> + +#define private public +#define protected public + +#include <crepe/util/Log.h> +#include <crepe/manager/ResourceManager.h> +#include <crepe/api/GameObject.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class ResourceManagerTest : public Test { + Mediator mediator; +public: + ResourceManager resource_manager{mediator}; + + Asset asset_a{"asset/texture/img.png"}; + Asset asset_b{"asset/texture/ERROR.png"}; + + class TestResource : public Resource { + public: + static unsigned instances; + + public: + const unsigned instance; + TestResource(const Asset & src) + : Resource(src), + instance(this->instances++) { } + ~TestResource() { this->instances--; } + bool operator == (const TestResource & other) const { + return this->instance == other.instance; + } + }; + +private: + void SetUp() override { + TestResource::instances = 0; + } +}; +unsigned ResourceManagerTest::TestResource::instances = 0; + +TEST_F(ResourceManagerTest, Default) { + TestResource & res_1 = resource_manager.get<TestResource>(asset_a); + TestResource & res_2 = resource_manager.get<TestResource>(asset_a); + TestResource & res_3 = resource_manager.get<TestResource>(asset_b); + TestResource & res_4 = resource_manager.get<TestResource>(asset_b); + + ASSERT_EQ(res_1, res_2); + ASSERT_EQ(res_3, res_4); + EXPECT_NE(res_1, res_3); + + EXPECT_EQ(TestResource::instances, 2); + + resource_manager.clear(); +} + +TEST_F(ResourceManagerTest, Persistent) { + resource_manager.set_persistent(asset_a, true); + EXPECT_EQ(TestResource::instances, 0); + + resource_manager.get<TestResource>(asset_a); + resource_manager.get<TestResource>(asset_a); + resource_manager.get<TestResource>(asset_b); + resource_manager.get<TestResource>(asset_b); + EXPECT_EQ(TestResource::instances, 2); + + resource_manager.clear(); + EXPECT_EQ(TestResource::instances, 1); + + resource_manager.clear_all(); + EXPECT_EQ(TestResource::instances, 0); +} + diff --git a/src/test/main.cpp b/src/test/main.cpp index aece72d..54f74fd 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -1,8 +1,4 @@ #include <gtest/gtest.h> - -#define protected public -#define private public - #include <crepe/api/Config.h> 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, + }, + }; } }; @@ -28,3 +26,4 @@ int main(int argc, char ** argv) { return RUN_ALL_TESTS(); } + |