add sparkle explosions

This commit is contained in:
gmueller
2011-01-05 23:02:10 +01:00
parent b19f44ec32
commit a02ad6bd34
106 changed files with 19753 additions and 88 deletions

View File

@ -0,0 +1,171 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_ARRAYBUFFER
#define H_SPK_ARRAYBUFFER
#include "Core/SPK_Buffer.h"
namespace SPK
{
class Group;
template<class T> class ArrayBufferCreator;
/**
* @brief A template buffer that holds an array of elements of type T
* @since 1.03.02
*/
template<class T>
class ArrayBuffer : public Buffer
{
friend class ArrayBufferCreator<T>;
public :
/**
* @brief Gets the starting address of the inner array
* @return the starting address of the first element of the inner array
*/
inline T* getData() const;
/**
* @brief Gets the number of elements for a single particle
* @return the number of elements for a single particle
*/
inline const size_t getParticleSize() const;
/**
* @brief Gets the total number of T in the inner array
* The value is equal to <i>particleSize * nbParticles</i>.
* @return the total number of T in the inner array
*/
inline size_t getDataSize() const;
private :
T* data;
size_t particleSize;
size_t dataSize;
ArrayBuffer<T>(size_t nbParticles,size_t particleSize);
ArrayBuffer<T>(const ArrayBuffer<T>& buffer);
virtual ~ArrayBuffer<T>();
virtual void swap(size_t index0,size_t index1);
};
/**
* @brief Template class to create an ArrayBuffer
* @since 1.03.02
*/
template<class T>
class ArrayBufferCreator : public BufferCreator
{
public :
/**
* @brief Constructor of ArrayBuffer
* @param particleSize : the number of elements per particle in the buffer to be created
*/
ArrayBufferCreator<T>(size_t particleSize);
private :
size_t particleSize;
virtual ArrayBuffer<T>* createBuffer(size_t nbParticles,const Group& group) const;
};
// Typedefs
/** @brief A buffer storing an array of floats */
typedef ArrayBuffer<float> FloatBuffer;
/** @brief the buffer creator of the float buffer */
typedef ArrayBufferCreator<float> FloatBufferCreator;
template<class T>
ArrayBuffer<T>::ArrayBuffer(size_t nbParticles,size_t particleSize) :
Buffer(),
dataSize(nbParticles * particleSize),
particleSize(particleSize)
{
data = new T[dataSize];
}
template<class T>
ArrayBuffer<T>::ArrayBuffer(const ArrayBuffer<T>& buffer) :
Buffer(buffer),
dataSize(buffer.dataSize),
particleSize(buffer.particleSize)
{
data = new T[dataSize];
memcpy(data,buffer.data,dataSize * sizeof(T));
}
template<class T>
ArrayBuffer<T>::~ArrayBuffer()
{
delete[] data;
}
template<class T>
inline T* ArrayBuffer<T>::getData() const
{
return data;
}
template<class T>
inline const size_t ArrayBuffer<T>::getParticleSize() const
{
return particleSize;
}
template<class T>
inline size_t ArrayBuffer<T>::getDataSize() const
{
return dataSize;
}
template<class T>
void ArrayBuffer<T>::swap(size_t index0,size_t index1)
{
T* address0 = data + index0 * particleSize;
T* address1 = data + index1 * particleSize;
for (size_t i = 0; i < particleSize; ++i)
std::swap(address0[i],address1[i]);
}
template<class T>
ArrayBufferCreator<T>::ArrayBufferCreator(size_t particleSize) :
BufferCreator(),
particleSize(particleSize)
{}
template<class T>
ArrayBuffer<T>* ArrayBufferCreator<T>::createBuffer(size_t nbParticles,const Group& group) const
{
return new ArrayBuffer<T>(nbParticles,particleSize);
}
}
#endif

View File

@ -0,0 +1,125 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_BUFFER
#define H_SPK_BUFFER
namespace SPK
{
class Particle;
class Group;
/**
* @brief An abstract class that defines the interface for the additional buffers of Group
*
* A buffer allows a Group to hold additional data.<br>
* Typically, they are used for rendering as the GPU or the rendering engine needs data to be organized in a specific way.<br>
* <br>
* Their use can be extended to anything to store data within a group.<br>
* Buffers can also be swapped as particles are swap within a group. This allows to have the ordering of data consistent with the ordering of particles.<br>
* However, if the buffers are only used for temporary storage on a single frame (most of the renderers), it is not necessary to swap the data.<br>
* <br>
* A buffer also contains a flag which is an unsigned integer that can be used to check the validity of the buffer from frame to frame.<br>
* <br>
* Note that only a group can create and delete a buffer. The user can ask a group to create a new buffer by passing a BufferCreator object to it.<br>
* Check out the group interface about buffers for more info.
*
* @since 1.03.02
*/
class Buffer
{
friend class BufferCreator;
friend class Group;
friend void swapParticles(Particle& a,Particle& b);
public :
/**
* @brief Gets the current flag of this buffer
* @return the current flag of this buffer
*/
inline unsigned int getFlag() const;
/**
* @brief Tells whether data is swapped as particles in the group are swapped
* @return true if data must be swapped with particles, false if not
*/
inline bool isSwapEnabled() const;
protected :
Buffer() {};
virtual ~Buffer() {};
private :
unsigned int flag;
bool swapEnabled;
/**
* @brief Swaps 2 particles data in this buffer
*
* This is a pure virtual method that must be implemented by inherited classes of buffer.
*
* @param index0 : the index of the first particle to swap
* @param index1 : the index of the second particle to swap
*/
virtual void swap(size_t index0,size_t index1) = 0;
};
/**
* @brief A class used by a Group to create an additional Buffer
*
* This class defines a temporary object to pass to a Group so that it can create and store a new buffer.
* Check out the method <i>Group::createBuffer(const std::string&,const BufferCreator&,unsigned int,bool)</i> for more information.
*
* @since 1.03.02
*/
class BufferCreator
{
friend class Group;
/**
* @brief Creates a new buffer
*
* This method is called internally by a group to create and store an new buffer.<br>
* This is a pure virtual method that must be implemented by inherited classes of buffer.
*
* @param nbParticles : the number of particles the buffer must be able to store
* @param group : the group which contains the buffer
*/
virtual Buffer* createBuffer(size_t nbParticles,const Group& group) const = 0;
};
inline unsigned int Buffer::getFlag() const
{
return flag;
}
inline bool Buffer::isSwapEnabled() const
{
return swapEnabled;
}
}
#endif

View File

@ -0,0 +1,146 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_BUFFERHANDLER
#define H_SPK_BUFFERHANDLER
#include "Core/SPK_DEF.h"
namespace SPK
{
class Group;
/**
* @class BufferHandler
* @brief A base interface that allows manipulation on Buffer
* @since 1.04.00
*/
class SPK_PREFIX BufferHandler
{
public :
////////////////
// Destructor //
////////////////
/** @brief Destructor of BufferHandler */
virtual ~BufferHandler() {}
/////////////
// Setters //
/////////////
/**
* @brief Enables or disables the automatic buffers creation in a static way
*
* By default, the buffers creation is enabled.
*
* @param creation : true to enable the buffers creation, false to disable it
*/
static void enableBuffersCreation(bool creation);
/////////////
// Getters //
/////////////
/**
* @brief Tells whether the automatic buffers creation is enabled or not
* @return true if the buffers creation is enabled, false if it is disabled
*/
static bool isBuffersCreationEnabled();
///////////////
// Interface //
///////////////
/**
* @brief Creates the buffers for this buffer handler in the given group
*
* If the buffers for this type of buffer handler already exists within the Group, they are priorly destroyed.<br>
* The type of buffers created depends on the state of the buffer handler at the time this method is called.<br>
* <br>
* This method has to be overridden in derived classes that use buffers
*
* @param group : the Group in which to create the buffers for this buffer handler
*/
virtual inline void createBuffers(const Group& group) {};
/**
* @brief Destroys the buffers for this buffer handler in the given group
*
* if the buffers dont exist, nothing happens.<br>
* <br>
* This method has to be overridden in derived classes that use buffers
*
* @param group : the Group in which to destroy the buffers for this buffer handler
*/
virtual inline void destroyBuffers(const Group& group) {};
protected :
// The constructor is private so that the class is not instanciable
BufferHandler() {}
/**
* @brief prepares the buffers of the given Group for processing
*
* Internally, this methods perfoms the following operations :<pre><i>
* if check buffers is false
* if buffers creation is enabled
* destroy buffers
* create buffers
* return true
* else return false
* else return true
* </i></pre>
*
* @param group : the group whose buffers must be prepared
* @return true if the buffers are ready, false if not
*/
bool prepareBuffers(const Group& group);
/**
* @brief checks the buffers and prepare them
*
* This method has to be implemented in derived class that uses buffers.<br>
* true must be returned if the buffers are found and initialized, false otherwise.
*
* @param group : the group in which to check the buffers
* @return true if buffers are ready, false otherwise
*/
virtual inline bool checkBuffers(const Group& group);
private :
static bool bufferCreation;
};
inline bool BufferHandler::checkBuffers(const Group& group)
{
return true;
}
}
#endif

View File

@ -0,0 +1,158 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_DEF
#define H_SPK_DEF
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <deque>
#include <list>
#include <iostream>
#include <vector>
#include <limits>
#include <map>
#include <set>
#include <string>
#include <cstring>
// 1.02.02 Compatibility with older versions
#ifdef SPK_DLL
#define SPK_CORE_IMPORT
#endif
#ifdef SPK_CORE_EXPORT
#define SPK_PREFIX __declspec(dllexport)
#elif defined(SPK_IMPORT) || defined(SPK_CORE_IMPORT)
#define SPK_PREFIX __declspec(dllimport)
#else
#define SPK_PREFIX
#endif
#ifdef _MSC_VER
#pragma warning(disable : 4251) // disables the warning about exporting STL classes in DLLs
#endif
// Trace for debugging
//#define SPK_DEBUG
#ifdef SPK_DEBUG
#define SPK_TRACE(text) std::cout << text << std::endl;
#else
#define SPK_TRACE(text)
#endif
/**
* @mainpage SPARK Particle Engine
*
* SPARK is an open source library allowing to easily implement full particle systems in C++ applications.<br>
* <br>
* SPARK has been designed to be :
* <ul>
* <li>user friendly and easy to implement</li>
* <li>very configurable and as complete as possible</li>
* <li>evolving and upgradable by users</li>
* <li>portable and library free (it only uses the standard library)</li>
* </ul>
* <br>
* @section intro_sec Global Description
* in SPARK, a SPK::System is a collection of Groups of Particles.
* A SPK::Group contains a SPK::Pool of Particles and defines an complete universe for Particle evolution.
* This universe holds 3 types of physical objects :
* <ul>
* <li>the Emitters : an SPK::Emitter is an object that generates Particles</li>
* <li>the Modifiers : a SPK::Modifier is an object that will modify Particles behavior</li>
* <li>the Particles themselves : a SPK::Particle is a point that will follow physical laws and will be given some parameters that will evolve from their birth to their death.</li>
* </ul>
* Those parameters are defined by a SPK::Model of Particles.<br>
* The Emitters and Modifiers are physical entities whose body is represented by a SPK::Zone.<br>
* A SPK::Vector3D is the primitive object used in SPARK to represents triplets of coordinates in a universe 3D.<br>
* <br>
* Finally a system/groups can be renderered using a SPK::Renderer.
*/
/**
* @namespace SPK
* @brief the namespace for the whole SPARK library
*/
namespace SPK
{
/** @brief the random seed for the pseudo random numbers generation (1 by default) */
extern SPK_PREFIX unsigned int randomSeed;
/**
* @brief Returns a random number in the range [min,max[
*
* Note that the sequence of pseudo random number generated depends on the initial seed which can be set by setting randomSeed.<br>
*
* @param min : the minimum value
* @param max : the maximum value
*
* @return a random number within [min,max[
*/
template<typename T>
T random(T min,T max)
{
// optimized standard minimal
long tmp0 = 16807L * (randomSeed & 0xFFFFL);
long tmp1 = 16807L * (randomSeed >> 16);
long tmp2 = (tmp0 >> 16) + tmp1;
tmp0 = ((tmp0 & 0xFFFF)|((tmp2 & 0x7FFF) << 16)) + (tmp2 >> 15);
// correction of the error
if ((tmp0 & 0x80000000L) != 0)
tmp0 = (tmp0 + 1) & 0x7FFFFFFFL;
randomSeed = tmp0;
// find a random number in the interval
return static_cast<T>(min + ((randomSeed - 1) / 2147483646.0) * (max - min));
}
/////////////////////////
// global enumerations //
/////////////////////////
/**
* @enum ModelParam
* @brief Constants for the Model parameters
*/
enum ModelParam
{
PARAM_RED = 0, /**< The red component of the Particle */
PARAM_GREEN = 1, /**< The green component of the Particle */
PARAM_BLUE = 2, /**< The blue component of the Particle */
PARAM_ALPHA = 3, /**< The alpha component of the Particle */
PARAM_SIZE = 4, /**< The size of the Particle */
PARAM_MASS = 5, /**< The mass of the Particle */
PARAM_ANGLE = 6, /**< The angle of the texture of the Particle */
PARAM_TEXTURE_INDEX = 7, /**< the index of texture of the Particle */
PARAM_ROTATION_SPEED = 8, /**< the rotation speed of the particle (must be used with a rotator modifier) */
PARAM_CUSTOM_0 = 9, /**< Reserved for a user custom parameter. This is not used by SPARK */
PARAM_CUSTOM_1 = 10, /**< Reserved for a user custom parameter. This is not used by SPARK */
PARAM_CUSTOM_2 = 11, /**< Reserved for a user custom parameter. This is not used by SPARK */
};
}
#endif

View File

