aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/crepe/CMakeLists.txt2
-rw-r--r--src/crepe/Component.h11
-rw-r--r--src/crepe/Resource.cpp6
-rw-r--r--src/crepe/Resource.h26
-rw-r--r--src/crepe/api/AssetManager.cpp17
-rw-r--r--src/crepe/api/AssetManager.h62
-rw-r--r--src/crepe/api/AssetManager.hpp22
-rw-r--r--src/crepe/api/AudioSource.cpp20
-rw-r--r--src/crepe/api/AudioSource.h61
-rw-r--r--src/crepe/api/CMakeLists.txt7
-rw-r--r--src/crepe/api/Config.h27
-rw-r--r--src/crepe/facade/Sound.cpp31
-rw-r--r--src/crepe/facade/Sound.h26
-rw-r--r--src/crepe/facade/SoundContext.cpp5
-rw-r--r--src/crepe/facade/SoundContext.h6
-rw-r--r--src/crepe/manager/CMakeLists.txt3
-rw-r--r--src/crepe/manager/Mediator.h2
-rw-r--r--src/crepe/manager/ResourceManager.cpp34
-rw-r--r--src/crepe/manager/ResourceManager.h48
-rw-r--r--src/crepe/manager/ResourceManager.hpp26
-rw-r--r--src/crepe/system/AudioSystem.cpp24
-rw-r--r--src/crepe/system/AudioSystem.h19
-rw-r--r--src/crepe/system/CMakeLists.txt2
-rw-r--r--src/crepe/util/Log.cpp2
-rw-r--r--src/crepe/util/Log.h16
-rw-r--r--src/example/asset_manager.cpp22
-rw-r--r--src/test/AudioTest.cpp27
-rw-r--r--src/test/CMakeLists.txt2
-rw-r--r--src/test/ResourceManagerTest.cpp75
-rw-r--r--src/test/main.cpp13
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();
}
+