////////////////////////////////////////////////////////////////////////////////// // SPARK particle engine // // Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com // // // // This software is provided 'as-is', without any express or implied // // warranty. In no event will the authors be held liable for any damages // // arising from the use of this software. // // // // Permission is granted to anyone to use this software for any purpose, // // including commercial applications, and to alter it and redistribute it // // freely, subject to the following restrictions: // // // // 1. The origin of this software must not be misrepresented; you must not // // claim that you wrote the original software. If you use this software // // in a product, an acknowledgment in the product documentation would be // // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source distribution. // ////////////////////////////////////////////////////////////////////////////////// #ifndef H_SPK_SYSTEM #define H_SPK_SYSTEM #include "Core/SPK_DEF.h" #include "Core/SPK_Registerable.h" #include "Core/SPK_Transformable.h" #include "Core/SPK_Vector3D.h" namespace SPK { class Group; class Vector3D; /** * @enum StepMode * @brief Enumeration defining how to handle the step time of particle systems * @since 1.05.00 */ enum StepMode { STEP_REAL, /**< The step time is the deltatime passed by the user */ STEP_CONSTANT, /**< The step time is a constant time therefore 0 to many updates may occur in a call */ STEP_ADAPTIVE, /**< The step time is a range between 2 values therefore 0 to many updates may occur in a call */ }; /** * @class System * @brief A whole system of particles * * This class defines a whole system of particles. It contains particle groups.
* It offers a way to handle a system very easily.
* Basically a particle system is updated by calling update(unsigned int) and renderered with render() at each frame.
*
* Note that a System is only a helper class to manage many Groups. However it can be omitted and groups can be updated and rendered alone.
*
* A System is transformable. If the system is transformed, all its sub emitters will be transformed as well. However, its modifiers will not * (modifiers can be described in the world coordinates already). If you wish to transform some of its modifiers as well, you will have to do it aside. */ class SPK_PREFIX System : public Registerable, public Transformable { SPK_IMPLEMENT_REGISTERABLE(System) public : ///////////////// // Constructor // ///////////////// /** @brief Constructor of System */ System(); /** * @brief Creates and registers a new System * @return A new registered System * @since 1.04.00 */ static inline System* create(); //////////////// // Destructor // //////////////// virtual ~System() {} ///////////// // Setters // ///////////// /** * @brief Sets the camera position * * Note that the camera position is only useful if a group has to be sorted.
* In that case this vector will be used as the camera position to derive the distance between the particle and the camera position.
* The camera position has to be updated before an update of the sorted group. * * @param cameraPosition the camera position */ static void setCameraPosition(const Vector3D& cameraPosition); /** * @brief Enables or not the clamping on the deltaTime when updating systems * * This allows to limit too big deltaTime which may spoil your particle systems.
* Basically if the deltaTime is higher than the clamp value, the clamp calue is used as the deltaTime.
*
* It allows in real step mode to avoid having too big deltaTimes and in the other 2 modes to avoid having too * many updates that may slow down the application.
*
* Note that setting the clamp value too low may slow down your systems * * @param useClampStep : true to use a clamp value on the step, false not to * @param clamp : the clamp value * @since 1.05.00 */ static void setClampStep(bool useClampStep,float clamp = 1.0f); /** * @brief Uses a constant step to update the systems * * This tells the system to be updated with a constant time.
* Depending on the deltaTime passed for the update, 0 to many updates can occur.
* For example if the delta time is 1.0 and the constant step is 0.1 then 10 updates of time 0.1 will occur.
*
* This mode is useful when the update must be constant (accurate collisions...) but be aware it can be very computationnaly intensive. * * @param constantStep : the value of the step * @since 1.05.00 */ static void useConstantStep(float constantStep); /** * @brief Uses an adaptive step to update the systems * * This tells the system to be updated with a time between min and max.
* If the deltaTime passed is higher than maxStep or lower than minStep then this mode operates like the constant step mode with * either constant time being maxStep or minStep (respectivally).
* If the deltaTime lies between minStep and maxStep then this mode performs like the real step mode.
*
* This mode is a good alternative between the other two.
* Combined with the clamp step, it allows to correctly handle the step time without being to much frame rate dependant. * * @param minStep : the minimal time step * @param maxStep : the maximal time step * @since 1.05.00 */ static void useAdaptiveStep(float minStep,float maxStep); /** * @brief Uses the real step to update the systems * * This is the basic mode (and the mode per default) to update the systems.
* One call to update means one update of time deltaTime.
*
* This mode is the simpler and the one that allows best performance on low end systems.
* However the update may be inaccurate (due to too big deltaTime) and it performs badly with frame rate variation. * * @since 1.05.00 */ static void useRealStep(); /** * @brief Enables or disables the computation of the axis aligned Vector for this System * * Enabling the computation of the AABB for the System only takes the AABB of all AABB of the Groups within the System where AABB computation is enabled.
* see Group::enableAABBComputing(bool) for more details. * * @param AABB : true to enable the computing of the AABB of this System, false to disable it */ inline void enableAABBComputing(bool AABB); ///////////// // Getters // ///////////// /** * @brief Gets the camera position * * Note that the camera position vector is only read by SPARK. Only the user modifies it. * * @return the camera position */ static const Vector3D& getCameraPosition(); /** * @brief Gets the current step mode * @return the current step mode */ static StepMode getStepMode(); /** * @brief Gets the number of active particles in this system * * The number of active particles in the system is the addition of the number of active particles in each group of the system.
* Note that the number of active particle of the system is updated after each update of the system.
* This means if the user changes manually the number of particles in a group and call this method before an update, the number returned will not be up to date.
* To compute and get the real number of active particles in the System, see computeNbParticles(). * * @return the number of active particle in the system */ inline size_t getNbParticles() const; /** * @brief Computes the number of active particles in this System and returns it * * Unlike getNbParticles() which returns the last number of particles computed (after a call to update(float) or empty()), * this method recomputes the current number of active particles by parsing all the groups of this System.
* In that way, this method must not be used as an accessor but call once when necesseray between 2 updates.
*
* Note that this method updates the inner number of particles of this System, which means a call to getNbParticles() will * then return the computed number. * * @return the number of active particle in the system * @since 1.02.01 */ size_t computeNbParticles(); /** * @brief Gets the number of groups in the System * @return the number of groups in the System */ inline size_t getNbGroups() const; /** * @brief Gets the vector of the groups (pointers) in this System * * This method allows to modify Group parameters within the System.
* Note that for addition and removal, methods addGroup(Group*) and removeGroup(Group*) must exist.
* * @return a STL vector containing the groups in the System */ inline const std::vector& getGroups() const; /** * @brief Gets the Group at index * * Note that no bound check is performed. * * @param index : the index of the Group to get * @return the Group at index * @since 1.03.00 */ inline Group* getGroup(size_t index); /** * @brief Tells whether the computation of the axis aligned bouding box is enabled * * For a description of the computation of the AABB, see enableAABBComputing(bool). * * @return true if the computation of the AABB is enabled, false if it is disabled */ inline bool isAABBComputingEnabled() const; /** * @brief Gets a Vector3D holding the minimum coordinates of the AABB of this System. * * Note that this method is only useful when the AABB computation is enabled (see enableAABBComputing(bool)). * * @return a Vector3D holding the minimum coordinates of the AABB of this System * @since 1.01.00 */ inline const Vector3D& getAABBMin() const; /** * @brief Gets a Vector3D holding the maximum coordinates of the AABB of this System. * * Note that this method is only useful when the AABB computation is enabled (see enableAABBComputing(bool)). * * @return a Vector3D holding the maximum coordinates of the AABB of this System * @since 1.01.00 */ inline const Vector3D& getAABBMax() const; /////////////// // Interface // /////////////// /** * @brief Adds a Group to the System * @param group : a pointer on the Group to add to the System */ void addGroup(Group* group); /** * @brief Removes a Group from the System * * If the Group cannot be found, nothing happens. * * @param group : a pointer on the Group to remove from the System */ void removeGroup(Group* group); /** * @brief Updates the System of the current time step * * Note that this method updates all groups in the System from first to last. * * @param deltaTime : the time step * @return true if the System is still active (has active groups) */ virtual bool update(float deltaTime); /** * @brief Renders particles in the System * * Note that this method renders all groups in the System from first to last. */ virtual void render() const; /** * @brief Makes this System grow to the given time * * This method is useful to get a newwly created System to a mature state.
* This method only calls update(float) with the step until the total update time reaches the time. * * @param time : the total time of which to update this System * @param step : the time the System is updated at each call to update(float) * * @since 1.01.00 */ void grow(float time,float step); /** * @brief Empties the System * * This method will make all particles in the System inactive.
* However all connections are kept which means groups are still in theSystem. */ void empty(); /** * @brief Sorts the particles in all the group of this System where the sorting is enabled * * Note that the sorting is also performed during the update.
* This method is therefore only useful when the camera position changes several times between 2 updates.
*
* This methods calls the Group::sortParticles() of each Group in this System. * * @since 1.01.00 */ void sortParticles(); /** * @brief Computes the distances between each Particle in each Group of this System * * Note that the distances computation is also performed during the update.
* This method is therefore only useful when the camera position changes several times between 2 updates.
*
* This methods calls the Group::computeDistances() of each Group in this System. * * @since 1.01.00 */ void computeDistances(); /** * @brief Computes the bounding box of this System and of all groups in the System * * The bounding box of the System is only computed if the System has its bounding box computing enabled.
* In the same way, the bounding box of a Group within the System is only computed if the Group has its bounding box computing enabled.
*
* Note that the computation of bounding boxes is also performed during the update.
* This method is therefore only useful when the bounding boxes have to be recomputed between 2 updates.
*
* This methods calls the Group::computeAABB() of each Group in this System. * * @since 1.01.00 */ void computeAABB(); virtual Registerable* findByName(const std::string& name); protected : std::vector groups; virtual void registerChildren(bool registerAll); virtual void copyChildren(const System& system,bool keepChildren); virtual void destroyChildren(bool createBase); virtual void propagateUpdateTransform(); private : static Vector3D cameraPosition; static StepMode stepMode; static float constantStep; static float minStep; static float maxStep; static bool clampStepEnabled; static float clampStep; float deltaStep; size_t nbParticles; bool boundingBoxEnabled; Vector3D AABBMin; Vector3D AABBMax; bool innerUpdate(float deltaTime); }; inline System* System::create() { System* obj = new System; registerObject(obj); return obj; } inline void System::enableAABBComputing(bool AABB) { boundingBoxEnabled = AABB; } inline size_t System::getNbParticles() const { return nbParticles; } inline size_t System::getNbGroups() const { return groups.size(); } inline const std::vector& System::getGroups() const { return groups; } inline Group* System::getGroup(size_t index) { return groups[index]; } inline bool System::isAABBComputingEnabled() const { return boundingBoxEnabled; } inline const Vector3D& System::getAABBMin() const { return AABBMin; } inline const Vector3D& System::getAABBMax() const { return AABBMax; } } #endif