diff options
Diffstat (limited to 'src/crepe')
| -rw-r--r-- | src/crepe/Resource.h | 18 | ||||
| -rw-r--r-- | src/crepe/api/AudioSource.h | 9 | ||||
| -rw-r--r-- | src/crepe/facade/Sound.cpp | 34 | ||||
| -rw-r--r-- | src/crepe/facade/Sound.h | 9 | ||||
| -rw-r--r-- | src/crepe/facade/SoundContext.cpp | 7 | ||||
| -rw-r--r-- | src/crepe/facade/SoundContext.h | 48 | ||||
| -rw-r--r-- | src/crepe/manager/ResourceManager.h | 44 | ||||
| -rw-r--r-- | src/crepe/system/AudioSystem.cpp | 4 | ||||
| -rw-r--r-- | src/crepe/system/AudioSystem.h | 29 | ||||
| -rw-r--r-- | src/crepe/util/Private.h | 60 | ||||
| -rw-r--r-- | src/crepe/util/Private.hpp | 2 | 
11 files changed, 189 insertions, 75 deletions
| diff --git a/src/crepe/Resource.h b/src/crepe/Resource.h index a0c8859..a2d65df 100644 --- a/src/crepe/Resource.h +++ b/src/crepe/Resource.h @@ -6,21 +6,19 @@ class ResourceManager;  class Asset;  /** - * Resource is an interface class used to represent a (deserialized) game - * resource (e.g. textures, sounds). + * \brief Resource interface + * + * Resource is an interface class used to represent a (deserialized) game resource (e.g. + * textures, sounds). Resources are always created from \ref Asset "assets" by ResourceManager. + * + * The game programmer has the ability to use the ResourceManager to keep instances of concrete + * resources between scenes, preventing them from being reinstantiated during a scene + * transition.   */  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/AudioSource.h b/src/crepe/api/AudioSource.h index 63b4bc4..330e8e1 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -17,16 +17,19 @@ class AudioSource : public Component {  	friend class AudioSystem;  protected: +	/** +	 * \param source Sound sample to load +	 */  	AudioSource(game_object_id_t id, const Asset & source); -	//! Only ComponentManager can create components +	//! Only ComponentManager creates components  	friend class ComponentManager;  public: -	// But std::unique_ptr needs to be able to destoy this component again +	// std::unique_ptr needs to be able to destoy this component  	virtual ~AudioSource() = default;  public: -	//! Start or resume this audio source +	//! Start this audio source  	void play(bool looping = false);  	//! Stop this audio source  	void stop(); diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 33a0c47..ad50637 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -2,7 +2,6 @@  #include "../util/Log.h"  #include "Sound.h" -#include "SoundContext.h"  using namespace crepe;  using namespace std; @@ -12,36 +11,3 @@ Sound::Sound(const Asset & src) : Resource(src) {  	dbg_trace();  }  Sound::~Sound() { dbg_trace(); } - -// void Sound::play(SoundContext & ctx) { -// 	if (ctx.engine.getPause(this->handle)) { -// 		// resume if paused -// 		ctx.engine.setPause(this->handle, false); -// 	} else { -// 		// or start new sound -// 		this->handle = ctx.engine.play(this->sample, this->volume); -// 		ctx.engine.setLooping(this->handle, this->looping); -// 	} -// } -// -// void Sound::pause(SoundContext & ctx) { -// 	if (ctx.engine.getPause(this->handle)) return; -// 	ctx.engine.setPause(this->handle, true); -// } -// -// void Sound::rewind(SoundContext & ctx) { -// 	if (!ctx.engine.isValidVoiceHandle(this->handle)) return; -// 	ctx.engine.seek(this->handle, 0); -// } -// -// void Sound::set_volume(SoundContext & ctx, float volume) { -// 	this->volume = volume; -// 	if (!ctx.engine.isValidVoiceHandle(this->handle)) return; -// 	ctx.engine.setVolume(this->handle, this->volume); -// } -// -// void Sound::set_looping(SoundContext & ctx, bool looping) { -// 	this->looping = looping; -// 	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 35bccdb..a78a2a7 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -12,21 +12,24 @@ 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. + * 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 : public Resource {  public:  	Sound(const Asset & src);  	~Sound(); // dbg_trace +	//! Voice handle wrapper  	struct Handle { +		//! Voice handle (soloud), used by SoundContext  		SoLoud::handle handle;  	};  private: +	//! Deserialized resource (soloud)  	SoLoud::Wav sample; - +	//! SoundContext uses \c sample  	friend class SoundContext;  }; diff --git a/src/crepe/facade/SoundContext.cpp b/src/crepe/facade/SoundContext.cpp index 470b3cc..8bd7e74 100644 --- a/src/crepe/facade/SoundContext.cpp +++ b/src/crepe/facade/SoundContext.cpp @@ -17,17 +17,16 @@ SoundContext::~SoundContext() {  Sound::Handle SoundContext::play(Sound & resource) {  	return { -		.handle = this->engine.play(resource.sample, this->default_volume), +		.handle = this->engine.play(resource.sample, 1.0f),  	};  }  void SoundContext::stop(Sound::Handle & handle) { this->engine.stop(handle.handle); } -void SoundContext::set_volume(Sound & resource, Sound::Handle & handle, float volume) { +void SoundContext::set_volume(Sound::Handle & handle, float volume) {  	this->engine.setVolume(handle.handle, volume); -	this->default_volume = volume;  } -void SoundContext::set_loop(Sound & resource, Sound::Handle & handle, bool loop) { +void SoundContext::set_loop(Sound::Handle & handle, bool loop) {  	this->engine.setLooping(handle.handle, loop);  } diff --git a/src/crepe/facade/SoundContext.h b/src/crepe/facade/SoundContext.h index c651cd5..3bc8be5 100644 --- a/src/crepe/facade/SoundContext.h +++ b/src/crepe/facade/SoundContext.h @@ -11,8 +11,8 @@ namespace crepe {  /**   * \brief Sound engine facade   * - * This class is a wrapper around a \c SoLoud::Soloud instance, which provides - * the methods for playing \c Sound instances. It is part of the sound facade. + * This class is a wrapper around a \c SoLoud::Soloud instance, which provides the methods for + * playing \c Sound instances. It is part of the sound facade.   */  class SoundContext {  public: @@ -24,15 +24,51 @@ public:  	SoundContext & operator=(const SoundContext &) = delete;  	SoundContext & operator=(SoundContext &&) = delete; +	/** +	 * \brief Play a sample +	 * +	 * Plays a Sound from the beginning of the sample and returns a handle to control it later. +	 * +	 * \param resource Sound instance to play +	 * +	 * \returns Handle to control this voice +	 */  	virtual Sound::Handle play(Sound & resource); -	virtual void stop(Sound::Handle &); -	virtual void set_volume(Sound &, Sound::Handle &, float); -	virtual void set_loop(Sound &, Sound::Handle &, bool); +	/** +	 * \brief Stop a voice immediately if it is still playing +	 * +	 * \note This function does nothing if the handle is invalid or if the sound is already +	 * stopped / finished playing. +	 * +	 * \param handle Voice handle returned by SoundContext::play +	 */ +	virtual void stop(Sound::Handle & handle); +	/** +	 * \brief Change the volume of a voice +	 * +	 * \note This function does nothing if the handle is invalid or if the sound is already +	 * stopped / finished playing. +	 * +	 * \param handle Voice handle returned by SoundContext::play +	 * \param volume New gain value (0=silent, 1=default) +	 */ +	virtual void set_volume(Sound::Handle & handle, float volume); +	/** +	 * \brief Set the looping behavior of a voice +	 * +	 * \note This function does nothing if the handle is invalid or if the sound is already +	 * stopped / finished playing. +	 * +	 * \param handle Voice handle returned by SoundContext::play +	 * \param loop Looping behavior (false=oneshot, true=loop) +	 */ +	virtual void set_loop(Sound::Handle & handle, bool loop);  private: +	//! Abstracted class  	SoLoud::Soloud engine; -	float default_volume = 1.0f; +	//! Config reference  	Config & config = Config::get_instance();  }; diff --git a/src/crepe/manager/ResourceManager.h b/src/crepe/manager/ResourceManager.h index e7e6abc..84b275d 100644 --- a/src/crepe/manager/ResourceManager.h +++ b/src/crepe/manager/ResourceManager.h @@ -11,13 +11,11 @@  namespace crepe {  /** - * \brief The ResourceManager is responsible for storing and managing assets over - * multiple scenes. + * \brief Owner of concrete Resource instances   *  - * 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. + * ResourceManager caches concrete Resource instances per Asset. Concrete resources are + * destroyed at the end of scenes by default, unless the game programmer marks them as + * persistent.   */  class ResourceManager : public Manager {  public: @@ -25,21 +23,53 @@ public:  	virtual ~ResourceManager(); // dbg_trace  private: +	//! Cache entry  	struct CacheEntry { +		//! Concrete resource instance  		std::unique_ptr<Resource> resource = nullptr; +		//! Prevent ResourceManager::clear from removing this entry  		bool persistent = false;  	}; -	//! A cache that holds all the assets, accessible by their file path, over multiple scenes. +	//! Internal cache  	std::unordered_map<const Asset, CacheEntry> resources; +	/** +	 * \brief Ensure a cache entry exists for this asset and return a mutable reference to it +	 * +	 * \param asset Asset the concrete resource is instantiated from +	 * +	 * \returns Mutable reference to cache entry +	 */  	CacheEntry & get_entry(const Asset & asset);  public: +	/** +	 * \brief Mark a resource as persistent (i.e. used across multiple scenes) +	 * +	 * \param asset Asset the concrete resource is instantiated from +	 * \param persistent Whether this resource is persistent (true=keep, false=destroy) +	 */  	void set_persistent(const Asset & asset, bool persistent); +	/** +	 * \brief Retrieve reference to concrete Resource by Asset +	 * +	 * \param asset Asset the concrete resource is instantiated from +	 * \tparam Resource Concrete derivative of Resource +	 * +	 * This class instantiates the concrete resource if it is not yet stored in the internal +	 * cache, or returns a reference to the cached resource if it already exists. +	 * +	 * \returns Reference to concrete resource +	 * +	 * \throws std::runtime_error if the \c Resource parameter does not match with the actual +	 * type of the resource stored in the cache for this Asset +	 */  	template <typename Resource>  	Resource & get(const Asset & asset); +	//! Clear non-persistent resources from cache  	void clear(); +	//! Clear all resources from cache regardless of persistence  	void clear_all();  }; diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index 0696b34..26913c0 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -52,10 +52,10 @@ void AudioSystem::diff_update(AudioSource & component, ComponentPrivate & data,  		component.oneshot_stop = false;  	}  	if (component.volume != data.last_volume) { -		context.set_volume(resource, data.handle, component.volume); +		context.set_volume(data.handle, component.volume);  	}  	if (component.loop != data.last_loop) { -		context.set_loop(resource, data.handle, component.loop); +		context.set_loop(data.handle, component.loop);  	}  } diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h index c941470..4d21883 100644 --- a/src/crepe/system/AudioSystem.h +++ b/src/crepe/system/AudioSystem.h @@ -14,9 +14,7 @@ public:  	void update() override;  private: -	/** -	 * \brief Private data stored by AudioSystem on AudioSource component -	 */ +	//! Private data stored by AudioSystem on AudioSource component  	struct ComponentPrivate {  		//! This sample's voice handle  		Sound::Handle handle; @@ -31,14 +29,39 @@ private:  		//! \}  	}; +	/** +	 * \brief Update `last_*` members of \c data +	 * +	 * Copies all component properties stored for comparison between AudioSystem::update() calls +	 * +	 * \param component Source properties +	 * \param data Destination properties +	 */  	void update_last(const AudioSource & component, ComponentPrivate & data); +	/** +	 * \brief Compare update component +	 * +	 * Compares properties of \c component and \c data, and calls SoundContext functions where +	 * applicable. +	 * +	 * \param component AudioSource component to update +	 * \param data AudioSource's private data +	 * \param resource Sound instance for AudioSource's Asset +	 */  	void diff_update(AudioSource & component, ComponentPrivate & data, Sound & resource);  protected: +	/** +	 * \brief Get SoundContext +	 * +	 * SoundContext is retrieved through this function instead of being a direct member of +	 * AudioSystem to aid with testability. +	 */  	virtual SoundContext & get_context();  private: +	//! Actually stores SoundContext if the base AudioSystem::get_context implementation is used  	Private context;  }; diff --git a/src/crepe/util/Private.h b/src/crepe/util/Private.h index 62a2e1a..d725a5e 100644 --- a/src/crepe/util/Private.h +++ b/src/crepe/util/Private.h @@ -5,26 +5,82 @@  namespace crepe { +/** + * \brief Utility for storing type hidden from user + * + * This class can be used to store types which cannot be used in the API directly due to header + * distribution limitations. This class is similar to `std::any`, but provides a method for + * retrieving a mutable reference to the stored object. + */  class Private {  public:  	Private() = default;  	~Private(); +	/** +	 * \name Copy +	 * +	 * \note These functions do not do anything, resulting in `*this` being an empty (default) +	 * instance. +	 * +	 * \{ +	 */  	Private(const Private &); -	Private(Private &&);  	Private & operator=(const Private &); +	//! \} +	/** +	 * \name Move +	 * +	 * These functions actually move the stored type if present. +	 * +	 * \{ +	 */ +	Private(Private &&);  	Private & operator=(Private &&); +	//! \} +	/** +	 * \brief Get the stored object +	 * +	 * \tparam T Type of stored object +	 * +	 * \returns Mutable reference to stored object +	 * +	 * \throws std::out_of_range if this instance does not contain any object +	 * \throws std::logic_error if the stored type and requested type differ +	 */  	template <typename T> -	T & get(); +	T & get() const; +	/** +	 * \brief Create and store an arbitrary object +	 * +	 * \tparam T Type of object +	 * \tparam Args Perfect forwarding arguments +	 * \param args Perfect forwarding arguments +	 * +	 * All arguments to this function are forwarded using `std::forward` to the constructor of T. +	 * +	 * \returns Mutable reference to stored object +	 * +	 * \note If this instance already contained an object, this function implicitly destroys the +	 * previous object. +	 */  	template <typename T, typename... Args>  	T & set(Args &&... args); +	/** +	 * \brief Check if this instance contains an object +	 * +	 * \returns `true` if this instance is empty, `false` if it contains an object +	 */  	bool empty() const noexcept;  private: +	//! Wrapper for destructor call of stored object type  	std::function<void(void *)> destructor; +	//! Stored object's type  	std::type_index type = typeid(void); +	//! Stored object  	void * instance = nullptr;  }; diff --git a/src/crepe/util/Private.hpp b/src/crepe/util/Private.hpp index 3a87a9f..b2174c0 100644 --- a/src/crepe/util/Private.hpp +++ b/src/crepe/util/Private.hpp @@ -18,7 +18,7 @@ T & Private::set(Args &&... args) {  }  template <typename T> -T & Private::get() { +T & Private::get() const {  	using namespace std;  	if (this->empty()) throw out_of_range("Private: get() called on empty object");  	type_index requested_type = typeid(T); |