//////////////////////////////////////////////////////////////////////////////////
// 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_PARTICLE
#define H_SPK_PARTICLE
#include "Core/SPK_DEF.h"
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Pool.h"
#include "Core/SPK_Model.h"
namespace SPK
{
/**
* @class Particle
* @brief A single particle (a point in space with a velocity and different parameters)
*
* A Particle is the primitive on which all the SPARK engine relies.
* Particles are designed to be handled in large amounts (called Group).
* This is why the user cannot update or render directly a single Particle.
*
* Note that the Particle class is only a class that presents an interface to the user (since 1.02.00), particles data are stored in the groups.
* This is why copying a Particle will not copy its data.
*/
class SPK_PREFIX Particle
{
friend inline bool isFurtherToCamera(const Particle&,const Particle&);
friend void swapParticles(Particle& a,Particle& b);
friend class Group;
friend class Pool;
public :
/**
* @brief Sets the current value for the given parameter
*
* Note that the method will have no effect if the parameter is not enabled in the Particle's Model.
* In this case, the method returns false.
*
* @param type : the parameter to set
* @param value : the value of the parameter
* @return true if the parameter can be set, false otherwise (if the parameter is not enabled)
*/
bool setParamCurrentValue(ModelParam type,float value);
/**
* @brief Sets the final value for the given parameter
*
* The final value is the value the parameter will have at the end of the Particle's life.
* Note that the method will have no effect if the parameter is not mutable in the Particle's Model.
* In this case, the method returns false and setParamCurrentValue(ModelParam,float) should be used.
*
* @param type : the parameter to set
* @param value : the value of the parameter
* @return true if the parameter can be set, false otherwise (if the parameter is not mutable)
*/
bool setParamFinalValue(ModelParam type,float value);
/**
* @brief Changes the current value for the given parameter
*
* The delta is added to the current value of the parameter.
* For more information see setParamCurrentValue(ModelParam,float).
*
* @param type : the parameter to set
* @param delta : the delta
* @return true if the parameter can be changed, false otherwise (if the parameter is not enabled)
* @since 1.02.00
*/
bool changeParamCurrentValue(ModelParam type,float delta);
/**
* @brief Changes the final value for the given parameter
*
* The delta is added to the final value of the parameter.
* For more information see setParamFinalValue(ModelParam,float).
*
* @param type : the parameter to set
* @param delta : the delta
* @return true if the parameter can be changed, false otherwise (if the parameter is not mutable)
* @since 1.02.00
*/
bool changeParamFinalValue(ModelParam type,float delta);
/**
* @brief Sets the life left of the Particle.
*
* When the Particle's life reaches 0, the Particle is inactivated.
*
* @param life : the amount of life left of the Particle
*/
inline void setLifeLeft(float life);
/////////////
// Getters //
/////////////
/**
* @brief Gets the position of the Particle
* @return the position of this Particle
* @since 1.02.00
*/
inline Vector3D& position();
/**
* @brief Gets the velocity of the Particle
* @return the velocity of this Particle
* @since 1.02.00
*/
inline Vector3D& velocity();
/**
* @brief Gets the old position of the Particle
* @return the old position of this Particle
* @since 1.02.00
*/
inline Vector3D& oldPosition();
/**
* @brief Gets the position of the Particle
*
* This is the constant version of position()
*
* @return the position of this Particle
* @since 1.02.00
*/
inline const Vector3D& position() const;
/**
* @brief Gets the velocity of the Particle
*
* This is the constant version of velocity()
*
* @return the velocity of this Particle
* @since 1.02.00
*/
inline const Vector3D& velocity() const;
/**
* @brief Gets the old position of the Particle
*
* This is the constant version of oldPosition()
*
* @return the old position of this Particle
* @since 1.02.00
*/
inline const Vector3D& oldPosition() const;
/**
* @brief Gets the current value for the given parameter
*
* Note that if the the parameter is not enabled in the Particle's Model, the default value for the parameter is returned.
*
* @param type : the parameter to get the value
* @return the current value of the parameter
*/
float getParamCurrentValue(ModelParam type) const;
/**
* @brief Gets the final value for the given parameter
*
* Note that if the the parameter is not enabled in the Particle's Model, the default value for the parameter is returned.
* If the parameter is enabled but not mutable, the current value is returned.
*
* @param type : the parameter to get the value
* @return the current value of the parameter
*/
float getParamFinalValue(ModelParam type) const;
/**
* @brief Gets the Model of this Particle
* @return A pointer on the Model of this Particle
*/
Model* getModel() const;
/**
* @brief Gets the group of this Particle
* @return A pointer on the Group of this Particle
* @since 1.02.00
*/
inline Group* getGroup() const;
/**
* @brief Gets the index of this Particle in its Group
* @return the index of thi Particle in its Group
* @since 1.03.00
*/
inline size_t getIndex() const;
/**
* @brief Gets the amount of life left of the Particle
*
* The life left of the Particle is the time left before the Particle dies.
* Note that in case of immortal particles, this value does not evolve.
*
* @return the amount of life left
*/
inline float getLifeLeft() const;
/**
* @brief Gets the age of the Particle
*
* The age of a Particle starts at zero when it is initialized and evolve at each update.
* Note that even immortal particles gets older.
*
* @return the age of the particle
* @since 1.03.00
*/
inline float getAge() const;
/**
* @brief Gets the distance of this Particle from the camera.
*
* Note that the correct distance is only returned if the Group of this Particles has its distance computation enabled.
*
* @return the distance of this Particle from the camera
* @since 1.01.00
*/
inline float getDistanceFromCamera() const;
/**
* @brief Gets the square distance of this Particle from the camera.
*
* Note that the correct distance is only returned if the Group of this Particles has its distance computation enabled.
* This method is faster than getDistanceFromCamera() and should be used instead when possible.
*
* @return the square distance of this Particle from the camera
* @since 1.01.00
*/
inline float getSqrDistanceFromCamera() const;
/**
* @brief Tells whether this Particle was initialized at its latest update or not
*
* A call to this method is equivalent to getAge() == 0.0f
*
* @return true if this Particle was initialized at its latest update, false if not
* @since 1.03.00
*/
inline bool isNewBorn() const;
/**
* @brief Tells whether this Particle is alive or not
*
* A call to this method is equivalent to getLifeLeft > 0.0f
*
* @return true if this Particle is alive, false if it is dead
* @since 1.04.00
*/
inline bool isAlive() const;
///////////////
// Interface //
///////////////
/**
* @brief Initializes the Particle
*
* When a Particle is initialized, all its parameters are reinitialized as well as its life.
*/
void init();
/**
* @brief Kills this Particle
*
* This method is equivalent to a call to setLifeLeft(float) with life being 0.
*
* @since 1.01.00
*/
inline void kill();
// As we know the color component are always enabled, we optimizes it a bit for access
inline float getR() const { return currentParams[PARAM_RED]; }
inline float getG() const { return currentParams[PARAM_GREEN]; }
inline float getB() const { return currentParams[PARAM_BLUE]; }
private :
struct ParticleData
{
Vector3D oldPosition;
Vector3D position;
Vector3D velocity;
float age;
float life;
float sqrDist;
};
Group* group;
size_t index;
ParticleData* data;
float* currentParams;
float* extendedParams;
Particle(Group* group,size_t index);
bool update(float timeDelta);
void computeSqrDist();
void interpolateParameters();
};
inline Group* Particle::getGroup() const
{
return group;
}
inline size_t Particle::getIndex() const
{
return index;
}
inline void Particle::setLifeLeft(float life)
{
data->life = life;
}
inline Vector3D& Particle::position()
{
return data->position;
}
inline Vector3D& Particle::velocity()
{
return data->velocity;
}
inline Vector3D& Particle::oldPosition()
{
return data->oldPosition;
}
inline const Vector3D& Particle::position() const
{
return data->position;
}
inline const Vector3D& Particle::velocity() const
{
return data->velocity;
}
inline const Vector3D& Particle::oldPosition() const
{
return data->oldPosition;
}
inline float Particle::getLifeLeft() const
{
return data->life;
}
inline float Particle::getAge() const
{
return data->age;
}
inline float Particle::getDistanceFromCamera() const
{
return std::sqrt(data->sqrDist);
}
inline float Particle::getSqrDistanceFromCamera() const
{
return data->sqrDist;
}
inline bool Particle::isNewBorn() const
{
return data->age == 0.0f;
}
inline bool Particle::isAlive() const
{
return data->life > 0.0f;
}
inline void Particle::kill()
{
data->life = 0.0f;
}
// specialization of the swap for particle
template<>
inline void Pool::swapElements(Particle& a,Particle& b)
{
swapParticles(a,b);
}
//////////////////////////////////
// Global functions definitions //
//////////////////////////////////
inline bool isFurtherToCamera(const Particle& a, const Particle& b)
{
return a.getSqrDistanceFromCamera() > b.getSqrDistanceFromCamera();
}
// Swaps particle data. Used internally. Do not use with particles that are not from the same group !
extern void swapParticles(Particle& a,Particle& b);
}
#endif