@ -0,0 +1,364 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_EMITTER
#define H_SPK_EMITTER
#include "Core/SPK_DEF.h"
#include "Core/SPK_Registerable.h"
#include "Core/SPK_Transformable.h"
#include "Core/SPK_Zone.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
class Group;
class Particle;
/**
* @class Emitter
* @brief An abstract class that defines an emitter of particles
*
*
* An Emitter is an object that will launch particles by giving them a velocity and a position.<br>
* the position is derived from the Zone of the Emitter.<br>
* the velocity is derived from the Emitter itself.<br>
* <br>
* An Emitter has a flow and a tank of particles.
* The flow defines the rate at which particles are launched and the tank defines the total number of Particles the Emitter can launched.<br>
* Note that the flow and the tank of an Emitter are only used when the Emitter emits automatically from a Group
* but the user can also emit manually outside a Group.
*/
class SPK_PREFIX Emitter : public Registerable, public Transformable
{
friend class Group;
public :
/////////////////
// Constructor //
/////////////////
/** @brief Constructor of Emitter */
Emitter();
////////////////
// Destructor //
////////////////
/** @brief Destructor of Emitter */
virtual inline ~Emitter() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets this Emitter active or not.
*
* An inactive Emitter will not emit in its parent Group during update.<br>
* However it can still be used manually by the user.
*
* @param active : true to activate this Emitter, false to deactivate it
* @since 1.05.00
*/
inline void setActive(bool active);
/**
* @brief Sets the number of particles in this Emitter's tank
*
* Each time the Emitter is updated, the number of particles emitted is deduced from the Emitter tank.
* When the tank reaches 0, the Emitter will not emit any longer until it is refilled.<br>
* <br>
* A number of -1 (or any negative number) means the Emitter has an infinite tank which will never be empty.
*
* @param tank : the number of particles in this Emitters's tank
*/
inline void setTank(int tank);
/**
* @brief Changes the number of particles in this Emitters's tank
*
* The new number of particles in the tank is equal to : <i>number of particles in the tank + n</i>.<br>
* This method has no effect for Emitters with infinite tank (a negative number of particles) and an Emitter cannot become infinite with this method (the new number is clamped to 0).
*
* @param deltaTank : the number to add to the current tank
*/
void changeTank(int deltaTank);
/**
* @brief Sets the flow of this Emitter
*
* The flow is in the unit : nb of particle per step.
* A flow of -1 (or any negative number) indicates an infinite flow which means all particles in the Emitters(s tank are generated instantly.<br>
* Note that if both the flow and the tank are infinite, nothing will happen.
*
* @param flow : the flow of this Emitter
*/
inline void setFlow(float flow);
/**
* @brief Changes the flow of particles of this Emitter
*
* The new flow is equal to : <i>flow of the Emitter + deltaFlow</i>.<br>
* This method has no effect for Emitters with infinite flow (a negative flow of particles) and an Emitter's flow cannot become infinite with this method (the new flow is clamped to 0).
*
* @param deltaFlow : the number to add to the current flow
*/
void changeFlow(float deltaFlow);
/**
* @brief Sets the force of this Emitter
*
* The force of the Emitter vary for each launch of a Particle between a minimum and a maximum.
* To have a fixed force for the Emitter, just have <i>min = max</i>.<br>
* <br>
* the speed at which a Particle will be launched is equal to : <i>force / weight of the Particle</i>.
*
* @param min : the minimum force of the Emitter
* @param max : the maximum force of the Emitter
*/
inline void setForce(float min,float max);
/**
* @brief Sets the Zone of this Emitter
*
* If the Zone is NULL, the default Zone will be used (A Point centered at the origin)
*
* @param zone : the Zone of this Emitter
* @param full : true to generate particles in the whole Zone, false to generate particles only at the Zone borders.
*/
void setZone(Zone* zone,bool full = true);
/////////////
// Getters //
/////////////
/**
* @brief Tells whether this Emitter is active or not
* @return true if this Emitter is active, false if is is inactive
* @since 1.05.00
*/
inline bool isActive() const;
/**
* @brief Gets the number of particles in this Emitter's tank
* @return the number of particles in this Emitters's tanl
*/
inline int getTank() const;
/**
* @brief Gets the flow of this Emitter
* @return the flow of this Emitter
*/
inline float getFlow() const;
/**
* @brief Gets the minimum force of this Emitter
* @return the minimum force of this Emitter
*/
inline float getForceMin() const;
/**
* @brief Gets the maximum force of this Emitter
* @return the maximum force of this Emitter
*/
inline float getForceMax() const;
/**
* @brief Gets the Zone of this Emitter
* @return the Zone of this Emitter
*/
inline Zone* getZone() const;
/**
* @brief Tells whether this Emitter emits in the whole Zone or only at its borders
* @return true if this EMitter emits in the whole Zone, false if it is only at its borders
*/
inline bool isFullZone() const;
/**
* @brief Tells whether this Emitter is sleeping or not
*
* An Emitter is considered as sleeping if his flow or his tank is equal to 0.
*
* @return true if this Emitter is sleeping, false if it is active
* @since 1.03.00
*/
inline bool isSleeping() const;
///////////////
// Interface //
///////////////
/**
* @brief Emits a Particle from this Emitter
*
* The Particle's velocity is updated with a call to generateVelocity(Particle&).<br>
* The Particle's position is updated with a call to Zone::generatePosition(Particle&) of the Emitter's Zone.<br>
*
* Note that this will not decrease the number of particles in the Emitter's tank.
* To do it, the user has to manually make a call to changeNumber(-1) after this call.
*
* @param particle : the Particle to emit from this Emitter
*/
inline void emit(Particle& particle) const;
/**
* @brief Generates the velocity of the Particle
*
* The velocity of the Particle is updated in function of the Emitter's nature and parameters.<br>
* Unlike emit() the position of the Particle remains unchanged.
*
* @param particle : the Particle whose velocity has to be updated
*/
inline void generateVelocity(Particle& particle) const;
virtual Registerable* findByName(const std::string& name);
protected :
virtual void registerChildren(bool registerAll);
virtual void copyChildren(const Emitter& emitter,bool createBase);
virtual void destroyChildren(bool keepChildren);
virtual inline void propagateUpdateTransform();
private :
Zone* zone;
bool full;
bool active;
int tank;
float flow;
float forceMin;
float forceMax;
mutable float fraction;
static Zone& getDefaultZone();
unsigned int updateNumber(float deltaTime);
/////////////////////////
// pure virtual method //
/////////////////////////
/**
* @brief A pure virtual method that generates the velocity of the Particle in function of a speed
*
* This is a pure virtual method to be implemented by children.<br>
* <br>
* the Particle velocity has to be set by this method.<br>
* the generated velocity of the Particle must have a norm equal to speed.
*
* @param particle : the Particle whose velocity has to be generated
* @param speed : the speed that the velocity must have
*/
virtual void generateVelocity(Particle& particle,float speed) const = 0;
};
inline void Emitter::setActive(bool active)
{
this->active = active;
}
inline void Emitter::setTank(int tank)
{
this->tank = tank;
}
inline void Emitter::setFlow(float flow)
{
this->flow = flow;
}
inline void Emitter::setForce(float min,float max)
{
forceMin = min;
forceMax = max;
}
inline bool Emitter::isActive() const
{
return active;
}
inline int Emitter::getTank() const
{
return tank;
}
inline float Emitter::getFlow() const
{
return flow;
}
inline float Emitter::getForceMin() const
{
return forceMin;
}
inline float Emitter::getForceMax() const
{
return forceMax;
}
inline Zone* Emitter::getZone() const
{
return zone;
}
inline bool Emitter::isFullZone() const
{
return full;
}
inline bool Emitter::isSleeping() const
{
return ((tank == 0)||(flow == 0.0f));
}
inline void Emitter::emit(Particle& particle) const
{
zone->generatePosition(particle,full);
generateVelocity(particle);
}
void Emitter::generateVelocity(Particle& particle) const
{
generateVelocity(particle,random(forceMin,forceMax) / particle.getParamCurrentValue(PARAM_MASS));
}
inline void Emitter::propagateUpdateTransform()
{
zone->updateTransform(this);
}
}
#endif

View File

