1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
#ifndef PARTICLE_MANAGER_H
#define PARTICLE_MANAGER_H
#pragma once
#include "globalincs/pstypes.h"
#include "particle/ParticleEffect.h"
#include "particle/ParticleSource.h"
#include "particle/ParticleSourceWrapper.h"
#include "utils/id.h"
namespace particle {
struct particle_effect_tag {
};
/**
* The particle index type.
*/
using ParticleEffectHandle = ::util::ID<particle_effect_tag, ptrdiff_t, -1>;
/**
* @brief Manages high-level particle effects and sources
*
* @ingroup particleSystems
*
* This class is responsible for managing the loaded effects and processing the created particle sources. The whole effect
* subsystem is designed to not allocate memory at runtime (except if the vector resizes but that should only happen a few times).
*/
class ParticleManager {
private:
SCP_vector<std::shared_ptr<ParticleEffect>> m_effects; //!< All parsed effects
SCP_vector<ParticleSource> m_sources; //!< The currently active sources
bool m_processingSources = false; //!< @c true if sources are currently being processed
/**
* If the sources are currently being processed, no additional sources can be added. Instead, they are added to this
* vector and then added to the main vector when processing is done.
*/
SCP_vector<ParticleSource> m_deferredSourceAdding;
/**
* The global paticle manager
*/
static std::unique_ptr<ParticleManager> m_manager;
/**
* @brief Creates a source and returns a pointer to it
*
* This also handles the case when a source is created when current processing the sources
*
* @warning The pointer is temporary and only valid until the #m_sources is modified!
* @return The source pointer
*/
ParticleSource* createSource();
public:
ParticleManager() {}
/**
* @brief Initializes the effect system
*
* This creates the ParticleManager and parses the config files
*/
static void init();
/**
* @brief Gets the global particle manager
* @return The particle manager
*/
static inline ParticleManager* get() {
Assertion(m_manager != nullptr, "ParticleManager was not properly inited!");
return m_manager.get();
}
/**
* @brief Shuts down the particle effect system
*/
static void shutdown();
/**
* @brief Gets an effect by index
* @param effectID The id of the effect to retrieve
* @return The particle effect pointer, will not be @c nullptr
*/
inline ParticleEffectPtr getEffect(ParticleEffectHandle effectID)
{
Assertion(effectID.value() >= 0 &&
effectID.value() < static_cast<ParticleEffectHandle::impl_type>(m_effects.size()),
"Particle effect index " PTRDIFF_T_ARG " is invalid!", effectID.value());
return m_effects[effectID.value()].get();
}
/**
* @brief Gets an effect by name
*
* @note If possible, only call this once and then store the index. The lookup is being done by a sequential search
* which means it's pretty slow.
*
* @param name The name of the effect that is being searched, may not be empty
* @return The index of the effect
*/
ParticleEffectHandle getEffectByName(const SCP_string& name);
/**
* @brief Adds an effect
* @param effect The effect to add
* @return The index of the added effect
*/
ParticleEffectHandle addEffect(ParticleEffectPtr effect);
/**
* @brief Does one processing step of the particle manager
* @param frameTime The length of the current frame
*/
void doFrame(float frameTime);
/**
* @brief Removes all sources
*/
void clearSources();
/**
* @brief Pages in all used effects
*/
void pageIn();
/**
* @brief Creates a source for the specified effect
*
* This returns a wrapper class because some effects may create multiple sources.
*
* @param index The index of the effect
* @return A wrapper class which allows access to the created sources
*/
ParticleSourceWrapper createSource(ParticleEffectHandle index);
};
namespace internal {
/**
* @brief Parses an effect element
*
* This can either be the name of an existing effect or a new effect which is created in-place. If forcedType is
* specified then the effect will have the specified type or an error will be generated.
*
* @param forcedType The type the effect should have, EffectType::Invalid can be specified for any effect type
* @param name The name of the created effect, an empty string means no special name
* @return The index of the added effect
*/
ParticleEffectHandle parseEffectElement(EffectType forcedType = EffectType::Invalid, const SCP_string& name = "");
/**
* @brief Utility function for required_string
*
* If no_create is @c false then this will act like #required_string, otherwise it will be an #optional_string
*
* @param token The token to check for
* @param no_create The no_create value
* @return @c true if the token was present, @c false otherwise
*/
bool required_string_if_new(const char* token, bool no_create);
/**
* @brief Parses an animation or list of animations.
*
* Parses an animation or list of animations and returns the handle(s). If critical is @c true then a failure to load the animation will cause
* an error. Otherwise it will be cause a warning.
*
* @param critical @c true if a failure is critical
* @return The vector of animation handles
*/
SCP_vector<int> parseAnimationList(bool critical = true);
}
namespace util {
/**
* @brief Parses an effect name
*
* This can be used to parse an effect from another part of the engine. This parses an effect name and returns the
* index. If the name is not valid an error is displayed.
*
* @param objectName Can be optionally specified so the error message is a bit more specific
* @return The index
*/
ParticleEffectHandle parseEffect(const SCP_string& objectName = "");
}
}
#endif // PARTICLE_MANAGER_H
|