//////////////////////////////////////////////////////////////////////////////////
// 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