@ -0,0 +1,291 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_FACTORY
#define H_SPK_FACTORY
#include "Core/SPK_DEF.h"
#include "Core/SPK_Registerable.h"
/**
* @def SPK_Copy(ClassName,arg)
* @brief Creates a new registered object from an existing one
*
* This macro is simply a shortcut call to :<br>
* <i>dynamic_cast<SPK::ClassName*>(SPK::SPKFactory::getInstance().create(arg)</i><br>
* with <i>arg</i> being either an SPK_ID or a pointer to an object and ClassName being the class of the object.<br>
* <br>
* If the ID does not exist or the object is not registered, NULL is returned.<br>
* <br>
* Note that a bad_cast exception can be throw as there is a dynamic_cast call.
*
* @since 1.03.00
*/
#define SPK_Copy(ClassName,arg) \
dynamic_cast<ClassName*>(SPK::SPKFactory::getInstance().copy(arg))
/**
* @def SPK_Get(ClassName,ID)
* @brief Gets a registered object
*
* This macro is simply a shortcut call to :<br>
* <i>dynamic_cast<ClassName*>(SPK::SPKFactory::getInstance().get(ID)</i><br>
* <br>
* If the ID does not exist, NULL is returned.<br>
* <br>
* Note that a bad_cast exception can be throw as there is a dynamic_cast call.
*
* @since 1.03.00
*/
#define SPK_Get(ClassName,ID) \
dynamic_cast<ClassName*>(SPK::SPKFactory::getInstance().get(ID))
/**
* @def SPK_Copy(arg)
* @brief Destroys a registered object
* @since 1.03.00
*/
#define SPK_Destroy(arg) \
SPK::SPKFactory::getInstance().destroy(arg)
/**
* @def SPK_Create(object)
* @brief Creates a registered object
* @since 1.03.00
*/
#define SPK_Create(object) \
SPK::SPKFactory::getInstance().create(object)
namespace SPK
{
/**
* @class SPKFactory
* @brief A singleton class that allows to easily define, create, destroy and organize SPARK objects (Registerable)
*
* A Registerable can either be registered or not. A Registerable created with the SPKFactory becomes registered :
* it is given a unique ID and is stored within a map in the SPKFactory.<br>
* <br>
* the SPKFactory allows the correct copy of a Registerable with all its children Registerable. Children registerable are only copied
* within the given Registerable if they are not shared (see Registerable) else only the reference to the shared Registerable is copied<br>
* <br>
* Moreover, destruction of Registerable and all children is very easy with the factory. Destroying a Registerable will destroy and all its
* children which are destroyable and only referenced within the Registerable being destroyed.<br>
* Note that the process is recursive through the tree, so destroyable children of destroyable children will be destroyed as well and so on.<br>
* <br>
* 4 main actions are performed by the SPKFactory :
* <ul>
* <li>Create a registered Registerable : This is performed with create(const Registerable&). the passed Registerable is used to create a registered Registerable
* which is an exact copy. Every elements will be copied even the shared ones. The base Registerable can be registered or not.</li>
* <li>Copy a registered Registerable : This is performed with copy(SPK_ID) or copy(const Registerable*). A registered copy of the registered Registerable is created.
* The shared children are only referenced while the not shared ones are copied as well. The same happens for children of children and so on.</li>
* <li>Destroy a registered Registerable : This is performed with destroy(SPK_ID,bool) or destroy(Registerable*,bool). The Registerable and all its destroyable
* registered children will be destroyed. The tree is parsed to destroy children of children and so on. the boolean tells whether to check the number of
* references of children or not.</li>
* <li>Gets a registered Registerable from its ID. This is performed with get(SPK_ID). Every registered Registerable is stored in a map. The user can retrieve
* the address of the Registerable with its ID (if the ID exists in the map).</li>
* </ul>
* Note that macros are implemented to ease the syntax :
* <ul>
* <li>SPK_Create(object)</li>
* <li>SPK_Copy(ClassName,arg)</li>
* <li>SPK_Get(ClassName,arg)</li>
* <li>SPK_Destroy(arg)</li>
* </ul>
*
* @since 1.03.00
*/
class SPK_PREFIX SPKFactory
{
friend class Registerable;
public :
/**
* @brief Returns the unique instance of the SPKFactory
* @return the unique instance of the SPKFactory
*/
static SPKFactory& getInstance();
static void destroyInstance();
/**
* @brief Returns the number of Regiterable objects registered in the SPKFactory
* @return the number of Regiterable objects registered in the SPKFactoty
*/
inline size_t getNbObjects() const;
/**
* @brief Creates a registered Registerable from the passed Registerable
* @param base : The Registerable to create the new registered Registerable from
* @return the ID of the new registered object
*/
SPK_ID create(const Registerable& base);
/**
* @brief Creates a new Registerable object which is a copy of the object at the given ID
*
* If no Registerable with this ID is registered, NULL is returned.
*
* @param ID : the ID of the Registerable to copy
* @return a registered copy of the Registerable or NULL if the passed ID is not registered
*/
Registerable* copy(SPK_ID ID);
/**
* @brief Creates a new Registerable object which is a copy of the object
*
* If the passed Registerable is NULL or not registered, NULL is returned.<br>
* Note that this function call internally <i>copy(registerable->getSPKID())</i>.
*
* @param registerable : the registered Registerable to copy
* @return a registered copy of the Registerable or NULL if the passed object is not registered
*/
Registerable* copy(const Registerable* registerable);
/**
* @brief Gets the Registerable of the given ID
*
* If the ID is not registered, NULL is returned
*
* @param ID : the ID of the Registerable to get
* @return the Registerable with the passed ID or NULL if the ID is not registered
*/
Registerable* get(SPK_ID ID);
/**
* @brief Destroys the Registerable with the given ID and all its destroyable children
*
* If the ID is not registered, nothing is destroyed and false is returned.<br>
* <br>
* The checkNbReferences boolean tells the factory if the number of references of the Registerable to be destroyed
* has to be checked.<br>
* If set to true, the Registerable will be destroyed only if the number or references within the SPKFactory
* (ie in all registered object in the SPKFactory) is 0.<br>
* If set to false, the Registerable will be destroyed in any case. Meaning that any reference within the SPKFactory
* becomes invalid.
*
* @param ID : the ID of the Registerable to destroy
* @param checkNbReferences : true to destroy only a Registerable with no references in the SPKFactory (safer), false not to perform the check
* @return true if the Registerable has been deleted, false if not
*/
bool destroy(SPK_ID ID,bool checkNbReferences = true);
/**
* @brief Destroys the Registerable and all its destroyable children
*
* If the Registerable is NULL or is not registered, nothing is destroyed and false is returned.<br>
* Note that this function call internally <i>destroy(registerable->getSPKID())</i>.<br>
* <br>
* see destroy(SPK_ID,bool) for more information.
*
* @param registerable the Registerable to destroy
* @param checkNbReferences : true to destroy only a Registerable with no references in the SPKFactory (safer), false not to perform the check
* @return true if the Registerable has been deleted, false if not
*/
bool destroy(Registerable* registerable,bool checkNbReferences = true);
/** @brief Destroys all the registered Registerable in the SPKFactory */
void destroyAll();
/**
* @brief Trace information on the Registerable with the given ID
* @param ID : the ID of the Registerable to trace
*/
void trace(SPK_ID ID);
/**
* @brief Trace information on the Registerable
*
* Note that this function call internally <i>trace(registerable->getSPKID())</i>.
*
* @param registerable : the Registerable to trace
*/
void trace(const Registerable* registerable);
/** @brief Trace information on all the registered Registerable within the SPKFactory */
void traceAll();
/**
* @brief Finds a registerable by name in the factory
*
* Note that this method only checks registerables in the SPKFactory.<br>
* This method does not call the Registerable::findByName(const string&) of the registerables to check recursively.
*
* @param name : the name of the registerable to find in the factory
* @return the first registerable with that name or NULL of none is found
* @since 1.05.00
*/
Registerable* findByName(const std::string& name);
private :
static SPKFactory* instance;
static SPK_ID currentID;
std::map<SPK_ID,Registerable*> SPKRegister;
std::map<const Registerable*,Registerable*> SPKAdresses;
void traceObject(const std::map<SPK_ID,Registerable*>::iterator& it,bool nextLine);
inline bool isAlreadyProcessed(const Registerable* source);
inline Registerable* getProcessedObject(const Registerable* source);
inline void markAsProcessed(const Registerable* source,Registerable* object);
Registerable* registerObject(Registerable* object);
void unregisterObject(std::map<SPK_ID,Registerable*>::iterator& it,bool keepChildren = false);
bool unregisterObject(SPK_ID ID,bool keepChildren = false);
// private constructors
SPKFactory(){};
SPKFactory(const SPKFactory&){};
~SPKFactory(){this->destroyAll();}
#ifdef SPK_DEBUG
size_t nbAlloc;
size_t nbDesalloc;
#endif
};
inline size_t SPKFactory::getNbObjects() const
{
return SPKRegister.size();
}
inline bool SPKFactory::isAlreadyProcessed(const Registerable* source)
{
return SPKAdresses.find(source) != SPKAdresses.end();
}
inline Registerable* SPKFactory::getProcessedObject(const Registerable* source)
{
return SPKAdresses.find(source)->second;
}
inline void SPKFactory::markAsProcessed(const Registerable* source,Registerable* object)
{
SPKAdresses.insert(std::pair<const Registerable*,Registerable*>(source,object));
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,403 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_INTERPOLATOR
#define H_SPK_INTERPOLATOR
#include "Core/SPK_DEF.h"
namespace SPK
{
class Particle;
/**
* @enum InterpolationType
* @brief Constants defining which type of value is used for interpolation
* @since 1.05.00
*/
enum InterpolationType
{
INTERPOLATOR_LIFETIME, /**< Constant defining the life time as the value used to interpolate */
INTERPOLATOR_AGE, /**< Constant defining the age as the value used to interpolate */
INTERPOLATOR_PARAM, /**< Constant defining a parameter as the value used to interpolate */
INTERPOLATOR_VELOCITY, /**< Constant defining the square norm of the velocity as the value used to interpolate */
};
/**
* @brief An entry in the interpolator graph
*
* See the Interpolator description for more information
*
* @since 1.05.00
*/
struct InterpolatorEntry
{
float x; /**< x value of this entry */
float y0; /**< y first value of this entry */
float y1; /**< y second value of this entry */
/** @brief Default constructor of interpolator entry. All values are set to 0 */
InterpolatorEntry() : x(0.0f),y0(0.0f),y1(0.0f) {}
/**
* @brief Constructs an interpolator entry with y0 and y1 having the same value
* @param x : the x value
* @param y : the y value (value of y0 and y1)
*/
InterpolatorEntry(float x,float y) : x(x),y0(y),y1(y) {}
/**
* @brief Constructs and interpolator entry
* @param x : the x value
* @param y0 : the y0 value
* @param y1 : the y1 value
*/
InterpolatorEntry(float x,float y0,float y1) : x(x),y0(y0),y1(y1) {}
// used internally
InterpolatorEntry(float x) : x(x) {}
};
// forward declaration to allow the set of entries in interpolator to be constructed
inline bool operator<(const InterpolatorEntry& entry0,const InterpolatorEntry& entry1);
/**
* @class Interpolator
* @brief An interpolator that offers flexible control over particle parameters
*
* An interpolator is created for each parameter of a model which is set as interpolated.<br>
* The user can get the interpolator of a parameter for a given model by calling Model::getInterpolator(ModelParam).<br>
* <br>
* An interpolator can use several types of value to interpolate a given parameter :
* <ul>
* <li>the lifetime of a particle : it is defined in a range between 0 and 1, 0 being the birth of the particle and 1 being its death</li>
* <li>the age of a particle</li>
* <li>the value of another parameter of a particle (which can be any of the parameters)</li>
* <li>the square norm of the velocity of a particle</li>
* </ul>
* Here is a description of how an interpolator works :<br>
* <br>
* Internally an interpolator holds a list of entries which defines a 2D graph. The entries are sorted internally along the x axis.<br>
* Each entry have a unique x value and 2 y values (although both y can have the same value).<br>
* <br>
* The x defines the value that will be used to interpolate the parameter value. This value depends on the type set of the interpolator.<br>
* For instance, if the type is INTERPOLATOR_AGE, the current x value will be the age of the particle.<br>
* <br>
* Knowing the current x value, the interpolator interpolates the y value in function of the entries y values.<br>
* An interpolator holds 2 curves : the y0 one and the y1 one.<br>
* Each particle is given a random value between 0 and 1 which defines where between the y0 and the y1 curve the interpolated y value will be.<br>
* The final interpolated y value will be the value of the interpolated particle parameter for this frame.<br>
* <br>
* Moreover the graph can loop or not :
* <ul>
* <li>If the graph does not loop, the current x value is clamped between the minimum x and the maximum x of the graph.</li>
* <li>If the graph loops, the current x is recomputed to fit in the range between the minimum x and the maximum x of the graph.</li>
* </ul>
* Finally, it is possible to set a variation in the offset and the scale of the current x computed :<br>
* Each particle is given an offset and a scale to compute its current x depending on the variations set. The formula to compute the final current x is the following :<br>
* <i>final current x = (current x + offset) * scale</i><br>
* offset being randomly generated per particle in <i>[-offsetXVariation,+offsetXVariation]</i><br>
* scale being randomly generated per particle in <i>1.0 + [-scaleXVariation,+scaleXVariation]</i><br>
* <br>
* The default values of the interpolator are the following :
* <ul>
* <li>type : INTERPOLATOR_LIFETIME</li>
* <li>offset x variation : 0.0</li>
* <li>scale x variation : 0.0</li>
* </ul>
*
* @since 1.05.00
*/
class SPK_PREFIX Interpolator
{
friend class Particle;
friend class Model;
public :
/////////////
// Setters //
/////////////
/**
* @brief Sets the value used to interpolate
*
* See the class description for more information.<br>
* Note that the argument param is only used when the type is INTERPOLATOR_PARAM.
*
* @param type : the type of value used to interpolate
* @param param : the parameter used to interpolate when the type is INTERPOLATOR_PARAM.
*/
inline void setType(InterpolationType type,ModelParam param = PARAM_SIZE);
/**
* @brief Enables or disables the looping of the graph
*
* The range of the graph is defined between the entry with the minimum x and the entry with the maximum y.<br>
* If the looping is disabled, the x are clamped to the range.<br>
* If the looping is enabled, the value of x is reported in the range. It is better that the xmin and xmax have
* the same y values so that the graph tiles perfectly.
*
* @param loop : true to enabled the looping, false to disable it
*/
inline void enableLooping(bool loop);
/**
* @brief Sets the scale variation in x
*
* See the class description for more information
*
* @param scaleXVariation : the scale variation in x
*/
inline void setScaleXVariation(float scaleXVariation);
/**
* @brief Sets the offset variation in x
*
* See the class description for more information
*
* @param offsetXVariation : the offset variation in x
*/
inline void setOffsetXVariation(float offsetXVariation);
/////////////
// Getters //
/////////////
/**
* @brief Gets the type of value used to interpolate
* @return the type of value used to interpolate
*/
inline InterpolationType getType() const;
/**
* @brief Gets the parameter used to interpolate
*
* Note that the parameter is only used if the type is INTERPOLATOR_PARAM
*
* @return the parameter used to interpolate
*/
inline ModelParam getInterpolatorParam() const;
/**
* @brief Tells whether the looping is enabled or not
* @return true if the looping is enabled, false if not
*/
inline bool isLoopingEnabled() const;
/**
* @brief Gets the scale variation along x
* @return the scale variation along x
*/
inline float getScaleXVariation() const;
/**
* @brief Gets the offset variation along x
* @return the offset variation along x
*/
inline float getOffsetXVariation() const;
/**
* @brief Gets the graph of the interpolator
* @return the graph of the interpolator
*/
inline std::set<InterpolatorEntry>& getGraph();
/**
* @brief Gets the graph of the interpolator (constant version)
* @return the graph of the interpolator
*/
inline const std::set<InterpolatorEntry>& getGraph() const;
///////////////
// Interface //
///////////////
/**
* @brief Adds an entry to the graph
* @param entry : the entry to add to the graph
* @return true if the entry has been added to the graph, false if not (the graph already contains an entry with the same x)
*/
inline bool addEntry(const InterpolatorEntry& entry);
/**
* @brief Adds an entry to the graph
* @param x : the x of the entry to add
* @param y : the y of the entry to add (y0 and y1 are set to y)
* @return true if the entry has been added to the graph, false if not (the graph already contains an entry with the same x)
*/
inline bool addEntry(float x,float y);
/**
* @brief Adds an entry to the graph
* @param x : the x of the entry to add
* @param y0 : the y0 of the entry to add
* @param y1 : the y1 of the entry to add
* @return true if the entry has been added to the graph, false if not (the graph already contains an entry with the same x)
*/
inline bool addEntry(float x,float y0,float y1);
/** @brief Clears the graph (removes all the entries) */
inline void clearGraph();
/**
* @brief Generates a sinusoidal curve
*
* Note that the graph is previously cleared from all its entries
*/
void generateSinCurve(float period,float amplitudeMin,float amplitudeMax,float offsetX,float offsetY,float startX,unsigned int length,unsigned int nbSamples);
/**
* @brief Generates a polynomial curve
*
* Note that the graph is previously cleared from all its entries
*/
void generatePolyCurve(float constant,float linear,float quadratic,float cubic,float startX,float endX,unsigned int nbSamples);
private :
std::set<InterpolatorEntry> graph;
InterpolationType type;
ModelParam param;
bool loopingEnabled;
float scaleXVariation;
float offsetXVariation;
float interpolate(const Particle& particle,ModelParam interpolatedParam,float ratioY,float offsetX,float scaleX);
inline float interpolateY(const InterpolatorEntry& entry,float ratio);
// methods to compute X
typedef float (Interpolator::*computeXFn)(const Particle&) const;
static computeXFn COMPUTE_X_FN[4];
float computeXLifeTime(const Particle& particle) const;
float computeXAge(const Particle& particle) const;
float computeXParam(const Particle& particle) const;
float computeXVelocity(const Particle& particle) const;
// Only a model can create and destroy an interpolator
Interpolator();
~Interpolator() {};
};
inline void Interpolator::setType(InterpolationType type,ModelParam param)
{
this->type = type;
this->param = param;
}
inline void Interpolator::enableLooping(bool loop)
{
loopingEnabled = loop;
}
inline void Interpolator::setScaleXVariation(float scaleXVariation)
{
this->scaleXVariation = scaleXVariation;
}
inline void Interpolator::setOffsetXVariation(float offsetXVariation)
{
this->offsetXVariation = offsetXVariation;
}
inline InterpolationType Interpolator::getType() const
{
return type;
}
inline ModelParam Interpolator::getInterpolatorParam() const
{
return param;
}
inline bool Interpolator::isLoopingEnabled() const
{
return loopingEnabled;
}
inline float Interpolator::getScaleXVariation() const
{
return scaleXVariation;
}
inline float Interpolator::getOffsetXVariation() const
{
return offsetXVariation;
}
inline std::set<InterpolatorEntry>& Interpolator::getGraph()
{
return graph;
}
inline const std::set<InterpolatorEntry>& Interpolator::getGraph() const
{
return graph;
}
inline bool Interpolator::addEntry(const InterpolatorEntry& entry)
{
return graph.insert(entry).second;
}
inline bool Interpolator::addEntry(float x,float y)
{
return addEntry(InterpolatorEntry(x,y));
}
inline bool Interpolator::addEntry(float x,float y0,float y1)
{
return addEntry(InterpolatorEntry(x,y0,y1));
}
inline void Interpolator::clearGraph()
{
graph.clear();
}
inline float Interpolator::interpolateY(const InterpolatorEntry& entry,float ratio)
{
return entry.y0 + (entry.y1 - entry.y0) * ratio;
}
/////////////////////////////////////////////////////////////
// Functions to sort the entries on the interpolator graph //
/////////////////////////////////////////////////////////////
inline bool operator<(const InterpolatorEntry& entry0,const InterpolatorEntry& entry1)
{
return entry0.x < entry1.x;
}
inline bool operator==(const InterpolatorEntry& entry0,const InterpolatorEntry& entry1)
{
return entry0.x == entry1.x;
}
}
#endif

View File

@ -0,0 +1,570 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_MODEL
#define H_SPK_MODEL
#include "Core/SPK_DEF.h"
#include "Core/SPK_Registerable.h"
#include "Core/SPK_Interpolator.h"
namespace SPK
{
/**
* @enum ModelParamFlag
* @brief Constants used to set bits in Model flags
*
* These constant values are simply <i>1 << ModelParam</i> constants
*/
enum ModelParamFlag
{
FLAG_NONE = 0, /**< the flag bit for no parameter */
FLAG_RED = 1 << PARAM_RED, /**< the flag bit for PARAM_RED */
FLAG_GREEN = 1 << PARAM_GREEN, /**< the flag bit for PARAM_GREEN */
FLAG_BLUE = 1 << PARAM_BLUE, /**< the flag bit for PARAM_BLUE */
FLAG_ALPHA = 1 << PARAM_ALPHA, /**< the flag bit for PARAM_ALPHA */
FLAG_SIZE = 1 << PARAM_SIZE, /**< the flag bit for PARAM_SIZE */
FLAG_MASS = 1 << PARAM_MASS, /**< the flag bit for PARAM_MASS */
FLAG_ANGLE = 1 << PARAM_ANGLE, /**< the flag bit for PARAM_ANGLE */
FLAG_TEXTURE_INDEX = 1 << PARAM_TEXTURE_INDEX, /**< the flag bit for PARAM_TEXTURE_INDEX */
FLAG_ROTATION_SPEED = 1 << PARAM_ROTATION_SPEED, /**< the flag bit for PARAM_ROTATION_SPEED */
FLAG_CUSTOM_0 = 1 << PARAM_CUSTOM_0, /**< the flag bit for PARAM_CUSTOM_0 */
FLAG_CUSTOM_1 = 1 << PARAM_CUSTOM_1, /**< the flag bit for PARAM_CUSTOM_1 */
FLAG_CUSTOM_2 = 1 << PARAM_CUSTOM_2, /**< the flag bit for PARAM_CUSTOM_2 */
};
/**
* @class Model
* @brief A model of particles for particles' generation and evolution
*
* This class defines a behavior for particles generation and evolution over time.<br>
* A Particle is generated under a Model that cannot be changed during its life time.
* A Particle Model can however be changed but it will reinitialize the Particle parameters and life.<br>
* <br>
* A Model defines which parameters to use/update for a Particle. To do that an Model holds 4 flags that are :
* <ul>
* <li>Enabled : The parameter is enabled and can be set. Otherwise its default value is used.</li>
* <li>Mutable : The parameter will vary linearly over the life time of the Particle.</li>
* <li>Random : The parameter will be randomly generated for the Particle.</li>
* <li>Interpolated : The parameter will be interpolated by an object Interpolator to allow flexible variations.</li>
* </ul>
* The flags are processed when building up a model so that they are consistent :
* <ul>
* <li>All flags are masked so that they have not bit set at a higher position than the number of parameters.</li>
* <li>The mutable,random and interpolated flags are masked with the enabled flag : a parameter must be enabled to be either random, mutable or interpolated.</li>
* <li>An interpolated parameter cannot be mutable or/and random as well. The interpolated flag has the priority.</li>
* </ul>
* The life time of a particle and immortality is also defined by the Model.<br>
* <br>
* The default values for the parameters are the following :
* <ul>
* <li>PARAM_RED : 1.0</li>
* <li>PARAM_GREEN : 1.0</li>
* <li>PARAM_BLUE : 1.0</li>
* <li>PARAM_ALPHA : 1.0</li>
* <li>PARAM_SIZE : 1.0</li>
* <li>PARAM_MASS : 1.0</li>
* <li>PARAM_ANGLE : 0.0</li>
* <li>PARAM_TEXTURE_INDEX : 0.0</li>
* <li>PARAM_ROTATION_SPEED : 0.0</li>
* <li>PARAM_CUSTOM_0 : 0.0</li>
* <li>PARAM_CUSTOM_1 : 0.0</li>
* <li>PARAM_CUSTOM_2 : 0.0</li>
* </ul>
*/
class SPK_PREFIX Model : public Registerable
{
friend class Particle;
SPK_IMPLEMENT_REGISTERABLE(Model)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief The constructor for Model
*
* The user have to pass the Model flags that cannot be changed afterwards.<br>
* To set up flags enumerators from ModelParamFlag can be used in a OR way.<br>
* For instance, <i>Model(FLAG_RED | FLAG_GREEN | FLAG_BLUE | FLAG_ALPHA,FLAG_NONE,FLAG_NONE,FLAG_NONE)</i>
* constructs a Model that will generate Particles with a defined color that will not change over time.<br>
* <br>
* Since 1.03.00, PARAM_RED, PARAM_GREEN and PARAM_BLUE are enabled by default.
* This is needed to pass the values to the GPU in an optimized way.<br>
* Note that even the enable flag passed by the user does not containt those params, they will be enabled anyway.
*
* @param enableFlag : the enable flag
* @param mutableFlag : the mutable flag
* @param randomFlag : the random flag
* @param interpolatedFlag : the interpolated flag
*/
Model(int enableFlag = FLAG_RED | FLAG_GREEN | FLAG_BLUE,int mutableFlag = FLAG_NONE,int randomFlag = FLAG_NONE,int interpolatedFlag = FLAG_NONE);
/**
* @brief The copy constructor for Model
* @param model : The Model to construct the new Model from
*/
Model(const Model& model);
/**
* @brief Creates and registers a new Model
* @param enableFlag : the enable flag
* @param mutableFlag : the mutable flag
* @param randomFlag : the random flag
* @param interpolatedFlag : the interpolated flag
* @return A new registered Model
* @since 1.04.00
*/
static inline Model* create(int enableFlag = FLAG_RED | FLAG_GREEN | FLAG_BLUE,int mutableFlag = FLAG_NONE,int randomFlag = FLAG_NONE,int interpolatedFlag = FLAG_NONE);
////////////////
// Destructor //
////////////////
/** @brief The destructor for Model */
~Model();
/////////////
// Setters //
/////////////
/**
* @brief Sets the life time
*
* All particles generated under this Model will be given a life time randomly generated within [lifeTimeMin,lifeTimeMax[.<br>
* To generate particles with a non random life time, simply use <i>setLifeTime(a,a)</i>.
*
* @param lifeTimeMin : the minimum life time
* @param lifeTimeMax : the maximum life time
*/
inline void setLifeTime(float lifeTimeMin,float lifeTimeMax);
/**
* @brief Defines whether to generate immortal particles or not
*
* Immortal particles will still be given a life time. However the age of immortal particles will not increase so that they cannot die.
* An immortal Particle whose Model immortality is unset will grow older again.<br>
* The immortality is therefore dynamic and can be granted or removed by impacting all particles generated under this Model.
*
* @param immortal : whether the Model will generate immortal particles or not
*/
inline void setImmortal(bool immortal);
/**
* @brief Sets a given parameter with 4 values
*
* This method will only set parameters that are enabled, mutable and random.<br>
* If not nothing will happen and the method will return false.
*
* @param type : the parameter to set
* @param startMin : the minimum value at the Particle birth
* @param startMax : the maximum value at the Particle birth
* @param endMin : the minimum value at the Particle death
* @param endMax : the maximum value at the Particle death
* @return true if the parameter can be set (right flags), false otherwise
*/
bool setParam(ModelParam type,float startMin,float startMax,float endMin,float endMax);
/**
* @brief Sets a given parameter with 2 values
*
* This method will only set parameters that are enabled and <b>either</b> mutable or random.<br>
* If not nothing will happen and the method will return false.<br>
* <br>
* In case of a mutable parameter : value0 defines the birth value and value0 defines the death value.<br>
* In case of a random parameter : value0 defines the minimum value and value1 defines the maximum value.<br>
*
* @param type : the parameter to set
* @param value0 : the first value (the meaning depends on the flag)
* @param value1 : the second value (the meaning depends on the flag)
* @return true if the parameter can be set (right flags), false otherwise
*/
bool setParam(ModelParam type,float value0,float value1);
/**
* @brief Sets a given parameter with 1 value
*
* This method will only set parameters that are enabled and <b>neither</b> mutable or random.<br>
* If not nothing will happen and the method will return false.<br>
* <br>
* Note that to set the value of an interpolated parameter cannot be set with this function,
* you must used the interpolator object associated to the parameter to control its value.
*
* @param type : the parameter to set
* @param value : the value of the parameter
* @return true if the parameter can be set (right flags), false otherwise
*/
bool setParam(ModelParam type,float value);
/////////////
// Getters //
/////////////
/**
* @brief Gets the minimum life time
* @return the minimum life time
*/
inline float getLifeTimeMin() const;
/**
* @brief Gets the maximum life time
* @return the minimum life time
*/
inline float getLifeTimeMax() const;
/**
* @brief Returns whether immortility is set or not
* @return whether immortility is set or not
*/
inline bool isImmortal() const;
/**
* @brief Checks whether a parameter is enabled or not
* @param type : the parameter
* @return 0 is the parameter is not enabled, a flag with the parameter bit set otherwise
*/
inline int isEnabled(ModelParam type) const;
/**
* @brief Checks whether a parameter is mutable or not
* @param type : the parameter
* @return 0 is the parameter is not mutable, a flag with the parameter bit set otherwise
*/
inline int isMutable(ModelParam type) const;
/**
* @brief Checks whether a parameter is random or not
* @param type : the parameter
* @return 0 is the parameter is not random, a flag with the parameter bit set otherwise
*/
inline int isRandom(ModelParam type) const;
/**
* @brief Checks whether a parameter is interpolated or not
* @param type : the parameter
* @return 0 is the parameter is not interpolated, a flag with the parameter bit set otherwise
* @since 1.05.00
*/
inline int isInterpolated(ModelParam type) const;
/**
* @brief Gets a parameter value
*
* If index is superior or equal to the number of values for the parameter, the default value of the parameter is returned.<br>
* Otherwise the value returned depending on the index is :
* <ul>
* <li>Enabled parameters :
* <ul>
* <li>0 : the value of the parameter</li>
* </ul>
* </li>
* <li>Mutable parameters :
* <ul>
* <li>0 : the birth value of the parameter</li>
* <li>1 : the death value of the parameter</li>
* </ul>
* </li>
* <li>Random parameters :
* <ul>
* <li>0 : the minimum value of the parameter</li>
* <li>1 : the maximum value of the parameter</li>
* </ul>
* </li>
* <li>Mutable and random parameters :
* <ul>
* <li>0 : the minimum birth value of the parameter</li>
* <li>1 : the maximum birth value of the parameter</li>
* <li>2 : the minimum death value of the parameter</li>
* <li>3 : the maximum death value of the parameter</li>
* </ul>
* </li>
* </ul>
*
* Note that in case of an interpolated parameter, the default value is always returned.<br>
* The user has to use the interpolator object associated to the parameter to get its values.
*
* @param type : the parameter
* @param index : the index of the value to get
* @return the value
*/
float getParamValue(ModelParam type,size_t index) const;
/**
* @brief Gets the number of values for a parameter
*
* The number of values depends on the Model flags :
* <ul>
* <li>Enabled parameter : 1</li>
* <li>Mutable <b>or</b> random parameter : 2</li>
* <li>Mutable <b>and</b> random parameter : 4</li>
* <li>Interpolated parameter : 0</li>
* <li>Not Enabled : 0</li>
* </ul>
* @param type : the parameter
* @return the number of values stored in the Model for the parameter
*/
unsigned int getNbValues(ModelParam type) const;
/**
* @brief Gets the number of enabled parameters
* @return the number of enabled parameters in the model
* @since 1.05.00
*/
inline size_t getNbEnabled() const;
/**
* @brief Gets the number of mutable parameters
* @return the number of mutable parameters in the model
* @since 1.05.00
*/
inline size_t getNbMutable() const;
/**
* @brief Gets the number of random parameters
* @return the number of random parameters in the model
* @since 1.05.00
*/
inline size_t getNRandom() const;
/**
* @brief Gets the interpolator for the given parameter
* @param param : the parameter whose intepolator must be retrieved
* @return a pointer to the interpolator of the given parameter or NULL if the parameter is not interpolated
* @since 1.05.00
*/
inline Interpolator* getInterpolator(ModelParam param);
/**
* @brief Gets the number of interpolated parameters
* @return the number of interpolated parameters in the model
* @since 1.05.00
*/
inline size_t getNbInterpolated() const;
/**
* @brief Gets the number of float values in the particle current array
*
* The particle current array holds the current values of enabled parameters for a particle.<br>
* This is used internally and should not be needed by the user.
*
* @return the number of float values in the particle current array
* @since 1.02.00
*/
inline size_t getSizeOfParticleCurrentArray() const;
/**
* @brief Gets the number of float values in the particle extended array
*
* The particle extended array holds the extended values needed for parameters interpolation for a particle.<br>
* This is used internally and should not be needed by the user.
*
* @return the number of float values in the particle extended array
* @since 1.03.00
*/
inline size_t getSizeOfParticleExtendedArray() const;
/**
* @brief Gets the number of float values in the model array
*
* This is used internally and should not be needed by the user.
*
* @return the number of float values in the model array
* @since 1.02.00
*/
inline size_t getSizeOfModelArray() const;
/**
* @brief Gets the offset of the given parameter in the current array
*
* This methods is used internally by the engine
*
* @param param : the parameter
* @return the offset of the given parameter in the current array
* @since 1.03.00
*/
inline size_t getParameterOffset(ModelParam param) const;
/**
* @brief Gets the default value of the parameter
* @param param : the parameter to get the default value from
* @return the default value of the parameter
* @since 1.05.00
*/
static float getDefaultValue(ModelParam param);
private :
// total number of parameters
static const size_t NB_PARAMS = 12;
// default values for the parameters
static const float DEFAULT_VALUES[NB_PARAMS];
// arrays storing the values of parameters for the model following that form :
// enable : 1 value -> value
// mutable : 2 values -> start value | end value
// random : 2 values -> min value | max value
// mutable and random : 4 values -> start min value | start max value | end min value | end max value
// interpolated : 0 value
float* params;
size_t paramsSize;
// array storing the parameters that are enabled
size_t nbEnableParams;
int* enableParams;
// array storing the parameters that are mutable
size_t nbMutableParams;
int* mutableParams;
// array storing the parameters that are interpolated
size_t nbInterpolatedParams;
int* interpolatedParams;
// nb of random parameters
size_t nbRandomParams;
// array of interpolators
Interpolator* interpolators[NB_PARAMS];
// the flags of the model
int enableFlag;
int mutableFlag;
int randomFlag;
int interpolatedFlag;
int particleEnableIndices[NB_PARAMS]; // array storing the index of a parameter in the enableParams array
int particleMutableIndices[NB_PARAMS]; // array storing the index of a parameter in the mutableParams array
int indices[NB_PARAMS]; // array storing the index of a parameter in the model param array
float lifeTimeMin;
float lifeTimeMax;
bool immortal;
void initParamArrays(const Model& model);
};
inline Model* Model::create(int enableFlag,int mutableFlag,int randomFlag,int interpolatedFlag)
{
Model* obj = new Model(enableFlag,mutableFlag,randomFlag,interpolatedFlag);
registerObject(obj);
return obj;
}
inline void Model::setLifeTime(float lifeTimeMin,float lifeTimeMax)
{
this->lifeTimeMin = lifeTimeMin;
this->lifeTimeMax = lifeTimeMax;
}
inline void Model::setImmortal(bool immortal)
{
this->immortal = immortal;
}
inline float Model::getLifeTimeMin() const
{
return lifeTimeMin;
}
inline float Model::getLifeTimeMax() const
{
return lifeTimeMax;
}
inline bool Model::isImmortal() const
{
return immortal;
}
inline int Model::isEnabled(ModelParam type) const
{
return enableFlag & (1 << type);
}
inline int Model::isMutable(ModelParam type) const
{
return mutableFlag & (1 << type);
}
inline int Model::isRandom(ModelParam type) const
{
return randomFlag & (1 << type);
}
inline int Model::isInterpolated(ModelParam type) const
{
return interpolatedFlag & (1 << type);
}
inline size_t Model::getNbEnabled() const
{
return nbEnableParams;
}
inline size_t Model::getNbMutable() const
{
return nbMutableParams;
}
inline size_t Model::getNRandom() const
{
return nbRandomParams;
}
inline Interpolator* Model::getInterpolator(ModelParam param)
{
return interpolators[param];
}
inline size_t Model::getNbInterpolated() const
{
return nbInterpolatedParams;
}
inline size_t Model::getSizeOfParticleCurrentArray() const
{
return nbEnableParams;
}
inline size_t Model::getSizeOfParticleExtendedArray() const
{
return nbMutableParams + (nbInterpolatedParams << 1) + nbInterpolatedParams; // nbMutable + nbInterpolated * 3
}
inline size_t Model::getSizeOfModelArray() const
{
return paramsSize;
}
inline size_t Model::getParameterOffset(ModelParam param) const
{
return particleEnableIndices[param];
}
}
#endif

View File

@ -0,0 +1,375 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_MODIFIER
#define H_SPK_MODIFIER
#include "Core/SPK_DEF.h"
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Registerable.h"
#include "Core/SPK_BufferHandler.h"
#include "Core/SPK_Zone.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
class ModifierGroup;
/**
* @enum ModifierTrigger
* @brief Constants defining the triggers for Modifier
*/
enum ModifierTrigger
{
ALWAYS = 1 << 0, /**< No trigger, a Particle is always modified */
INSIDE_ZONE = 1 << 1, /**< Trigger defining a Particle inside the Zone */
OUTSIDE_ZONE = 1 << 2, /**< Trigger defining a Particle outside the Zone */
INTERSECT_ZONE = 1 << 3, /**< Trigger defining a Particle intersecting the Zone (in any direction) */
ENTER_ZONE = 1 << 4, /**< Trigger defining a Particle entering the Zone */
EXIT_ZONE = 1 << 5, /**< Trigger defining a Particle exiting the Zone */
};
/**
* @class Modifier
* @brief A abstract class that defines a physical object acting on particles
*
* A Modifier is first defined by a Zone and a trigger to that Zone.<br>
* If the Particle triggers the Modifier, the Modifier's action is applied to the Particle.<br>
* An action can be anything that has effect on the Particle's parameters, position, velocity, life...<br>
* <br>
* If no Zone is attached to a Modifier the Zone is considered to be the entire universe.<br>
* <br>
* Like an Emitter, a Modifier can either be used automatically within a Group or manually directly by the user.
*/
class SPK_PREFIX Modifier : public Registerable,
public Transformable,
public BufferHandler
{
friend class ModifierGroup;
friend class Group;
friend class Particle;
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of Modifier
* @param availableTriggers : the available triggers for this Modifier (OR-ed)
* @param trigger : the default trigger of the Modifier
* @param needsIntersection : true if the computation of the intersection is needed, false otherwise
* @param needsNormal : true if the computation of the normal is needed, false otherwise
* @param zone : the Zone of the Modifier
*/
Modifier(int availableTriggers = ALWAYS,ModifierTrigger trigger = ALWAYS,bool needsIntersection = false,bool needsNormal = false,Zone* zone = NULL);
////////////////
// Destructor //
////////////////
/** @brief Destructor of Modifier */
virtual inline ~Modifier() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets this Modifier active or not.
*
* An inactive Modifier will not affect its parent Group during update.<br>
* However it can still be used manually by the user.
*
* @param active : true to activate this Modifier, false to deactivate it
* @since 1.03.00
*/
inline void setActive(bool active);
/**
* @brief Sets the Zone of this Modifier
*
* If the Zone is NULL, the Zone is considered to be the entire universe.
*
* @param zone : the Zone of this Modifier
* @param full : true to consider the Zone as a full object so that particles are not allowed to be within
*/
void setZone(Zone* zone,bool full = false);
/**
* @brief Sets the trigger of this Modifier
*
* if the trigger is not one of the available triggers (see getAvailableTriggers()) for this Modifier,
* nothing happens ad false is returned else the trigger is set and true is returned.
*
* @param trigger : the trigger of this Modifier
* @return true if the trigger can be set, false otherwise
*/
bool setTrigger(ModifierTrigger trigger);
/**
* @brief Sets whether to consider this modifier local to a system or not
*
* A local modifier is transformed when its system is transformed, a non local one will not.
*
* @param local : true to consider the modifier local, false not to
* @since 1.03.02
*/
inline void setLocalToSystem(bool local);
/////////////
// Getters //
/////////////
/**
* @brief Tells whether this Modifier is active or not
* @return true if this Modifier is active, false if is is inactive
* @since 1.03.00
*/
inline bool isActive() const;
/**
* @brief Gets the Zone of this Modifier
* @return the Zone of this Modifier
*/
inline Zone* getZone() const;
/**
* @brief Gets the trigger of this Modifier
* @return the trigger of this Modifier
*/
inline ModifierTrigger getTrigger() const;
/**
* @brief Gets a flag containing all the available triggers for this Modifier
* @return a flag containing all the available triggers for this Modifier
*/
inline int getAvailableTriggers() const;
/**
* @brief Tells whether the Zone of this Modifier is considerered to be full or not
* @return true if the Zone of this Modifier is considerered to be full, false if not
*/
inline bool isFullZone() const;
/**
* @brief Tells whether this modifier is considered as being local to a system or not
*
* A local modifier is transformed when its system is transformed, a non local one will not.
*
* @return true if it is local, false if not
* @since 1.03.02
*/
inline bool isLocalToSystem() const;
///////////////
// Interface //
///////////////
virtual Registerable* findByName(const std::string& name);
protected :
/** @brief the Vector3D that holds the intersection coordinates */
static Vector3D intersection;
/** @brief the Vector3D that holds the intersection coordinates */
static Vector3D normal;
/** @brief true if the Modifier needs the intersection computation, false if not */
bool needsIntersection;
/** @brief true if the Modifier needs the normal computation, false if not */
bool needsNormal;
/** @brief the current trigger of this Modifier */
ModifierTrigger trigger;
/** @brief a flag containing all the available triggers */
const int availableTriggers;
virtual void registerChildren(bool registerAll);
virtual void copyChildren(const Modifier& modifier,bool createBase);
virtual void destroyChildren(bool keepChildren);
virtual inline void propagateUpdateTransform();
private :
Zone* zone;
bool full;
bool active;
mutable bool savedActive;
bool local;
void beginProcess(Group& group);
inline void endProcess(Group& group);
inline void process(Particle& particle,float deltaTime) const;
//////////////////////////
// Pure virtual methods //
//////////////////////////
/**
* @brief A pure virtual method that modifies the Particle
*
* This is a pure virtual method to be implemented by children.<br>
* The Modifier on this Particle has already been triggered and the Particle must be modified by this method.
*
* @param particle : the Particle that has to be modified
* @param deltaTime : the time step
*/
virtual void modify(Particle& particle,float deltaTime) const = 0;
/**
* @brief A pure virtual method that handles particles on the wrong side of this Modifier Zone.
*
* This is a pure virtual method to be implemented by children.<br>
* This method can be called internally with all triggers except SPK::TRIGGER_INTERSECTS.<br>
* <br>
* The method isFullZone() can be called to vary the behavior whether the Zone is full or not.<br>
* The boolean inside indicates whether the wrong side is inside (true) or outside (false) the Zone.
*
* @param particle : the Particle which is on the wrong side
* @param inside : true if the wrong side is inside, false if it is oustside
*/
virtual void modifyWrongSide(Particle& particle,bool inside) const {}
};
inline void Modifier::setActive(bool active)
{
this->active = active;
}
inline void Modifier::setLocalToSystem(bool local)
{
this->local = local;
}
inline bool Modifier::isActive() const
{
return active;
}
inline Zone* Modifier::getZone() const
{
return zone;
}
inline ModifierTrigger Modifier::getTrigger() const
{
return trigger;
}
inline int Modifier::getAvailableTriggers() const
{
return availableTriggers;
}
inline bool Modifier::isFullZone() const
{
return full;
}
inline bool Modifier::isLocalToSystem() const
{
return local;
}
inline void Modifier::propagateUpdateTransform()
{
if (zone != NULL)
zone->updateTransform(this);
}
inline void Modifier::endProcess(Group& group)
{
active = savedActive; // Restores the active state of the modifier
}
inline void Modifier::process(Particle& particle,float deltaTime) const
{
switch(trigger)
{
case ALWAYS :
modify(particle,deltaTime);
break;
case INSIDE_ZONE :
if ((zone == NULL)||(zone->contains(particle.position())))
modify(particle,deltaTime);
else
modifyWrongSide(particle,true);
break;
case OUTSIDE_ZONE :
if (zone == NULL)
return;
if (!zone->contains(particle.position()))
modify(particle,deltaTime);
else
modifyWrongSide(particle,false);
break;
case INTERSECT_ZONE :
if (zone == NULL)
return;
if (zone->intersects(particle.oldPosition(),
particle.position(),
needsIntersection ? &intersection : NULL,
needsNormal ? &normal : NULL))
modify(particle,deltaTime);
break;
case ENTER_ZONE :
if (zone == NULL)
return;
if (zone->contains(particle.oldPosition()))
modifyWrongSide(particle,true);
else if (zone->intersects(particle.oldPosition(),
particle.position(),
needsIntersection ? &intersection : NULL,
needsNormal ? &normal : NULL))
modify(particle,deltaTime);
break;
case EXIT_ZONE :
if (zone == NULL)
return;
if (!zone->contains(particle.oldPosition()))
modifyWrongSide(particle,false);
else if (zone->intersects(particle.oldPosition(),
particle.position(),
needsIntersection ? &intersection : NULL,
needsNormal ? &normal : NULL))
modify(particle,deltaTime);
break;
}
}
}
#endif

View File

@ -0,0 +1,428 @@
//////////////////////////////////////////////////////////////////////////////////
// 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.<br>
* Particles are designed to be handled in large amounts (called Group).
* This is why the user cannot update or render directly a single Particle.<br>
* <br>
* 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.<br>
*/
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<Particle>;
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.<br>
* 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.<br>
* 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.<br>
* 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.<br>
* 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.<br>
* 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.<br>
* 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.<br>
* 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 <i>getAge() == 0.0f</i>
*
* @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 <i>getLifeLeft > 0.0f</i>
*
* @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.<br>
*
* @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<Particle>::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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_REGWRAPPER
#define H_SPK_REGWRAPPER
#include "Core/SPK_DEF.h"
#include "Core/SPK_Registerable.h"
namespace SPK
{
/**
* @class RegWrapper
* @brief A Wrapper class that allows to use any type of object as a Registerable
*
* It simply encapsulates an object of type defined at compilation time.<br>
* It allows to define the behavior of these Group attributes when a copy of the Group occurs.<br>
* <br>
* The user can use it to define an attribute of a custom Registerable child class that needs to act as a Registerable.<br>
* <br>
* WARNING : T must obviously not be itself a Registerable.
*
* @since 1.03.00
*/
template<class T>
class RegWrapper : public Registerable
{
SPK_IMPLEMENT_REGISTERABLE(RegWrapper<T>)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Default constructor of RegWrapper
* @param object : the inner object
*/
RegWrapper<T>(const T& object = T());
/**
* @brief Creates and registers a new RegWrapper
* @param object : the inner object
* @return A new registered RegWrapper
* @since 1.04.00
*/
static inline RegWrapper<T>* create(const T& object = T());
/////////////
// Getters //
/////////////
/**
* @brief Gets a reference on the inner object
* @return a reference on the inner object
*/
inline T& get();
/**
* @brief Gets a constant reference on the inner object
* @return a constant reference on the inner object
*/
inline const T& get() const;
private :
T object;
};
template<class T>
inline RegWrapper<T>* RegWrapper<T>::create(const T& object)
{
RegWrapper<T>* obj = new RegWrapper<T>(object);
registerObject(obj);
return obj;
}
template<class T>
inline T& RegWrapper<T>::get()
{
return object;
}
template<class T>
inline const T& RegWrapper<T>::get() const
{
return object;
}
}
#endif

View File

@ -0,0 +1,468 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_REGISTERABLE
#define H_SPK_REGISTERABLE
#include "Core/SPK_DEF.h"
#include "Core/SPK_Vector3D.h"
// A macro implementing the clone method for Registerable children
// Note that copyChildren and destroyChildren have to be implemented manually if needed
#define SPK_IMPLEMENT_REGISTERABLE(ClassName) \
\
virtual ClassName* clone(bool createBase) const \
{ \
ClassName* cloneObject = new ClassName(*this); \
cloneObject->copyChildren(*this,createBase); \
return cloneObject; \
} \
\
public : \
virtual std::string getClassName() const {return #ClassName;}
namespace SPK
{
/** @brief the ID type of a Registerable */
typedef unsigned long SPK_ID;
/** @brief the ID constant value for unregistered Registerable */
extern SPK_PREFIX const SPK_ID NO_ID;
/** @brief an empty string defining the name of an object with no name */
extern SPK_PREFIX const std::string NO_NAME;
/**
* @class Registerable
* @brief the abstract base class for SPARK objects
*
* A Registerable defines a SPARK object that can be managed by the SPKFactory.<br>
* <br>
* In SPARK, a particle System is defined as a tree of objects. For instance, a System
* will contain some Renderer, Emitter and Modifier. Every Emitter and Modifier will
* contain a Zone...<br>
* All those Registerable are linked by association. A Registerable can be shared to several
* Registerable or belong to a single Registerable and die with it (composition).<br>
* <br>
* The SPKFactory offers a flexible system to define, create and destroy complex association
* of Registerable.<br>
* <br>
* Basically a Registerable has 3 parameters that will define its behavior :
* <ul>
* <li><b>Registered</b> : a registered Registerable is managed by the SPKFactory to deal with copy and destruction.</li>
* <li><b>Shared</b> : a shared Registerable will not be copied when copying its parent. Only its reference will. This allows
* for instance to change a parameter for many system with only a call. Note that this is valid only for registered
* Registerable copied with the SPKFactory.</li>
* <li><b>Destroyable</b> : a destroyable Registerable is a Registerable that is allowed to be destroyed by the SPKFactory when destroying
* its parent (if it has no more references on it see below). If not destroyable, the destruction of the Registerable is the user's responsability.
* Note that a non destroyable Registerable can still be destroyed by the SPKFactory by a direct call.</li>
* </ul>
* Moreover, every registered Registerable holds a counter of references that indicates how many registered Registerable hold a reference to it.
* A registered Registerable will only be destroyed by the SPKFactory if its number of references is 0 (except for a direct call to its destruction).
*
* @since 1.03.00
*/
class SPK_PREFIX Registerable
{
friend class SPKFactory;
public :
//////////////////
// Constructors //
//////////////////
/** @brief Default constructor of Registerable */
Registerable();
/**
* @brief Copy constructor of Registerable
* @param registerable : the Registerable to construct the new Registerable from
*/
Registerable(const Registerable& registerable);
////////////////
// Destructor //
////////////////
/** @brief Destructor of Registerable */
virtual ~Registerable();
/////////////
// Setters //
/////////////
/**
* @brief Makes this Registerable shared or not
*
* By default, a Registerable is not shared
*
* @param shared : true to make this Registerable shared, false to make it unshared
*/
inline void setShared(bool shared);
/**
* @brief Makes this Registerable destroyable or not
*
* A non destroyable Registerable cannot be destroyed internally.
*
* @param destroyable : true to make this Registerable destroyable, false to make it undestroyable
*/
inline void setDestroyable(bool destroyable);
/**
* @brief Sets the name of this Registerable
*
* The name is an easy to find registerable in a tree.<br>
* See getName() and findByName(const std::string&)
*
* A constant NO_NAME exists to give no name to the registerable (an empty string)
*
* @param name : the name of this registerable
* @since 1.05.00
*/
inline void setName(const std::string& name);
/////////////
// Getters //
/////////////
/**
* @brief Gets the ID of this Registerable
*
* If this Registerable is unregistered, NO_ID is returned.<br>
* Else an SPK_ID is returned. This ID uniquely identifies the Registerable.
*
* @return the ID of this Registerable or NO_ID if it is not registered
* @since 1.05.04
*/
inline SPK_ID getSPKID() const;
/**
* @brief Gets the ID of this Registerable
* @return the ID of this Registerable or NO_ID if it is not registered
* @deprecated 1.05.04 Use getSPKID instead
*/
inline SPK_ID getID() const;
/**
* @brief Gets the number of references of this Registerable
*
* The number of references defines the number of times a registered Registerable
* is references within all the registered Registerable.<br>
* <br>
* 0 is always returned for an unregistered Registerable.
*
* @return the number of references of this Registerable
*/
inline unsigned int getNbReferences() const;
/**
* @brief Tells whether this Registerable is registered or not
* @return true if this Registerable is registered, false if not
*/
inline bool isRegistered() const;
/**
* @brief Tells whether this Registerable is shared or not
* @return true if this Registerable is shared, false if not
*/
inline bool isShared() const;
/**
* @brief Tells whether this Registerable is destroyable or not
* @return true if this Registerable is destroyable, false if not
*/
inline bool isDestroyable() const;
/**
* @brief Gets the name of this registerable
*
* The name is an easy to find registerable in a tree.<br>
* See setName(const std::string&) and findByName(const std::string&)
*
* @return the name of this registerable
* @since 1.05.00
*/
inline const std::string& getName() const;
/**
* @brief Gets the name of the class of the object
*
* This method is implemented in non abstract derived class of Registerable with the macro SPK_IMPLEMENT_REGISTERABLE(ClassName).
*
* @return the name of the class of the object as a std::string
*/
virtual std::string getClassName() const = 0;
///////////////
// Interface //
///////////////
/**
* @brief Finds a registerable with its name recursively from this registerable
*
* If the name is not found, NULL is returned.<br>
* If the several objects with the same name exists, only the first one is returned.<br>
* <br>
* Note that the name of the registerable itself is already tested.
*
* @param name : the name of the registerable to find
* @return : the first registerable with that name within this registerable or NULL if none is found
* @since 1.05.00
*/
inline virtual Registerable* findByName(const std::string& name);
protected :
/**
* @brief Registers a child of this Registerable
*
* This method has to be called in the registerChildren(bool) implementation of a derived class of Registerable.<br>
* It is called to allow correct registering and correct reference counting of the children Registerable when registering the Registerable.
*
* @param child : the child of this Registerable to register
* @param registerAll : true to register an unregistered child, false to only increment ref counts of an already registered child
* @since 1.04.00
*/
void registerChild(Registerable* child,bool registerAll);
/**
* @brief Copies a child of this Registerable
*
* This method has to be called in the copyChildren(const Registerable&,bool) implementation of a derived class of Registerable.<br>
* It is called to allow correct copy (of the object or of the reference only) of the children Registerable when copying the Registerable.
*
* @param child : the child of this Registerable to copy
* @param createBase : true if a base is created, false otherwise
* @return the children of the copy of this Registerable
*/
Registerable* copyChild(Registerable* child,bool createBase);
/**
* @brief Destroys a child of this Registerable
*
* This method has to be called in the destroyChildren(bool) implementation of a derived class of Registerable.<br>
* It is called to allows the correct destruction (if not destroyable or references exist) of the children Registerable when destroying the Registerable.
*
* @param child : the child of this Registerable to destroy
* @param keepChildren : true to keep the children (used when destroying all registered Registerable)
* @return true if the child was destroyed, false if not
*/
bool destroyChild(Registerable* child,bool keepChildren);
/**
* @brief Increments the number of references of the child by one
*
* This method has to be called when adding a child in the implementation of a derived class of Registerable.<br>
* It allows to keep the number of references of the child correct.
*
* @param child : the child of this Registerable to increment references of
*/
inline void incrementChildReference(Registerable* child);
/**
* @brief Decrements the number of references of the child by one
*
* This method has to be called when removing a child in the implementation of a derived class of Registerable.<br>
* It allows to keep the number of references of the child correct.
*
* @param child : the child of this Registerable to decrement references of
*/
inline void decrementChildReference(Registerable* child);
/**
* @brief Registers a Registerable in the factory
*
* This method allows to register an unregistered given object.<br>
* If the registerable is already registered nothing happen.<br>
* <br>
* If registerAll is set to true, all the unregistered children of this Registerable will be registered as well.<br>
* Apart from that, all registered children see their reference count increments by one, no matter the value of registerAll.<br>
* <br>
* Use this method with care as it is very important to never register a object that is allocated on the stack, as the factory
* may delete its registered object with a call to delete.
*
* @param obj : the registerable object to register
* @param registerAll : true to register all its unregistered children and chidren of children and so on, false not to
* @since 1.04.00
*/
static void registerObject(Registerable* obj,bool registerAll = false);
/////////////////////
// Virtual methods //
/////////////////////
/**
* @brief Registers the children of this Registerable
*
* This method has to be implemented in derived classes of Registerable which hold pointers or references of Registerable children.<br>
* The registerChild(Registerable*,bool) has to be called within it for each child to copy from object.<br>
* The registerAll parameter of registerChild is simply the registerAll parameter of registerChildren.
*
* @param registerAll : true to register unregistered children, false to only increment ref counts of already registered children
* @since 1.04.00
*/
virtual void registerChildren(bool registerAll){};
/**
* @brief Copies the children of object in this Registerable
*
* This method has to be implemented in derived classes of Registerable which hold pointers or references of Registerable children.<br>
* The copyChild(Registerable*,bool) has to be called within it for each child to copy from object.<br>
* The createBase parameter of copyChild is simply the createBase parameter of copyChildren.
*
* @param object : the object to copy the children from
* @param createBase : true if a base is created, false otherwise
*/
virtual void copyChildren(const Registerable& object,bool createBase){};
/**
* @brief Destroys the children of this Registerable
*
* This method has to be implemented in derived classes of Registerable which hold pointers or references of Registerable children.<br>
* The destroyChild(Registerable*,bool) has to be called within it for each child to destroy.<br>
* The keepChildren parameter of destroyChild is simply the keepChildren parameter of destroyChildren.
*
* @param keepChildren : true to keep the children (used when destroying all registered Registerable)
*/
virtual void destroyChildren(bool keepChildren){};
private :
SPK_ID ID;
unsigned int nbReferences;
std::string name;
bool shared;
bool destroyable;
// Those methods allow specific behavior when registering and unregistering in the SPKFactory
virtual inline void onRegister() {} // Called when a registerable is registered in the SPKFactory
virtual inline void onUnregister() {} // Called when a registerable is unregistered from the SPKFactory
inline void incrementReference();
inline void decrementReference();
// the assignment operator is private
Registerable& operator=(const Registerable& registerable);
/////////////////////////
// Pure virtual method //
/////////////////////////
/**
* @brief Clones this Registerable
*
* This method is implemented in non abstract derived class of Registerable with the macro SPK_IMPLEMENT_REGISTERABLE(ClassName).
*
* @param createBase : true if a base is created, false otherwise
* @return the clone of this Registerable
*/
virtual Registerable* clone(bool createBase) const = 0;
};
inline void Registerable::setShared(bool shared)
{
this->shared = shared;
}
inline void Registerable::setDestroyable(bool destroyable)
{
this->destroyable = destroyable;
}
inline void Registerable::setName(const std::string& name)
{
this->name = name;
}
inline SPK_ID Registerable::getSPKID() const
{
return ID;
}
inline SPK_ID Registerable::getID() const
{
return getSPKID();
}
inline unsigned int Registerable::getNbReferences() const
{
return nbReferences;
}
inline bool Registerable::isRegistered() const
{
return ID != NO_ID;
}
inline bool Registerable::isShared() const
{
return shared;
}
inline bool Registerable::isDestroyable() const
{
return destroyable;
}
inline const std::string& Registerable::getName() const
{
return name;
}
inline Registerable* Registerable::findByName(const std::string& name)
{
return getName().compare(name) == 0 ? this : NULL;
}
inline void Registerable::incrementReference()
{
if (isRegistered())
++nbReferences;
}
inline void Registerable::decrementReference()
{
if ((isRegistered())&&(nbReferences > 0))
--nbReferences;
}
inline void Registerable::incrementChildReference(Registerable* child)
{
if ((isRegistered())&&(child != NULL))
child->incrementReference();
}
inline void Registerable::decrementChildReference(Registerable* child)
{
if ((isRegistered())&&(child != NULL))
child->decrementReference();
}
}
#endif

View File

@ -0,0 +1,220 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_RENDERER
#define H_SPK_RENDERER
#include "Core/SPK_DEF.h"
#include "Core/SPK_Registerable.h"
#include "Core/SPK_BufferHandler.h"
namespace SPK
{
class Group;
class Particle;
/**
* @enum BlendingMode
* @brief Constants defining the available blending modes
* @since 1.04.00
*/
enum BlendingMode
{
BLENDING_NONE, /**< No blending is applied. The particles will appeared as opaque */
BLENDING_ADD, /**< The additive blending is useful to render particles that supposed to emit light (fire, magic spells...) */
BLENDING_ALPHA, /**< The alpha blending is useful to render transparent particles */
};
/**
* @enum RenderingHint
* @brief Constants defining the available rendering hints
* @since 1.04.00
*/
enum RenderingHint
{
ALPHA_TEST = 1 << 0, /**< The alpha test. Enabling it is useful when rendering fully opaque particles with fully transparent zones (a texture of ball for instance) */
DEPTH_TEST = 1 << 1, /**< The depth test. Disabling it is useful when rendering particles with additive blending without having to sort them. Note that disabling the depth test will disable the depth write as well. */
DEPTH_WRITE = 1 << 2, /**< The depth write. Disabling it is useful when rendering particles with additive blending without having to sort them. Particles are still culled with the Zbuffer (when behind a wall for instance) */
};
/**
* @class Renderer
* @brief An abstract class that renders particles
*
* A renderer is used to represent particle systems.<br>
* the representation of a particle system is totally independant to its computation.<br>
* <br>
* Some renderers (or renderers modes) may need some buffers be attached to the Group of particles they render.<br>
* rendering buffers are attached to groups but used by renderers. Their creation can also be given to renderer when needed.<br>
* By enabling the buffer creation with the static method enableBuffersCreation(bool), the renderer will create the buffers he needs,
* if not already created in the group, before rendering. If buffer creation is disabled, a group that dont have the correct buffers for the renderer, cannot
* be renderered, the render method of the renderer will simply exit.<br>
* <br>
* Note that buffers are linked to a class of renderer, not to a given renderer object.<br>
* Moreover buffers have an inner flag that can vary function of the states of the renderer used.
*/
class SPK_PREFIX Renderer : public Registerable,
public BufferHandler
{
public :
/////////////////
// Constructor //
/////////////////
/** @brief Constructor of Renderer */
Renderer();
////////////////
// Destructor //
////////////////
/** @brief Destructor of Renderer */
virtual ~Renderer();
/////////////
// Setters //
/////////////
/**
* @brief Sets this Renderer active or not.
*
* An inactive Renderer will render its parent Group when a call to Group::render() is made.<br>
* However it can still be used manually by the user with render(Group&).
*
* @param active : true to activate this Renderer, false to deactivate it
* @since 1.03.00
*/
inline void setActive(bool active);
/**
* @brief Sets the blending mode of this renderer
*
* This is a generic method that allows to set most common blending modes in a generic way.
* However renderers can implement method to give more control over the blending mode used.
*
* @param blendMode : the blending mode to use
* @since 1.04.00
*/
virtual void setBlending(BlendingMode blendMode) = 0;
/**
* @brief Enables or disables a rendering hint
*
* Note that as stated, these are only hints that may not be taken into account in all rendering APIs
*
* @param renderingHint : the renderingHint to enable or disable
* @param enable : true to enable it, false to disable it
* @since 1.04.00
*/
virtual inline void enableRenderingHint(RenderingHint renderingHint,bool enable);
/**
* @brief Tells the alpha threshold to use when the ALPHA_TEST is enabled
*
* The operation performs by the alpha test is <i>greater or equal to threshold</i>
*
* @param alphaThreshold : the alpha threshold to use for the alpha test
* @since 1.04.00
*/
virtual inline void setAlphaTestThreshold(float alphaThreshold);
/////////////
// Getters //
/////////////
/**
* @brief Tells whether this Renderer is active or not
* @return true if this Renderer is active, false if is is inactive
* @since 1.03.00
*/
inline bool isActive() const;
/**
* @brief Tells whether a rendering hint is enabled or not
* @param renderingHint : the rendering hint
* @since 1.04.00
*/
virtual inline bool isRenderingHintEnabled(RenderingHint renderingHint) const;
/**
* @brief Gets the alpha threhold used by the alpha test
* @return the alpha threhold used by the alpha test
* @since 1.04.00
*/
inline float getAlphaTestThreshold() const;
///////////////
// Interface //
///////////////
/**
* @brief Renders a Group of particles
* @param group : the Group to render
*/
virtual void render(const Group& group) = 0;
private :
bool active;
int renderingHintsMask;
float alphaThreshold;
};
inline void Renderer::setActive(bool active)
{
this->active = active;
}
inline void Renderer::enableRenderingHint(RenderingHint renderingHint,bool enable)
{
if (enable)
renderingHintsMask |= renderingHint;
else
renderingHintsMask &= ~renderingHint;
}
inline void Renderer::setAlphaTestThreshold(float alphaThreshold)
{
this->alphaThreshold = alphaThreshold;
}
inline bool Renderer::isActive() const
{
return active;
}
inline bool Renderer::isRenderingHintEnabled(RenderingHint renderingHint) const
{
return (renderingHintsMask & renderingHint) != 0;
}
inline float Renderer::getAlphaTestThreshold() const
{
return alphaThreshold;
}
}
#endif

View File

@ -0,0 +1,457 @@
//////////////////////////////////////////////////////////////////////////////////
// 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.<br>
* It offers a way to handle a system very easily.<br>
* Basically a particle system is updated by calling update(unsigned int) and renderered with render() at each frame.<br>
* <br>
* 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.<br>
* <br>
* 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.<br>
* In that case this vector will be used as the camera position to derive the distance between the particle and the camera position.<br>
* 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.<br>
* Basically if the deltaTime is higher than the clamp value, the clamp calue is used as the deltaTime.<br>
* <br>
* 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.<br>
* <br>
* 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.<br>
* Depending on the deltaTime passed for the update, 0 to many updates can occur.<br>
* 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.<br>
* <br>
* 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.<br>
* 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).<br>
* If the deltaTime lies between minStep and maxStep then this mode performs like the real step mode.<br>
* <br>
* This mode is a good alternative between the other two.<br>
* 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.<br>
* One call to update means one update of time deltaTime.<br>
* <br>
* This mode is the simpler and the one that allows best performance on low end systems.<br>
* 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.<br>
* 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.<br>
* Note that the number of active particle of the system is updated after each update of the system.<br>
* 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.<br>
* 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.<br>
* In that way, this method must not be used as an accessor but call once when necesseray between 2 updates.<br>
* <br>
* 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.<br>
* Note that for addition and removal, methods <i>addGroup(Group*)</i> and <i>removeGroup(Group*)</i> must exist.<br>
*
* @return a STL vector containing the groups in the System
*/
inline const std::vector<Group*>& 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.<br>
* 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.<br>
* 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.<br>
* This method is therefore only useful when the camera position changes several times between 2 updates.<br>
* <br>
* 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.<br>
* This method is therefore only useful when the camera position changes several times between 2 updates.<br>
* <br>
* 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.<br>
* 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.<br>
* <br>
* Note that the computation of bounding boxes is also performed during the update.<br>
* This method is therefore only useful when the bounding boxes have to be recomputed between 2 updates.<br>
* <br>
* 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<Group*> 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<Group*>& 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

View File

@ -0,0 +1,590 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_TRANSFORMABLE
#define H_SPK_TRANSFORMABLE
#include "Core/SPK_Vector3D.h"
namespace SPK
{
class Zone;
/**
* @class Transformable
* @brief an abstract class that allows matrix transformations
*
* Every SPARK object that can be transformated thanks to a matrix should derive from this class.<br>
* A Transformable stores a matrix and performs operation on object parameters function of its matrix.<br>
* <br>
* It allows for instance to transform all emitters and zones in a system with a transform matrix.<br>
* Particles are still living in the world coordinates (unlike transforming the rendering process).<br>
* <br>
* Note that SPARK is not a linear algebra library, so this class does not offers lots of matri operations.<br>
* It is rather designed to be plugged within an existing engine with its own matrix system.<br>
* <br>
* SPARK was not designed to offer a complete scene graph. Even if the library can handle matrices stack, it does not
* offer lots of possibilities. Once again it was designed to be used with an existing outer scene graph.
* <br>
* The transforms used are continuous-in-memory homogeneous matrices with vectors being stored with their coordinates contiguous :<br>
* <i>[side.x side.y side.z side.w up.x up.y up.z up.w look.x look.y look.z look.w pos.x pos.y pos.z pos.w]</i><br>
* (look being -look in right-handed coordinate systems)<br>
*
* @since 1.03.00
*/
class SPK_PREFIX Transformable
{
public :
///////////////
// Constants //
///////////////
/** @brief The number of floats held by a transform */
static const size_t TRANSFORM_LENGTH = 16;
/** @brief The identity matrix */
static const float IDENTITY[TRANSFORM_LENGTH];
/////////////////
// Constructor //
/////////////////
/** @brief Constructor of Transformable */
Transformable();
Transformable(const Transformable& transformable);
////////////////
// Destructor //
////////////////
/** @brief Destructor of Transformable */
virtual inline ~Transformable() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets the local transform of this Transformable
*
* Note that the matrix must contain the following value in that order :<br>
* <i>[side.x side.y side.z side.w up.x up.y up.z up.w look.x look.y look.z look.w pos.x pos.y pos.z pos.w]</i><br>
* (look being -look in right-handed coordinate systems)<br>
* <br>
* The matrix being row or column major is just a convention which is not important.<br>
* The only thing that matters is that vectors coordinates are contiguous in memory.<br>
* If not, see setTransformNC(const float*)
*
* @param transform : the transform to copy its content from
*/
inline void setTransform(const float* transform);
/**
* @brief Sets the local transfom of this Transformable from a "non contiguous vector coordinates" matrix
*
* Note that the matrix must contain the following value in that order :<br>
* <i>[side.x up.x look.x pos.x side.x up.x look.x pos.x side.x up.x look.x pos.x side.w up.w look.w pos.w]</i><br>
* (look being -look in right-handed coordinate systems)<br>
* <br>
* Note the inner transform is stored with vector coordinates being contiguous in memory.<br>
* See setTransform(const float*)
*
* @param transform : the transform to copy its content from
*/
void setTransformNC(const float* transform);
/**
* @brief Sets the position of the local transform
*
* The orientation is left untouched.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param pos : the position of the local transform
* @since 1.05.00
*/
void setTransformPosition(const Vector3D& pos);
/**
* @brief Sets the orientation of the local transform in a right-handed system
*
* The position is left untouched.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param look : the look vector of the transformable
* @param up : the up vector of the transformable
* @since 1.05.00
*/
void setTransformOrientationRH(Vector3D look,Vector3D up);
/**
* @brief Sets the orientation of the local transform in a left-handed system
*
* The position is left untouched.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param look : the look vector of the transformable
* @param up : the up vector of the transformable
* @since 1.05.00
*/
void setTransformOrientationLH(Vector3D look,Vector3D up);
/**
* @brief Sets the orientation of the local transform
*
* This method allows to set the orientation around an arbitrary axis.<br>
* The position is left untouched.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param axis : the axis of rotation
* @param angle : the angle of rotation around the axis
* @since 1.05.00
*/
void setTransformOrientation(Vector3D axis,float angle);
/**
* @brief Sets the orientation of the local transform
*
* This method allows to set the orientation around an the x axis.<br>
* The position is left untouched.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param angle : the angle of rotation around the x axis
* @since 1.05.00
*/
void setTransformOrientationX(float angle);
/**
* @brief Sets the orientation of the local transform
*
* This method allows to set the orientation around an the y axis.<br>
* The position is left untouched.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param angle : the angle of rotation around the y axis
* @since 1.05.00
*/
void setTransformOrientationY(float angle);
/**
* @brief Sets the orientation of the local transform
*
* This method allows to set the orientation around an the z axis.<br>
* The position is left untouched.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param angle : the angle of rotation around the z axis
* @since 1.05.00
*/
void setTransformOrientationZ(float angle);
/////////////
// Getters //
/////////////
/**
* @brief Gets the local transform of this Transformable
* @return a pointer to the local transform of this Transformable
*/
inline const float* getLocalTransform() const;
/**
* @brief Gets the world transform of this Transformable
* @return a pointer to the world transform of this Transformable
*/
inline const float* getWorldTransform() const;
/**
* @brief Tells whether the local transform is the identity or not
* @return true if the local transform is identity, false if not
*/
inline bool isLocalIdentity() const;
/**
* @brief Gets the position of the local transform
* @return the position of the local transform
* @since 1.05.00
*/
inline Vector3D getLocalTransformPos() const;
/**
* @brief Gets the side vector of the local transform
* @return the side vector of the local transform
* @since 1.05.00
*/
inline Vector3D getLocalTransformSide() const;
/**
* @brief Gets the up vector of the local transform
* @return the up vector of the local transform
* @since 1.05.00
*/
inline Vector3D getLocalTransformUp() const;
/**
* @brief Gets the look vector of the local transform in a right-handed system
* @return the look vector of the local transform
* @since 1.05.00
*/
inline Vector3D getLocalTransformLookRH() const;
/**
* @brief Gets the look vector of the local transform in a left-handed system
* @return the look vector of the local transform
* @since 1.05.00
*/
inline Vector3D getLocalTransformLookLH() const;
/**
* @brief Gets the position of the world transform
* @return the position of the world transform
* @since 1.05.00
*/
inline Vector3D getWorldTransformPos() const;
/**
* @brief Gets the side vector of the world transform
* @return the side vector of the world transform
* @since 1.05.00
*/
inline Vector3D getWorldTransformSide() const;
/**
* @brief Gets the up vector of the world transform
* @return the up vector of the world transform
* @since 1.05.00
*/
inline Vector3D getWorldTransformUp() const;
/**
* @brief Gets the look vector of the world transform in a right-handed system
* @return the look vector of the world transform
* @since 1.05.00
*/
inline Vector3D getWorldTransformLookRH() const;
/**
* @brief Gets the look vector of the world transform in a left-handed system
* @return the look vector of the world transform
* @since 1.05.00
*/
inline Vector3D getWorldTransformLookLH() const;
///////////////
// Interface //
///////////////
/**
* @brief lookAt method for a right-handed system
*
* The vectors are normalized internally.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param target : the point the transformable is looking at
* @param up : the up vector of the transformable
* @param pos : the position of the transformable
* @since 1.05.00
*/
inline void lookAtRH(const Vector3D& target,Vector3D up,const Vector3D& pos);
/**
* @brief lookAt method for a left-handed system
*
* The vectors are normalized internally.<br>
* <br>
* Note that this methods sets the local transform.
* To compute the world transform and propagate it, updateTransform(const Transformable*) must be called afterwards.
*
* @param target : the point the transformable is looking at
* @param up : the up vector of the transformable
* @param pos : the position of the transformable
* @since 1.05.00
*/
inline void lookAtLH(const Vector3D& target,Vector3D up,const Vector3D& pos);
/**
* @brief Updates the world transform of this Transformable
*
* The parent transform and the local transform is used to derive the world transform.<br>
* If parent is NULL, the local transform is simply copied to the world transform.<br>
* <br>
* Note that this method only updates the transform if needed
*
* @param parent : the parent node of this Transformable or NULL
*/
void updateTransform(const Transformable* parent = NULL);
/** @brief Resets the transform to identity */
inline void resetTransform();
protected :
/**
* @brief A helper method to transform a position from local to world coordinates
* @param tPos : the resulting transformed position
* @param pos : the position in local coordinates
*/
void transformPos(Vector3D& tPos,const Vector3D& pos);
/**
* @brief A helper method to transform a direction from local to world coordinates
* @param tDir : the resulting transformed direction
* @param dir : the direction in local coordinates
*/
void transformDir(Vector3D& tDir,const Vector3D& dir);
/**
* @brief Tells whether this Transformable needs update or not
* @return true if it needs update, false if not
*/
inline bool isUpdateNotified() const;
/**
* @brief Notifies the Transformable for a update need
*
* This method has to be called when modifying a parameter that impose the transform's recomputation.
*/
inline void notifyForUpdate();
/**
* @brief Gets the latest parent of this Transformable
* @return the latest parent of this Transformable or NULL
*/
inline const Transformable* getParentTransform() const;
/**
* @brief Updates all the parameters in the world coordinates
*
* This method can be overriden in derived classes of Transformable (By default it does nothing).<br>
* It is this method task to compute all parameters of the class that are dependent of the world transform.
*/
virtual inline void innerUpdateTransform() {}
/**
* @brief Propagates the update of the transform to transformable children of this transformable
*
* This method can be overriden in derived classes of Transformable (By default it does nothing).<br>
* It is this method task to call the updateTransform method of transformable children of this transformable.
*
* @since 1.05.00
*/
virtual inline void propagateUpdateTransform() {}
private :
float local[TRANSFORM_LENGTH];
float world[TRANSFORM_LENGTH];
unsigned long int currentUpdate;
unsigned long int lastUpdate;
unsigned long int lastParentUpdate;
bool localIdentity;
const Transformable* parent;
inline static void multiply(
float* dest,
const float* src0,
const float* src1);
inline static void multiply(
Vector3D& dest,
const Vector3D& v,
const float* m);
inline static void rotate(
Vector3D& dest,
const Vector3D& v,
const float* m);
};
inline void Transformable::setTransform(const float* transform)
{
memcpy(local,transform,sizeof(float) * TRANSFORM_LENGTH);
localIdentity = false;
notifyForUpdate();
}
inline const float* Transformable::getLocalTransform() const
{
return local;
}
inline const float* Transformable::getWorldTransform() const
{
return world;
}
inline bool Transformable::isLocalIdentity() const
{
return localIdentity;
}
inline Vector3D Transformable::getLocalTransformPos() const
{
return Vector3D(local[12],local[13],local[14]);
}
inline Vector3D Transformable::getLocalTransformSide() const
{
return Vector3D(local[0],local[1],local[2]);
}
inline Vector3D Transformable::getLocalTransformUp() const
{
return Vector3D(local[4],local[5],local[6]);
}
inline Vector3D Transformable::getLocalTransformLookRH() const
{
return Vector3D(-local[8],-local[9],-local[10]);
}
inline Vector3D Transformable::getLocalTransformLookLH() const
{
return Vector3D(local[8],local[9],local[10]);
}
inline Vector3D Transformable::getWorldTransformPos() const
{
return Vector3D(world[12],world[13],world[14]);
}
inline Vector3D Transformable::getWorldTransformSide() const
{
return Vector3D(world[0],world[1],world[2]);
}
inline Vector3D Transformable::getWorldTransformUp() const
{
return Vector3D(world[4],world[5],world[6]);
}
inline Vector3D Transformable::getWorldTransformLookRH() const
{
return Vector3D(-world[8],-world[9],-world[10]);
}
inline Vector3D Transformable::getWorldTransformLookLH() const
{
return Vector3D(world[8],world[9],world[10]);
}
inline void Transformable::lookAtRH(const Vector3D& target,Vector3D up,const Vector3D& pos)
{
setTransformOrientationRH(target - pos,up);
setTransformPosition(pos);
}
inline void Transformable::lookAtLH(const Vector3D& target,Vector3D up,const Vector3D& pos)
{
setTransformOrientationLH(target - pos,up);
setTransformPosition(pos);
}
inline void Transformable::resetTransform()
{
setTransform(IDENTITY);
localIdentity = true;
}
inline bool Transformable::isUpdateNotified() const
{
return lastUpdate != currentUpdate;
}
inline void Transformable::notifyForUpdate()
{
++currentUpdate;
}
inline const Transformable* Transformable::getParentTransform() const
{
return parent;
}
void Transformable::multiply(
float* dest,
const float* src0,
const float* src1)
{
// naive matrix multiplication approach
// warning : no self assignment !
for (size_t i = 0; i < 4; ++i)
{
for (size_t j = 0; j < 4; ++j)
{
dest[(i << 2) + j] = 0.0f;
for (size_t k = 0; k < 4; ++k)
dest[(i << 2) + j] += src0[(k << 2) + j] * src1[(i << 2) + k];
//++dest;
}
//++dest;
}
}
void Transformable::multiply(
Vector3D& dest,
const Vector3D& v,
const float* m)
{
// warning : no self assignment !
// w coord of vectors is implicitely 1
dest.x = v.x * m[0] + v.y * m[4] + v.z * m[8] + m[12];
dest.y = v.x * m[1] + v.y * m[5] + v.z * m[9] + m[13];
dest.z = v.x * m[2] + v.y * m[6] + v.z * m[10] + m[14];
}
void Transformable::rotate(
Vector3D& dest,
const Vector3D& v,
const float* m)
{
// warning : no self assignment !
// w coord of vectors is implicitely 1
dest.x = v.x * m[0] + v.y * m[4] + v.z * m[8];
dest.y = v.x * m[1] + v.y * m[5] + v.z * m[9];
dest.z = v.x * m[2] + v.y * m[6] + v.z * m[10];
}
}
#endif

View File

@ -0,0 +1,570 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_VECTOR3D
#define H_SPK_VECTOR3D
#include "Core/SPK_DEF.h"
namespace SPK
{
/**
* @class Vector3D
* @brief A triplet of coordinates in 3D
*
* This class offers a set of methods to manipulate 3D points/vectors.<br>
* To make the use of 3D points/vectors easier and more intuitive, some operators are overloaded.<br>
* Vector3D are the basic primitive used in SPARK to define 3D points/vectors.<br>
* <br>
* Note that Vector3D coordinates are accessible directly without any setters or getters.
*/
class SPK_PREFIX Vector3D
{
public :
////////////////
// Parameters //
////////////////
float x; /**< @brief x coordinate of the vector */
float y; /**< @brief y coordinate of the vector */
float z; /**< @brief z coordinate of the vector */
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor for the Vector3D
* @param x : x coordinate
* @param y : y coordinate
* @param z : z coordinate
*/
Vector3D(float x = 0.0f,float y = 0.0f,float z = 0.0f);
///////////////
// Operators //
///////////////
/**
* @brief Adds a Vector3D
*
* This method performs these operations :<br><i>
* x += v.x<br>
* y += v.y<br>
* z += v.z</i>
*
* @param v : the Vector3D to add
* @return the result Vector3D
*/
Vector3D& operator+=(const Vector3D& v);
/**
* @brief Substracts a Vector3D
*
* This method performs these operations :<br><i>
* x -= v.x<br>
* y -= v.y<br>
* z -= v.z</i>
*
* @param v : the Vector3D to substract
* @return the result Vector3D
*/
Vector3D& operator-=(const Vector3D& v);
/**
* @brief Adds a floating number
*
* This method performs these operations :<br><i>
* x += f<br>
* y += f<br>
* z += f</i>
*
* @param f : the number to add
* @return the result Vector3D
*/
Vector3D& operator+=(float f);
/**
* @brief Substracts a floating number
*
* This method performs these operations :<br><i>
* x -= f<br>
* y -= f<br>
* z -= f</i>
*
* @param f : the number to substract
* @return the result Vector3D
*/
Vector3D& operator-=(float f);
/**
* @brief Multiplies by a floating number
*
* This method performs these operations :<br><i>
* x *= f<br>
* y *= f<br>
* z *= f</i>
*
* @param f : the number to multiply the Vector3D by
* @return the result Vector3D
*/
Vector3D& operator*=(float f);
/**
* @brief Divides by a floating number
*
* This method performs these operations :<br><i>
* x /= f<br>
* y /= f<br>
* z /= f</i>
*
* @param f : the number to divide the Vector3D by
* @return the result Vector3D
*/
Vector3D& operator/=(float f);
/**
* @brief Unary - operator of Vector3D
*
* This method performs that operation :<br><i>
* return Vector3D(-x,-y,-z)</i>
*
* return a Vector3D which is the reverse of this Vector3D
*/
inline Vector3D operator-() const;
/**
* @brief Accesses the Vector3D coordinates in an container like fashion
*
* <ul>
* <li>index 0 is X</li>
* <li>index 1 is Y</li>
* <li>index 2 is Z</li>
* </ul>
* Note that no check for out of bounds index is performed
*
* @param index : the index of the coordinate to get (from 0 to 2)
* @return : the coordinate value at index
* @since 1.03.00
*/
float& operator[](size_t index);
/**
* @brief Accesses the Vector3D coordinates in an container like fashion
*
* This is the constant version of operator[](size_t)
*
* @param index : the index of the coordinate to get (from 0 to 2)
* @return : the coordinate value at index
* @since 1.03.00
*/
const float& operator[](size_t index) const;
/////////////
// Setters //
/////////////
/**
* @brief Sets the values of the Vector3D
* @param x : x coordinate
* @param y : y coordinate
* @param z : z coordinate
*/
void set(float x,float y,float z = 0.0f);
///////////////
// Interface //
///////////////
/**
* @brief Gets the square norm of the Vector3D
*
* the square norm is defined as <i>x * x + y * y + z * z</i>.
* This method is faster than getNorm() and should be used when possible.
*
* @return the square norm of the Vector3D
*/
inline float getSqrNorm() const;
/**
* @brief Gets the norm of the Vector3D
*
* the norm is defined as <i>sqrt(x * x + y * y + z * z)</i>.
*
* @return the norm of the Vector3D
*/
inline float getNorm() const;
/**
* @brief Normalizes the Vector3D
*
* This method performs these operations :<br><i>
* x /= |v|<br>
* y /= |v|<br>
* z /= |v|<br></i>
* Note that if the norm is equal to 0, nothing happens and false is returned.
*
* @return true if this Vector3D can be normalized, false otherwise
*/
bool normalize();
/**
* @brief Reverts the Vector3D
*
* This method performs these operations :<br><i>
* x = -x<br>
* y = -y<br>
* z = -z</i>
*/
void revert();
/**
* @brief Sets this Vector3D to its absolute values
*
* This method performs these operations :<br><i>
* x = abs(x)<br>
* y = abs(y)<br>
* z = abs(z)</i>
*
* @since 1.02.00
*/
void abs();
/**
* @brief Computes the cross product between v and the vector3D and store the result in the vector3D
* @param v : the vector3D used to compute the cross product (*this x v)
*/
void crossProduct(const Vector3D& v);
};
////////////////////////
// External operators //
////////////////////////
/**
* @brief Adds two Vector3D
*
* This function performs these operations :<br><i>
* result.x = v0.x + v1.x<br>
* result.y = v0.y + v1.y<br>
* result.z = v0.z + v1.z</i>
*
* @param v0 : the first vector3D
* @param v1 : the second vector3D
* @return the result vector3D
*/
inline Vector3D operator+(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Substracts two Vector3D
*
* This function performs these operations :<br><i>
* result.x = v0.x - v1.x<br>
* result.y = v0.y - v1.y<br>
* result.z = v0.z - v1.z</i>
*
* @param v0 : the first vector3D
* @param v1 : the second vector3D
* @return the result vector3D
*/
inline Vector3D operator-(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Adds a Vector3D and a float
*
* This function performs these operations :<br><i>
* result.x = v.x + f<br>
* result.y = v.y + f<br>
* result.z = v.z + f</i>
*
* @param v : the vector3D
* @param f : the floating number
* @return the result vector3D
*/
inline Vector3D operator+(const Vector3D& v,float f);
/**
* @brief Adds a float and a Vector3D
*
* This function performs these operations :<br><i>
* result.x = f + v.x<br>
* result.y = f + v.y<br>
* result.z = f + v.z</i>
*
* @param f : the floating number
* @param v : the vector3D
* @return the result vector3D
*/
inline Vector3D operator+(float f,const Vector3D& v);
/**
* @brief Substracts a float to a Vector3D
*
* This function performs these operations :<br><i>
* result.x = v.x - f<br>
* result.y = v.y - f<br>
* result.z = v.z - f</i>
*
* @param v : the vector3D
* @param f : the floating number
* @return the result vector3D
*/
inline Vector3D operator-(const Vector3D& v,float f);
/**
* @brief Substracts a Vector3D to a float
*
* This function performs these operations :<br><i>
* result.x = f - v.x<br>
* result.y = f - v.y<br>
* result.z = f - v.z</i>
*
* @param f : the floating number
* @param v : the vector3D
* @return the result vector3D
*/
inline Vector3D operator-(float f,const Vector3D& v);
/**
* @brief Multiplies a Vector3D by a float
*
* This function performs these operations :<br><i>
* result.x = v.x * f<br>
* result.y = v.y * f<br>
* result.z = v.z * f</i>
*
* @param v : the vector3D
* @param f : the floating number
* @return the result vector3D
*/
inline Vector3D operator*(const Vector3D& v,float f);
/**
* @brief Multiplies a float by a Vector3D
*
* This function performs these operations :<br><i>
* result.x = f * v.x<br>
* result.y = f * v.y<br>
* result.z = f * v.z</i>
*
* @param f : the floating number
* @param v : the vector3D
* @return the result vector3D
*/
inline Vector3D operator*(float f,const Vector3D& v);
/**
* @brief Divides a Vector3D by a float
*
* This function performs these operations :<br><i>
* result.x = v.x / f<br>
* result.y = v.y / f<br>
* result.z = v.z / f</i>
*
* @param v : the vector3D
* @param f : the floating number
* @return the result vector3D
*/
inline Vector3D operator/(const Vector3D& v,float f);
/**
* @brief Divides a float by a Vector3D
*
* This function performs these operations :<br><i>
* result.x = f / v.x<br>
* result.y = f / v.y<br>
* result.z = f / v.z</i>
*
* @param f : the floating number
* @param v : the vector3D
* @return the result vector3D
*/
inline Vector3D operator/(float f,const Vector3D& v);
/**
* @brief Tests whether 2 Vector3D are equal
* @param v0 : the first Vector3D to compare
* @param v1 : the second Vector3D to compare
* @return true if the Vector3D are equal, false if not
* @since 1.01.01
*/
inline bool operator==(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Tests whether 2 Vector3D are different
* @param v0 : the first Vector3D to compare
* @param v1 : the second Vector3D to compare
* @return true if the Vector3D are different, false if not
* @since 1.01.01
*/
inline bool operator!=(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Writes a Vector3D on an output stream
*
* The Vector3D is written that way : <i>(x,y,z)</i>
*
* @param s : the output stream where to write
* @param v : the Vector3D to write to the output stream
* @return the output stream
* @since 1.01.01
*/
inline std::ostream& operator<<(std::ostream& s,const Vector3D& v);
////////////////////////
// External functions //
////////////////////////
/**
* @brief Returns the square distance between two Vector3D
*
* This method is faster than getDist(const Vector3D&,const Vector3D&) and should be used when possible.
*
* @param v0 : the first Vector3D
* @param v1 : the second Vector3D
* @return the square distance between the two Vector3D
*/
extern SPK_PREFIX float getSqrDist(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Returns the distance between two Vector3D
* @param v0 : the first Vector3D
* @param v1 : the second Vector3D
* @return the distance between the two Vector3D
*/
extern SPK_PREFIX float getDist(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Returns the dot product between two Vector3D
* @param v0 : the first Vector3D
* @param v1 : the second Vector3D
* @return the dot product (v0 . v1)
*/
inline float dotProduct(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Returns the cross product between two Vector3D
* @param v0 : the first Vector3D
* @param v1 : the second Vector3D
* @return the cross product (v0 x v1)
*/
extern SPK_PREFIX Vector3D crossProduct(const Vector3D& v0,const Vector3D& v1);
/**
* @brief Computes the cross product between two Vector3D and stores the result in the Vector3D result
* @param v0 : the first Vector3D
* @param v1 : the second Vector3D
* @param result : the Vector3D where to store the cross product (v0 x v1)
*/
extern SPK_PREFIX void crossProduct(const Vector3D& v0,const Vector3D& v1,Vector3D& result);
inline float Vector3D::getSqrNorm() const
{
return x * x + y * y + z * z;
}
inline float Vector3D::getNorm() const
{
return sqrt(getSqrNorm());
}
inline Vector3D Vector3D::operator-() const
{
return Vector3D(-x,-y,-z);
}
inline float dotProduct(const Vector3D& v0,const Vector3D& v1)
{
return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
}
inline Vector3D operator+(const Vector3D& v0,const Vector3D& v1)
{
return Vector3D(v0.x + v1.x,v0.y + v1.y,v0.z + v1.z);
}
inline Vector3D operator-(const Vector3D& v0,const Vector3D& v1)
{
return Vector3D(v0.x - v1.x,v0.y - v1.y,v0.z - v1.z);
}
inline Vector3D operator+(const Vector3D& v,float f)
{
return Vector3D(v.x + f,v.y + f,v.z + f);
}
inline Vector3D operator+(float f,const Vector3D& v)
{
return Vector3D(v.x + f,v.y + f,v.z + f);
}
inline Vector3D operator-(const Vector3D& v,float f)
{
return Vector3D(v.x - f,v.y - f,v.z - f);
}
inline Vector3D operator-(float f,const Vector3D& v)
{
return Vector3D(v.x - f,v.y - f,v.z - f);
}
inline Vector3D operator*(const Vector3D& v,float f)
{
return Vector3D(v.x * f,v.y * f,v.z * f);
}
inline Vector3D operator*(float f,const Vector3D& v)
{
return Vector3D(v.x * f,v.y * f,v.z * f);
}
inline Vector3D operator/(const Vector3D& v,float f)
{
float mul = 1.0f / f;
return Vector3D(v.x * mul,v.y * mul,v.z * mul);
}
inline Vector3D operator/(float f,const Vector3D& v)
{
return Vector3D(f / v.x,f / v.y,f / v.z);
}
inline bool operator==(const Vector3D& v0,const Vector3D& v1)
{
return (v0.x == v1.x)&&(v0.y == v1.y)&&(v0.z == v1.z);
}
inline bool operator!=(const Vector3D& v0,const Vector3D& v1)
{
return (v0.x != v1.x)||(v0.y != v1.y)||(v0.z != v1.z);
}
inline std::ostream& operator<<(std::ostream& s,const Vector3D& v)
{
return s << '(' << v.x << ',' << v.y << ',' << v.z << ')';
}
}
#endif

View File

@ -0,0 +1,197 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_ZONE
#define H_SPK_ZONE
#include "Core/SPK_DEF.h"
#include "Core/SPK_Registerable.h"
#include "Core/SPK_Transformable.h"
#include "Core/SPK_Vector3D.h"
namespace SPK
{
class Particle;
/**
* @class Zone
* @brief An abstract class that defines a zone in space
*
* A Zone is used in SPARK to :
* <ul>
* <li>define the area of an Emitter</li>
* <li>define the area of a Modifier</li>
* </ul>
*/
class SPK_PREFIX Zone : public Registerable, public Transformable
{
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Default constructor for Zone
* @param position : the position of the Zone
*/
Zone(const Vector3D& position = Vector3D());
////////////////
// Destructor //
////////////////
/** @brief Destructor of Zone */
virtual inline ~Zone() {}
////////////
// Setter //
////////////
/**
* @brief Sets the position of this Zone
* @param v : the position of this Zone
*/
virtual inline void setPosition(const Vector3D& v);
/////////////
// Getters //
/////////////
/**
* @brief Gets the position of this Zone
* @return the position of this Zone
*/
inline const Vector3D& getPosition() const;
/**
* @brief Gets the transformed position of this Zone
* @return the transformed position of this Zone
* @since 1.03.00
*/
inline const Vector3D& getTransformedPosition() const;
///////////////
// Interface //
///////////////
/**
* @brief Randomly generates a position inside this Zone for a given Particle
* @param particle : the Particle whose position will be generated
* @param full : true to generate a position in the whole volume of this Zone, false to generate a position only at borders
*/
virtual void generatePosition(Particle& particle,bool full) const = 0;
/**
* @brief Checks whether a point is within the Zone
* @param point : the point to check
* @return true if the point is within the Zone, false otherwise
*/
virtual bool contains(const Vector3D& point) const = 0;
/**
* @brief Checks whether a line intersects the Zone
*
* The intersection is computed only if the Vector3D* intersection is not NULL.<br>
* The normal is computed if the Vector3D* normal AND intersection are not NULL.
*
* @param v0 : start of the line
* @param v1 : end of the line
* @param intersection : the Vector3D where the intersection will be stored, NULL not to compute the intersection
* @param normal : the Vector3D where the normal will be stored, NULL not to compute the normal
* @return true if the line intersects with the Zone, false otherwise
*/
virtual bool intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const = 0;
/**
* @brief Moves a point at the border of the Zone
* @param point : the point that will be moved to the border of the Zone
* @param inside : true to move the point inside the Zone of APPROXIMATION_VALUE, false to move it outside of APPROXIMATION_VALUE
*/
virtual void moveAtBorder(Vector3D& point,bool inside) const = 0;
/**
* @brief Computes the normal for the point
* @param point : the point from where the normal is computed
* @return the normal vector
* @since 1.02.00
*/
virtual Vector3D computeNormal(const Vector3D& point) const = 0;
protected :
/** @brief Value used for approximation */
static const float APPROXIMATION_VALUE;
/**
* @brief A helper static method to normalize a Vector3D
*
* If the Vector3D is NULL, a random normal Vector3D is set.<br>
* The randomness is guaranteed to be uniformely distributed.
*
* @param v : the Vector3D to normalize or randomize if not normalizable
* @since 1.03.00
*/
static inline void normalizeOrRandomize(Vector3D& v);
virtual inline void innerUpdateTransform();
private :
Vector3D position;
Vector3D tPosition; // transformed position
};
inline void Zone::setPosition(const Vector3D& v)
{
position = tPosition = v;
notifyForUpdate();
}
inline const Vector3D& Zone::getPosition() const
{
return position;
}
inline const Vector3D& Zone::getTransformedPosition() const
{
return tPosition;
}
inline void Zone::normalizeOrRandomize(Vector3D& v)
{
while(!v.normalize())
{
do v = Vector3D(random(-1.0f,1.0f),random(-1.0f,1.0f),random(-1.0f,1.0f));
while (v.getSqrNorm() > 1.0f);
}
}
inline void Zone::innerUpdateTransform()
{
transformPos(tPosition,position);
}
}
#endif