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

@ -3,4 +3,5 @@ project (GREMLIN C CXX)
add_subdirectory (libs/glfw)
add_subdirectory (libs/enet)
add_subdirectory (libs/spark)
add_subdirectory (src)

Binary file not shown.

BIN
data/explosion/flash.tga Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
data/explosion/point.tga Normal file

Binary file not shown.

BIN
data/explosion/spark.tga Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
data/explosion/wave.tga Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
include_directories (include)
add_library (spark
src/SPK_All
src/SPK_GL_All
)

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

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_NORMALEMITTER
#define H_SPK_NORMALEMITTER
#include "Core/SPK_Emitter.h"
namespace SPK
{
/**
* @class NormalEmitter
* @brief An Emitter that emits particles following a Zone normals
*
* The Zone used to derive the direction of emission can either be the Emitter Zone
* or another Zone that can be set with setNormalZone(Zone*).<br>
* If the normal zone is NULL the emitter Zone is used.
*
* @since 1.02.00
*/
class SPK_PREFIX NormalEmitter : public Emitter
{
SPK_IMPLEMENT_REGISTERABLE(NormalEmitter)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of NormalEmitter
* @param normalZone : the Zone used to compute normals (NULL to used the Emitter Zone)
* @param inverted : true to invert the normals, false otherwise
*/
NormalEmitter(Zone* normalZone = NULL,bool inverted = false);
/**
* @brief Creates and registers a new NormalEmitter
* @param normalZone : the Zone used to compute normals (NULL to used the Emitter Zone)
* @param inverted : true to invert the normals, false otherwise
* @return A new registered NormalEmitter
* @since 1.04.00
*/
static inline NormalEmitter* create(Zone* normalZone = NULL,bool inverted = false);
/////////////
// Setters //
/////////////
/**
* @brief Sets whether normals are inverted or not
* @param inverted true to use inverted normals, false not to
*/
inline void setInverted(bool inverted);
/**
* @brief the Zone used to compute normals
*
* Note that if the normal zone is NULL, the Emitter Zone is used.
*
* @param zone : the Zone used to compute normals (NULL to used the Emitter Zone)
*/
void setNormalZone(Zone* zone);
/////////////
// Getters //
/////////////
/**
* @brief Tells whether normals are inverted for this NormalEmitter
* @return true if normals are inverted, false if not
*/
inline bool isInverted() const;
/**
* @brief Gets the normal Zone of this NormalEmitter
* @return the normal Zone of this NormalEmitter
*/
inline Zone* getNormalZone() const;
///////////////
// Interface //
///////////////
virtual Registerable* findByName(const std::string& name);
protected :
virtual void registerChildren(bool registerAll);
virtual void copyChildren(const NormalEmitter& emitter,bool createBase);
virtual void destroyChildren(bool keepChildren);
private :
bool inverted;
Zone* normalZone;
virtual void generateVelocity(Particle& particle,float speed) const;
};
inline NormalEmitter* NormalEmitter::create(Zone* normalZone,bool inverted)
{
NormalEmitter* obj = new NormalEmitter(normalZone,inverted);
registerObject(obj);
return obj;
}
inline void NormalEmitter::setInverted(bool inverted)
{
this->inverted = inverted;
}
inline bool NormalEmitter::isInverted() const
{
return inverted;
}
inline Zone* NormalEmitter::getNormalZone() const
{
return normalZone;
}
}
#endif

View File

@ -0,0 +1,63 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_RANDOMEMITTER
#define H_SPK_RANDOMEMITTER
#include "Core/SPK_Emitter.h"
namespace SPK
{
/**
* @class RandomEmitter
* @brief An Emitter that emits in a random direction
* @since 1.02.00
*/
class SPK_PREFIX RandomEmitter : public Emitter
{
SPK_IMPLEMENT_REGISTERABLE(RandomEmitter)
public :
/**
* @brief Creates and registers a new RandomEmitter
* @return A new registered RandomEmitter
* @since 1.04.00
*/
static inline RandomEmitter* create();
private :
virtual void generateVelocity(Particle& particle,float speed) const;
};
inline RandomEmitter* RandomEmitter::create()
{
RandomEmitter* obj = new RandomEmitter;
registerObject(obj);
return obj;
}
}
#endif

View File

@ -0,0 +1,183 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_SPHERICEMITTER
#define H_SPK_SPHERICEMITTER
#include "Core/SPK_Emitter.h"
namespace SPK
{
/**
* @class SphericEmitter
* @brief An Emitter that emits particles in a portion of sphere
*
* This Emitter can emit particles in a spheric way.
* To do that 2 angles and a direction Vector3D can be parametered :
* <ul>
* <li>The direction Vector3D defines the direction of the emitter.</li>
* <li>The angles defines the area in between which wil be emitted the particles velocities.</li>
* </ul>
* Here are a few examples :
* <ul>
* <li><i>0 and 2 * PI</i> will define a complete sphere ie equivalent to a RandomEmitter</li>
* <li><i>0 and 0</i> will define a Emitter equivalent to a StraightEmitter</li>
* <li><i>PI and PI</i> will define a disk</li>
* <li><i>PI / 2 and PI / 2</i> will define a Cone of angle PI / 2</li>
* <li>...</li>
* </ul>
*/
class SPK_PREFIX SphericEmitter : public Emitter
{
SPK_IMPLEMENT_REGISTERABLE(SphericEmitter)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of SphericEmitter
* @param direction : the direction of the SphericEmitter
* @param angleA : the first angle in radians of the SphericEmitter
* @param angleB : the second angle in radians of the SphericEmitter
*/
SphericEmitter(const Vector3D& direction = Vector3D(0.0f,0.0f,-1.0f),float angleA = 0.0f,float angleB = 0.0f);
/**
* @brief Creates and registers a new SphericEmitter
* @param direction : the direction of the SphericEmitter
* @param angleA : the first angle in radians of the SphericEmitter
* @param angleB : the second angle in radians of the SphericEmitter
* @since 1.04.00
*/
static inline SphericEmitter* create(const Vector3D& direction = Vector3D(0.0f,0.0f,-1.0f),float angleA = 0.0f,float angleB = 0.0f);
/////////////
// Setters //
/////////////
/**
* @brief Sets the direction of this SphericEmitter
*
* Note that it is not necessary to provide a normalized Vector3D.
* This Vector3D only indicates a direction, its norm does not matter.
*
* @param direction : the direction of this SphericEmitter
*/
void setDirection(const Vector3D& direction);
/**
* @brief Sets the angles of this SphericEmitter
*
* Note that angles are clamped between 0 and 2 * PI
* AngleA does not have to be inferior to angleB, it has no importance as angles are sorted within the method.
*
* @param angleA : the first angle in radians of this SphericEmitter
* @param angleB : the second angle in radians of this SphericEmitter
*/
void setAngles(float angleA,float angleB);
/////////////
// Getters //
/////////////
/**
* @brief Gets the direction of this SphericEmitter
* @return the direction of this SphericEmitter
*/
inline const Vector3D& getDirection() const;
/**
* @brief Gets the direction of this SphericEmitter
* @return the direction of this SphericEmitter
*/
inline const Vector3D& getTransformedDirection() const;
/**
* @brief Gets the minimum angle of this SphericEmitter
* @return the minimum angle of this SphericEmitter
*/
inline float getAngleMin() const;
/**
* @brief Gets the maximum angle of this SphericEmitter
* @return the maximum angle of this SphericEmitter
*/
inline float getAngleMax() const;
protected :
virtual void innerUpdateTransform();
private :
static const float PI;
Vector3D direction;
Vector3D tDirection; // transformed direction
float angleMin;
float angleMax;
float cosAngleMin;
float cosAngleMax;
float matrix[9];
void computeMatrix();
virtual void generateVelocity(Particle& particle,float speed) const;
};
inline SphericEmitter* SphericEmitter::create(const Vector3D& direction,float angleA,float angleB)
{
SphericEmitter* obj = new SphericEmitter(direction,angleA,angleB);
registerObject(obj);
return obj;
}
inline const Vector3D& SphericEmitter::getDirection() const
{
return direction;
}
inline const Vector3D& SphericEmitter::getTransformedDirection() const
{
return tDirection;
}
inline float SphericEmitter::getAngleMin() const
{
return angleMin;
}
inline float SphericEmitter::getAngleMax() const
{
return angleMax;
}
}
#endif

View File

@ -0,0 +1,69 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_STATICEMITTER
#define H_SPK_STATICEMITTER
#include "Core/SPK_Emitter.h"
namespace SPK
{
/**
* @class StaticEmitter
* @brief An Emitter that emits particles with no initial velocity
* @since 1.05.00
*/
class StaticEmitter : public Emitter
{
SPK_IMPLEMENT_REGISTERABLE(StaticEmitter)
public :
/**
* @brief Creates and registers a new StaticEmitter
* @return A new registered StaticEmitter
*/
static inline StaticEmitter* create();
private :
virtual inline void generateVelocity(Particle& particle,float speed) const;
};
inline StaticEmitter* StaticEmitter::create()
{
StaticEmitter* obj = new StaticEmitter;
registerObject(obj);
return obj;
}
inline void StaticEmitter::generateVelocity(Particle& particle,float speed) const
{
particle.velocity().set(0.0f,0.0f,0.0f); // no initial velocity
}
}
#endif

View File

@ -0,0 +1,126 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_STRAIGHEMITTER
#define H_SPK_STRAIGHEMITTER
#include "Core/SPK_Emitter.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
/**
* @class StraightEmitter
* @brief An Emitter that emits in a given direction
*/
class SPK_PREFIX StraightEmitter : public Emitter
{
SPK_IMPLEMENT_REGISTERABLE(StraightEmitter)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief The constructor of StraightEmitter
* @param direction : the direction of the StraighEmitter
*/
StraightEmitter(const Vector3D& direction = Vector3D(0.0f,0.0f,-1.0f));
/**
* @brief Creates and registers a new StraightEmitter
* @param direction : the direction of the StraighEmitter
* @since 1.04.00
*/
static inline StraightEmitter* create(const Vector3D& direction = Vector3D(0.0f,0.0f,-1.0f));
/////////////
// Setters //
/////////////
/**
* @brief Sets the direction of this StraightEmitter
*
* Note that it is not necessary to provide a normalized Vector3D.
* This Vector3D only indicates a direction, its norm does not matter.
*
* @param direction : the direction of this StraightEmitter
*/
void setDirection(const Vector3D& direction);
/////////////
// Getters //
/////////////
/**
* @brief Gets the direction of this StraightEmitter
* @return the direction of this StraightEmitter
*/
inline const Vector3D& getDirection() const;
/**
* @brief Gets the transformed direction of this StraightEmitter
* @return the transformed direction of this StraightEmitter
*/
inline const Vector3D& getTransformedDirection() const;
protected :
virtual void innerUpdateTransform();
private :
Vector3D direction;
Vector3D tDirection;
virtual inline void generateVelocity(Particle& particle,float speed) const;
};
inline StraightEmitter* StraightEmitter::create(const Vector3D& direction)
{
StraightEmitter* obj = new StraightEmitter(direction);
registerObject(obj);
return obj;
}
inline const Vector3D& StraightEmitter::getDirection() const
{
return direction;
}
inline const Vector3D& StraightEmitter::getTransformedDirection() const
{
return tDirection;
}
inline void StraightEmitter::generateVelocity(Particle& particle,float speed) const
{
particle.velocity() = tDirection;
particle.velocity() *= speed;
}
}
#endif

View File

@ -0,0 +1,165 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_COLLISION
#define H_SPK_COLLISION
#include "Core/SPK_Modifier.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
/**
* @class Collision
* @brief A Modifier that perfoms particle against particle collisions in the Group
*
* The collision between particles uses the size of the particle to determine its radius.<br>
* The radius of a particle is computed as follows :
* <i>radius = size * scale * 0.5f</i><br>
* <br>
* Moreover the mass ratio of two particles colliding is used to get realistic collision.<br>
* <br>
* The collision can be set as being elastic or inelastic. This is determined thanks to the elasticity of this modifier :
* <ul>
* <li>An elasticity of 1.0f means the collision is fully elastic</li>
* <li>An elasticity of 0.0f means the collision is fully inelastic</li>
* <li>An elasticity superior to 1.0f means the collision creates energy. It is physically not possible but can however be set</li>
* <li>An elasticity inferior to 0.0f has no sens and cannot be set</li>
* <li>To simulate collisions the elasticity will generally be set between ]0.0f,1.0f[ depending on the material of the particle</li>
* </ul>
* Note that collision particle vs particles requires intensive processing.
* Moreover the algorithm has a complexity that badly scales which means processing times increase fastly as particles count increase.<br>
* Tries to limitate the number of particles to perform collision on. More than 1000 particles can require a lot of processing time even of recent hardware.<br>
* <br>
* The accuracy of the collisions is better with small update steps.
* Therefore try to keep the update time small by for instance multiplying the number of updates per frame.
*
* @since 1.04.00
*/
class SPK_PREFIX Collision : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(Collision)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of the Collision modifier
* @param scale : the scale of the particles
* @param elasticity : the elasticity of the collisions
*/
Collision(float scale = 1.0f,float elasticity = 1.0f);
/**
* @brief Creates and registers a new Collision
* @param scale : the scale of the particles
* @param elasticity : the elasticity of the collisions
* @since 1.04.00
*/
static inline Collision* create(float scale = 1.0f,float elasticity = 1.0f);
/////////////
// Setters //
/////////////
/**
* @brief Sets the scale of particles to compute their radius
*
* The radius of a particle is computed as follows :<br>
* <i>radius = size * scale * 0.5f</i><br>
*
* @param scale : the scale of the particles
*/
inline void setScale(float scale);
/**
* @brief Sets the elasticity of the collisions
*
* The elasticity of the collisions refers to the coefficient of restitution (also called bounciness).<br>
* See the class description for more information.
*
* @param elasticity : the elasticity of the collisions
*/
inline void setElasticity(float elasticity);
/////////////
// Getters //
/////////////
/**
* @brief Gets the elasticity of the collisions
* @return the elasticity of the collisions
*/
inline float getElasticity() const;
/**
* @brief Gets the scale applied on particle radius
* @return the scale
*/
inline float getScale() const;
private :
float elasticity;
float scale;
virtual void modify(Particle& particle,float deltaTime) const;
static inline void getMinMax(const Vector3D& v0,const Vector3D& v1,Vector3D& min,Vector3D& max);
static inline bool checkBoundingRect(const Vector3D& min1,const Vector3D& max1,const Vector3D& min2,const Vector3D& max2);
};
inline Collision* Collision::create(float scale,float elasticity)
{
Collision* obj = new Collision(scale,elasticity);
registerObject(obj);
return obj;
}
inline void Collision::setElasticity(float elasticity)
{
if (elasticity >= 0.0f)
this->elasticity = elasticity;
}
inline void Collision::setScale(float scale)
{
this->scale = scale;
}
inline float Collision::getElasticity() const
{
return elasticity;
}
inline float Collision::getScale() const
{
return scale;
}
}
#endif

View File

@ -0,0 +1,76 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_DESTROYER
#define H_SPK_DESTROYER
#include "Core/SPK_Modifier.h"
namespace SPK
{
/**
* @class Destroyer
* @brief A Modifier that destroy particles
*/
class SPK_PREFIX Destroyer : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(Destroyer)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of Destroyer
* @param zone : the Zone of the Destroyer
* @param trigger : the trigger of the Destroyer
*/
Destroyer(Zone* zone = NULL,ModifierTrigger trigger = INSIDE_ZONE);
/**
* @brief Creates and registers a new Destroyer
* @param zone : the Zone of the Destroyer
* @param trigger : the trigger of the Destroyer
* @return A new registered Destroyer
* @since 1.04.00
*/
static inline Destroyer* create(Zone* zone = NULL,ModifierTrigger trigger = INSIDE_ZONE);
private :
virtual void modify(Particle& particle,float deltaTime) const;
virtual void modifyWrongSide(Particle& particle,bool inside) const;
};
inline Destroyer* Destroyer::create(Zone* zone,ModifierTrigger trigger)
{
Destroyer* obj = new Destroyer(zone,trigger);
registerObject(obj);
return obj;
}
}
#endif

View File

@ -0,0 +1,209 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_LINEARFORCE
#define H_SPK_LINEARFORCE
#include "Core/SPK_Modifier.h"
#include "Core/SPK_Model.h"
namespace SPK
{
/**
* @enum ForceFactor
* @brief An enum defining the way a factor is applied to a force
* @since 1.03.00
*/
enum ForceFactor
{
FACTOR_NONE, /**< No factor is applied */
FACTOR_LINEAR, /**< A linear factor is applied */
FACTOR_SQUARE, /**< A square factor is applied */
};
/**
* @class LinearForce
* @brief A Modifier applying a linear force on particles
*
* The force is identical from any points of the universe (only if the modifier is triggered).<br>
* In that way, particles under the influence of a LinearForce can theorically reach an infinite speed if not
* under the influence of a friction.<br>
* <br>
* The force can be multiplied or not by a particle parameter either linearly or squared.
* <br>
* Note that this Modifier can be used to set a global gravity that can be updated for all groups at a time.<br>
* To do so, the LinearForce has to be used with the param : <i>PARAM_MASS</i> and the FactorType <i>FACTOR_LINEAR</i>.
*
* @since 1.03.00
*/
class SPK_PREFIX LinearForce : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(LinearForce)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Default constructor for LinearForce
* @param zone : the Zone of the LinearForce or NULL if no Zone
* @param trigger : the trigger of the LinearForce
* @param force : the force of the LinearForce
* @param type : the type of multiplier for the factor
* @param param : the parameter used as the factor (if type != FACTOR_NONE)
*/
LinearForce(Zone* zone = NULL,
ModifierTrigger trigger = INSIDE_ZONE,
const Vector3D& force = Vector3D(),
ForceFactor type = FACTOR_NONE,
ModelParam param = PARAM_SIZE);
/**
* @brief Creates and registers a new LinearForce
* @param zone : the Zone of the LinearForce or NULL if no Zone
* @param trigger : the trigger of the LinearForce
* @param force : the force of the LinearForce
* @param type : the type of multiplier for the factor
* @param param : the parameter used as the factor (if type != FACTOR_NONE)
* @return A new registered LinearForce
* @since 1.04.00
*/
static inline LinearForce* create(Zone* zone = NULL,
ModifierTrigger trigger = INSIDE_ZONE,
const Vector3D& force = Vector3D(),
ForceFactor type = FACTOR_NONE,
ModelParam param = PARAM_SIZE);
/////////////
// Setters //
/////////////
/**
* @brief Sets the force vector
* @param force : the force vector
* @since 1.03.02
*/
inline void setForce(const Vector3D& force);
/**
* @brief Sets the factor type to apply to the force
* @param type : the type of multiplier for the factor
* @param param : the parameter of the Particle to use as the factor
*/
inline void setFactor(ForceFactor type,ModelParam param = PARAM_SIZE);
/////////////
// Getters //
/////////////
/**
* @brief Gets the force vector
* @return the force vector
* @since 1.03.02
*/
inline const Vector3D& getForce() const;
/**
* @brief Gets the transformed force vector
* @return the transformed force vector
* @since 1.03.02
*/
inline const Vector3D& getTransformedForce() const;
/**
* @brief Gets the factor multiplier of this LinearForce
* @return the factor multiplier of this LinearForce
*/
inline ForceFactor getFactorType() const;
/**
* @brief Gets the factor parameter of this LinearForce
* @return the factor parameter of this LinearForce
*/
inline ModelParam getFactorParam() const;
protected :
virtual inline void innerUpdateTransform();
private :
Vector3D force;
Vector3D tForce;
ForceFactor factorType;
ModelParam factorParam;
virtual void modify(Particle& particle,float deltaTime) const;
};
inline LinearForce* LinearForce::create(Zone* zone,ModifierTrigger trigger,const Vector3D& force,ForceFactor type,ModelParam param)
{
LinearForce* obj = new LinearForce(zone,trigger,force,type,param);
registerObject(obj);
return obj;
}
inline void LinearForce::setForce(const Vector3D& force)
{
this->force = tForce = force;
notifyForUpdate();
}
inline void LinearForce::setFactor(ForceFactor type,ModelParam param)
{
factorType = type;
factorParam = param;
}
inline const Vector3D& LinearForce::getForce() const
{
return force;
}
inline const Vector3D& LinearForce::getTransformedForce() const
{
return tForce;
}
inline ForceFactor LinearForce::getFactorType() const
{
return factorType;
}
inline ModelParam LinearForce::getFactorParam() const
{
return factorParam;
}
inline void LinearForce::innerUpdateTransform()
{
Modifier::innerUpdateTransform();
transformDir(tForce,force);
}
}
#endif

View File

@ -0,0 +1,287 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_MODIFIERGROUP
#define H_SPK_MODIFIERGROUP
#include "Core/SPK_Modifier.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
/**
* @class ModifierGroup
* @brief A Group of Modifiers
*
* This modifier can be used in 2 ways :
* <ul>
* <li>Partition group : to partition the universe and make a global light test before testing inner modifiers more precisely.</li>
* <li>Global group : To activate several modifiers with a single trigger.</li>
* </ul>
* By default a ModifierGroup is used as a partition group. the user can change it by calling useGlobalGroup(bool,bool) or usePartitionGroup(bool).
*
* @since 1.02.00
*/
class SPK_PREFIX ModifierGroup : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(ModifierGroup)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of ModifierGroup
* @param zone : the Zone of this ModifierGroup
* @param trigger : the trigger of the ModifierGroup
*/
ModifierGroup(Zone* zone = NULL,ModifierTrigger trigger = INSIDE_ZONE);
/**
* @brief Creates and registers a new ModifierGroup
* @param zone : the Zone of this ModifierGroup
* @param trigger : the trigger of the ModifierGroup
* @return A new registered ModifierGroup
* @since 1.04.00
*/
static inline ModifierGroup* create(Zone* zone = NULL,ModifierTrigger trigger = INSIDE_ZONE);
/////////////
// Setters //
/////////////
/**
* @brief Uses this ModifierGroup as a global group
*
* A global group allows to use only one trigger for many modifiers. It works as follow :<ul>
* <li>If the trigger of the partition group is activated, then the all children modifiers are activated no matter their Zone.</li>
* <li>The same happens for the wrong side.</li>
* </ul>
* Note that if a child Modifier needs intersection or normal computation (the Modifier Obstacle for instance), the variables have to be set.
*
* @param useIntersection : true to enable intersection computation in this ModifierGroup
* @param useNormal : true to enable normal computation in this ModifierGroup
*/
inline void useGlobalGroup(bool useIntersection = false,bool useNormal = false);
/**
* @brief Uses this ModifierGroup as a partition group
*
* A partition group allows to partition the space in order to have faster tests. It works as follow :<ul>
* <li>If the trigger of the partition group is activated, then modifiers within are tested to check if they are triggered.</li>
* <li>If yes, the Modifier is activated, if no, nothing happens.</li>
* <li>If handleWrongSize if set, the isWrongSide() method of the partition group calls the isWrongSide() of its children if it has to.</li>
* </ul>
*
* @param handleWrongSide : true to enable intersection computation in this ModifierGroup
*/
inline void usePartitionGroup(bool handleWrongSide = false);
/////////////
// Getters //
/////////////
/**
* @brief Gets the number of modifiers in this ModifierGroup
* @return the number of modifiers in this ModifierGroup
*/
inline size_t getNb() const;
/**
* @brief Gets the vector containing all the children modifiers
* @return the vector containing all the children modifiers
*/
inline const std::vector<Modifier*>& getModifiers() const;
/**
* @brief Tells whether this ModifierGroup is a global group
*
* For more information about global groups, see useGlobalGroup(bool,bool).
*
* @return true if this ModifierGroup is a global group, false if not
*/
inline bool isGlobalGroup() const;
/**
* @brief Tells whether this ModifierGroup is a partition group
*
* For more information about partition groups, see usePartitionGroup(bool).
*
* @return true if this ModifierGroup is a partition group, false if not
*/
inline bool isPartitionGroup() const;
/**
* @brief Tells whether this partition group handles wrong side
*
* If this ModifierGroup is a global group, the return value is not used.<br>
* For more information about partition groups, see usePartitionGroup(bool).<br>
* <br>
* Note that the wrong side can only be used with the following triggers :<ul>
* <li>ModifierTrigger::INSIDE_ZONE</li>
* <li>ModifierTrigger::OUTSIDE_ZONE</li>
* <li>ModifierTrigger::ENTER_ZONE</li>
* <li>ModifierTrigger::EXIT_ZONE</li>
* </ul>
*
* @return true if this ModifierGroup handles wrong size, false if not
*/
inline bool handlesWrongSide() const;
/**
* @brief Tells whether this global group computes the intersection
*
* If this ModifierGroup is a partition group, the return value is not used.<br>
* For more information about global groups, see useGlobalGroup(bool,bool).<br>
* <br>
* Note that the intersection can only be used with the following triggers :<ul>
* <li>ModifierTrigger::INTERSECT_ZONE</li>
* <li>ModifierTrigger::ENTER_ZONE</li>
* <li>ModifierTrigger::EXIT_ZONE</li>
* </ul>
*
* @return true if this ModifierGroup computes the intersection, false if not
*/
inline bool usesIntersection() const;
/**
* @brief Tells whether this global group computes the normal
*
* If this ModifierGroup is a partition group, the return value is not used.<br>
* For more information about global groups, see useGlobalGroup(bool,bool).<br>
* <br>
* Note that the normal can only be used with the following triggers :<ul>
* <li>ModifierTrigger::INTERSECT_ZONE</li>
* <li>ModifierTrigger::ENTER_ZONE</li>
* <li>ModifierTrigger::EXIT_ZONE</li>
* </ul>
*
* @return true if this ModifierGroup computes the normal, false if not
*/
inline bool usesNormal() const;
///////////////
// Interface //
///////////////
/**
* @brief Adds a Modifier to this ModifierGroup
* @param modifier : the Modifier to add to this ModifierGroup
*/
void addModifier(Modifier* modifier);
/**
* @brief Removes a Modifier from this ModifierGroup
* @param modifier : the Modifier to remove from this ModifierGroup
* @return true if the Modifier has been found and removed, false if not
*/
bool removeModifier(const Modifier* modifier);
/**
* @brief Removes all Modifier children from this ModifierGroup
*/
inline void clear();
virtual void createBuffers(const Group& group);
virtual void destroyBuffers(const Group& group);
virtual Registerable* findByName(const std::string& name);
protected :
virtual void registerChildren(bool registerAll);
virtual void copyChildren(const ModifierGroup& modifier,bool createBase);
virtual void destroyChildren(bool keepChildren);
virtual bool checkBuffers(const Group& group);
private :
std::vector<Modifier*> modifiers;
bool globalZone;
bool handleWrongSide;
virtual void modify(Particle& particle,float deltaTime) const;
virtual void modifyWrongSide(Particle& particle,bool inside) const;
};
inline ModifierGroup* ModifierGroup::create(Zone* zone,ModifierTrigger trigger)
{
ModifierGroup* obj = new ModifierGroup(zone,trigger);
registerObject(obj);
return obj;
}
inline void ModifierGroup::useGlobalGroup(bool useIntersection,bool useNormal)
{
globalZone = true;
needsIntersection = useIntersection;
needsNormal = useNormal;
}
inline void ModifierGroup::usePartitionGroup(bool handleWrongSide)
{
globalZone = false;
this->handleWrongSide = handleWrongSide;
}
inline size_t ModifierGroup::getNb() const
{
return modifiers.size();
}
inline const std::vector<Modifier*>& ModifierGroup::getModifiers() const
{
return modifiers;
}
inline bool ModifierGroup::isGlobalGroup() const
{
return globalZone;
}
inline bool ModifierGroup::isPartitionGroup() const
{
return !globalZone;
}
inline bool ModifierGroup::handlesWrongSide() const
{
return handleWrongSide;
}
inline bool ModifierGroup::usesIntersection() const
{
return needsIntersection;
}
inline bool ModifierGroup::usesNormal() const
{
return needsNormal;
}
}
#endif

View File

@ -0,0 +1,148 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_OBSTACLE
#define H_SPK_OBSTACLE
#include "Core/SPK_Modifier.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
/**
* @class Obstacle
* @brief A Modifier that acts as an obstacle on particles
*/
class SPK_PREFIX Obstacle : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(Obstacle)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of Obstacle
* @param zone : the Zone of the Obstacle
* @param trigger : the trigger of the Destructor
* @param bouncingRatio : the bouncingRatio of the Obstacle
* @param friction : the friction of the Obstacle
*/
Obstacle(Zone* zone = NULL,ModifierTrigger trigger = INTERSECT_ZONE,float bouncingRatio = 1.0f,float friction = 1.0f);
/**
* @brief Creates and registers a new Obstacle
* @param zone : the Zone of the Obstacle
* @param trigger : the trigger of the Destructor
* @param bouncingRatio : the bouncingRatio of the Obstacle
* @param friction : the friction of the Obstacle
* @return A new registered Obstacle
* @since 1.04.00
*/
static inline Obstacle* create(Zone* zone = NULL,ModifierTrigger trigger = INTERSECT_ZONE,float bouncingRatio = 1.0f,float friction = 1.0f);
/////////////
// Setters //
/////////////
/**
* @brief Sets the bouncing ratio of this Obstacle
*
* The bouncing ratio is the multiplier applied to the normal component of the rebound.
*
* @param bouncingRatio : the bouncing ratio of this Obstacle
*/
inline void setBouncingRatio(float bouncingRatio);
/**
* @brief Sets the friction of this Obstacle
*
* The bouncing ratio is the multiplier applied to the tangent component of the rebound.
*
* @param friction : the friction of this Obstacle
*/
inline void setFriction(float friction);
/////////////
// Getters //
/////////////
/**
* @brief Gets the bouncing ratio of this Obstacle
* @return the bouncing ratio of this Obstacle
*/
inline float getBouncingRatio() const;
/**
* @brief Gets the friction of this Obstacle
* @return the friction of this Obstacle
*/
inline float getFriction() const;
private :
float bouncingRatio;
float friction;
virtual void modify(Particle& particle,float deltaTime) const;
virtual inline void modifyWrongSide(Particle& particle,bool inside) const;
};
inline Obstacle* Obstacle::create(Zone* zone,ModifierTrigger trigger,float bouncingRatio,float friction)
{
Obstacle* obj = new Obstacle(zone,trigger,bouncingRatio,friction);
registerObject(obj);
return obj;
}
inline void Obstacle::setBouncingRatio(float bouncingRatio)
{
this->bouncingRatio = bouncingRatio < 0.0f ? 0.0f : bouncingRatio;
}
inline void Obstacle::setFriction(float friction)
{
this->friction = friction;
}
inline float Obstacle::getBouncingRatio() const
{
return bouncingRatio;
}
inline float Obstacle::getFriction() const
{
return friction;
}
inline void Obstacle::modifyWrongSide(Particle& particle,bool inside) const
{
if (isFullZone())
getZone()->moveAtBorder(particle.position(),inside);
}
}
#endif

View File

@ -0,0 +1,199 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_POINTMASS
#define H_SPK_POINTMASS
#include "Core/SPK_Modifier.h"
namespace SPK
{
/**
* @class PointMass
* @brief A Modifier defining a point with a mass that attracts or repulses particles
*
* A PointMass triggered on a Particle will affect its velocity as followed :<br>
* <i>dist = pointMassPosition - particlePosition<br>
* particleVelocity += dist * mass * step / max(minDistance,|dist|)</i>
*/
class SPK_PREFIX PointMass : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(PointMass)
public :
////////////////
// Construtor //
////////////////
/**
* @brief Constructor of PointMass
* @param zone : the Zone of the PointMass
* @param trigger : the trigger of the PointMass
* @param mass : the mass of the PointMass
* @param minDistance : the minimum distance of the PointMass
*/
PointMass(Zone* zone = NULL,ModifierTrigger trigger = INSIDE_ZONE,float mass = 1.0f,float minDistance = 0.05f);
/**
* @brief Creates and registers a new PointMass
* @param zone : the Zone of the PointMass
* @param trigger : the trigger of the PointMass
* @param mass : the mass of the PointMass
* @param minDistance : the minimum distance of the PointMass
* @return A new registered PointMass
* @since 1.04.00
*/
static inline PointMass* create(Zone* zone = NULL,ModifierTrigger trigger = INSIDE_ZONE,float mass = 1.0f,float minDistance = 0.05f);
/////////////
// Setters //
/////////////
/**
* @brief Sets the delta position from the position of the zone (or origin if no zone set)
* @param pos : the delta position
* @since 1.03.02
*/
inline void setPosition(const Vector3D& pos);
/**
* @brief Sets the mass of this PointMass
*
* The mass defines the strenght of the attraction. The more the mass, the stronger the attraction.<br>
* A position mass will result into an attraction while a negative mass will result into a repulsion.
* Moreover a mass equal to 0 make the PointMass have no effect.
*
* @param mass : the mass of this PointMass
*/
inline void setMass(float mass);
/**
* @brief Sets the minimum distance of this PointMass
*
* The minimum distance of the PointMass is the minimum distance that can be considered to compute the force implied by the PointMass.
* If a distance between a Particle and a PointMass is inferior to the minimum distance of the PointMass, the distance is clamped to the minimum distance.<br>
* This avoids forces that approaching the infinity with Particle getting very close to the PointMass.
*
* @param minDistance : the minimum distance of this PointMass
*/
inline void setMinDistance(float minDistance);
/////////////
// Getters //
/////////////
/**
* @brief Gets the delta position
* @return the delta position
* @since 1.03.02
*/
inline const Vector3D& getPosition() const;
/**
* @brief Gets the transformed delta position
* @return the transformed delta position
* @since 1.03.02
*/
inline const Vector3D& getTransformedPosition() const;
/**
* @brief Gets the mass of this PointMass
* @return the mass of this PointMass
*/
inline float getMass() const;
/**
* @brief Gets the minimum distance of this PointMass
* @return the minimum distance of this PointMass
*/
inline float getMinDistance() const;
protected :
virtual inline void innerUpdateTransform();
private :
Vector3D position;
Vector3D tPosition;
float mass;
float minDistance;
float sqrMinDistance;
virtual void modify(Particle& particle,float deltaTime) const;
};
inline PointMass* PointMass::create(Zone* zone,ModifierTrigger trigger,float mass,float minDistance)
{
PointMass* obj = new PointMass(zone,trigger,mass,minDistance);
registerObject(obj);
return obj;
}
inline void PointMass::setPosition(const Vector3D& pos)
{
position = tPosition = pos;
notifyForUpdate();
}
inline void PointMass::setMass(float mass)
{
this->mass = mass;
}
inline void PointMass::setMinDistance(float minDistance)
{
this->minDistance = minDistance;
sqrMinDistance = minDistance * minDistance;
}
inline const Vector3D& PointMass::getPosition() const
{
return position;
}
inline const Vector3D& PointMass::getTransformedPosition() const
{
return tPosition;
}
inline float PointMass::getMass() const
{
return mass;
}
inline float PointMass::getMinDistance() const
{
return minDistance;
}
inline void PointMass::innerUpdateTransform()
{
Modifier::innerUpdateTransform();
transformDir(tPosition,position); // the delta position is actually a direction not a position
}
}
#endif

View File

@ -0,0 +1,84 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_ROTATOR
#define H_SPK_ROTATOR
#include "Core/SPK_Modifier.h"
namespace SPK
{
/**
* @class Rotator
* @brief A Modifier allowing to rotate particle with their rotation speed
*
* Instead of controlling directly the particle angle, this modifier allows to control the particle rotation speed.<br>
* The rotator derives the particle angle from the particle rotation speed.<br>
* <br>
* For this modifier to work, the PARAM_ANGLE must be enabled (and can be random in addition but not mutable or interpolated)
* and the PARAM_ROTATION_SPEED must be at least enabled in the model of the group of particles that are modified.
*
* @since 1.05.00
*/
class Rotator : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(Rotator)
public :
/////////////////
// Constructor //
/////////////////
/** @brief Constructor of Rotator */
inline Rotator();
/**
* @brief Creates and registers a new Rotator
* @return A new registered Rotator
*/
static inline Rotator* create();
private :
virtual inline void modify(Particle& particle,float deltaTime) const;
};
inline Rotator::Rotator() : Modifier(ALWAYS | INSIDE_ZONE | OUTSIDE_ZONE) {}
inline Rotator* Rotator::create()
{
Rotator* obj = new Rotator;
registerObject(obj);
return obj;
}
inline void Rotator::modify(Particle& particle,float deltaTime) const
{
float angle = particle.getParamCurrentValue(PARAM_ANGLE) + deltaTime * particle.getParamCurrentValue(PARAM_ROTATION_SPEED);
particle.setParamCurrentValue(PARAM_ANGLE,angle);
}
}
#endif

View File

@ -0,0 +1,338 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_VORTEX
#define H_SPK_VORTEX
#include "Core/SPK_Modifier.h"
namespace SPK
{
/**
* @brief A modifier defining a vortex in the universe
*
* A vortex is a spinning flow around a center. Its center (its eye) is defined as a line in the universe.<br>
* In addition to its center line, a vortex is defined by 2 speeds :
* <ul>
* <li>the rotation speed which defines the speed of rotation around the vortex eye.</li>
* <li>the attraction speed which defined the speeds at which a particle is attracted by the eye (or repeled).</li>
* </ul>
* The rotation speed can be defined either in units per second or in radians per seconds. In the first case,
* the closer to the eye particles are, the faster they will spin around. In the second case, the speed is constant.<br>
* <br>
* The attraction speed can be either constant or linear (function of the distance to the eye). In the second case,
* the farther particles are from the eye, the faster the are attracted (or repeled). First case can be assimilated
* to a Archimedes' spiral while second is more a logarithmic spiral (Bernoulli's).
* <br>
* The vertex eye radius can be defined. The user has also the possibility to tell the vortex to destroy particles
* that enter its eye automatically.<br>
* <br>
* Note that this modifier does not update particle's velocity. Therefore particles modified by a vortex does not have any inertia.<br>
* This is because defining an accurate vortex in a discrete environment cannot be performed by using the derivatives of the position and velocity.
*
* @since 1.05.00
*/
class SPK_PREFIX Vortex : public Modifier
{
SPK_IMPLEMENT_REGISTERABLE(Vortex)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of vortex
* @param position : the position of the eye
* @param direction : the direction of the eye
* @param rotationSpeed : the speed of rotation
* @param attractionSpeed : the speed of attraction
*/
Vortex(const Vector3D& position = Vector3D(),const Vector3D& direction = Vector3D(0.0f,1.0f,0.0f),float rotationSpeed = 1.0f,float attractionSpeed = 0.0f);
/**
* @brief Creates and registers a new Vortex
* @param position : the position of the eye
* @param direction : the direction of the eye
* @param rotationSpeed : the speed of rotation
* @param attractionSpeed : the speed of attraction
* @return a new registered vortex
*/
static inline Vortex* create(const Vector3D& position = Vector3D(),const Vector3D& direction = Vector3D(0.0f,1.0f,0.0f),float rotationSpeed = 1.0f,float attractionSpeed = 0.0f);
/////////////
// Setters //
/////////////
/**
* @brief Sets the position of the eye of the vortex
*
* The eye of the vortex is an infinite line defined by a position and a direction.
*
* @param position : the position of the eye of the vortex
*/
inline void setPosition(const Vector3D& position);
/**
* @brief Sets the direction of the eye of the vortex
*
* The eye of the vortex is an infinite line defined by a position and a direction.<br>
* Note that the direction is normalized internally.
*
* @param direction : the direction of the eye of the vortex
*/
inline void setDirection(const Vector3D& direction);
/**
* @brief Sets the rotation speed of the vortex
*
* The rotation speed can either be in units per second or in radians per second (angular).<br>
* In the case the rotation speed is angular, all particles are rotated around the eye at the same speed.<br>
* In the other case, the more particles are close to the eye, the faster they rotate.<br>
* <br>
* The sens of rotation is defined by the sens of the speed (and depends also on whether we are in a right or left handed system).<br>
* A speed of 0 means no rotation.
*
* @param rotationSpeed : the speed of rotation (either in units per unit of time or in radians per unit of time dependent on the second parameter)
* @param angular : true to have the rotation in radians per unit of time, false to have it in unit per unit of time.
*/
inline void setRotationSpeed(float rotationSpeed,bool angular);
/**
* @brief Sets the attraction speed of the vortex
*
* The attraction speed is the speed that move particles towards the eye of the vortex.<br>
* It can either be constant or linear (function of the distance of the particle from the eye).<br>
* <br>
* A constant attraction speed is defined in units per unit of time,
* a linear attraction speed is also defined in units per unit of time and the value is the speed at a distance of 1.0f from the eye.<br>
* <br>
* A negative speed means particles are repelled by the eye.<br>
* A speed of 0.0f means particles are neither attracted nor repelled by the eye of the vortex.
*
* @param attractionSpeed : the attraction speed of the vortex in units per unit of time
* @param linear : true to set the speed function of the distance from the eye, false to set it constant
*/
inline void setAttractionSpeed(float attractionSpeed,bool linear);
/**
* @brief Sets the eye radius
*
* Note that an negative radius is inverted internally
*
* @param eyeRadius : the eye radius
*/
inline void setEyeRadius(float eyeRadius);
/**
* @brief Tells whether particles is the eye must be killed or not
* @param kill : true to kill particles in the eye, false not to
*/
inline void enableParticleKilling(bool kill);
/////////////
// Getters //
/////////////
/**
* @brief Gets the position of the eye
* @return the position of the eye
*/
inline const Vector3D& getPosition() const;
/**
* @brief Gets the direction of the eye
* @return the direction of the eye (normalized)
*/
inline const Vector3D& getDirection() const;
/**
* @brief Gets the transformed position of the eye
* @return the transformed position of the eye
*/
inline const Vector3D& getTransformedPosition() const;
/**
* @brief Gets the transformed direction of the eye
* @return the transformed direction of the eye (normalized)
*/
inline const Vector3D& getTransformedDirection() const;
/**
* @brief Gets the rotation speed
* @return the rotation speed
*/
inline float getRotationSpeed() const;
/**
* @brief Gets the attraction speed
* @return the attraction speed
*/
inline float getAttractionSpeed() const;
/**
* @brief Tells whether rotation speed is angular
* @return true if rotation speed is angular, false if not
*/
inline bool isRotationSpeedAngular() const;
/**
* @brief Tells whether attraction speed is function of the distance from the eye
* @return true if attraction speed is linear, false if it is constant
*/
inline bool isAttractionSpeedLinear() const;
/**
* @brief Returns the eye radius
* @return the eye radius
*/
inline float getEyeRadius() const;
/**
* @brief Tells whether particles are killed when in the eye
* @return true if particles are killed in the eye, false if not
*/
inline bool isParticleKillingEnabled() const;
protected :
virtual void innerUpdateTransform();
private :
Vector3D position;
Vector3D direction;
Vector3D tPosition;
Vector3D tDirection;
float rotationSpeed;
float attractionSpeed;
bool angularSpeedEnabled;
bool linearSpeedEnabled;
float eyeRadius;
bool killingParticleEnabled;
virtual void modify(Particle& particle,float deltaTime) const;
};
inline Vortex* Vortex::create(const Vector3D& position,const Vector3D& direction,float rotationSpeed,float attractionSpeed)
{
Vortex* obj = new Vortex(position,direction,rotationSpeed,attractionSpeed);
registerObject(obj);
return obj;
}
inline void Vortex::setPosition(const Vector3D& position)
{
this->position = position;
tPosition = this->position;
notifyForUpdate();
}
inline void Vortex::setDirection(const Vector3D& direction)
{
this->direction = direction;
this->direction.normalize();
tDirection = this->direction;
notifyForUpdate();
}
inline void Vortex::setRotationSpeed(float rotationSpeed,bool angular)
{
this->rotationSpeed = rotationSpeed;
angularSpeedEnabled = angular;
}
inline void Vortex::setAttractionSpeed(float attractionSpeed,bool linear)
{
this->attractionSpeed = attractionSpeed;
linearSpeedEnabled = linear;
}
inline void Vortex::setEyeRadius(float eyeRadius)
{
if (eyeRadius < 0.0f) eyeRadius = -eyeRadius;
this->eyeRadius = eyeRadius;
}
inline void Vortex::enableParticleKilling(bool kill)
{
killingParticleEnabled = kill;
}
inline const Vector3D& Vortex::getPosition() const
{
return position;
}
inline const Vector3D& Vortex::getDirection() const
{
return direction;
}
inline const Vector3D& Vortex::getTransformedPosition() const
{
return tPosition;
}
inline const Vector3D& Vortex::getTransformedDirection() const
{
return tDirection;
}
inline float Vortex::getRotationSpeed() const
{
return rotationSpeed;
}
inline float Vortex::getAttractionSpeed() const
{
return attractionSpeed;
}
inline bool Vortex::isRotationSpeedAngular() const
{
return angularSpeedEnabled;
}
inline bool Vortex::isAttractionSpeedLinear() const
{
return linearSpeedEnabled;
}
inline float Vortex::getEyeRadius() const
{
return eyeRadius;
}
inline bool Vortex::isParticleKillingEnabled() const
{
return killingParticleEnabled;
}
}
#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_LINERENDERERINTERFACE
#define H_SPK_LINERENDERERINTERFACE
#include "Core/SPK_DEF.h"
namespace SPK
{
/**
* @brief Base Interface for rendering particles with lines
* @since 1.04.00
*/
class LineRendererInterface
{
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of LineRendererInterface
* @param length : the length multiplier of this LineRendererInterface
* @param width : the width of this GLLineRenderer
*/
inline LineRendererInterface(float length = 1.0f,float width = 1.0f);
////////////////
// Destructor //
////////////////
/** @brief Destructor of LineRendererInterface */
virtual inline ~LineRendererInterface() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets the length multiplier of this LineRendererInterface
*
* The length multiplier is the value which will be multiplied by the Particle velocity to get the line length in the universe.<br>
* A positive length means the line will be drawn in advance to the Particle, as opposed to a negative length.
*
* @param length : the length multiplier of this GLLineRenderer
*/
inline void setLength(float length);
/**
* @brief Sets the width of this LineRendererInterface
* @param width : the width of this LineRendererInterface
*/
virtual inline void setWidth(float width);
/////////////
// Getters //
/////////////
/**
* @brief Gets the length multiplier of this LineRendererInterface
* @return the length multiplier of this LineRendererInterface
*/
inline float getLength() const;
/**
* @brief Gets the width of this LineRendererInterface
* @return the width of this LineRendererInterface
*/
inline float getWidth() const;
protected :
float length;
float width;
};
inline LineRendererInterface::LineRendererInterface(float length,float width) :
length(length),
width(width)
{}
inline void LineRendererInterface::setLength(float length)
{
this->length = length;
}
inline void LineRendererInterface::setWidth(float width)
{
this->width = width;
}
inline float LineRendererInterface::getLength() const
{
return length;
}
inline float LineRendererInterface::getWidth() const
{
return width;
}
}
#endif

View File

@ -0,0 +1,216 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_ORIENTED2DRENDERERINTERFACE
#define H_SPK_ORIENTED2DRENDERERINTERFACE
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Group.h"
namespace SPK
{
/**
* @brief Defines the orientation of a particle oriented in 2D
* @since 1.04.00
*/
enum Orientation2D
{
ORIENTATION2D_UP, /**< Oriented towards the camera plane */
ORIENTATION2D_DIRECTION, /**< Oriented towards the direction of the particle */
ORIENTATION2D_POINT, /**< Oriented towards a point in the universe */
ORIENTATION2D_AXIS /**< The orientation vector is defined by an axis */
};
/**
* @brief Base Interface for rendering particles that can be oriented in a 2D world
* @since 1.04.00
*/
class Oriented2DRendererInterface
{
public :
///////////////
// Parameter //
///////////////
/**
* @brief The orientation vector
*
* It is used in 2 orientation modes :
* <ul>
* <li>ORIENTATION2D_AXIS : The orientation vector is used as the axis</li>
* <li>ORIENTATION2D_POINT : The orientation vector is the point particle look to</li>
* </ul>
* In other modes the orientation vector is not used
*/
Vector3D orientationVector;
//////////////////
// Constructors //
//////////////////
/** @brief Constructor of Oriented2DRendererInterface */
inline Oriented2DRendererInterface();
////////////////
// Destructor //
////////////////
/** @brief Destructor of Oriented2DRendererInterface */
virtual inline ~Oriented2DRendererInterface() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets the way quads are oriented in the universe
* @param orientation : the orientation of the quad
*/
inline void setOrientation(Orientation2D orientation);
/////////////
// Getters //
/////////////
/**
* @brief Gets the orientation of the quads
* @return the orientation of the quads
*/
inline Orientation2D getOrientation() const;
protected :
Orientation2D orientation;
inline bool hasGlobalOrientation();
inline void computeGlobalOrientation2D();
inline void computeSingleOrientation2D(const Particle& particle);
inline void scaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const;
inline void rotateAndScaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const;
inline const Vector3D& quadUp() const;
inline const Vector3D& quadSide() const;
private :
// Used to store the orientation of quads before scaling
mutable Vector3D up;
mutable Vector3D side;
// This is where are stored quad orientation info after computation
mutable Vector3D sideQuad;
mutable Vector3D upQuad;
};
inline Oriented2DRendererInterface::Oriented2DRendererInterface() :
orientation(ORIENTATION2D_UP)
{
orientationVector.set(0.0f,-1.0f);
}
inline void Oriented2DRendererInterface::setOrientation(Orientation2D orientation)
{
this->orientation = orientation;
}
inline Orientation2D Oriented2DRendererInterface::getOrientation() const
{
return orientation;
}
inline const Vector3D& Oriented2DRendererInterface::quadUp() const
{
return upQuad;
}
inline const Vector3D& Oriented2DRendererInterface::quadSide() const
{
return sideQuad;
}
inline bool Oriented2DRendererInterface::hasGlobalOrientation()
{
return ((orientation == ORIENTATION2D_UP)||(ORIENTATION2D_AXIS));
}
inline void Oriented2DRendererInterface::computeGlobalOrientation2D()
{
if (orientation == ORIENTATION2D_UP)
up.set(0.0f,-0.5f);
else if (orientation == ORIENTATION2D_AXIS)
{
up.set(orientationVector.x,orientationVector.y);
up.normalize();
up *= 0.5f;
}
}
inline void Oriented2DRendererInterface::computeSingleOrientation2D(const Particle& particle)
{
if (orientation == ORIENTATION2D_DIRECTION)
up = particle.velocity();
else if (orientation == ORIENTATION2D_POINT)
{
up = orientationVector;
up -= particle.position();
}
up.z = 0.0f;
up.normalize();
up *= 0.5f;
}
inline void Oriented2DRendererInterface::scaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const
{
float size = particle.getParamCurrentValue(PARAM_SIZE);
upQuad.set(up.x,up.y);
upQuad *= size * scaleY;
sideQuad.set(-up.y,up.x);
sideQuad *= size * scaleX;
}
inline void Oriented2DRendererInterface::rotateAndScaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const
{
float size = particle.getParamCurrentValue(PARAM_SIZE);
float angleTexture = particle.getParamCurrentValue(PARAM_ANGLE);
float cosA = cos(angleTexture);
float sinA = sin(angleTexture);
upQuad.x = cosA * up.x + sinA * up.y;
upQuad.y = -sinA * up.x + cosA * up.y;
upQuad.z = 0.0f;
sideQuad.set(-upQuad.y,upQuad.x);
sideQuad *= size * scaleX;
upQuad *= size * scaleY;
}
}
#endif

View File

@ -0,0 +1,387 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_ORIENTED3DRENDERERINTERFACE
#define H_SPK_ORIENTED3DRENDERERINTERFACE
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Group.h"
// Packs the orientations parameters into one int for orientation presets
#define PACK_ORIENTATION(lock,look,up) ((lock << 0x10)|(look << 0x8)|(up))
namespace SPK
{
/**
* @brief Defines the orientation of the vector Look of an oriented 3D particle
*
* Enumerators marked as (fast) are the ones that only needs to be computed once for
* a set of particles instead of being computed for each particles.
*
* @since 1.04.00
*/
enum LookOrientation
{
LOOK_CAMERA_PLANE, /**< Look towards the camera plane (fast) */
LOOK_CAMERA_POINT, /**< Look towards the camera point (better effect but more expensive) */
LOOK_AXIS, /**< The look vector is defined by an axis (fast) */
LOOK_POINT, /**< Look towards a point in the universe */
};
/**
* @brief Defines the orientation of the vector Up of an oriented 3D particle
*
* Enumerators marked as (fast) are the ones that only needs to be computed once for
* a set of particles instead of being computed for each particles.
*
* @since 1.04.00
*/
enum UpOrientation
{
UP_CAMERA, /**< The up vector is defined by the up vector of the camera (fast) */
UP_DIRECTION, /**< The up vector is oriented towards the direction of the particle */
UP_AXIS, /**< The up vector is is defined by an axis (fast) */
UP_POINT, /**< The up vector is oriented towards a point */
};
/**
* @brief Defines which axis is locked and will not change when computing a cross product.
*
* Note that the side vector cannot be locked as it is always derived from the look and up vectors.
*
* @since 1.04.00
*/
enum LockedAxis
{
LOCK_LOOK, /**< The look vector is locked */
LOCK_UP, /**< The up vector is locked */
};
/**
* @brief Orientation presets to easily set up common orientations
* @since 1.04.00
*/
enum OrientationPreset
{
CAMERA_PLANE_ALIGNED = PACK_ORIENTATION(LOCK_LOOK,LOOK_CAMERA_PLANE,UP_CAMERA), /**< Particles are oriented towards the camera plane (the most common) */
CAMERA_POINT_ALIGNED = PACK_ORIENTATION(LOCK_LOOK,LOOK_CAMERA_POINT,UP_CAMERA), /**< Particles are oriented towards the camera point (better effect but more expensive) */
DIRECTION_ALIGNED = PACK_ORIENTATION(LOCK_UP,LOOK_CAMERA_PLANE,UP_DIRECTION), /**< Particles are oriented function of their direction and try to look to the camera */
AROUND_AXIS = PACK_ORIENTATION(LOCK_UP,LOOK_CAMERA_POINT,LOOK_AXIS), /**< Particles can only rotate around an axis and try to look to the camera */
TOWARDS_POINT = PACK_ORIENTATION(LOCK_LOOK,LOOK_POINT,UP_CAMERA), /**< Particles are oriented towards a point in the universe */
FIXED_ORIENTATION = PACK_ORIENTATION(LOCK_LOOK,LOOK_AXIS,UP_AXIS), /**< Particles have a fixed orientation in the universe */
};
/**
* @brief Base Interface for rendering particles that can be oriented in a 3D world
* @since 1.04.00
*/
class SPK_PREFIX Oriented3DRendererInterface
{
public :
///////////////
// Parameter //
///////////////
/**
* @brief The look vector
*
* It is used in 2 LookOrientation modes :
* <ul>
* <li>LOOK_AXIS : The look vector is used as the axis</li>
* <li>LOOK_POINT : The look vector is the point quads look to</li>
* </ul>
* In other modes the look vector is not used
*/
Vector3D lookVector;
/**
* @brief The up vector
*
* It is used in 2 UpOrientation modes :
* <ul>
* <li>UP_AXIS : The up axis is used as the axis</li>
* <li>UP_POINT : The up axis is the point quads will be oriented towards</li>
* </ul>
* In other modes the up vector is not used
*/
Vector3D upVector;
//////////////////
// Constructors //
//////////////////
/** @brief Constructor of Oriented3DRendererInterface */
Oriented3DRendererInterface();
////////////////
// Destructor //
////////////////
/** @brief Destructor of Oriented3DRendererInterface */
virtual inline ~Oriented3DRendererInterface() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets the way quads are oriented in the universe
*
* This method allows to accuratly configure the orientation of quads.<br>
* Another method with only one parameters that take presets exist.<br>
* See setOrientation(OrientationPreset)
*
* @param lookOrientation : The way the look vector of the quad is set
* @param upOrientation : The way the up vector of the quad is set
* @param lockedAxis : tells which axis prevails over the other
*/
void setOrientation(LookOrientation lookOrientation,UpOrientation upOrientation,LockedAxis lockedAxis);
/**
* @brief Sets the way quads are oriented in the universe
*
* This method takes some presets to orientate the quads.<br>
* Another method that has more options to configure orientation exists<br>
* See setOrientation(LookOrientation,UpOrientation,LockedAxis)
*
* @param orientation : the orientation preset of the quad
*/
void setOrientation(OrientationPreset orientation);
/////////////
// Getters //
/////////////
/**
* @brief Gets the look orientation of the quads
* @return the look orientation of the quads
*/
inline LookOrientation getLookOrientation() const;
/**
* @brief Gets the up orientation of the quads
* @return the up orientation of the quads
*/
inline UpOrientation getUpOrientation() const;
/**
* @brief Gets the locked axis (the one prevailing over the others)
* @return the locked axis
*/
inline LockedAxis getLockedAxis() const;
protected :
// Orientation
LookOrientation lookOrientation;
UpOrientation upOrientation;
LockedAxis lockedAxis;
inline bool precomputeOrientation3D(const Group& group,const Vector3D& look,const Vector3D& up,const Vector3D& pos);
inline void computeGlobalOrientation3D();
inline void computeSingleOrientation3D(const Particle& particle);
inline void scaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const;
inline void rotateAndScaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const;
inline const Vector3D& quadUp() const;
inline const Vector3D& quadSide() const;
private :
// Used to store modelview information
mutable Vector3D mVLook;
mutable Vector3D mVUp;
mutable Vector3D mVPos;
// Used to store precomputed orientation
mutable Vector3D globalLook;
mutable Vector3D globalUp;
// Used to store the orientation of quads before scaling
mutable Vector3D up;
mutable Vector3D side;
mutable Vector3D look;
// Is using rotation
mutable int quadRotated;
// This is where are stored quad orientation info after computation
mutable Vector3D sideQuad;
mutable Vector3D upQuad;
};
inline LookOrientation Oriented3DRendererInterface::getLookOrientation() const
{
return lookOrientation;
}
inline UpOrientation Oriented3DRendererInterface::getUpOrientation() const
{
return upOrientation;
}
inline LockedAxis Oriented3DRendererInterface::getLockedAxis() const
{
return lockedAxis;
}
inline const Vector3D& Oriented3DRendererInterface::quadUp() const
{
return upQuad;
}
inline const Vector3D& Oriented3DRendererInterface::quadSide() const
{
return sideQuad;
}
inline bool Oriented3DRendererInterface::precomputeOrientation3D(const Group& group,const Vector3D& modelViewLook,const Vector3D& modelViewUp,const Vector3D& modelViewPos)
{
mVLook = modelViewLook;
mVUp = modelViewUp;
mVPos = modelViewPos;
bool globalOrientation = true;
if (lookOrientation == LOOK_CAMERA_PLANE)
globalLook = -mVLook;
else if (lookOrientation == LOOK_AXIS)
globalLook = lookVector;
else
globalOrientation = false;
if (upOrientation == UP_CAMERA)
globalUp = mVUp;
else if (upOrientation == UP_AXIS)
globalUp = upVector;
else globalOrientation = false;
quadRotated = group.getModel()->isEnabled(PARAM_ANGLE);
return globalOrientation;
}
inline void Oriented3DRendererInterface::computeGlobalOrientation3D()
{
look = globalLook;
up = globalUp;
crossProduct(up,look,side);
if (lockedAxis == LOCK_LOOK)
crossProduct(look,side,up);
else if (quadRotated)
{
crossProduct(side,up,look);
look.normalize();
}
up.normalize();
up *= 0.5f;
side.normalize();
side *= 0.5f;
}
inline void Oriented3DRendererInterface::computeSingleOrientation3D(const Particle& particle)
{
if (lookOrientation == LOOK_CAMERA_POINT)
{
look = mVPos;
look -= particle.position();
}
else if (lookOrientation == LOOK_POINT)
{
look = lookVector;
look -= particle.position();
}
else
look = globalLook;
if (upOrientation == UP_DIRECTION)
up = particle.velocity();
else if (upOrientation == UP_POINT)
{
up = upVector;
up -= particle.position();
}
else
up = globalUp;
crossProduct(up,look,side);
if (lockedAxis == LOCK_LOOK)
crossProduct(look,side,up);
else if (quadRotated)
{
crossProduct(side,up,look);
look.normalize();
}
side.normalize();
side *= 0.5f;
up.normalize();
up *= 0.5f;
}
inline void Oriented3DRendererInterface::scaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const
{
float size = particle.getParamCurrentValue(PARAM_SIZE);
sideQuad = side;
sideQuad *= size * scaleX;
upQuad = up;
upQuad *= size * scaleY;
}
inline void Oriented3DRendererInterface::rotateAndScaleQuadVectors(const Particle& particle,float scaleX,float scaleY) const
{
float size = particle.getParamCurrentValue(PARAM_SIZE);
float angleTexture = particle.getParamCurrentValue(PARAM_ANGLE);
float cosA = cos(angleTexture);
float sinA = sin(angleTexture);
upQuad.x = (look.x * look.x + (1.0f - look.x * look.x) * cosA) * up.x
+ (look.x * look.y * (1.0f - cosA) - look.z * sinA) * up.y
+ (look.x * look.z * (1.0f - cosA) + look.y * sinA) * up.z;
upQuad.y = (look.x * look.y * (1.0f - cosA) + look.z * sinA) * up.x
+ (look.y * look.y + (1.0f - look.y * look.y) * cosA) * up.y
+ (look.y * look.z * (1.0f - cosA) - look.x * sinA) * up.z;
upQuad.z = (look.x * look.z * (1.0f - cosA) - look.y * sinA) * up.x
+ (look.y * look.z * (1.0f - cosA) + look.x * sinA) * up.y
+ (look.z * look.z + (1.0f - look.z * look.z) * cosA) * up.z;
crossProduct(upQuad,look,sideQuad);
sideQuad *= size * scaleX;
upQuad *= size * scaleY;
}
}
#endif

View File

@ -0,0 +1,137 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_POINTRENDERERINTERFACE
#define H_SPK_POINTRENDERERINTERFACE
#include "Core/SPK_DEF.h"
namespace SPK
{
/**
* @enum PointType
* @brief Constants defining the type of points to render
*/
enum PointType
{
POINT_SQUARE, /**< Points are renderered as squares */
POINT_CIRCLE, /**< Points are renderered as circles */
POINT_SPRITE, /**< Points are renderered as point sprites (textured points) */
};
/**
* @brief Base Interface for rendering particles with points
* @since 1.04.00
*/
class PointRendererInterface
{
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of PointRendererInterface
* @param type : the initial type of this PointRendererInterface (must be supported by default by the platform)
* @param size : the width of this PointRendererInterface
*/
inline PointRendererInterface(PointType type = POINT_SQUARE,float size = 1.0f);
////////////////
// Destructor //
////////////////
/** @brief Destructor of PointRendererInterface */
virtual inline ~PointRendererInterface() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets the type of points to use in this PointRendererInterface
*
* If the type is not supported by the platform, false is returned and the type per default is set.
*
* @param type : the type of points to use in this PointRendererInterface
* @return true if the type can be set, false otherwise
*/
virtual inline bool setType(PointType type);
/**
* @brief Sets the size of the points in this PointRendererInterface
* @param size : the size of the points in this PointRendererInterface
*/
virtual inline void setSize(float size);
/////////////
// Getters //
/////////////
/**
* @brief Gets the type of points in this PointRendererInterface
* @return the type of points in this PointRendererInterface
*/
inline PointType getType() const;
/**
* @brief Gets the size of points in this PointRendererInterface
* @return the size of points in this PointRendererInterface
*/
inline float getSize() const;
protected :
PointType type;
float size;
};
inline PointRendererInterface::PointRendererInterface(PointType type,float size) :
type(type),
size(size)
{}
inline bool PointRendererInterface::setType(PointType type)
{
this->type = type;
return true;
}
inline void PointRendererInterface::setSize(float size)
{
this->size = size;
}
inline PointType PointRendererInterface::getType() const
{
return type;
}
inline float PointRendererInterface::getSize() const
{
return size;
}
}
#endif

View File

@ -0,0 +1,265 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_QUADRENDERERINTERFACE
#define H_SPK_QUADRENDERERINTERFACE
#include "Core/SPK_DEF.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
/**
* @enum TexturingMode
* @brief Constants defining the way to apply texture over the particles
* @since 1.02.00
*/
enum TexturingMode
{
TEXTURE_NONE, /**< Constant telling no texturing is used */
TEXTURE_2D, /**< Constant telling a 2D texture is used */
TEXTURE_3D, /**< Constant telling a 3D texture is used */
};
/**
* @brief Base Interface for rendering particles with quads
* @since 1.04.00
*/
class SPK_PREFIX QuadRendererInterface
{
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of QuadRendererInterface
* @param scaleX the scale of the width of the quad
* @param scaleY the scale of the height of the quad
*/
QuadRendererInterface(float scaleX = 1.0f,float scaleY = 1.0f);
////////////////
// Destructor //
////////////////
/** @brief Destructor of QuadRendererInterface */
virtual inline ~QuadRendererInterface() {}
/////////////
// Setters //
/////////////
/**
* @brief Sets the texturing mode for this GLQuadRenderer
*
* The texturing mode defines whether or not to apply a texture
* and if so which type of texture to apply (2D,3D or atlas).<br>
* <br>
* Note that the validity of the texturing mode depends on the rendering API below.<br>
* The method returns true if the rendering mode can be set, false if it cannot
*
* @param mode : the texturing mode of this GLQuadRenderer
* @return true if the rendering mode can be set, false if it cannot
*/
virtual inline bool setTexturingMode(TexturingMode mode);
/**
* @brief Sets the cut of the texture
*
* This is available only if SPK::PARAM_TEXTURE_INDEX is enabled and texturing mode is TEXTURE_2D.<br>
* <br>
* Particles can be rendered only with a part of the texture depending on their texture index value.<br>
* The cut can only be constant.<br>
* The user defines in how many parts the texture must be divided in X and Y.<br>
* The first index is located at the top left cut, the it goes from left to right and from top to bottom.<br>
* <br>
* For instance a cut with nbX = 3 and nbY = 2 will be as followed :
* <br><i>
* -------------<br>
* | 0 | 1 | 2 |<br>
* -------------<br>
* | 3 | 4 | 5 |<br>
* -------------</i><br>
* <br>
* By default nbX and nbY are equal to 1.<br>
*
* @param nbX : the number of cuts in the X axis
* @param nbY : the number of cuts in the Y axis
*/
void setAtlasDimensions(size_t nbX,size_t nbY);
/**
* @brief Sets the size ratio of this GLQuadRenderer
*
* These values defines how quads are scaled.
* The height and width of a quad in the universe is defined as followed :
* <ul>
* <li><i>width = size * ratioX</i>
* <li><i>height = size * ratioY</i>
* </ul>
*
* @param scaleX : the scale of the width of the quad
* @param scaleY : the scale of the height of the quad
*/
inline void setScale(float scaleX,float scaleY);
/////////////
// Getters //
/////////////
/**
* @brief Gets the texturing mode of this GLQuadRenderer
* @return the texturing mode of this GLQuadRenderer
*/
inline TexturingMode getTexturingMode() const;
/**
* @brief Gets the atlas dimension on the X axis
*
* See setAtlasDimensions(size_t,size_t) for more information
*
* @return the atlas dimension on the X axis
*/
inline size_t getAtlasDimensionX() const;
/**
* @brief Gets the atlas dimension on the Y axis
*
* See setAtlasDimensions(size_t,size_t) for more information
*
* @return the atlas dimension on the Y axis
*/
inline size_t getAtlasDimensionY() const;
/**
* @brief Gets the scale of the width of this GLQuadRenderer
* @return the scale of the width of this GLQuadRenderer
*/
inline float getScaleX() const;
/**
* @brief Gets the scale of the height of this GLQuadRenderer
* @return the scale of the height of this GLQuadRenderer
*/
inline float getScaleY() const;
protected :
TexturingMode texturingMode;
float scaleX;
float scaleY;
// texture atlas info
size_t textureAtlasNbX;
size_t textureAtlasNbY;
float textureAtlasW;
float textureAtlasH;
inline void computeAtlasCoordinates(const Particle& particle) const;
inline float textureAtlasU0() const;
inline float textureAtlasU1() const;
inline float textureAtlasV0() const;
inline float textureAtlasV1() const;
private :
// this is where textureAtlas are stored after computation
mutable float atlasU0;
mutable float atlasU1;
mutable float atlasV0;
mutable float atlasV1;
};
inline bool QuadRendererInterface::setTexturingMode(TexturingMode mode)
{
texturingMode = mode;
return true;
}
inline void QuadRendererInterface::setScale(float scaleX,float scaleY)
{
this->scaleX = scaleX;
this->scaleY = scaleY;
}
inline TexturingMode QuadRendererInterface::getTexturingMode() const
{
return texturingMode;
}
inline size_t QuadRendererInterface::getAtlasDimensionX() const
{
return textureAtlasNbX;
}
inline size_t QuadRendererInterface::getAtlasDimensionY() const
{
return textureAtlasNbY;
}
inline float QuadRendererInterface::getScaleX() const
{
return scaleX;
}
inline float QuadRendererInterface::getScaleY() const
{
return scaleY;
}
inline float QuadRendererInterface::textureAtlasU0() const
{
return atlasU0;
}
inline float QuadRendererInterface::textureAtlasU1() const
{
return atlasU1;
}
inline float QuadRendererInterface::textureAtlasV0() const
{
return atlasV0;
}
inline float QuadRendererInterface::textureAtlasV1() const
{
return atlasV1;
}
inline void QuadRendererInterface::computeAtlasCoordinates(const Particle& particle) const
{
int textureIndex = static_cast<int>(particle.getParamCurrentValue(PARAM_TEXTURE_INDEX));
atlasU0 = atlasU1 = static_cast<float>(textureIndex % textureAtlasNbX) / textureAtlasNbX;
atlasV0 = atlasV1 = static_cast<float>(textureIndex / textureAtlasNbY) / textureAtlasNbY;
atlasU1 += textureAtlasW;
atlasV1 += textureAtlasH;
}
}
#endif

View File

@ -0,0 +1,154 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_AABOX
#define H_SPK_AABOX
#include "Core/SPK_Zone.h"
namespace SPK
{
/**
* @class AABox
* @brief A Zone defining an axis-aligned Box
*
* An AABox is defined by its center and a dimension in each axis.
*/
class SPK_PREFIX AABox : public Zone
{
SPK_IMPLEMENT_REGISTERABLE(AABox)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of AABox
* @param position : the position of the AABox
* @param dimension : the dimension of the AABox
*/
AABox(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),const Vector3D& dimension = Vector3D(0.0f,0.0f,0.0f));
/**
* @brief Creates and registers a new AABox
* @param position : the position of the AABox
* @param dimension : the dimension of the AABox
* @since 1.04.00
*/
static inline AABox* create(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),const Vector3D& dimension = Vector3D(0.0f,0.0f,0.0f));
////////////
// Setter //
////////////
/**
* @brief Sets the dimensions of this AABox
*
* The negative dimensions are clamped to 0.<br>
* An AABox with 0 as its 3 dimensions is equivalent to a Point
*
* @param dimension : the dimensions of this AABox
*/
void setDimension(const Vector3D& dimension);
////////////
// Getter //
////////////
/**
* @brief Gets the dimensions of this AABox
* @return the dimensions of this AABox
*/
inline const Vector3D& getDimension() const;
///////////////
// Interface //
///////////////
virtual void generatePosition(Particle& particle,bool full) const;
virtual bool contains(const Vector3D& v) const;
virtual bool intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const;
virtual void moveAtBorder(Vector3D& v,bool inside) const;
virtual Vector3D computeNormal(const Vector3D& point) const;
private :
Vector3D dimension;
inline bool slabIntersects(float p0,float p1,float bMin,float bMax,float& tEnter,float& tExit,int& firstAxis,int axis) const;
};
inline AABox* AABox::create(const Vector3D& position,const Vector3D& dimension)
{
AABox* obj = new AABox(position,dimension);
registerObject(obj);
return obj;
}
inline const Vector3D& AABox::getDimension() const
{
return dimension;
}
inline bool AABox::slabIntersects(float p0,float p1,float bMin,float bMax,float& tEnter,float& tExit,int& firstAxis,int axis) const
{
float dir = p1 - p0;
if (dir == 0.0f)
{
if ((p0 < bMin)||(p0 > bMax))
return false;
return true;
}
float t0 = (bMin - p0) / dir;
float t1 = (bMax - p0) / dir;
if (t0 > t1)
{
std::swap(t0,t1);
axis += 3;
}
if ((t1 < tEnter)||(t0 > tExit))
return false;
if (t0 > tEnter)
{
tEnter = t0;
firstAxis = (firstAxis & 0xF0) | (axis & 0x0F);
}
if (t1 < tExit)
{
tExit = t1;
firstAxis = (firstAxis & 0x0F) | ((axis << 4) & 0xF0);
}
return true;
}
}
#endif

View File

@ -0,0 +1,176 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_LINE
#define H_SPK_LINE
#include "Core/SPK_Zone.h"
namespace SPK
{
/**
* @class Line
* @brief A Zone defining a line in the universe
*
* As any Zone, a Line is defined by a position. The Line in itself is defined by two bounds.<br>
* Moving the position results in moving the 2 bounds in the universe by the same vector.<br>
* <br>
* To conform with the Zone class (the position is defined as the center of the Zone), the position is always set to
* be the center of the line. Therefore, if a bound is modified, the position will be modified as well.
*
* @since 1.01.00
*/
class SPK_PREFIX Line : public Zone
{
SPK_IMPLEMENT_REGISTERABLE(Line)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of Line
* @param p0 : the first bound of this Line
* @param p1 : the second bound of this Line
*/
Line(const Vector3D& p0 = Vector3D(0.0f,0.0f,0.0f),const Vector3D& p1 = Vector3D(0.0f,0.0f,0.0f));
/**
* @brief Creates and registers a new Line
* @param p0 : the first bound of this Line
* @param p1 : the second bound of this Line
* @since 1.04.00
*/
static inline Line* create(const Vector3D& p0 = Vector3D(0.0f,0.0f,0.0f),const Vector3D& p1 = Vector3D(0.0f,0.0f,0.0f));
/////////////
// Setters //
/////////////
void setPosition(const Vector3D& v);
/**
* @brief Sets the bounds of this Line
* @param p0 : the first bound of this Line
* @param p1 : the second bound of this Line
*/
void setBounds(const Vector3D& p0,const Vector3D& p1);
/////////////
// Getters //
/////////////
/**
* @brief Gets the bound of index of this Line
* @param index : the index of the bound (0 or 1)
* @return the first bound of index of this Line
* @since 1.03.00
*/
inline const Vector3D& getBound(size_t index) const;
/**
* @brief Gets the transformed bound of index of this Line
* @param index : the index of the bound (0 or 1)
* @return the transformed bound of index of this Line
* @since 1.03.00
*/
inline const Vector3D& getTransformedBound(size_t index) const;
///////////////
// Interface //
///////////////
/**
* @brief Pushes a new bound to this Line
*
* This method replaces the first bound by the second bound and the second bound by the new bound.<br>
* It allows to follow the trajectory of a moving object over time with a single Line.
*
* @param bound : the new bound of this Line
*/
void pushBound(const Vector3D& bound);
virtual void generatePosition(Particle& particle,bool full) const;
virtual inline bool contains(const Vector3D& v) const;
virtual inline bool intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const;
virtual inline void moveAtBorder(Vector3D& v,bool inside) const;
virtual Vector3D computeNormal(const Vector3D& point) const;
protected :
virtual void innerUpdateTransform();
private :
Vector3D bounds[2];
Vector3D tBounds[2];
Vector3D tDist;
inline void computeDist();
inline void computePosition();
};
inline Line* Line::create(const Vector3D& p0,const Vector3D& p1)
{
Line* obj = new Line(p0,p1);
registerObject(obj);
return obj;
}
inline const Vector3D& Line::getBound(size_t index) const
{
return bounds[index];
}
inline const Vector3D& Line::getTransformedBound(size_t index) const
{
return tBounds[index];
}
inline bool Line::contains(const Vector3D& v) const
{
return false;
}
inline bool Line::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
return false;
}
inline void Line::moveAtBorder(Vector3D& v,bool inside) const {}
inline void Line::computeDist()
{
tDist = tBounds[1] - tBounds[0];
}
inline void Line::computePosition()
{
Zone::setPosition((bounds[0] + bounds[1]) * 0.5f);
}
}
#endif

View File

@ -0,0 +1,163 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_PLANE
#define H_SPK_PLANE
#include "Core/SPK_Zone.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
/**
* @class Plane
* @brief A Zone defining a plane in the universe
*
* A Plane is defined by 2 parameters :
* <ul>
* <li>A Position is the universe</li>
* <li>A Normal</li>
* </ul>
* The defined Plane is the Plane having the normal and passing by the position.<br>
* The direction of the normal defines the sens of the plane. The normal goes from inside the Plane to outside.<br>
* <br>
* Note that the normal does not have to be normalized as it is normalized internally when set.
*/
class SPK_PREFIX Plane : public Zone
{
SPK_IMPLEMENT_REGISTERABLE(Plane)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of Plane
* @param position : the position of the Plane
* @param normal : the normal of the Plane
*/
Plane(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),const Vector3D& normal = Vector3D(0.0f,1.0f,0.0f));
/**
* @brief Creates and registers a new Plane
* @param position : the position of the Plane
* @param normal : the normal of the Plane
* @return a new registered plane
* @since 1.04.00
*/
static inline Plane* create(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),const Vector3D& normal = Vector3D(0.0f,1.0f,0.0f));
/////////////
// Setters //
/////////////
/**
* @brief Sets the normal of this Plane
*
* Note that the normal is normalized internally.
*
* @param normal : the normal of this Plane
*/
inline void setNormal(const Vector3D& normal);
/////////////
// Getters //
/////////////
/**
* @brief Gets the normal of this Plane
* @return the normal of this Plane
*/
inline const Vector3D& getNormal() const;
/**
* @brief Gets the transformed normal of this Plane
* @return the transformed normal of this Plane
* @since 1.05.00
*/
inline const Vector3D& getTransformedNormal() const;
///////////////
// Interface //
///////////////
virtual inline void generatePosition(Particle& particle,bool full) const;
virtual inline bool contains(const Vector3D& v) const;
virtual bool intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const;
virtual void moveAtBorder(Vector3D& v,bool inside) const;
virtual inline Vector3D computeNormal(const Vector3D& point) const;
protected :
virtual void innerUpdateTransform();
private :
Vector3D normal;
Vector3D tNormal;
};
inline Plane* Plane::create(const Vector3D& position,const Vector3D& normal)
{
Plane* obj = new Plane(position,normal);
registerObject(obj);
return obj;
}
inline void Plane::setNormal(const Vector3D& normal)
{
this->normal = normal;
this->normal.normalize();
tNormal = this->normal;
notifyForUpdate();
}
inline const Vector3D& Plane::getNormal() const
{
return normal;
}
inline const Vector3D& Plane::getTransformedNormal() const
{
return tNormal;
}
inline void Plane::generatePosition(Particle& particle,bool full) const
{
particle.position() = getTransformedPosition();
}
inline bool Plane::contains(const Vector3D& v) const
{
return dotProduct(normal,v - getTransformedPosition()) <= 0.0f;
}
inline Vector3D Plane::computeNormal(const Vector3D& point) const
{
return tNormal;
}
}
#endif

View File

@ -0,0 +1,93 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_POINT
#define H_SPK_POINT
#include "Core/SPK_Zone.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
/**
* @class Point
* @brief A Zone defining a point in the universe
*/
class SPK_PREFIX Point : public Zone
{
SPK_IMPLEMENT_REGISTERABLE(Point)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of Point
* @param position : the position of the Point
*/
Point(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f));
/**
* @brief Creates and registers a new Point
* @param position : the position of the Point
* @return A new registered Point
* @since 1.04.00
*/
static inline Point* create(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f));
// Interface
virtual inline void generatePosition(Particle& particle,bool full) const;
virtual inline bool contains(const Vector3D& v) const;
virtual inline bool intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const;
virtual inline void moveAtBorder(Vector3D& v,bool inside) const;
virtual Vector3D computeNormal(const Vector3D& point) const;
};
inline Point* Point::create(const Vector3D& position)
{
Point* obj = new Point(position);
registerObject(obj);
return obj;
}
inline void Point::generatePosition(Particle& particle,bool full) const
{
particle.position() = getTransformedPosition();
}
inline bool Point::contains(const Vector3D& v) const
{
return false;
}
inline bool Point::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
return false;
}
inline void Point::moveAtBorder(Vector3D& v,bool inside) const {}
}
#endif

View File

@ -0,0 +1,198 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_RING
#define H_SPK_RING
#include "Core/SPK_Zone.h"
namespace SPK
{
/**
* @brief A ZOne defining a flat ring in the universe
*
* A ring is defined by :
* <ul>
* <li>The position of its center</li>
* <li>The normal of the plane on which it lies</li>
* <li>A minimum and maximum radius</li>
* </ul>
* Note that by having the minimum radius equal to 0, the ring becomes a disk in the universe.<br>
* Note that the normal does not have to be normalized as it is normalized internally when set.
*
* @since 1.05.00
*/
class SPK_PREFIX Ring : public Zone
{
SPK_IMPLEMENT_REGISTERABLE(Ring)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of ring
* @param position : the position of the ring
* @param normal : the normal of the plane on which lies the ring
* @param minRadius : the minimum radius of the ring
* @param maxRadius : the maximum radius of the ring
*/
Ring(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),const Vector3D& normal = Vector3D(0.0f,1.0f,0.0f),float minRadius = 0.0f,float maxRadius = 1.0f);
/**
* @brief Creates and registers a new Ring
* @param position : the position of the ring
* @param normal : the normal of the plane on which lies the ring
* @param minRadius : the minimum radius of the ring
* @param maxRadius : the maximum radius of the ring
* @return a new registered ring
*/
static inline Ring* create(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),const Vector3D& normal = Vector3D(0.0f,1.0f,0.0f),float minRadius = 0.0f,float maxRadius = 1.0f);
/////////////
// Setters //
/////////////
/**
* @brief Sets the normal of the plane on which lies this ring
*
* Note that the normal is normalized internally
*
* @param normal : the normal of the plane on which lies the ring
*/
inline void setNormal(const Vector3D& normal);
/**
* @brief Sets the min and max radius of this ring
*
* A radius cannot be negative.<br>
* Note that negative radius are inverted internally
*
* @param minRadius : the minimum radius of this ring
* @param maxRadius : the maximum radius of this ring
*/
void setRadius(float minRadius,float maxRadius);
/////////////
// Getters //
/////////////
/**
* @brief Gets the normal of this ring
* @return the normal of this ring
*/
inline const Vector3D& getNormal() const;
/**
* @brief Gets the transformed normal of this ring
* @return the transformed normal of this ring
*/
inline const Vector3D& getTransformedNormal() const;
/**
* @brief Gets the minimum radius of this ring
* @return the minimum radius of this ring
*/
inline float getMinRadius() const;
/**
* @brief Gets the maximum radius of this ring
* @return the maximum radius of this ring
*/
inline float getMaxRadius() const;
///////////////
// Interface //
///////////////
virtual void generatePosition(Particle& particle,bool full) const;
virtual inline bool contains(const Vector3D& v) const;
virtual bool intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const;
virtual void moveAtBorder(Vector3D& v,bool inside) const;
virtual inline Vector3D computeNormal(const Vector3D& point) const;
protected :
virtual void innerUpdateTransform();
private :
Vector3D normal;
Vector3D tNormal;
float minRadius;
float maxRadius;
// Square of the radius (for optimization purpose)
float sqrMinRadius;
float sqrMaxRadius;
};
inline Ring* Ring::create(const Vector3D& position,const Vector3D& normal,float minRadius,float maxRadius)
{
Ring* obj = new Ring(position,normal,minRadius,maxRadius);
registerObject(obj);
return obj;
}
inline void Ring::setNormal(const Vector3D& normal)
{
this->normal = normal;
this->normal.normalize();
tNormal = this->normal;
notifyForUpdate();
}
inline const Vector3D& Ring::getNormal() const
{
return normal;
}
inline const Vector3D& Ring::getTransformedNormal() const
{
return tNormal;
}
inline float Ring::getMinRadius() const
{
return minRadius;
}
inline float Ring::getMaxRadius() const
{
return maxRadius;
}
inline bool Ring::contains(const Vector3D& v) const
{
return false;
}
inline Vector3D Ring::computeNormal(const Vector3D& point) const
{
return tNormal;
}
}
#endif

View File

@ -0,0 +1,117 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_SPHERE
#define H_SPK_SPHERE
#include "Core/SPK_Zone.h"
namespace SPK
{
/**
* @class Sphere
* @brief A Zone defining a sphere in the universe
*/
class SPK_PREFIX Sphere : public Zone
{
SPK_IMPLEMENT_REGISTERABLE(Sphere)
public :
/////////////////
// Constructor //
/////////////////
/**
* @brief Constructor of Sphere
* @param position : position of the center of the Sphere
* @param radius : radius of the Sphere
*/
Sphere(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),float radius = 0.0f);
/**
* @brief Creates and registers a new Sphere
* @param position : position of the center of the Sphere
* @param radius : radius of the Sphere
* @return A new registered Sphere
* @since 1.04.00
*/
static inline Sphere* create(const Vector3D& position = Vector3D(0.0f,0.0f,0.0f),float radius = 0.0f);
////////////
// Setter //
////////////
/**
* @brief Sets the radius of this Sphere
*
* A negative radius will be clamped to 0.0f and the Sphere will therefore acts as a Point.
*
* @param radius : the radius of this Sphere
*/
inline void setRadius(float radius);
////////////
// Getter //
////////////
/**
* @brief Gets the radius of this Sphere
* @return the radius of this Sphere
*/
inline float getRadius() const;
///////////////
// Interface //
///////////////
virtual void generatePosition(Particle& particle,bool full) const;
virtual bool contains(const Vector3D& v) const;
virtual bool intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const;
virtual void moveAtBorder(Vector3D& v,bool inside) const;
virtual Vector3D computeNormal(const Vector3D& point) const;
private :
float radius;
};
inline Sphere* Sphere::create(const Vector3D& position,float radius)
{
Sphere* obj = new Sphere(position,radius);
registerObject(obj);
return obj;
}
inline void Sphere::setRadius(float radius)
{
this->radius = radius >= 0.0f ? radius : 0.0f;
}
inline float Sphere::getRadius() const
{
return radius;
}
}
#endif

View File

@ -0,0 +1,381 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GLEXTHANDLER
#define H_SPK_GLEXTHANDLER
#include "Core/SPK_DEF.h"
#include "RenderingAPIs/OpenGL/SPK_GL_DEF.h"
// OpenGL defines (from glext.h)
#define GL_POINT_SPRITE 0x8861
#define GL_COORD_REPLACE 0x8862
#define GL_POINT_DISTANCE_ATTENUATION 0x8129
#define GL_POINT_SIZE_MIN 0x8126
#define GL_POINT_SIZE_MAX 0x8127
#define GL_TEXTURE_3D 0x806F
namespace SPK
{
namespace GL
{
/**
* @class GLExtHandler
* @brief A class to handle OpenGL extensions
*
* This class presents an interface to handle openGL extensions.<br>
* The interface is static an has a public and a protected side.<br>
* <br>
* A class willing to make use of the openGL extensions must derive from this class to access the protected interface.<br>
* <br>
* If an OpenGL extension is not handle by this class,
* the proper way to implement it within SPARK will be to derive this class to implement it.
* Then the Renderer which will use the extension has to extends the child class.
* <br>
* The opengl extensions implemented are :<ul>
* <li>point sprites : used in SPARK to attach images on points and therfore gain performance</li>
* <li>point parameters : used in SPARK both to allow to have points size function of the distance and
* to overtake the basic point size limitation (usually 64 pix).</li>
* <li>texture 3D : used in SPARK to animate texture</li>
* </ul>
*
* @since 1.01.00
*/
class SPK_GL_PREFIX GLExtHandler
{
public :
///////////////////
// Point Sprites //
///////////////////
/**
* @brief Loads the openGL point sprite extension
*
* Note that this methods is called internally when needed.<br>
* The extension is loaded or not only at the first call to this method,
* the following calls only tell whether the extension was loaded or not.<br>
* In that way, this method is only useful to the user, to check whether the extension is supported or not.
*
* @return true if the extension is loaded (supported by the hardware), false if not
*/
static bool loadGLExtPointSprite();
//////////////////////
// Point Parameters //
//////////////////////
/**
* @brief Loads the openGL extended point parameter extension
*
* Note that this methods is called internally when needed.<br>
* The extension is loaded or not only at the first call to this method,
* the further calls only tell whether the extension was loaded or not.<br>
* In that way, this method is only useful to the user, to check whether the extension is supported or not.
*
* @return true if the extension is loaded (supported by the hardware), false if not
*/
static bool loadGLExtPointParameter();
/**
* @brief Computes a conversion ratio between pixels and universe units
*
* This method must be called when using GLPointRenderer with world size enabled.<br>
* It allows to well transpose world size to pixel size by setting the right openGL parameters.<br>
* <br>
* Note that fovy can be replaced by fovx if screenHeight is replaced by screenWidth.
*
* @param fovy : the field of view in the y axis in radians
* @param screenHeight : the height of the viewport in pixels
*/
static void setPixelPerUnit(float fovy,int screenHeight);
////////////////
// Texture 3D //
////////////////
/**
* @brief Loads the OpenGL texture 3D extension
*
* Note that this methods is called internally when needed.<br>
* The extension is loaded or not only at the first call to this method,
* the further calls only tell whether the extension was loaded or not.<br>
* In that way, this method is only useful to the user, to check whether the extension is supported or not.
*
* @return true if the extension is loaded (supported by the hardware), false if not
* @since 1.02.00
*/
static bool loadGLExtTexture3D();
/**
* @brief Specifies a three-dimensional texture image
*
* This method is exactly like calling the glTexImage3D method of OpenGL
* excepts it is already defined.<br>
* If the OpenGL texture 3D extension is not supported, this method does nothing.<br>
* <br>
* For more information, check the OpenGL documentation of glTexImage3D.
*
* @param target : check the OpenGL documentation of glTexImage3D
* @param level : check the OpenGL documentation of glTexImage3D
* @param internalFormat : check the OpenGL documentation of glTexImage3D
* @param width : check the OpenGL documentation of glTexImage3D
* @param height : check the OpenGL documentation of glTexImage3D
* @param depth : check the OpenGL documentation of glTexImage3D
* @param border : check the OpenGL documentation of glTexImage3D
* @param format : check the OpenGL documentation of glTexImage3D
* @param type : check the OpenGL documentation of glTexImage3D
* @param pixels : check the OpenGL documentation of glTexImage3D
* @since 1.02.00
*/
static void glTexImage3D(GLenum target,
GLint level,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
const GLvoid* pixels);
/////////////
// Shaders //
/////////////
/**
* @brief Loads the shader extension
*
* Note that this methods is called internally when needed.<br>
* The extension is loaded or not only at the first call to this method,
* the further calls only tell whether the extension was loaded or not.<br>
* In that way, this method is only useful to the user, to check whether the extension is supported or not.<br>
* <br>
* NOTE THAT FOR THE MOMENT, EVEN IF SHADER EXTENSIONS CAN BE LOADED, THEY ARE NOT USED WITHIN SPARK
*
* @return true if the extension is loaded (supported by the hardware), false if not
* @since 1.04.00
*/
static bool loadGLExtShader();
protected :
/**
* @enum GLExtension
* @brief Constants for openGL extension loading
*/
enum GLExtension
{
UNCHECKED, /**< Constant meaning the openGL extension was not tested */
SUPPORTED, /**< Constant meaning the openGL extension is supported by the hardware */
UNSUPPORTED, /**< Constant meaning the openGL extension is not supported by the hardware */
};
/**
* @brief Gets the address of an OpenGL function in a portable way
* @param name : the name of the OpenGL function
* @return a pointer to the OpenGL function, or NULL if the function is not found
*/
static inline void* glGetProcAddress(const char* name);
///////////////////
// Point Sprites //
///////////////////
/**
* @brief Gets the state of the point sprite extension
* @return the state of the point sprite extension
*/
static GLExtension getPointSpriteGLExt();
/**
* @brief Enables the use of point sprites
*
* Note that before calling this method, the user must ensure that the point sprite extension is loaded.
*/
inline static void enablePointSpriteGLExt();
/**
* @brief Disables the use of point sprites
*
* Note that before calling this method, the user must ensure that the point sprite extension is loaded.
*/
inline static void disablePointSpriteGLExt();
//////////////////////
// Point Parameters //
//////////////////////
/**
* @brief Gets the state of the point parameters extension
* @return the state of the point parameters extension
*/
static GLExtension getPointParameterGLExt();
/**
* @brief Enables the use of point parameters
*
* This method will set the right point parameters to get the desired point size.<br>
* <br>
* It can either be used to have points size function of the distance to the camera (is distance is true)
* or only to allow bigger range for point sizes (if distance is false).
* <br>
* Note that if distance is set to true setPixelPerUnit(float,int) must be call once before.
* <br>
* Note that before calling this method, the user must ensure that the point parameters extension is loaded.
*
* @param size : the size of the point
* @param distance : true to enable the modification of the size function of the distance, false not to.
*/
static void enablePointParameterGLExt(float size,bool distance);
/**
* @brief Disables the use of point parameters
*
* Note that before calling this method, the user must ensure that the point parameters extension is loaded.
*/
static void disablePointParameterGLExt();
////////////////
// Texture 3D //
////////////////
/**
* @brief Gets the state of the texture 3D extension
* @return the state of the texture 3D extension
* @since 1.02.00
*/
static GLExtension getTexture3DGLExt();
/////////////
// Shaders //
/////////////
/**
* @brief Gets the state of the shader support
* @return the state of the vertex shader support
* @since 1.04.00
*/
static GLExtension getShaderGLExt();
private :
// GLchar definition
typedef char GLchar;
// typedefs for OpenGL pointers of functions (glext.h is however needed)
typedef void (APIENTRY *SPK_PFNGLPOINTPARAMETERFPROC)(GLenum,GLfloat);
typedef void (APIENTRY *SPK_PFNGLPOINTPARAMETERFVPROC)(GLenum,const GLfloat*);
typedef void (APIENTRY *SPK_PFNGLTEXIMAGE3DPROC)(GLenum,GLint,GLint,GLsizei,GLsizei,GLsizei,GLint,GLenum,GLenum,const GLvoid*);
typedef void (APIENTRY *SPK_PFNGLCREATESHADERPROC)(GLenum);
typedef void (APIENTRY *SPK_PFNGLDELETESHADERPROC)(GLuint);
typedef void (APIENTRY *SPK_PFNGLSHADERSOURCEPROC)(GLuint,GLsizei,const GLchar**,const GLint*);
typedef void (APIENTRY *SPK_PFNGLCOMPILESHADERPROC)(GLuint);
typedef void (APIENTRY *SPK_PFNGLCREATEPROGRAMPROC)(void);
typedef void (APIENTRY *SPK_PFNGLDELETEPROGRAMPROC)(GLuint);
typedef void (APIENTRY *SPK_PFNGLATTACHSHADERPROC)(GLuint,GLuint);
typedef void (APIENTRY *SPK_PFNGLDETACHSHADERPROC)(GLuint,GLuint);
typedef void (APIENTRY *SPK_PFNGLLINKPROGRAMPROC)(GLuint);
typedef void (APIENTRY *SPK_PFNGLUSEPROGRAMPROC)(GLuint);
// Gets the GL function address on MAC
#if defined(__APPLE__) || defined(macintosh)
static void* SPK_NSGLGetProcAddress(const char* name);
#endif
///////////////////
// Point Sprites //
///////////////////
static GLExtension pointSpriteGLExt;
//////////////////////
// Point Parameters //
//////////////////////
static GLExtension pointParameterGLExt;
static SPK_PFNGLPOINTPARAMETERFPROC SPK_glPointParameterf;
static SPK_PFNGLPOINTPARAMETERFVPROC SPK_glPointParameterfv;
static const float POINT_SIZE_CURRENT;
static const float POINT_SIZE_MIN;
static const float POINT_SIZE_MAX;
static float pixelPerUnit;
static const float QUADRATIC_SCREEN[3];
////////////////
// Texture 3D //
////////////////
static GLExtension texture3DGLExt;
static SPK_PFNGLTEXIMAGE3DPROC SPK_glTexImage3D;
//////////////
// Shaders //
//////////////
static GLExtension shaderGLExt;
static SPK_PFNGLCREATESHADERPROC SPK_glCreateShader;
static SPK_PFNGLDELETESHADERPROC SPK_glDeleteShader;
static SPK_PFNGLSHADERSOURCEPROC SPK_glShaderSource;
static SPK_PFNGLCOMPILESHADERPROC SPK_glCompileShader;
static SPK_PFNGLCREATEPROGRAMPROC SPK_glCreateProgram;
static SPK_PFNGLDELETEPROGRAMPROC SPK_glDeleteProgram;
static SPK_PFNGLATTACHSHADERPROC SPK_glAttachShader;
static SPK_PFNGLDETACHSHADERPROC SPK_glDetachShader;
static SPK_PFNGLLINKPROGRAMPROC SPK_glLinkProgram;
static SPK_PFNGLUSEPROGRAMPROC SPK_glUseProgram;
};
inline void* GLExtHandler::glGetProcAddress(const char* name)
{
#if defined(WIN32) || defined(_WIN32)
return (void*)wglGetProcAddress(name); // Windows
#elif defined(__APPLE__) || defined(macintosh)
return (void*)SPK_NSGLGetProcAddress(name); // MAC
#elif defined(linux) || defined(__linux)
return (void*)glXGetProcAddressARB((const GLubyte*)name); // Linux
#else
return (void*)NULL;
#endif
}
inline void GLExtHandler::enablePointSpriteGLExt()
{
glTexEnvf(GL_POINT_SPRITE,GL_COORD_REPLACE,GL_TRUE);
glEnable(GL_POINT_SPRITE);
}
inline void GLExtHandler::disablePointSpriteGLExt()
{
glDisable(GL_POINT_SPRITE);
}
}}
#endif

View File

@ -0,0 +1,106 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GLLINERENDERER
#define H_SPK_GLLINERENDERER
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.h"
#include "Extensions/Renderers/SPK_LineRendererInterface.h"
namespace SPK
{
namespace GL
{
/**
* @class GLLineRenderer
* @brief A Renderer drawing particles as OpenGL lines
*
* The length of the lines is function of the Particle velocity and is defined in the universe space
* while the width is fixed and defines in the screen space (in pixels).<br>
* <br>
* Below are the parameters of Particle that are used in this Renderer (others have no effects) :
* <ul>
* <li>SPK::PARAM_RED</li>
* <li>SPK::PARAM_GREEN</li>
* <li>SPK::PARAM_BLUE</li>
* <li>SPK::PARAM_ALPHA (only if blending is enabled)</li>
* </ul>
*/
class SPK_GL_PREFIX GLLineRenderer : public GLRenderer, public LineRendererInterface
{
SPK_IMPLEMENT_REGISTERABLE(GLLineRenderer)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of GLLineRenderer
* @param length : the length multiplier of this GLLineRenderer
* @param width : the width of this GLLineRenderer in pixels
*/
GLLineRenderer(float length = 1.0f,float width = 1.0f);
/**
* @brief Creates and registers a new GLLineRenderer
* @param length : the length multiplier of this GLLineRenderer
* @param width : the width of this GLLineRenderer in pixels
* @return A new registered GLLineRenderer
* @since 1.04.00
*/
static inline GLLineRenderer* create(float length = 1.0f,float width = 1.0f);
///////////////
// Interface //
///////////////
virtual void createBuffers(const Group& group);
virtual void destroyBuffers(const Group& group);
virtual void render(const Group& group);
protected :
virtual bool checkBuffers(const Group& group);
private :
// vertex buffers and iterators
static float* gpuBuffer;
static float* gpuIterator;
// buffers names
static const std::string GPU_BUFFER_NAME;
};
inline GLLineRenderer* GLLineRenderer::create(float length,float width)
{
GLLineRenderer* obj = new GLLineRenderer(length,width);
registerObject(obj);
return obj;
}
}}
#endif

View File

@ -0,0 +1,284 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GLLINETRAILRENDERER
#define H_SPK_GLLINETRAILRENDERER
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Model.h"
namespace SPK
{
namespace GL
{
/**
* @class GLLineTrailRenderer
* @brief A Renderer drawing particles as line trails defined by the positions of particles over time
*
* The trail coordinates are computed in a procedural manner over time.<br>
* A trail i defined by a duration. The faster the particle, the longer the trail. It is defined by a numbers of samples.<br>
* The sampling frequency of the trail is therefore computed by nbSamples / duration and defines its resolution.<br>
* The higher the sampling frequency, the smoother the trail but the bigger the compution time and the memory consumption.<br>
* <br>
* All the particles of a Group are renderered in a single batch of GL_LINE_STRIP,
* which means every trails belong to the same object to reduce overhead on GPU side.<br>
* To allow that, invisible lines link trails together. They are defined as degenerated lines.<br>
* This imposes the alpha value is taken into account and the blending is therefore forced with GLLineTrailRenderer.<br>
* The user has the possibility to set the RGBA values of degenerated lines to keep them invisible function of the blending mode and environment.<br>
* By default it is set to (0.0f,0.0f,0.0f,0.0f).
* <br>
* Below are the parameters of Particle that are used in this Renderer (others have no effects) :
* <ul>
* <li>SPK::PARAM_RED</li>
* <li>SPK::PARAM_GREEN</li>
* <li>SPK::PARAM_BLUE</li>
* <li>SPK::PARAM_ALPHA</li>
* </ul>
* @since 1.03.00
*/
class SPK_GL_PREFIX GLLineTrailRenderer : public GLRenderer
{
SPK_IMPLEMENT_REGISTERABLE(GLLineTrailRenderer)
public :
//////////////////
// Constructors //
//////////////////
/** @brief Default constructor of GLLineTrailRenderer */
GLLineTrailRenderer();
/**
* @brief Creates and registers a new GLLineTrailRenderer
* @return A new registered GLLineTrailRenderer
* @since 1.04.00
*/
static inline GLLineTrailRenderer* create();
/////////////
// Setters //
/////////////
/**
* @brief Sets the number of samples in a trail
*
* The number of samples defines the number of points used to construct the trail.<br>
* The bigger the number of samples, the smoother the trail but the bigger the compution time and the memory consumption.
*
* @param nbSamples : the number of samples to construct the trails
*/
inline void setNbSamples(size_t nbSamples);
/**
* @brief Sets the width of a trail
*
* Like for GLLineRenderer, the width is defined in pixels and is not dependant of the distance of the trail from the camera
*
* @param width : the width of trails in pixels
*/
inline void setWidth(float width);
/**
* @brief Sets the duration of a sample
*
* The duration of a sample is defined by its life time from its creation to its destruction.<br>
* Note that the alpha of a sample will decrease linearly from its initial alpha to 0.
*
* @param duration : the duration of a sample
*/
inline void setDuration(float duration);
/**
* @brief Sets the color components of degenerated lines
* @param r : the red component
* @param g : the green component
* @param b : the blue component
* @param a : the alpha component
*/
void setDegeneratedLines(float r,float g,float b,float a);
virtual inline void enableBlending(bool blendingEnabled);
/////////////
// Getters //
/////////////
/**
* @brief Gets the number of samples per trail
* @return the number of samples per trail
*/
inline size_t getNbSamples() const;
/**
* @brief Gets the width of a trail
* @return the width of a trail (in pixels)
*/
inline float getWidth() const;
/**
* @brief Gets the duration of a sample
* @return the duration of a sample
*/
inline float getDuration() const;
///////////////
// Interface //
///////////////
virtual void createBuffers(const Group& group);
virtual void destroyBuffers(const Group& group);
/**
* @brief Inits all the trails of the particle of the group
*
* All the samples are set to the current position of the particle.<br>
* The trail of each particle has therefore a length of 0 and is ready for update.<br>
* This function allows to clear the buffers for GLLineTrailRenderer of the given group.
*
* @param group : the Group whose buffers need to be initialized
*/
void init(const Group& group);
virtual void render(const Group& group);
protected :
virtual bool checkBuffers(const Group& group);
private :
size_t nbSamples;
float width;
float duration;
float degeneratedR;
float degeneratedG;
float degeneratedB;
float degeneratedA;
// vertex buffers and iterators
static float* vertexBuffer;
static float* vertexIterator;
static float* colorBuffer;
static float* colorIterator;
static float* valueBuffer;
static float* valueIterator;
// buffers names
static const std::string VERTEX_BUFFER_NAME;
static const std::string COLOR_BUFFER_NAME;
static const std::string VALUE_BUFFER_NAME;
inline void init(const Particle& particle,float age) const;
};
inline GLLineTrailRenderer* GLLineTrailRenderer::create()
{
GLLineTrailRenderer* obj = new GLLineTrailRenderer;
registerObject(obj);
return obj;
}
inline void GLLineTrailRenderer::enableBlending(bool blendingEnabled)
{
GLRenderer::enableBlending(true);
}
inline void GLLineTrailRenderer::setNbSamples(size_t nbSamples)
{
this->nbSamples = nbSamples;
}
inline void GLLineTrailRenderer::setWidth(float width)
{
this->width = width;
}
inline void GLLineTrailRenderer::setDuration(float duration)
{
this->duration = duration;
}
inline size_t GLLineTrailRenderer::getNbSamples() const
{
return nbSamples;
}
inline float GLLineTrailRenderer::getWidth() const
{
return width;
}
inline float GLLineTrailRenderer::getDuration() const
{
return duration;
}
inline void GLLineTrailRenderer::init(const Particle& particle,float age) const
{
// Gets the particle's values
const Vector3D& pos = particle.position();
float r = particle.getR();
float g = particle.getG();
float b = particle.getB();
float a = particle.getParamCurrentValue(PARAM_ALPHA);
// Inits position
for (size_t i = 0; i < nbSamples + 2; ++i)
{
*(vertexIterator++) = pos.x;
*(vertexIterator++) = pos.y;
*(vertexIterator++) = pos.z;
}
// Inits color
// degenerate pre vertex
*(colorIterator++) = degeneratedR;
*(colorIterator++) = degeneratedG;
*(colorIterator++) = degeneratedB;
*(colorIterator++) = degeneratedA;
for (size_t i = 0; i < nbSamples; ++i)
{
*(colorIterator++) = r;
*(colorIterator++) = g;
*(colorIterator++) = b;
*(colorIterator++) = a;
}
// degenerate post vertex
*(colorIterator++) = degeneratedR;
*(colorIterator++) = degeneratedG;
*(colorIterator++) = degeneratedB;
*(colorIterator++) = degeneratedA;
// Inits age
for (size_t i = 0; i < nbSamples; ++i)
*(valueIterator++) = age;
}
}}
#endif

View File

@ -0,0 +1,163 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GLPOINTRENDERER
#define H_SPK_GLPOINTRENDERER
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.h"
#include "RenderingAPIs/OpenGL/SPK_GLExtHandler.h"
#include "Extensions/Renderers/SPK_PointRendererInterface.h"
namespace SPK
{
namespace GL
{
/**
* @class GLPointRenderer
* @brief A Renderer drawing drawing particles as openGL points
*
* OpenGL points can be configured to render them in 3 different ways :
* <ul>
* <li>SPK::POINT_SQUARE : standard openGL points</li>
* <li>SPK::POINT_CIRCLE : antialiased openGL points</li>
* <li>SPK::POINT_SPRITE : OpenGL point sprites (must be supported by the hardware)</li>
* </ul>
* Moreover, points size can either be defined in screen space (in pixels) or in the universe space (must be supported by the hardware).
* The advantage of the universe space is that points size on the screen will be dependant to their distance to the camera, whereas in screen space
* all points will have the same size on the screen no matter their distance to the camera.
* <br>
* Below are the parameters of Particle that are used in this Renderer (others have no effects) :
* <ul>
* <li>SPK::PARAM_RED</li>
* <li>SPK::PARAM_GREEN</li>
* <li>SPK::PARAM_BLUE</li>
* <li>SPK::PARAM_ALPHA (only if blending is enabled)</li>
* </ul>
*/
class SPK_GL_PREFIX GLPointRenderer : public GLRenderer,
public PointRendererInterface,
public GLExtHandler
{
SPK_IMPLEMENT_REGISTERABLE(GLPointRenderer)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of GLPointRenderer
* @param size : the size of the points
*/
GLPointRenderer(float size = 1.0f);
/**
* @brief Creates and registers a new GLPointRenderer
* @param size : the size of the points
* @return A new registered GLPointRenderer
* @since 1.04.00
*/
static inline GLPointRenderer* create(float size = 1.0f);
/////////////
// Setters //
/////////////
virtual bool setType(PointType type);
/**
* @brief Sets the texture of this GLPointRenderer
*
* Note that the texture is only used if point sprites are used (type is set to SPK::POINT_SPRITE)
*
* @param textureIndex : the index of the openGL texture of this GLPointRenderer
*/
inline void setTexture(GLuint textureIndex);
/**
* @brief Sets the way size of points is computed in this GLPointRenderer
*
* if universe size is used (true), the extension is checked.<br>
* if universe size is not supported by the hardware, false is returned and nothing happens.<br>
* <br>
* If world size is enabled, the static method setPixelPetUnit(float,int) must be called to set the conversion between pixels and world units.
*
* @param worldSizeEnabled : true to enable universe size, false to use screen size
* @return true the type of size can be set, false otherwise
*/
bool enableWorldSize(bool worldSizeEnabled);
/////////////
// Getters //
/////////////
/**
* @brief Gets the texture of this GLPointRenderer
* @return the texture of this GLPointRenderer
*/
inline GLuint getTexture() const;
/**
* @brief Tells whether world size is enabled or not in this GLPointRenderer
* @return true if world size is enabled, false if not
*/
inline bool isWorldSizeEnabled() const;
///////////////
// Interface //
///////////////
virtual void render(const Group& group);
private :
GLuint textureIndex;
bool worldSize;
};
inline GLPointRenderer* GLPointRenderer::create(float size)
{
GLPointRenderer* obj = new GLPointRenderer(size);
registerObject(obj);
return obj;
}
inline void GLPointRenderer::setTexture(GLuint textureIndex)
{
this->textureIndex = textureIndex;
}
inline GLuint GLPointRenderer::getTexture() const
{
return textureIndex;
}
inline bool GLPointRenderer::isWorldSizeEnabled() const
{
return worldSize;
}
}}
#endif

View File

@ -0,0 +1,305 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GLQUADRENDERER
#define H_SPK_GLQUADRENDERER
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.h"
#include "RenderingAPIs/OpenGL/SPK_GLExtHandler.h"
#include "Extensions/Renderers/SPK_QuadRendererInterface.h"
#include "Extensions/Renderers/SPK_Oriented3DRendererInterface.h"
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Model.h"
namespace SPK
{
namespace GL
{
/**
* @class GLQuadRenderer
* @brief A Renderer drawing particles as OpenGL quads
*
* the orientation of the quads depends on the orientation parameters set.
* This orientation is computed during rendering by the CPU (further improvement of SPARK will allow to make the computation on GPU side).<br>
* <br>
* Below are the parameters of Particle that are used in this Renderer (others have no effects) :
* <ul>
* <li>SPK::PARAM_SIZE</li>
* <li>SPK::PARAM_RED</li>
* <li>SPK::PARAM_GREEN</li>
* <li>SPK::PARAM_BLUE</li>
* <li>SPK::PARAM_ALPHA (only if blending is enabled)</li>
* <li>SPK::PARAM_ANGLE</li>
* <li>SPK::PARAM_TEXTURE_INDEX (only if not in TEXTURE_NONE mode)</li>
* </ul>
*/
class SPK_GL_PREFIX GLQuadRenderer : public GLRenderer,
public QuadRendererInterface,
public Oriented3DRendererInterface,
public GLExtHandler
{
SPK_IMPLEMENT_REGISTERABLE(GLQuadRenderer)
public :
//////////////////
// Constructors //
//////////////////
/**
* @brief Constructor of GLQuadRenderer
* @param scaleX the scale of the width of the quad
* @param scaleY the scale of the height of the quad
*/
GLQuadRenderer(float scaleX = 1.0f,float scaleY = 1.0f);
/**
* @brief Creates and registers a new GLQuadRenderer
* @param scaleX the scale of the width of the quad
* @param scaleY the scale of the height of the quad
* @return A new registered GLQuadRenderer
* @since 1.04.00
*/
static inline GLQuadRenderer* create(float scaleX = 1.0f,float scaleY = 1.0f);
/////////////
// Setters //
/////////////
virtual bool setTexturingMode(TexturingMode mode);
inline void setTexture(GLuint textureIndex);
/////////////
// Getters //
/////////////
/**
* @brief Gets the texture of this GLQuadRenderer
* @return the texture of this GLQuadRenderer
*/
inline GLuint getTexture() const;
///////////////
// Interface //
///////////////
virtual void createBuffers(const Group& group);
virtual void destroyBuffers(const Group& group);
virtual void render(const Group& group);
protected :
virtual bool checkBuffers(const Group& group);
private :
mutable float modelView[16];
mutable float invModelView[16];
GLuint textureIndex;
// vertex buffers and iterators
static float* gpuBuffer;
static float* gpuIterator;
static float* textureBuffer;
static float* textureIterator;
// buffers names
static const std::string GPU_BUFFER_NAME;
static const std::string TEXTURE_BUFFER_NAME;
float* createTextureBuffer(const Group& group) const;
inline void invertModelView() const;
inline void GLCallColorAndVertex(const Particle& particle) const; // OpenGL calls for color and position
inline void GLCallTexture2DAtlas(const Particle& particle) const; // OpenGL calls for 2D atlastexturing
inline void GLCallTexture3D(const Particle& particle) const; // OpenGL calls for 3D texturing
static void (GLQuadRenderer::*renderParticle)(const Particle&) const; // pointer to the right render method
void render2D(const Particle& particle) const; // Rendering for particles with texture 2D or no texture
void render2DRot(const Particle& particle) const; // Rendering for particles with texture 2D or no texture and rotation
void render3D(const Particle& particle) const; // Rendering for particles with texture 3D
void render3DRot(const Particle& particle) const; // Rendering for particles with texture 3D and rotation
void render2DAtlas(const Particle& particle) const; // Rendering for particles with texture 2D atlas
void render2DAtlasRot(const Particle& particle) const; // Rendering for particles with texture 2D atlas and rotation
};
inline GLQuadRenderer* GLQuadRenderer::create(float scaleX,float scaleY)
{
GLQuadRenderer* obj = new GLQuadRenderer(scaleX,scaleY);
registerObject(obj);
return obj;
}
inline void GLQuadRenderer::setTexture(GLuint textureIndex)
{
this->textureIndex = textureIndex;
}
inline GLuint GLQuadRenderer::getTexture() const
{
return textureIndex;
}
inline void GLQuadRenderer::GLCallColorAndVertex(const Particle& particle) const
{
float x = particle.position().x;
float y = particle.position().y;
float z = particle.position().z;
// quads are drawn in a counter clockwise order :
// top right vertex
*(gpuIterator++) = x + quadSide().x + quadUp().x;
*(gpuIterator++) = y + quadSide().y + quadUp().y;
*(gpuIterator++) = z + quadSide().z + quadUp().z;
gpuIterator += 4;
// top left vertex
*(gpuIterator++) = x - quadSide().x + quadUp().x;
*(gpuIterator++) = y - quadSide().y + quadUp().y;
*(gpuIterator++) = z - quadSide().z + quadUp().z;
gpuIterator += 4;
// bottom left
*(gpuIterator++) = x - quadSide().x - quadUp().x;
*(gpuIterator++) = y - quadSide().y - quadUp().y;
*(gpuIterator++) = z - quadSide().z - quadUp().z;
gpuIterator += 4;
// bottom right
*(gpuIterator++) = x + quadSide().x - quadUp().x;
*(gpuIterator++) = y + quadSide().y - quadUp().y;
*(gpuIterator++) = z + quadSide().z - quadUp().z;
*(gpuIterator++) = particle.getR();
*(gpuIterator++) = particle.getG();
*(gpuIterator++) = particle.getB();
*(gpuIterator++) = particle.getParamCurrentValue(PARAM_ALPHA);
}
inline void GLQuadRenderer::GLCallTexture2DAtlas(const Particle& particle) const
{
computeAtlasCoordinates(particle);
*(textureIterator++) = textureAtlasU1();
*(textureIterator++) = textureAtlasV0();
*(textureIterator++) = textureAtlasU0();
*(textureIterator++) = textureAtlasV0();
*(textureIterator++) = textureAtlasU0();
*(textureIterator++) = textureAtlasV1();
*(textureIterator++) = textureAtlasU1();
*(textureIterator++) = textureAtlasV1();
}
inline void GLQuadRenderer::GLCallTexture3D(const Particle& particle) const
{
float textureIndex = particle.getParamCurrentValue(PARAM_TEXTURE_INDEX);
*(textureIterator + 2) = textureIndex;
*(textureIterator + 5) = textureIndex;
*(textureIterator + 8) = textureIndex;
*(textureIterator + 11) = textureIndex;
textureIterator += 12;
}
inline void GLQuadRenderer::invertModelView() const
{
float tmp[12];
float src[16];
/* transpose matrix */
for (int i = 0; i < 4; ++i)
{
src[i] = modelView[i << 2];
src[i + 4] = modelView[(i << 2) + 1];
src[i + 8] = modelView[(i << 2) + 2];
src[i + 12] = modelView[(i << 2) + 3];
}
/* calculate pairs for first 8 elements (cofactors) */
tmp[0] = src[10] * src[15];
tmp[1] = src[11] * src[14];
tmp[2] = src[9] * src[15];
tmp[3] = src[11] * src[13];
tmp[4] = src[9] * src[14];
tmp[5] = src[10] * src[13];
tmp[6] = src[8] * src[15];
tmp[7] = src[11] * src[12];
tmp[8] = src[8] * src[14];
tmp[9] = src[10] * src[12];
tmp[10] = src[8] * src[13];
tmp[11] = src[9] * src[12];
/* calculate first 8 elements (cofactors) */
invModelView[0] = tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7] - tmp[1] * src[5] - tmp[2] * src[6] - tmp[5] * src[7];
invModelView[1] = tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7] - tmp[0] * src[4] - tmp[7] * src[6] - tmp[8] * src[7];
invModelView[2] = tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7] - tmp[3] * src[4] - tmp[6] * src[5] - tmp[11] * src[7];
invModelView[3] = tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6] - tmp[4] * src[4] - tmp[9] * src[5] - tmp[10] * src[6];
invModelView[4] = tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3] - tmp[0] * src[1] - tmp[3] * src[2] - tmp[4] * src[3];
invModelView[5] = tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3] - tmp[1] * src[0]- tmp[6] * src[2] - tmp[9] * src[3];
invModelView[6] = tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3] - tmp[2] * src[0] - tmp[7] * src[1] - tmp[10] * src[3];
invModelView[7] = tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2] - tmp[5]*src[0] - tmp[8]*src[1] - tmp[11]*src[2];
/* calculate pairs for second 8 elements (cofactors) */
tmp[0] = src[2] * src[7];
tmp[1] = src[3] * src[6];
tmp[2] = src[1] * src[7];
tmp[3] = src[3] * src[5];
tmp[4] = src[1] * src[6];
tmp[5] = src[2] * src[5];
tmp[6] = src[0] * src[7];
tmp[7] = src[3] * src[4];
tmp[8] = src[0] * src[6];
tmp[9] = src[2] * src[4];
tmp[10] = src[0] * src[5];
tmp[11] = src[1] * src[4];
/* calculate second 8 elements (cofactors) */
invModelView[8] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15] - tmp[1] * src[13] - tmp[2] * src[14] - tmp[5] * src[15];
invModelView[9] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15] - tmp[0] * src[12] - tmp[7] * src[14] - tmp[8] * src[15];
invModelView[10] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15] - tmp[3] * src[12] - tmp[6] * src[13] - tmp[11] * src[15];
invModelView[11] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14] - tmp[4] * src[12] - tmp[9] * src[13] - tmp[10] * src[14];
invModelView[12] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9] - tmp[4] * src[11] - tmp[0] * src[9] - tmp[3] * src[10];
invModelView[13] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10] - tmp[6] * src[10] - tmp[9] * src[11] - tmp[1] * src[8];
invModelView[14] = tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8] - tmp[10] * src[11] - tmp[2] * src[8] - tmp[7] * src[9];
invModelView[15] = tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9] - tmp[8] * src[9] - tmp[11] * src[10] - tmp[5] * src[8];
/* calculate determinant */
float det = src[0] * invModelView[0] + src[1] * invModelView[1] + src[2] * invModelView[2] + src[3] * invModelView[3];
/* calculate matrix inverse */
det = 1 / det;
for (int i = 0; i < 16; ++i)
invModelView[i] *= det;
}
}}
#endif

View File

@ -0,0 +1,225 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GLRENDERER
#define H_SPK_GLRENDERER
#include "RenderingAPIs/OpenGL/SPK_GL_DEF.h"
#include "Core/SPK_Renderer.h"
namespace SPK
{
namespace GL
{
/**
* @class GLRenderer
* @brief An abstract Renderer for the openGL renderers
*/
class SPK_GL_PREFIX GLRenderer : public Renderer
{
public :
/////////////////
// Constructor //
/////////////////
/** @brief Constructor of GLRenderer */
GLRenderer();
////////////////
// Destructor //
////////////////
/** @brief Destructor of GLRenderer */
virtual ~GLRenderer();
/////////////
// Setters //
/////////////
/**
* @brief Enables or disables the blending of this GLRenderer
* @param blendingEnabled true to enable the blending, false to disable it
*/
virtual inline void enableBlending(bool blendingEnabled);
/**
* @brief Sets the blending functions of this GLRenderer
*
* the blending functions are one of the openGL blending functions.
*
* @param src : the source blending function of this GLRenderer
* @param dest : the destination blending function of this GLRenderer
*/
inline void setBlendingFunctions(GLuint src,GLuint dest);
virtual void setBlending(BlendingMode blendMode);
/**
* @brief Sets the texture blending function of this GLRenderer
*
* the texture blending function is one of the openGL texture blending functions.
*
* @param textureBlending : the texture blending function of this GLRenderer
*/
inline void setTextureBlending(GLuint textureBlending);
/////////////
// Getters //
/////////////
/**
* @brief Tells whether blending is enabled for this GLRenderer
* @return true if blending is enabled, false if it is disabled
*/
inline bool isBlendingEnabled() const;
/**
* @brief Gets the source blending function of this GLRenderer
* @return the source blending function of this GLRenderer
*/
inline GLuint getSrcBlendingFunction() const;
/**
* @brief Gets the destination blending function of this GLRenderer
* @return the source destination function of this GLRenderer
*/
inline GLuint getDestBlendingFunction() const;
/**
* @brief Gets the texture blending function of this GLRenderer
* @return the texture blending function of this GLRenderer
*/
inline GLuint getTextureBlending() const;
///////////////
// Interface //
///////////////
/**
* @brief Saves the current openGL states
*
* This method saves all the states that are likely to be modified by a GLRenderer.<br>
* Use restoreGLStates() to restore the states.<br>
* <br>
* Note that for one saveGLStates call, a call to restoreGLStates must occur.
* In case of several saveGLStates with no restoreGLStates, the restoreGLStates is called priorly in an implicit way.
*/
static void saveGLStates();
/**
* @brief Restores the openGL states
*
* This method restores the openGL states at the values they were at the last call of saveGLStates().
*/
static void restoreGLStates();
protected :
/** @brief Inits the blending of this GLRenderer */
inline void initBlending() const;
/**
* @brief Inits the rendering hints of this GLRenderer
* @since 1.04.00
*/
inline void initRenderingHints() const;
private :
bool blendingEnabled;
GLuint srcBlending;
GLuint destBlending;
GLuint textureBlending;
};
inline void GLRenderer::enableBlending(bool blendingEnabled)
{
this->blendingEnabled = blendingEnabled;
}
inline void GLRenderer::setBlendingFunctions(GLuint src,GLuint dest)
{
srcBlending = src;
destBlending = dest;
}
inline void GLRenderer::setTextureBlending(GLuint textureBlending)
{
this->textureBlending = textureBlending;
}
inline bool GLRenderer::isBlendingEnabled() const
{
return blendingEnabled;
}
inline GLuint GLRenderer::getSrcBlendingFunction() const
{
return srcBlending;
}
inline GLuint GLRenderer::getDestBlendingFunction() const
{
return destBlending;
}
inline GLuint GLRenderer::getTextureBlending() const
{
return textureBlending;
}
inline void GLRenderer::initBlending() const
{
if (blendingEnabled)
{
glBlendFunc(srcBlending,destBlending);
glEnable(GL_BLEND);
}
else
glDisable(GL_BLEND);
}
inline void GLRenderer::initRenderingHints() const
{
// alpha test
if (isRenderingHintEnabled(ALPHA_TEST))
{
glAlphaFunc(GL_GEQUAL,getAlphaTestThreshold());
glEnable(GL_ALPHA_TEST);
}
else
glDisable(GL_ALPHA_TEST);
// depth test
if (isRenderingHintEnabled(DEPTH_TEST))
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
// depth write
glDepthMask(isRenderingHintEnabled(DEPTH_WRITE));
}
}}
#endif

View File

@ -0,0 +1,74 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GL_DEF
#define H_SPK_GL_DEF
#ifdef _MSC_VER
#pragma warning(disable : 4275) // disables the warning about exporting DLL classes children of non DLL classes
#endif
// 1.02.02 Compatibility with older versions
#ifdef SPK_DLL
#define SPK_GL_IMPORT
#endif
#ifdef SPK_GL_EXPORT
#define SPK_GL_PREFIX __declspec(dllexport)
#elif defined(SPK_IMPORT) || defined(SPK_GL_IMPORT)
#define SPK_GL_PREFIX __declspec(dllimport)
#else
#define SPK_GL_PREFIX
#endif
#ifndef SPK_NO_GL_INC
#if defined(WIN32) || defined(_WIN32)
#include <windows.h>
#endif
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#elif defined(macintosh)
#include <gl.h>
#else
#include <GL/gl.h>
#endif
#if defined(linux) || defined(__linux)
#include <GL/glx.h>
#endif
#endif
// Defines the APIENTRY if not already done
#ifndef APIENTRY
#define APIENTRY
#endif
/**
* @namespace SPK::GL
* @brief the namespace for openGL dependent SPARK code
* @since 1.01.00
*/
#endif

78
libs/spark/include/SPK.h Normal file
View File

@ -0,0 +1,78 @@
//////////////////////////////////////////////////////////////////////////////////
// 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
#define H_SPK
// Defines
#include "Core/SPK_DEF.h"
// Core
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Buffer.h" // 1.03
#include "Core/SPK_ArrayBuffer.h" // 1.03
#include "Core/SPK_Registerable.h" // 1.03
#include "Core/SPK_Transformable.h" // 1.03
#include "Core/SPK_BufferHandler.h" // 1.04
#include "Core/SPK_RegWrapper.h" // 1.03
#include "Core/SPK_Renderer.h"
#include "Core/SPK_System.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Pool.h"
#include "Core/SPK_Zone.h"
#include "Core/SPK_Interpolator.h" // 1.05
#include "Core/SPK_Model.h"
#include "Core/SPK_Emitter.h"
#include "Core/SPK_Modifier.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_Factory.h" // 1.03
// Zones
#include "Extensions/Zones/SPK_AABox.h"
#include "Extensions/Zones/SPK_Point.h"
#include "Extensions/Zones/SPK_Sphere.h"
#include "Extensions/Zones/SPK_Plane.h"
#include "Extensions/Zones/SPK_Line.h" // 1.01
#include "Extensions/Zones/SPK_Ring.h" // 1.05
// Emitters
#include "Extensions/Emitters/SPK_StraightEmitter.h"
#include "Extensions/Emitters/SPK_SphericEmitter.h"
#include "Extensions/Emitters/SPK_NormalEmitter.h" // 1.02
#include "Extensions/Emitters/SPK_RandomEmitter.h" // 1.02
#include "Extensions/Emitters/SPK_StaticEmitter.h" // 1.05
// Modifiers
#include "Extensions/Modifiers/SPK_Obstacle.h"
#include "Extensions/Modifiers/SPK_Destroyer.h"
#include "Extensions/Modifiers/SPK_PointMass.h"
#include "Extensions/Modifiers/SPK_ModifierGroup.h" // 1.02
#include "Extensions/Modifiers/SPK_LinearForce.h" // 1.03
#include "Extensions/Modifiers/SPK_Collision.h" // 1.04
#include "Extensions/Modifiers/SPK_Vortex.h" // 1.05
#include "Extensions/Modifiers/SPK_Rotator.h" // 1.05
// Renderer Interfaces
#include "Extensions/Renderers/SPK_PointRendererInterface.h" // 1.04
#include "Extensions/Renderers/SPK_LineRendererInterface.h" // 1.04
#include "Extensions/Renderers/SPK_Oriented3DRendererInterface.h" // 1.04
#endif

View File

@ -0,0 +1,41 @@
//////////////////////////////////////////////////////////////////////////////////
// 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_GL
#define H_SPK_GL
// Defines
#include "RenderingAPIs/OpenGL/SPK_GL_DEF.h"
// Extension interface
#include "RenderingAPIs/OpenGL/SPK_GLExtHandler.h" // 1.01
// Mother Renderer
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.h"
// Renderers
#include "RenderingAPIs/OpenGL/SPK_GLPointRenderer.h"
#include "RenderingAPIs/OpenGL/SPK_GLLineRenderer.h"
#include "RenderingAPIs/OpenGL/SPK_GLQuadRenderer.h"
#include "RenderingAPIs/OpenGL/SPK_GLLineTrailRenderer.h" // 1.03
#endif

View File

@ -0,0 +1,3 @@
[Dolphin]
Timestamp=2011,1,5,19,24,26
ViewMode=1

View File

@ -0,0 +1,53 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_BufferHandler.h"
namespace SPK
{
bool BufferHandler::bufferCreation = true;
void BufferHandler::enableBuffersCreation(bool creation)
{
bufferCreation = creation;
}
bool BufferHandler::isBuffersCreationEnabled()
{
return bufferCreation;
}
bool BufferHandler::prepareBuffers(const Group& group)
{
if (!checkBuffers(group))
{
if (isBuffersCreationEnabled())
{
destroyBuffers(group);
createBuffers(group);
return true;
}
return false;
}
return true;
}
}

View File

@ -0,0 +1,28 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_DEF.h"
namespace SPK
{
unsigned int randomSeed = 1;
}

View File

@ -0,0 +1,131 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Emitter.h"
#include "Extensions/Zones/SPK_Point.h"
namespace SPK
{
Emitter::Emitter() :
Registerable(),
Transformable(),
zone(&getDefaultZone()),
full(true),
tank(-1),
flow(0.0f),
forceMin(0.0f),
forceMax(0.0f),
fraction(random(0.0f,1.0f)),
active(true)
{}
void Emitter::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
registerChild(zone,registerAll);
}
void Emitter::copyChildren(const Emitter& emitter,bool createBase)
{
Registerable::copyChildren(emitter,createBase);
zone = dynamic_cast<Zone*>(copyChild(emitter.zone,createBase));
}
void Emitter::destroyChildren(bool keepChildren)
{
destroyChild(zone,keepChildren);
Registerable::destroyChildren(keepChildren);
}
Registerable* Emitter::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if (object != NULL)
return object;
return zone->findByName(name);
}
void Emitter::changeTank(int deltaTank)
{
if (tank >= 0)
{
tank += deltaTank;
if (tank < 0)
tank = 0;
}
}
void Emitter::changeFlow(float deltaFlow)
{
if (flow >= 0.0f)
{
flow += deltaFlow;
if (flow < 0.0f)
flow = 0.0f;
}
}
void Emitter::setZone(Zone* zone,bool full)
{
decrementChildReference(this->zone);
incrementChildReference(zone);
if (zone == NULL)
zone = &getDefaultZone();
this->zone = zone;
this->full = full;
}
Zone& Emitter::getDefaultZone()
{
static Point defaultZone;
return defaultZone;
}
unsigned int Emitter::updateNumber(float deltaTime)
{
int nbBorn;
if (flow < 0.0f)
{
nbBorn = std::max(0,tank);
tank = 0;
}
else if (tank != 0)
{
fraction += flow * deltaTime;
nbBorn = static_cast<int>(fraction);
if (tank >= 0)
{
nbBorn = std::min(tank,nbBorn);
tank -= nbBorn;
}
fraction -= nbBorn;
}
else
nbBorn = 0;
return static_cast<unsigned int>(nbBorn);
}
}

View File

@ -0,0 +1,214 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Factory.h"
namespace SPK
{
SPKFactory* SPKFactory::instance = NULL;
SPK_ID SPKFactory::currentID = NO_ID;
SPKFactory& SPKFactory::getInstance()
{
if (instance == NULL)
instance = new SPKFactory;
return *instance;
}
void SPKFactory::destroyInstance()
{
if (instance != NULL)
{
delete instance;
instance = NULL;
}
}
SPK_ID SPKFactory::create(const Registerable& base)
{
// Clears the adresses set
SPKAdresses.clear();
// clones the reference
Registerable* innerBase = base.clone(true);
// registers the base
registerObject(innerBase);
return innerBase->ID;
}
Registerable* SPKFactory::get(SPK_ID ID)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
return it->second;
return NULL; // the ID is not registered
}
Registerable* SPKFactory::copy(SPK_ID ID)
{
// Clears the adresses set
SPKAdresses.clear();
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
return registerObject(it->second->clone(false)); // registers a copy
return NULL; // the ID is not registered
}
Registerable* SPKFactory::copy(const Registerable* registerable)
{
// Clears the adresses set
SPKAdresses.clear();
if (registerable->isRegistered())
return registerObject(registerable->clone(false)); // registers a copy
return NULL;
}
bool SPKFactory::destroy(SPK_ID ID,bool checkNbReferences)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if ((it != SPKRegister.end())&& // the ID was found
((!checkNbReferences)||
(it->second->getNbReferences() == 0)))
{
unregisterObject(it,false);
return true;
}
return false; // the ID is not registered
}
bool SPKFactory::destroy(Registerable* object,bool checkNbReferences)
{
if (object == NULL)
return false;
return destroy(object->getSPKID(),checkNbReferences);
}
void SPKFactory::destroyAll()
{
std::map<SPK_ID,Registerable*>::iterator it;
while((it = SPKRegister.begin()) != SPKRegister.end())
unregisterObject(it,true);
}
Registerable* SPKFactory::findByName(const std::string& name)
{
for (std::map<SPK_ID,Registerable*>::const_iterator it = SPKRegister.begin(); it != SPKRegister.end(); ++it)
if (it->second->getName().compare(name) == 0)
return it->second;
return NULL;
}
void SPKFactory::trace(SPK_ID ID)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
traceObject(it,true);
else // the ID is not registered
std::cout << "No object registered in the SPKFactory with this ID";
}
void SPKFactory::trace(const Registerable* registerable)
{
trace(registerable->getSPKID());
}
void SPKFactory::traceAll()
{
std::cout << "Nb of objects in the SPKFactory : " << getNbObjects() << std::endl;
for (std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.begin(); it != SPKRegister.end(); ++it)
traceObject(it,true);
}
void SPKFactory::traceObject(const std::map<SPK_ID,Registerable*>::iterator& it,bool nextLine)
{
SPK_ID ID = it->first;
Registerable* object = it->second;
std::cout << object
<< " ID:" << ID
<< " type:" << object->getClassName().c_str()
<< " nbRef:" << object->getNbReferences()
<< " flag:";
if (object->isShared()) std::cout << "S";
if (object->isDestroyable()) std::cout << "D";
if (object->getName().length() > 0) std::cout << " \"" << object->getName() << "\"";
if (nextLine) std::cout << std::endl;
}
Registerable* SPKFactory::registerObject(Registerable* object)
{
object->onRegister();
object->ID = ++currentID;
// optimisation at the insertion to get an amortized constant complexity instead of a logarithmic complexity
SPKRegister.insert(SPKRegister.size() != 0 ? --SPKRegister.end() : SPKRegister.begin(),
std::pair<SPK_ID,Registerable*>(object->ID,object));
// Traces allocations
#ifdef SPK_DEBUG
++nbAlloc;
std::cout << "REGISTER ";
traceObject(SPKRegister.find(object->ID),false);
std::cout << " nbAlloc:" << nbAlloc << " nbObj:" << getNbObjects() << std::endl;
#endif
return object;
}
void SPKFactory::unregisterObject(std::map<SPK_ID,Registerable*>::iterator& it,bool keepChildren)
{
Registerable* object = it->second;
object->onUnregister();
// traces desallocations
#ifdef SPK_DEBUG
++nbDesalloc;
std::cout << "UNREGISTER ";
traceObject(it,false);
std::cout << " nbDesalloc:" << nbDesalloc << " nbObj:" << getNbObjects() - 1 << std::endl;
#endif
SPKRegister.erase(it); // unregister object
object->ID = NO_ID;
object->destroyChildren(keepChildren); // unregister and destroy registered children
delete object; // destroy object
}
bool SPKFactory::unregisterObject(SPK_ID ID,bool keepChildren)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
{
unregisterObject(it,keepChildren);
return true;
}
return false;
}
}

View File

@ -0,0 +1,746 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Group.h"
#include "Core/SPK_Emitter.h"
#include "Core/SPK_Modifier.h"
#include "Core/SPK_Renderer.h"
#include "Core/SPK_Factory.h"
#include "Core/SPK_Buffer.h"
namespace SPK
{
bool Group::bufferManagement = true;
Group::Group(Model* m,size_t capacity) :
Registerable(),
Transformable(),
model(m != NULL ? m : &getDefaultModel()),
renderer(NULL),
friction(0.0f),
gravity(Vector3D()),
pool(Pool<Particle>(capacity)),
particleData(new Particle::ParticleData[capacity]),
particleCurrentParams(new float[capacity * model->getSizeOfParticleCurrentArray()]),
particleExtendedParams(new float[capacity * model->getSizeOfParticleExtendedArray()]),
sortingEnabled(false),
distanceComputationEnabled(false),
creationBuffer(),
nbBufferedParticles(0),
fupdate(NULL),
fbirth(NULL),
fdeath(NULL),
boundingBoxEnabled(false),
emitters(),
modifiers(),
activeModifiers(),
additionalBuffers(),
swappableBuffers()
{}
Group::Group(const Group& group) :
Registerable(group),
Transformable(group),
model(group.model),
renderer(group.renderer),
friction(group.friction),
gravity(group.gravity),
pool(group.pool),
sortingEnabled(group.sortingEnabled),
distanceComputationEnabled(group.distanceComputationEnabled),
creationBuffer(group.creationBuffer),
nbBufferedParticles(group.nbBufferedParticles),
fupdate(group.fupdate),
fbirth(group.fbirth),
fdeath(group.fdeath),
boundingBoxEnabled(group.boundingBoxEnabled),
emitters(group.emitters),
modifiers(group.modifiers),
activeModifiers(group.activeModifiers.capacity()),
additionalBuffers(),
swappableBuffers()
{
particleData = new Particle::ParticleData[pool.getNbReserved()];
particleCurrentParams = new float[pool.getNbReserved() * model->getSizeOfParticleCurrentArray()];
particleExtendedParams = new float[pool.getNbReserved() * model->getSizeOfParticleExtendedArray()];
memcpy(particleData,group.particleData,pool.getNbTotal() * sizeof(Particle::ParticleData));
memcpy(particleCurrentParams,group.particleCurrentParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleCurrentArray());
memcpy(particleExtendedParams,group.particleExtendedParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleExtendedArray());
for (Pool<Particle>::iterator it = pool.begin(); it != pool.endInactive(); ++it)
{
it->group = this;
it->data = particleData + it->index;
it->currentParams = particleCurrentParams + it->index * model->getSizeOfParticleCurrentArray();
it->extendedParams = particleExtendedParams + it->index * model->getSizeOfParticleExtendedArray();
}
}
Group::~Group()
{
delete[] particleData;
delete[] particleCurrentParams;
delete[] particleExtendedParams;
// destroys additional buffers
destroyAllBuffers();
}
void Group::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
registerChild(model,registerAll);
registerChild(renderer,registerAll);
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != emitters.end(); ++it)
registerChild(*it,registerAll);
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
registerChild(*it,registerAll);
}
void Group::copyChildren(const Group& group,bool createBase)
{
Registerable::copyChildren(group,createBase);
model = dynamic_cast<Model*>(copyChild(group.model,createBase));
renderer = dynamic_cast<Renderer*>(copyChild(group.renderer,createBase));
// we clear the copies of pointers pushed in the vectors by the copy constructor
emitters.clear();
modifiers.clear();
for (std::vector<Emitter*>::const_iterator it = group.emitters.begin(); it != group.emitters.end(); ++it)
emitters.push_back(dynamic_cast<Emitter*>(copyChild(*it,createBase)));
for (std::vector<Modifier*>::const_iterator it = group.modifiers.begin(); it != group.modifiers.end(); ++it)
modifiers.push_back(dynamic_cast<Modifier*>(copyChild(*it,createBase)));
}
void Group::destroyChildren(bool keepChildren)
{
destroyChild(model,keepChildren);
destroyChild(renderer,keepChildren);
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != emitters.end(); ++it)
destroyChild(*it,keepChildren);
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
destroyChild(*it,keepChildren);
Registerable::destroyChildren(keepChildren);
}
Registerable* Group::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if (object != NULL)
return object;
object = model->findByName(name);
if (object != NULL)
return object;
if (renderer != NULL)
{
object = renderer->findByName(name);
if (object != NULL)
return object;
}
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != emitters.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
return NULL;
}
void Group::setModel(Model* newmodel)
{
if(!newmodel) newmodel = &getDefaultModel();
if(model == newmodel) return;
// empty and change model
empty();
decrementChildReference(model);
incrementChildReference(newmodel);
model = newmodel;
// recreate data
delete[] particleData;
delete[] particleCurrentParams;
delete[] particleExtendedParams;
particleData = new Particle::ParticleData[pool.getNbReserved()];
particleCurrentParams = new float[pool.getNbReserved() * model->getSizeOfParticleCurrentArray()];
particleExtendedParams = new float[pool.getNbReserved() * model->getSizeOfParticleExtendedArray()];
pool.clear();
// Destroys all the buffers
destroyAllBuffers();
}
void Group::setRenderer(Renderer* renderer)
{
decrementChildReference(this->renderer);
incrementChildReference(renderer);
if ((bufferManagement)&&(renderer != this->renderer))
{
if (this->renderer != NULL) this->renderer->destroyBuffers(*this);
if (renderer != NULL) renderer->createBuffers(*this);
}
this->renderer = renderer;
}
void Group::addEmitter(Emitter* emitter)
{
if (emitter == NULL)
return;
// Checks if the emitter is already in the group (since 1.03.03)
std::vector<Emitter*>::const_iterator it = std::find(emitters.begin(),emitters.end(),emitter);
if (it != emitters.end())
return;
incrementChildReference(emitter);
emitters.push_back(emitter);
}
void Group::removeEmitter(Emitter* emitter)
{
std::vector<Emitter*>::iterator it = std::find(emitters.begin(),emitters.end(),emitter);
if (it != emitters.end())
{
decrementChildReference(emitter);
emitters.erase(it);
}
}
void Group::addModifier(Modifier* modifier)
{
if (modifier == NULL)
return;
incrementChildReference(modifier);
if (bufferManagement)
modifier->createBuffers(*this);
modifiers.push_back(modifier);
}
void Group::removeModifier(Modifier* modifier)
{
std::vector<Modifier*>::iterator it = std::find(modifiers.begin(),modifiers.end(),modifier);
if (it != modifiers.end())
{
decrementChildReference(modifier);
if (bufferManagement)
(*it)->createBuffers(*this);
modifiers.erase(it);
}
}
bool Group::update(float deltaTime)
{
unsigned int nbManualBorn = nbBufferedParticles;
unsigned int nbAutoBorn = 0;
bool hasActiveEmitters = false;
// Updates emitters
activeEmitters.clear();
std::vector<Emitter*>::const_iterator endIt = emitters.end();
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != endIt; ++it)
{
if ((*it)->isActive())
{
int nb = (*it)->updateNumber(deltaTime);
if (nb > 0)
{
EmitterData data = {*it,nb};
activeEmitters.push_back(data);
nbAutoBorn += nb;
}
}
hasActiveEmitters |= !((*it)->isSleeping());
}
std::vector<EmitterData>::iterator emitterIt = activeEmitters.begin();
unsigned int nbBorn = nbAutoBorn + nbManualBorn;
// Inits bounding box
if (boundingBoxEnabled)
{
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
}
// Prepare modifiers for processing
activeModifiers.clear();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != modifiers.end(); ++it)
{
(*it)->beginProcess(*this);
if ((*it)->isActive())
activeModifiers.push_back(*it);
}
// Updates particles
for (size_t i = 0; i < pool.getNbActive(); ++i)
{
if ((pool[i].update(deltaTime))||((fupdate != NULL)&&((*fupdate)(pool[i],deltaTime))))
{
if (fdeath != NULL)
(*fdeath)(pool[i]);
if (nbBorn > 0)
{
pool[i].init();
launchParticle(pool[i],emitterIt,nbManualBorn);
--nbBorn;
}
else
{
particleData[i].sqrDist = 0.0f;
pool.makeInactive(i);
--i;
}
}
else
{
if (boundingBoxEnabled)
updateAABB(pool[i]);
if (distanceComputationEnabled)
pool[i].computeSqrDist();
}
}
// Terminates modifiers processing
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != modifiers.end(); ++it)
(*it)->endProcess(*this);
// Emits new particles if some left
for (int i = nbBorn; i > 0; --i)
pushParticle(emitterIt,nbManualBorn);
// Sorts particles if enabled
if ((sortingEnabled)&&(pool.getNbActive() > 1))
sortParticles(0,pool.getNbActive() - 1);
if ((!boundingBoxEnabled)||(pool.getNbActive() == 0))
{
AABBMin.set(0.0f,0.0f,0.0f);
AABBMax.set(0.0f,0.0f,0.0f);
}
return (hasActiveEmitters)||(pool.getNbActive() > 0);
}
void Group::pushParticle(std::vector<EmitterData>::iterator& emitterIt,unsigned int& nbManualBorn)
{
Particle* ptr = pool.makeActive();
if (ptr == NULL)
{
if (pool.getNbEmpty() > 0)
{
Particle p(this,pool.getNbActive());
launchParticle(p,emitterIt,nbManualBorn);
pool.pushActive(p);
}
else if (nbManualBorn > 0)
popNextManualAdding(nbManualBorn);
}
else
{
ptr->init();
launchParticle(*ptr,emitterIt,nbManualBorn);
}
}
void Group::launchParticle(Particle& p,std::vector<EmitterData>::iterator& emitterIt,unsigned int& nbManualBorn)
{
if (nbManualBorn == 0)
{
emitterIt->emitter->emit(p);
if (--emitterIt->nbParticles == 0)
++emitterIt;
}
else
{
CreationData creationData = creationBuffer.front();
if (creationData.zone != NULL)
creationData.zone->generatePosition(p,creationData.full);
else
p.position() = creationData.position;
if (creationData.emitter != NULL)
creationData.emitter->generateVelocity(p);
else
p.velocity() = creationData.velocity;
popNextManualAdding(nbManualBorn);
}
// Resets old position (fix 1.04.00)
p.oldPosition() = p.position();
// first parameter interpolation
// must be here so that the velocity has already been initialized
p.interpolateParameters();
if (fbirth != NULL)
(*fbirth)(p);
if (boundingBoxEnabled)
updateAABB(p);
if (distanceComputationEnabled)
p.computeSqrDist();
}
void Group::render()
{
if ((renderer == NULL)||(!renderer->isActive()))
return;
renderer->render(*this);
}
void Group::empty()
{
for (size_t i = 0; i < pool.getNbActive(); ++i)
particleData[i].sqrDist = 0.0f;
pool.makeAllInactive();
creationBuffer.clear();
nbBufferedParticles = 0;
}
void Group::flushAddedParticles()
{
unsigned int nbManualBorn = nbBufferedParticles;
std::vector<EmitterData>::iterator emitterIt; // dummy emitterIt because we dont care
while(nbManualBorn > 0)
pushParticle(emitterIt,nbManualBorn);
}
float Group::addParticles(const Vector3D& start,const Vector3D& end,Emitter* emitter,float step,float offset)
{
if ((step <= 0.0f)||(offset < 0.0f))
return 0.0f;
Vector3D displacement = end - start;
float totalDist = displacement.getNorm();
while(offset < totalDist)
{
Vector3D position = start;
position += displacement * offset / totalDist;
addParticles(1,position,Vector3D(),NULL,emitter);
offset += step;
}
return offset - totalDist;
}
float Group::addParticles(const Vector3D& start,const Vector3D& end,const Vector3D& velocity,float step,float offset)
{
if ((step <= 0.0f)||(offset < 0.0f))
return 0.0f;
Vector3D displacement = end - start;
float totalDist = displacement.getNorm();
while(offset < totalDist)
{
Vector3D position = start;
position += displacement * (offset / totalDist);
addParticles(1,position,velocity,NULL,NULL);
offset += step;
}
return offset - totalDist;
}
void Group::addParticles(unsigned int nb,const Vector3D& position,const Vector3D& velocity,const Zone* zone,Emitter* emitter,bool full)
{
if (nb == 0)
return;
CreationData data = {nb,position,velocity,zone,emitter,full};
creationBuffer.push_back(data);
nbBufferedParticles += nb;
}
void Group::addParticles(unsigned int nb,Emitter* emitter)
{
addParticles(nb,Vector3D(),Vector3D(),emitter->getZone(),emitter,emitter->isFullZone());
}
void Group::addParticles(const Zone* zone,Emitter* emitter,float deltaTime,bool full)
{
addParticles(emitter->updateNumber(deltaTime),Vector3D(),Vector3D(),zone,emitter,full);
}
void Group::addParticles(const Vector3D& position,Emitter* emitter,float deltaTime)
{
addParticles(emitter->updateNumber(deltaTime),position,Vector3D(),NULL,emitter);
}
void Group::addParticles(Emitter* emitter,float deltaTime)
{
addParticles(emitter->updateNumber(deltaTime),Vector3D(),Vector3D(),emitter->getZone(),emitter,emitter->isFullZone());
}
void Group::sortParticles()
{
computeDistances();
if (sortingEnabled)
sortParticles(0,pool.getNbActive() - 1);
}
void Group::computeDistances()
{
if (!distanceComputationEnabled)
return;
Pool<Particle>::const_iterator endIt = pool.end();
for (Pool<Particle>::iterator it = pool.begin(); it != endIt; ++it)
it->computeSqrDist();
}
void Group::computeAABB()
{
if ((!boundingBoxEnabled)||(pool.getNbActive() == 0))
{
AABBMin.set(0.0f,0.0f,0.0f);
AABBMax.set(0.0f,0.0f,0.0f);
return;
}
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
Pool<Particle>::iterator endIt = pool.end();
for (Pool<Particle>::iterator it = pool.begin(); it != endIt; ++it)
updateAABB(*it);
}
void Group::reallocate(size_t capacity)
{
if (capacity > pool.getNbReserved())
{
pool.reallocate(capacity);
Particle::ParticleData* newData = new Particle::ParticleData[pool.getNbReserved()];
float* newCurrentParams = new float[pool.getNbReserved() * model->getSizeOfParticleCurrentArray()];
float* newExtendedParams = new float[pool.getNbReserved() * model->getSizeOfParticleExtendedArray()];
memcpy(newData,particleData,pool.getNbTotal() * sizeof(Particle::ParticleData));
memcpy(newCurrentParams,particleCurrentParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleCurrentArray());
memcpy(newExtendedParams,particleExtendedParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleExtendedArray());
delete[] particleData;
delete[] particleCurrentParams;
delete[] particleExtendedParams;
particleData = newData;
particleCurrentParams = newCurrentParams;
particleExtendedParams = newExtendedParams;
for (Pool<Particle>::iterator it = pool.begin(); it != pool.endInactive(); ++it)
{
it->group = this;
it->data = particleData + it->index;
it->currentParams = particleCurrentParams + it->index * model->getSizeOfParticleCurrentArray();
it->extendedParams = particleExtendedParams + it->index * model->getSizeOfParticleExtendedArray();
}
// Destroys all the buffers
destroyAllBuffers();
}
}
void Group::popNextManualAdding(unsigned int& nbManualBorn)
{
--creationBuffer.front().nb;
--nbManualBorn;
--nbBufferedParticles;
if (creationBuffer.front().nb <= 0)
creationBuffer.pop_front();
}
void Group::updateAABB(const Particle& particle)
{
const Vector3D& position = particle.position();
if (AABBMin.x > position.x)
AABBMin.x = position.x;
if (AABBMin.y > position.y)
AABBMin.y = position.y;
if (AABBMin.z > position.z)
AABBMin.z = position.z;
if (AABBMax.x < position.x)
AABBMax.x = position.x;
if (AABBMax.y < position.y)
AABBMax.y = position.y;
if (AABBMax.z < position.z)
AABBMax.z = position.z;
}
const void* Group::getParamAddress(ModelParam param) const
{
return particleCurrentParams + model->getParameterOffset(param);
}
size_t Group::getParamStride() const
{
return model->getSizeOfParticleCurrentArray() * sizeof(float);
}
Buffer* Group::createBuffer(const std::string& ID,const BufferCreator& creator,unsigned int flag,bool swapEnabled) const
{
destroyBuffer(ID);
Buffer* buffer = creator.createBuffer(pool.getNbReserved(),*this);
buffer->flag = flag;
buffer->swapEnabled = swapEnabled;
additionalBuffers.insert(std::pair<std::string,Buffer*>(ID,buffer));
if (swapEnabled)
swappableBuffers.insert(buffer);
return buffer;
}
void Group::destroyBuffer(const std::string& ID) const
{
std::map<std::string,Buffer*>::iterator it = additionalBuffers.find(ID);
if (it != additionalBuffers.end())
{
if (it->second->isSwapEnabled())
swappableBuffers.erase(it->second);
delete it->second;
additionalBuffers.erase(it);
}
}
void Group::destroyAllBuffers() const
{
for (std::map<std::string,Buffer*>::const_iterator it = additionalBuffers.begin(); it != additionalBuffers.end(); ++it)
delete it->second;
additionalBuffers.clear();
swappableBuffers.clear();
}
Buffer* Group::getBuffer(const std::string& ID,unsigned int flag) const
{
Buffer* buffer = getBuffer(ID);
if ((buffer != NULL)&&(buffer->flag == flag))
return buffer;
return NULL;
}
Buffer* Group::getBuffer(const std::string& ID) const
{
std::map<std::string,Buffer*>::const_iterator it = additionalBuffers.find(ID);
if (it != additionalBuffers.end())
return it->second;
return NULL;
}
void Group::enableBuffersManagement(bool manage)
{
bufferManagement = manage;
}
bool Group::isBuffersManagementEnabled()
{
return bufferManagement;
}
void Group::sortParticles(int start,int end)
{
if (start < end)
{
int i = start - 1;
int j = end + 1;
float pivot = particleData[(start + end) >> 1].sqrDist;
while (true)
{
do ++i;
while (particleData[i].sqrDist > pivot);
do --j;
while (particleData[j].sqrDist < pivot);
if (i < j)
swapParticles(pool[i],pool[j]);
else break;
}
sortParticles(start,j);
sortParticles(j + 1,end);
}
}
void Group::propagateUpdateTransform()
{
for (std::vector<Emitter*>::const_iterator emitterIt = emitters.begin(); emitterIt != emitters.end(); ++emitterIt)
(*emitterIt)->updateTransform(this);
for (std::vector<Modifier*>::const_iterator modifierIt = modifiers.begin(); modifierIt != modifiers.end(); ++modifierIt)
if ((*modifierIt)->isLocalToSystem())
(*modifierIt)->updateTransform(this);
}
Model& Group::getDefaultModel()
{
static Model defaultModel;
return defaultModel;
}
}

View File

@ -0,0 +1,148 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Interpolator.h"
#include "Core/SPK_Model.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Interpolator::computeXFn Interpolator::COMPUTE_X_FN[4] =
{
&Interpolator::computeXLifeTime,
&Interpolator::computeXAge,
&Interpolator::computeXParam,
&Interpolator::computeXVelocity,
};
Interpolator::Interpolator() :
graph(),
type(INTERPOLATOR_LIFETIME),
param(PARAM_SIZE),
scaleXVariation(0.0f),
offsetXVariation(0.0f),
loopingEnabled(false)
{}
float Interpolator::computeXLifeTime(const Particle& particle) const
{
return particle.getAge() / (particle.getAge() + particle.getLifeLeft());
}
float Interpolator::computeXAge(const Particle& particle) const
{
return particle.getAge();
}
float Interpolator::computeXParam(const Particle& particle) const
{
return particle.getParamCurrentValue(param);
}
float Interpolator::computeXVelocity(const Particle& particle) const
{
return particle.velocity().getSqrNorm();
}
float Interpolator::interpolate(const Particle& particle,ModelParam interpolatedParam,float ratioY,float offsetX,float scaleX)
{
// First finds the current X of the particle
InterpolatorEntry currentKey((this->*Interpolator::COMPUTE_X_FN[type])(particle));
currentKey.x += offsetX; // Offsets it
currentKey.x *= scaleX; // Scales it
if (loopingEnabled)
{
// If the graph has les than 2 entries, we cannot loop
if (graph.size() < 2)
{
if (graph.empty())
return Model::getDefaultValue(interpolatedParam);
else
return interpolateY(*(graph.begin()),ratioY);
}
// Else finds the current X in the range
float newX = (currentKey.x - graph.begin()->x) / (graph.rbegin()->x - graph.begin()->x);
newX -= static_cast<int>(newX);
if (newX < 0.0f)
newX = 1.0f + newX;
currentKey.x = graph.begin()->x + newX * (graph.rbegin()->x - graph.begin()->x);
}
// Gets the entry that is immediatly after the current X
std::set<InterpolatorEntry>::const_iterator nextIt = graph.upper_bound(currentKey);
// If the current X is higher than the one of the last entry
if (nextIt == graph.end())
{
if (graph.empty()) // If the graph has no entry, sets the default value
return Model::getDefaultValue(interpolatedParam);
else // Else sets the value of the last entry
return interpolateY(*(--nextIt),ratioY);
}
else if (nextIt == graph.begin()) // If the current X is lower than the first entry, sets the value to the first entry
{
return interpolateY(*nextIt,ratioY);
}
else // Else interpolated between the entries before and after the current X
{
const InterpolatorEntry& nextEntry = *nextIt;
const InterpolatorEntry& previousEntry = *(--nextIt);
float y0 = interpolateY(previousEntry,ratioY);
float y1 = interpolateY(nextEntry,ratioY);
float ratioX = (currentKey.x - previousEntry.x) / (nextEntry.x - previousEntry.x);
return y0 + ratioX * (y1 - y0);
}
}
void Interpolator::generateSinCurve(float period,float amplitudeMin,float amplitudeMax,float offsetX,float offsetY,float startX,unsigned int length,unsigned int nbSamples)
{
// First clear any previous entry
clearGraph();
const float PI = 3.1415926535897932384626433832795f;
for (size_t i = 0; i < nbSamples; ++i)
{
float x = startX + i * period * length / (nbSamples - 1);
float sin = std::sin((x + offsetX) * 2 * PI / period);
addEntry(x,amplitudeMin * sin + offsetY,amplitudeMax * sin + offsetY);
}
}
void Interpolator::generatePolyCurve(float constant,float linear,float quadratic,float cubic,float startX,float endX,unsigned int nbSamples)
{
// First clear any previous entry
clearGraph();
for (size_t i = 0; i < nbSamples; ++i)
{
float x = startX + i * (endX - startX) / (nbSamples - 1);
float x2 = x * x;
float x3 = x2 * x;
addEntry(x,constant + x * linear + x2 * quadratic + x3 * cubic);
}
}
}

View File

@ -0,0 +1,299 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Model.h"
#include "Core/SPK_Interpolator.h"
namespace SPK
{
const float Model::DEFAULT_VALUES[NB_PARAMS] =
{
1.0f, // RED
1.0f, // GREEN
1.0f, // BLUE
1.0f, // ALPHA
1.0f, // SIZE
1.0f, // MASS
0.0f, // ANGLE
0.0f, // TEXTURE_INDEX
0.0f, // ROTATION_SPEED
0.0f, // CUSTOM_0
0.0f, // CUSTOM_1
0.0f, // CUSTOM_2
};
Model::Model(int enableFlag,int mutableFlag,int randomFlag,int interpolatedFlag) :
Registerable(),
lifeTimeMin(1.0f),
lifeTimeMax(1.0f),
immortal(false),
paramsSize(0),
nbEnableParams(0),
nbMutableParams(0),
nbRandomParams(0),
nbInterpolatedParams(0)
{
enableFlag |= FLAG_RED | FLAG_GREEN | FLAG_BLUE; // Adds the color parameters to the enable flag
this->enableFlag = enableFlag & ((1 << (NB_PARAMS + 1)) - 1); // masks the enable flag with the existing parameters
this->interpolatedFlag = interpolatedFlag & this->enableFlag; // masks the interpolated flag with the enable flag
this->mutableFlag = mutableFlag & this->enableFlag; // masks the mutable flag with the enable flag
this->mutableFlag &= ~this->interpolatedFlag; // a param cannot be both interpolated and mutable
this->randomFlag = randomFlag & this->enableFlag; // masks the random flag with the enable flag
this->randomFlag &= ~this->interpolatedFlag; // a param cannot be both interpolated and random
int particleEnableParamsSize = 0;
int particleMutableParamsSize = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
{
ModelParam param = static_cast<ModelParam>(i);
int paramSize = 0;
if (isEnabled(param))
{
++nbEnableParams;
if (!isInterpolated(param))
{
interpolators[i] = NULL;
paramSize = 1;
if (isMutable(param))
{
paramSize = 2;
++nbMutableParams;
}
if (isRandom(param))
{
paramSize <<= 1;
++nbRandomParams;
}
}
else
{
interpolators[i] = new Interpolator(); // Creates the interpolator
++nbInterpolatedParams;
}
}
else
interpolators[i] = NULL;
particleEnableIndices[i] = particleEnableParamsSize;
particleMutableIndices[i] = particleMutableParamsSize;
particleEnableParamsSize += isEnabled(param) >> i;
particleMutableParamsSize += isMutable(param) >> i;
indices[i] = paramsSize;
paramsSize += paramSize;
}
// creates the array of params for this model
if (paramsSize > 0)
{
params = new float[paramsSize];
unsigned int currentParamIndex = 0;
unsigned int currentIndex = 0;
while (currentIndex < paramsSize)
{
unsigned int nbValues = getNbValues(static_cast<ModelParam>(currentParamIndex));
for (size_t i = 0; i < nbValues; ++i)
params[currentIndex + i] = DEFAULT_VALUES[currentParamIndex];
++currentParamIndex;
currentIndex += nbValues;
}
}
else
params = NULL;
if (nbEnableParams > 0)
{
enableParams = new int[nbEnableParams];
size_t index = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
if (isEnabled(static_cast<ModelParam>(i)))
enableParams[index++] = i;
}
else
enableParams = NULL;
if (nbMutableParams > 0)
{
mutableParams = new int[nbMutableParams];
size_t index = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
if (isMutable(static_cast<ModelParam>(i)))
mutableParams[index++] = i;
}
else
mutableParams = NULL;
if (nbInterpolatedParams > 0)
{
interpolatedParams = new int[nbInterpolatedParams];
size_t index = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
if (isInterpolated(static_cast<ModelParam>(i)))
interpolatedParams[index++] = i;
}
else
interpolatedParams = NULL;
}
Model::Model(const Model& model) :
Registerable(model),
lifeTimeMin(model.lifeTimeMin),
lifeTimeMax(model.lifeTimeMax),
immortal(model.immortal),
paramsSize(model.paramsSize),
nbEnableParams(model.nbEnableParams),
nbMutableParams(model.nbMutableParams),
nbRandomParams(model.nbRandomParams),
nbInterpolatedParams(model.nbInterpolatedParams),
enableFlag(model.enableFlag),
mutableFlag(model.mutableFlag),
randomFlag(model.randomFlag),
interpolatedFlag(model.interpolatedFlag),
params(NULL),
enableParams(NULL),
mutableParams(NULL),
interpolatedParams(NULL)
{
if (paramsSize > 0)
{
params = new float[paramsSize];
for (size_t i = 0; i < paramsSize; ++i)
params[i] = model.params[i];
}
if (nbEnableParams > 0)
{
enableParams = new int[nbEnableParams];
for (size_t i = 0; i < nbEnableParams; ++i)
enableParams[i] = model.enableParams[i];
}
if (nbMutableParams > 0)
{
mutableParams = new int[nbMutableParams];
for (size_t i = 0; i < nbMutableParams; ++i)
mutableParams[i] = model.mutableParams[i];
}
if (nbInterpolatedParams > 0)
{
interpolatedParams = new int[nbMutableParams];
for (size_t i = 0; i < nbInterpolatedParams; ++i)
interpolatedParams[i] = model.interpolatedParams[i];
}
for (size_t i = 0; i < NB_PARAMS; ++i)
{
indices[i] = model.indices[i];
particleEnableIndices[i] = model.particleEnableIndices[i];
particleMutableIndices[i] = model.particleMutableIndices[i];
if (model.interpolators[i] != NULL)
interpolators[i] = new Interpolator(*model.interpolators[i]);
else
interpolators[i] = NULL;
}
}
Model::~Model()
{
delete[] enableParams;
delete[] mutableParams;
delete[] interpolatedParams;
delete[] params;
for (size_t i = 0; i < NB_PARAMS; ++i)
delete interpolators[i];
}
bool Model::setParam(ModelParam type,float startMin,float startMax,float endMin,float endMax)
{
// if the given param doesnt have 4 values, return
if (getNbValues(type) != 4)
return false;
// Sets the values at the right position in params
float* ptr = params + indices[type];
*ptr++ = startMin;
*ptr++ = startMax;
*ptr++ = endMin;
*ptr = endMax;
return true;
}
bool Model::setParam(ModelParam type,float value0,float value1)
{
// if the given param doesnt have 2 values, return
if (getNbValues(type) != 2)
return false;
// Sets the values at the right position in params
float* ptr = params + indices[type];
*ptr++ = value0;
*ptr = value1;
return true;
}
bool Model::setParam(ModelParam type,float value)
{
// if the given param doesnt have 1 value, return
if (getNbValues(type) != 1)
return false;
// Sets the value at the right position in params
params[indices[type]] = value;
return true;
}
float Model::getParamValue(ModelParam type,size_t index) const
{
unsigned int nbValues = getNbValues(type);
if (index < nbValues)
return params[indices[type] + index];
return DEFAULT_VALUES[type];
}
unsigned int Model::getNbValues(ModelParam type) const
{
int value = 1 << type;
if (!(enableFlag & value) || (interpolatedFlag & value))
return 0;
if (!(mutableFlag & value) && !(randomFlag & value))
return 1;
if ((mutableFlag & value) && (randomFlag & value))
return 4;
return 2;
}
float Model::getDefaultValue(ModelParam param)
{
return DEFAULT_VALUES[param];
}
}

View File

@ -0,0 +1,100 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Modifier.h"
namespace SPK
{
Vector3D Modifier::intersection;
Vector3D Modifier::normal;
Modifier::Modifier(int availableTriggers,ModifierTrigger trigger,bool needsIntersection,bool needsNormal,Zone* zone) :
Registerable(),
Transformable(),
BufferHandler(),
availableTriggers(availableTriggers),
trigger(trigger),
zone(zone),
needsIntersection(needsIntersection),
needsNormal(needsNormal),
full(false),
active(true),
local(false)
{}
void Modifier::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
registerChild(zone,registerAll);
}
void Modifier::copyChildren(const Modifier& modifier,bool createBase)
{
Registerable::copyChildren(modifier,createBase);
zone = dynamic_cast<Zone*>(copyChild(modifier.zone,createBase));
}
void Modifier::destroyChildren(bool keepChildren)
{
destroyChild(zone,keepChildren);
Registerable::destroyChildren(keepChildren);
}
Registerable* Modifier::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if ((object != NULL)||(zone == NULL))
return object;
return zone->findByName(name);
}
void Modifier::setZone(Zone* zone,bool full)
{
decrementChildReference(this->zone);
incrementChildReference(zone);
this->zone = zone;
this->full = full;
}
bool Modifier::setTrigger(ModifierTrigger trigger)
{
if ((trigger & availableTriggers) != 0)
{
this->trigger = trigger;
return true;
}
return false;
}
void Modifier::beginProcess(Group& group)
{
savedActive = active;
if (!active)
return;
if (!prepareBuffers(group))
active = false; // if buffers of the modifier in the group are not ready, the modifier is made incative for the frame
}
}

View File

@ -0,0 +1,237 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_Modifier.h"
#include "Core/SPK_System.h"
#include "Core/SPK_Buffer.h"
#include "Core/SPK_Interpolator.h"
namespace SPK
{
Particle::Particle(Group* group,size_t index) :
group(group),
index(index),
data(group->particleData + index),
currentParams(group->particleCurrentParams + index * group->model->getSizeOfParticleCurrentArray()),
extendedParams(group->particleExtendedParams + index * group->model->getSizeOfParticleExtendedArray())
{
init();
}
void Particle::init()
{
const Model* model = group->getModel();
data->age = 0.0f;
data->life = random(model->lifeTimeMin,model->lifeTimeMax);
// creates pseudo-iterators to parse arrays
float* particleCurrentIt = currentParams;
float* particleMutableIt = extendedParams;
float* particleInterpolatedIt = extendedParams + model->nbMutableParams;
const int* paramIt = model->enableParams;
// initializes params
for (size_t i = model->nbEnableParams; i != 0; --i)
{
ModelParam param = static_cast<ModelParam>(*paramIt);
const float* templateIt = &model->params[model->indices[param]];
if (model->isInterpolated(param))
{
*particleCurrentIt++ = Model::DEFAULT_VALUES[param];
*particleInterpolatedIt++ = random(0.0f,1.0f); // ratioY
Interpolator* interpolator = model->interpolators[param];
float offsetVariation = interpolator->getOffsetXVariation();
float scaleVariation = interpolator->getScaleXVariation();
*particleInterpolatedIt++ = random(-offsetVariation,offsetVariation); // offsetX
*particleInterpolatedIt++ = 1.0f + random(-scaleVariation,scaleVariation); // scaleX
}
else if (model->isRandom(param))
{
*particleCurrentIt++ = random(*templateIt,*(templateIt + 1));
if (model->isMutable(param))
*particleMutableIt++ = random(*(templateIt + 2),*(templateIt + 3));
}
else
{
*particleCurrentIt++ = *templateIt;
if (model->isMutable(param))
*particleMutableIt++ = *(templateIt + 1);
}
++paramIt;
}
}
void Particle::interpolateParameters()
{
const Model* model = group->getModel();
float* interpolatedIt = extendedParams + model->nbMutableParams;
for (size_t i = 0; i < model->nbInterpolatedParams; ++i)
{
size_t index = model->interpolatedParams[i];
size_t enableIndex = model->particleEnableIndices[index];
currentParams[enableIndex] = model->interpolators[index]->interpolate(*this,static_cast<ModelParam>(index),interpolatedIt[0],interpolatedIt[1],interpolatedIt[2]);
interpolatedIt += 3;
}
}
bool Particle::update(float deltaTime)
{
const Model* model = group->getModel();
data->age += deltaTime;
if (!model->immortal)
{
// computes the ratio between the life of the particle and its lifetime
float ratio = std::min(1.0f,deltaTime / data->life);
data->life -= deltaTime;
// updates mutable parameters
for (size_t i = 0; i < model->nbMutableParams; ++i)
{
size_t index = model->mutableParams[i];
size_t enableIndex = model->particleEnableIndices[index];
currentParams[enableIndex] += (extendedParams[i] - currentParams[enableIndex]) * ratio;
}
}
// updates interpolated parameters
interpolateParameters();
// updates position
oldPosition() = position();
position() += velocity() * deltaTime;
// updates velocity
velocity() += group->getGravity() * deltaTime;
std::vector<Modifier*>::const_iterator end = group->activeModifiers.end();
for (std::vector<Modifier*>::const_iterator it = group->activeModifiers.begin(); it != end; ++it)
(*it)->process(*this,deltaTime);
if (group->getFriction() != 0.0f)
velocity() *= 1.0f - std::min(1.0f,group->getFriction() * deltaTime / getParamCurrentValue(PARAM_MASS));
return data->life <= 0.0f;
}
bool Particle::setParamCurrentValue(ModelParam type,float value)
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
{
currentParams[model->particleEnableIndices[type]] = value;
return true;
}
return false;
}
bool Particle::setParamFinalValue(ModelParam type,float value)
{
const Model* const model = group->getModel();
if (model->isMutable(type))
{
extendedParams[model->particleMutableIndices[type]] = value;
return true;
}
return false;
}
bool Particle::changeParamCurrentValue(ModelParam type,float delta)
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
{
currentParams[model->particleEnableIndices[type]] += delta;
return true;
}
return false;
}
bool Particle::changeParamFinalValue(ModelParam type,float delta)
{
const Model* const model = group->getModel();
if (model->isMutable(type))
{
extendedParams[model->particleMutableIndices[type]] += delta;
return true;
}
return false;
}
float Particle::getParamCurrentValue(ModelParam type) const
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
return currentParams[model->particleEnableIndices[type]];
return Model::DEFAULT_VALUES[type];
}
float Particle::getParamFinalValue(ModelParam type) const
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
{
if (model->isMutable(type))
return extendedParams[model->particleMutableIndices[type] + 1];
return currentParams[model->particleEnableIndices[type]];
}
return Model::DEFAULT_VALUES[type];
}
Model* Particle::getModel() const
{
return group->getModel();
}
void Particle::computeSqrDist()
{
data->sqrDist = getSqrDist(position(),System::getCameraPosition());
}
extern void swapParticles(Particle& a,Particle& b)
{
//std::swap(a.index,b.index);
std::swap(*a.data,*b.data);
for (size_t i = 0; i < a.getModel()->getSizeOfParticleCurrentArray(); ++i)
std::swap(a.currentParams[i],b.currentParams[i]);
for (size_t i = 0; i < a.getModel()->getSizeOfParticleExtendedArray(); ++i)
std::swap(a.extendedParams[i],b.extendedParams[i]);
// swap additional data (groups are assumed to be the same)
for (std::set<Buffer*>::iterator it = a.group->swappableBuffers.begin(); it != a.group->swappableBuffers.end(); ++it)
(*it)->swap(a.index,b.index);
}
}

View File

@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Registerable.h"
#include "Core/SPK_Factory.h"
namespace SPK
{
const SPK_ID NO_ID(0);
const std::string NO_NAME;
Registerable::Registerable() :
ID(NO_ID),
nbReferences(0),
shared(false),
destroyable(true),
name(NO_NAME)
{}
Registerable::Registerable(const Registerable& registerable) :
ID(NO_ID),
nbReferences(0),
shared(registerable.shared),
destroyable(registerable.destroyable),
name(registerable.name)
{}
Registerable::~Registerable(){}
Registerable* Registerable::copyChild(Registerable* child,bool createBase)
{
if (child == NULL)
return NULL;
if (((child->isRegistered())&&(!child->isShared()))||(createBase))
{
if (SPKFactory::getInstance().isAlreadyProcessed(child))
{
Registerable* processedClone = SPKFactory::getInstance().getProcessedObject(child);
processedClone->incrementReference();
return processedClone;
}
Registerable* cloneChild = child->clone(createBase);
SPKFactory::getInstance().registerObject(cloneChild);
cloneChild->incrementReference();
SPKFactory::getInstance().markAsProcessed(child,cloneChild);
return cloneChild;
}
child->incrementReference();
return child;
}
bool Registerable::destroyChild(Registerable* child,bool keepChildren)
{
if ((child == NULL)||(keepChildren))
return false;
child->decrementReference();
if ((child->isRegistered())&&
(child->isDestroyable())&&
(child->getNbReferences() == 0))
{
SPKFactory::getInstance().unregisterObject(child->getSPKID());
return true;
}
return false;
}
void Registerable::registerChild(Registerable* child,bool registerAll)
{
if (child == NULL)
return;
if (child->isRegistered())
{
child->incrementReference();
child->registerChildren(registerAll);
}
else if (registerAll)
{
SPKFactory::getInstance().registerObject(child);
child->incrementReference();
child->registerChildren(registerAll);
}
}
void Registerable::registerObject(Registerable* obj,bool registerAll)
{
if ((obj != NULL)&&(!obj->isRegistered()))
{
SPKFactory::getInstance().registerObject(obj);
obj->registerChildren(registerAll);
}
}
}

View File

@ -0,0 +1,37 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Renderer.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Renderer::Renderer() :
Registerable(),
BufferHandler(),
active(true),
renderingHintsMask(DEPTH_TEST | DEPTH_WRITE),
alphaThreshold(1.0f)
{}
Renderer::~Renderer(){}
}

View File

@ -0,0 +1,330 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_System.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Emitter.h"
#include "Core/SPK_Modifier.h"
namespace SPK
{
Vector3D System::cameraPosition;
StepMode System::stepMode(STEP_REAL);
float System::constantStep(0.0f);
float System::minStep(0.0f);
float System::maxStep(0.0f);
bool System::clampStepEnabled(false);
float System::clampStep(1.0f);
System::System() :
Registerable(),
Transformable(),
groups(),
nbParticles(0),
boundingBoxEnabled(false),
AABBMin(),
AABBMax(),
deltaStep(0.0f)
{}
void System::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
registerChild(*it,registerAll);
}
void System::copyChildren(const System& system,bool createBase)
{
Registerable::copyChildren(system,createBase);
// we clear the copies of pointers pushed in the vectors by the copy constructor
groups.clear();
for (std::vector<Group*>::const_iterator it = system.groups.begin(); it != system.groups.end(); ++it)
groups.push_back(dynamic_cast<Group*>(copyChild(*it,createBase)));
}
void System::destroyChildren(bool keepChildren)
{
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
destroyChild(*it,keepChildren);
Registerable::destroyChildren(keepChildren);
}
void System::addGroup(Group* group)
{
incrementChildReference(group);
groups.push_back(group);
nbParticles += group->getNbParticles();
}
void System::removeGroup(Group* group)
{
std::vector<Group*>::iterator it = std::find(groups.begin(),groups.end(),group);
if (it != groups.end())
{
decrementChildReference(group);
groups.erase(it);
}
}
size_t System::computeNbParticles()
{
nbParticles = 0;
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
nbParticles += (*it)->getNbParticles();
return nbParticles;
}
bool System::innerUpdate(float deltaTime)
{
nbParticles = 0;
bool isAlive = false;
bool hasGroupsWithAABB = false;
if (boundingBoxEnabled)
{
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
}
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
{
isAlive |= (*it)->update(deltaTime);
nbParticles += (*it)->getNbParticles();
if ((boundingBoxEnabled)&&((*it)->isAABBComputingEnabled()))
{
Vector3D groupMin = (*it)->getAABBMin();
Vector3D groupMax = (*it)->getAABBMax();
if (AABBMin.x > groupMin.x)
AABBMin.x = groupMin.x;
if (AABBMin.y > groupMin.y)
AABBMin.y = groupMin.y;
if (AABBMin.z > groupMin.z)
AABBMin.z = groupMin.z;
if (AABBMax.x < groupMax.x)
AABBMax.x = groupMax.x;
if (AABBMax.y < groupMax.y)
AABBMax.y = groupMax.y;
if (AABBMax.z < groupMax.z)
AABBMax.z = groupMax.z;
hasGroupsWithAABB = true;
}
}
if ((!boundingBoxEnabled)||(!hasGroupsWithAABB))
{
AABBMin.set(0.0f,0.0f,0.0f);
AABBMax.set(0.0f,0.0f,0.0f);
}
return isAlive;
}
bool System::update(float deltaTime)
{
if ((clampStepEnabled)&&(deltaTime > clampStep))
deltaTime = clampStep;
if (stepMode != STEP_REAL)
{
deltaTime += deltaStep;
float updateStep;
if (stepMode == STEP_ADAPTIVE)
{
if (deltaTime > maxStep)
updateStep = maxStep;
else if (deltaTime < minStep)
updateStep = minStep;
else
{
deltaStep = 0.0f;
return innerUpdate(deltaTime);
}
}
else
updateStep = constantStep;
bool isAlive = true;
while(deltaTime >= updateStep)
{
if ((isAlive)&&(!innerUpdate(updateStep)))
isAlive = false;
deltaTime -= updateStep;
}
deltaStep = deltaTime;
return isAlive;
}
else
return innerUpdate(deltaTime);
}
void System::render() const
{
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->render();
}
void System::grow(float time,float step)
{
if (step <= 0.0f)
step = time;
while (time > 0.0f)
{
float currentStep = time > step ? step : time;
update(currentStep);
time -= currentStep;
}
}
void System::empty()
{
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->empty();
nbParticles = 0;
}
void System::setCameraPosition(const Vector3D& cameraPosition)
{
System::cameraPosition = cameraPosition;
}
void System::setClampStep(bool enableClampStep,float clamp)
{
clampStepEnabled = enableClampStep;
clampStep = clamp;
}
void System::useConstantStep(float constantStep)
{
stepMode = STEP_CONSTANT;
System::constantStep = constantStep;
}
void System::useAdaptiveStep(float minStep,float maxStep)
{
stepMode = STEP_ADAPTIVE;
System::minStep = minStep;
System::maxStep = maxStep;
}
void System::useRealStep()
{
stepMode = STEP_REAL;
}
const Vector3D& System::getCameraPosition()
{
return cameraPosition;
}
StepMode System::getStepMode()
{
return stepMode;
}
void System::sortParticles()
{
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->sortParticles();
}
void System::computeDistances()
{
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->computeDistances();
}
void System::computeAABB()
{
if (boundingBoxEnabled)
{
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
}
bool hasGroupsWithAABB = false;
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
{
(*it)->computeAABB();
if ((boundingBoxEnabled)&&((*it)->isAABBComputingEnabled()))
{
Vector3D groupMin = (*it)->getAABBMin();
Vector3D groupMax = (*it)->getAABBMax();
if (AABBMin.x > groupMin.x)
AABBMin.x = groupMin.x;
if (AABBMin.y > groupMin.y)
AABBMin.y = groupMin.y;
if (AABBMin.z > groupMin.z)
AABBMin.z = groupMin.z;
if (AABBMax.x < groupMax.x)
AABBMax.x = groupMax.x;
if (AABBMax.y < groupMax.y)
AABBMax.y = groupMax.y;
if (AABBMax.z < groupMax.z)
AABBMax.z = groupMax.z;
hasGroupsWithAABB = true;
}
}
if ((!boundingBoxEnabled)||(!hasGroupsWithAABB))
{
const Vector3D pos = getWorldTransformPos();
AABBMin = AABBMax = pos;
}
}
Registerable* System::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if (object != NULL)
return object;
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
return NULL;
}
void System::propagateUpdateTransform()
{
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->updateTransform(this);
}
}

View File

@ -0,0 +1,239 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Transformable.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
const float Transformable::IDENTITY[] =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
Transformable::Transformable() :
currentUpdate(0),
lastUpdate(0),
lastParentUpdate(0),
parent(NULL),
localIdentity(true)
{
memcpy(local,IDENTITY,sizeof(float) * TRANSFORM_LENGTH);
memcpy(world,IDENTITY,sizeof(float) * TRANSFORM_LENGTH);
}
Transformable::Transformable(const Transformable& transformable) :
currentUpdate(0),
lastUpdate(0),
lastParentUpdate(0),
parent(NULL),
localIdentity(transformable.localIdentity)
{
memcpy(local,transformable.local,sizeof(float) * TRANSFORM_LENGTH);
memcpy(world,transformable.world,sizeof(float) * TRANSFORM_LENGTH);
}
void Transformable::setTransformNC(const float* transform)
{
for (size_t i = 0; i < TRANSFORM_LENGTH; ++i)
local[i] = transform[(i >> 2) + ((i & 3) << 2)]; // conversion
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformPosition(const Vector3D& pos)
{
local[12] = pos.x;
local[13] = pos.y;
local[14] = pos.z;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationRH(Vector3D look,Vector3D up)
{
look.normalize();
up.normalize();
Vector3D side = crossProduct(look,up);
side.normalize();
up = crossProduct(side,look);
local[0] = side.x;
local[1] = side.y;
local[2] = side.z;
local[4] = up.x;
local[5] = up.y;
local[6] = up.z;
local[8] = -look.x;
local[9] = -look.y;
local[10] = -look.z;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationLH(Vector3D look,Vector3D up)
{
look.normalize();
Vector3D side = crossProduct(look,up);
side.normalize();
up = crossProduct(side,look);
local[0] = side.x;
local[1] = side.y;
local[2] = side.z;
local[4] = up.x;
local[5] = up.y;
local[6] = up.z;
local[8] = look.x;
local[9] = look.y;
local[10] = look.z;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientation(Vector3D axis,float angle)
{
axis.normalize();
float c = std::cos(angle);
float s = std::sin(angle);
float a = 1 - c;
Vector3D axis2(axis.x * axis.x,axis.y * axis.y,axis.z * axis.z);
local[0] = axis2.x + (1 - axis2.x) * c;
local[1] = axis.x * axis.y * a + axis.z * s;
local[2] = axis.x * axis.z * a - axis.y * s;
local[4] = axis.x * axis.y * a - axis.z * s;
local[5] = axis2.y + (1 - axis2.y) * c;
local[6] = axis.y * axis.z * a + axis.x * s;
local[8] = axis.x * axis.z * a + axis.y * s;
local[9] = axis.y * axis.z * a - axis.x * s;
local[10] = axis2.z + (1 - axis2.z) * c;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationX(float angle)
{
float cosA = std::cos(angle);
float sinA = std::sin(angle);
local[0] = 1.0f;
local[1] = 0.0f;
local[2] = 0.0f;
local[4] = 0.0f;
local[5] = cosA;
local[6] = sinA;
local[8] = 0.0f;
local[9] = -sinA;
local[10] = cosA;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationY(float angle)
{
float cosA = std::cos(angle);
float sinA = std::sin(angle);
local[0] = cosA;
local[1] = 0.0f;
local[2] = -sinA;
local[4] = 0.0f;
local[5] = 1.0f;
local[6] = 0.0f;
local[8] = sinA;
local[9] = 0.0f;
local[10] = cosA;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationZ(float angle)
{
float cosA = std::cos(angle);
float sinA = std::sin(angle);
local[0] = cosA;
local[1] = sinA;
local[2] = 0.0f;
local[4] = -sinA;
local[5] = cosA;
local[6] = 0.0f;
local[8] = 0.0f;
local[9] = 0.0f;
local[10] = 1.0f;
localIdentity = false;
notifyForUpdate();
}
void Transformable::updateTransform(const Transformable* parent)
{
if (isUpdateNotified() || // the local transform or instance param have been updated
parent != this->parent || // the parent has changed
(parent != NULL && lastParentUpdate != parent->currentUpdate)) // the parent transform has been modified
{
if (parent == NULL)
memcpy(world,local,sizeof(float) * TRANSFORM_LENGTH);
else if (isLocalIdentity())
{
memcpy(world,parent->world,sizeof(float) * TRANSFORM_LENGTH);
lastParentUpdate = parent->lastUpdate;
}
else
{
multiply(world,parent->world,local);
lastParentUpdate = parent->lastUpdate;
}
this->parent = parent;
lastUpdate = ++currentUpdate;
innerUpdateTransform();
}
propagateUpdateTransform();
}
void Transformable::transformPos(Vector3D& tPos,const Vector3D& pos)
{
multiply(tPos,pos,world);
}
void Transformable::transformDir(Vector3D& tDir,const Vector3D& dir)
{
rotate(tDir,dir,world); // To transform a direction, the translation is ignored
}
}

View File

@ -0,0 +1,177 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Vector3D.h"
namespace SPK
{
Vector3D::Vector3D(float x,float y,float z) :
x(x),
y(y),
z(z) {}
Vector3D& Vector3D::operator+=(const Vector3D& v)
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
Vector3D& Vector3D::operator-=(const Vector3D& v)
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
Vector3D& Vector3D::operator+=(float f)
{
x += f;
y += f;
z += f;
return *this;
}
Vector3D& Vector3D::operator-=(float f)
{
x -= f;
y -= f;
z -= f;
return *this;
}
Vector3D& Vector3D::operator*=(float f)
{
x *= f;
y *= f;
z *= f;
return *this;
}
Vector3D& Vector3D::operator/=(float f)
{
f = 1.0f / f;
x *= f;
y *= f;
z *= f;
return *this;
}
float& Vector3D::operator[](size_t index)
{
switch(index)
{
case 0 : return x;
case 1 : return y;
default : return z;
}
}
const float& Vector3D::operator[](size_t index) const
{
switch(index)
{
case 0 : return x;
case 1 : return y;
default : return z;
}
}
void Vector3D::set(float x,float y,float z)
{
this->x = x;
this->y = y;
this->z = z;
}
bool Vector3D::normalize()
{
float norm = getNorm();
if (norm != 0.0f)
{
x /= norm;
y /= norm;
z /= norm;
return true;
}
return false;
}
void Vector3D::revert()
{
x = -x;
y = -y;
z = -z;
}
void Vector3D::abs()
{
if (x < 0.0f) x = -x;
if (y < 0.0f) y = -y;
if (z < 0.0f) z = -z;
}
void Vector3D::crossProduct(const Vector3D& v)
{
Vector3D result;
result.x = y * v.z - z * v.y;
result.y = z * v.x - x * v.z;
result.z = x * v.y - y * v.x;
*this = result;
}
float getSqrDist(const Vector3D& v0,const Vector3D& v1)
{
float dx = v0.x - v1.x;
float dy = v0.y - v1.y;
float dz = v0.z - v1.z;
return dx * dx + dy * dy + dz * dz;
}
float getDist(const Vector3D& v0,const Vector3D& v1)
{
return std::sqrt(getSqrDist(v0,v1));
}
Vector3D crossProduct(const Vector3D& v0,const Vector3D& v1)
{
Vector3D result;
result.x = v0.y * v1.z - v0.z * v1.y;
result.y = v0.z * v1.x - v0.x * v1.z;
result.z = v0.x * v1.y - v0.y * v1.x;
return result;
}
void crossProduct(const Vector3D& v0,const Vector3D& v1,Vector3D& result)
{
result.x = v0.y * v1.z - v0.z * v1.y;
result.y = v0.z * v1.x - v0.x * v1.z;
result.z = v0.x * v1.y - v0.y * v1.x;
}
}

View File

@ -0,0 +1,35 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Zone.h"
namespace SPK
{
const float Zone::APPROXIMATION_VALUE = 0.01f;
Zone::Zone(const Vector3D& position) :
Registerable(),
Transformable()
{
setPosition(position);
}
}

View File

@ -0,0 +1,75 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_NormalEmitter.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
NormalEmitter::NormalEmitter(Zone* normalZone,bool inverted) :
Emitter(),
normalZone(normalZone),
inverted(inverted)
{}
void NormalEmitter::registerChildren(bool registerAll)
{
Emitter::registerChildren(registerAll);
registerChild(normalZone,registerAll);
}
void NormalEmitter::copyChildren(const NormalEmitter& emitter,bool createBase)
{
Emitter::copyChildren(emitter,createBase);
normalZone = dynamic_cast<Zone*>(copyChild(emitter.normalZone,createBase));
}
void NormalEmitter::destroyChildren(bool keepChildren)
{
destroyChild(normalZone,keepChildren);
Emitter::destroyChildren(keepChildren);
}
Registerable* NormalEmitter::findByName(const std::string& name)
{
Registerable* object = Emitter::findByName(name);
if ((object != NULL)||(normalZone == NULL))
return object;
return normalZone->findByName(name);
}
void NormalEmitter::setNormalZone(Zone* zone)
{
decrementChildReference(normalZone);
incrementChildReference(zone);
normalZone = zone;
}
void NormalEmitter::generateVelocity(Particle& particle,float speed) const
{
if (inverted) speed = -speed;
const Zone* zone = (normalZone == NULL ? getZone() : normalZone);
particle.velocity() = zone->computeNormal(particle.position()) * speed;
}
}

View File

@ -0,0 +1,39 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_RandomEmitter.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
void RandomEmitter::generateVelocity(Particle& particle,float speed) const
{
float norm;
do
{
particle.velocity().set(random(-1.0f,1.0f),random(-1.0f,1.0f),random(-1.0f,1.0f));
norm = particle.velocity().getNorm();
}
while((norm > 1.0f) || (norm == 0.0f));
particle.velocity() *= speed / norm;
}
}

View File

@ -0,0 +1,123 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_SphericEmitter.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
const float SphericEmitter::PI = 3.1415926535897932384626433832795f;
SphericEmitter::SphericEmitter(const Vector3D& direction,float angleA,float angleB) :
Emitter()
{
setDirection(direction);
setAngles(angleA,angleB);
}
void SphericEmitter::setDirection(const Vector3D& direction)
{
tDirection = direction;
computeMatrix();
this->direction = tDirection; // as tDirection was normalized in computeMatrix()
notifyForUpdate();
}
void SphericEmitter::setAngles(float angleA,float angleB)
{
if (angleB < angleA)
std::swap(angleA,angleB);
angleA = std::min(2.0f * PI,std::max(0.0f,angleA));
angleB = std::min(2.0f * PI,std::max(0.0f,angleB));
angleMin = angleA;
angleMax = angleB;
cosAngleMin = cos(angleMin * 0.5f);
cosAngleMax = cos(angleMax * 0.5f);
}
void SphericEmitter::computeMatrix()
{
tDirection.normalize();
if ((tDirection.x == 0.0f)&&(tDirection.y == 0.0f))
{
matrix[0] = tDirection.z;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = tDirection.z;
matrix[5] = 0.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = tDirection.z;
}
else
{
Vector3D axis;
crossProduct(tDirection,Vector3D(0.0f,0.0f,1.0f),axis);
float cosA = tDirection.z;
float sinA = -axis.getNorm();
axis /= -sinA;
float x = axis.x;
float y = axis.y;
float z = axis.z;
matrix[0] = x * x + cosA * (1.0f - x * x);
matrix[1] = x * y * (1.0f - cosA) - z * sinA;
matrix[2] = tDirection.x;
matrix[3] = x * y * (1.0f - cosA) + z * sinA;
matrix[4] = y * y + cosA * (1.0f - y * y);
matrix[5] = tDirection.y;
matrix[6] = x * z * (1.0f - cosA) - y * sinA;
matrix[7] = y * z * (1.0f - cosA) + x * sinA;
matrix[8] = tDirection.z;
}
}
void SphericEmitter::generateVelocity(Particle& particle,float speed) const
{
float a = random(cosAngleMax,cosAngleMin);
float theta = acos(a);
float phi = random(0.0f,2.0f * PI);
float sinTheta = sin(theta);
float x = sinTheta * cos(phi);
float y = sinTheta * sin(phi);
float z = cos(theta);
particle.velocity().x = speed * (matrix[0] * x + matrix[1] * y + matrix[2] * z);
particle.velocity().y = speed * (matrix[3] * x + matrix[4] * y + matrix[5] * z);
particle.velocity().z = speed * (matrix[6] * x + matrix[7] * y + matrix[8] * z);
}
void SphericEmitter::innerUpdateTransform()
{
Emitter::innerUpdateTransform();
transformDir(tDirection,direction);
computeMatrix();
}
}

View File

@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_StraightEmitter.h"
namespace SPK
{
StraightEmitter::StraightEmitter(const Vector3D& direction) :
Emitter()
{
setDirection(direction);
}
void StraightEmitter::setDirection(const Vector3D& direction)
{
this->direction = direction;
this->direction.normalize();
tDirection = this->direction;
notifyForUpdate();
}
void StraightEmitter::innerUpdateTransform()
{
Emitter::innerUpdateTransform();
transformDir(tDirection,direction);
tDirection.normalize();
}
}

View File

@ -0,0 +1,122 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Collision.h"
#include "Core/SPK_Group.h"
namespace SPK
{
Collision::Collision(float scale,float elasticity) :
Modifier(),
scale(scale)
{
setElasticity(elasticity);
}
void Collision::modify(Particle& particle,float deltaTime) const
{
size_t index = particle.getIndex();
float radius1 = particle.getParamCurrentValue(PARAM_SIZE) * scale * 0.5f;
float m1 = particle.getParamCurrentValue(PARAM_MASS);
Group& group = *particle.getGroup();
// Tests collisions with all the particles that are stored before in the pool
for (size_t i = 0; i < index; ++i)
{
Particle& particle2 = group.getParticle(i);
float radius2 = particle2.getParamCurrentValue(PARAM_SIZE) * scale * 0.5f;
float sqrRadius = radius1 + radius2;
sqrRadius *= sqrRadius;
// Gets the normal of the collision plane
Vector3D normal = particle.position();
normal -= particle2.position();
float sqrDist = normal.getSqrNorm();
if (sqrDist < sqrRadius) // particles are intersecting each other
{
Vector3D delta = particle.velocity();
delta -= particle2.velocity();
if (dotProduct(normal,delta) < 0.0f) // particles are moving towards each other
{
float oldSqrDist = getSqrDist(particle.oldPosition(),particle2.oldPosition());
if (oldSqrDist > sqrDist)
{
// Disables the move from this frame
particle.position() = particle.oldPosition();
particle2.position() = particle2.oldPosition();
normal = particle.position();
normal -= particle2.position();
if (dotProduct(normal,delta) >= 0.0f)
continue;
}
normal.normalize();
// Gets the normal components of the velocities
Vector3D normal1(normal);
Vector3D normal2(normal);
normal1 *= dotProduct(normal,particle.velocity());
normal2 *= dotProduct(normal,particle2.velocity());
// Resolves collision
float m2 = particle2.getParamCurrentValue(PARAM_MASS);
if (oldSqrDist < sqrRadius && sqrDist < sqrRadius)
{
// Tweak to separate particles that intersects at both t - deltaTime and t
// In that case the collision is no more considered as punctual
if (dotProduct(normal,normal1) < 0.0f)
{
particle.velocity() -= normal1;
particle2.velocity() += normal1;
}
if (dotProduct(normal,normal2) > 0.0f)
{
particle2.velocity() -= normal2;
particle.velocity() += normal2;
}
}
else
{
// Else classic collision equations are applied
// Tangent components of the velocities are left untouched
particle.velocity() -= (1.0f + (elasticity * m2 - m1) / (m1 + m2)) * normal1;
particle2.velocity() -= (1.0f + (elasticity * m1 - m2) / (m1 + m2)) * normal2;
normal1 *= ((1.0f + elasticity) * m1) / (m1 + m2);
normal2 *= ((1.0f + elasticity) * m2) / (m1 + m2);
particle.velocity() += normal2;
particle2.velocity() += normal1;
}
}
}
}
}
}

View File

@ -0,0 +1,51 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Destroyer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
Destroyer::Destroyer(Zone* zone,ModifierTrigger) :
Modifier(INSIDE_ZONE | OUTSIDE_ZONE | INTERSECT_ZONE | ENTER_ZONE | EXIT_ZONE,INSIDE_ZONE,true,false,zone)
{
setTrigger(trigger);
}
void Destroyer::modify(Particle& particle,float deltaTime) const
{
particle.kill();
if ((trigger != INSIDE_ZONE)||(trigger != OUTSIDE_ZONE))
particle.position() = intersection;
}
void Destroyer::modifyWrongSide(Particle& particle,bool inside) const
{
if (isFullZone())
{
getZone()->moveAtBorder(particle.position(),inside);
particle.kill();
}
}
}

View File

@ -0,0 +1,50 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_LinearForce.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
LinearForce::LinearForce(Zone* zone,ModifierTrigger trigger,const Vector3D& force,ForceFactor type,ModelParam param) :
Modifier(ALWAYS | INSIDE_ZONE | OUTSIDE_ZONE,ALWAYS,false,false,zone),
force(force),
tForce(force),
factorType(type),
factorParam(param)
{}
void LinearForce::modify(Particle& particle,float deltaTime) const
{
float factor = deltaTime / particle.getParamCurrentValue(PARAM_MASS);
if (factorType != FACTOR_NONE)
{
float param = particle.getParamCurrentValue(factorParam);
factor *= param; // linearity function of the parameter
if (factorType == FACTOR_SQUARE)
factor *= param; // linearity function of the square of the parameter
}
particle.velocity() += tForce * factor;
}
}

View File

@ -0,0 +1,169 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_ModifierGroup.h"
namespace SPK
{
ModifierGroup::ModifierGroup(Zone* zone,ModifierTrigger trigger) :
Modifier(INSIDE_ZONE | OUTSIDE_ZONE | INTERSECT_ZONE | ENTER_ZONE | EXIT_ZONE,trigger,false,false,zone),
modifiers(),
globalZone(false),
handleWrongSide(false)
{}
void ModifierGroup::registerChildren(bool registerAll)
{
Modifier::registerChildren(registerAll);
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
registerChild(*it,registerAll);
}
void ModifierGroup::copyChildren(const ModifierGroup& modifier,bool createBase)
{
Modifier::copyChildren(modifier,createBase);
// we clear the copies of pointers pushed in the vectors by the copy constructor
modifiers.clear();
for (std::vector<Modifier*>::const_iterator it = modifier.modifiers.begin(); it != modifier.modifiers.end(); ++it)
modifiers.push_back(dynamic_cast<Modifier*>(copyChild(*it,createBase)));
}
void ModifierGroup::destroyChildren(bool keepChildren)
{
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
destroyChild(*it,keepChildren);
Modifier::destroyChildren(keepChildren);
}
Registerable* ModifierGroup::findByName(const std::string& name)
{
Registerable* object = Modifier::findByName(name);
if (object != NULL)
return object;
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
return NULL;
}
void ModifierGroup::addModifier(Modifier* modifier)
{
if (modifier == NULL)
return;
incrementChildReference(modifier);
modifiers.push_back(modifier);
}
bool ModifierGroup::removeModifier(const Modifier* modifier)
{
std::vector<Modifier*>::iterator it = std::find<std::vector<Modifier*>::iterator,const Modifier*>(modifiers.begin(),modifiers.end(),modifier);
if (it != modifiers.end())
{
decrementChildReference(*it);
modifiers.erase(it);
return true;
}
return false;
}
void ModifierGroup::clear()
{
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != modifiers.end(); ++it)
decrementChildReference(*it);
modifiers.clear();
}
void ModifierGroup::modify(Particle& particle,float deltaTime) const
{
std::vector<Modifier*>::const_iterator end = modifiers.end();
if (globalZone)
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
{
Zone* oldZone = (*it)->getZone();
(*it)->setZone(getZone());
(*it)->modify(particle,deltaTime);
(*it)->setZone(oldZone);
}
else
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
(*it)->process(particle,deltaTime);
}
void ModifierGroup::modifyWrongSide(Particle& particle,bool inside) const
{
if (globalZone)
{
std::vector<Modifier*>::const_iterator end = modifiers.end();
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
{
Zone* oldZone = (*it)->getZone();
(*it)->setZone(getZone());
(*it)->modifyWrongSide(particle,inside);
(*it)->setZone(oldZone);
}
}
else if (handleWrongSide)
{
std::vector<Modifier*>::const_iterator end = modifiers.end();
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
if (((*it)->getZone() != NULL)&&((*it)->getTrigger() != INTERSECT_ZONE))
modifyWrongSide(particle,true);
}
}
void ModifierGroup::createBuffers(const Group& group)
{
std::vector<Modifier*>::iterator end = modifiers.end();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != end; ++it)
(*it)->createBuffers(group);
}
void ModifierGroup::destroyBuffers(const Group& group)
{
std::vector<Modifier*>::iterator end = modifiers.end();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != end; ++it)
(*it)->destroyBuffers(group);
}
bool ModifierGroup::checkBuffers(const Group& group)
{
std::vector<Modifier*>::iterator end = modifiers.end();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != end; ++it)
if (!(*it)->checkBuffers(group))
return false;
return true;
}
}

View File

@ -0,0 +1,57 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Obstacle.h"
namespace SPK
{
Obstacle::Obstacle(Zone* zone,ModifierTrigger trigger,float bouncingRatio,float friction) :
Modifier(INTERSECT_ZONE | ENTER_ZONE | EXIT_ZONE,INTERSECT_ZONE,true,true,zone),
bouncingRatio(bouncingRatio),
friction(friction)
{
setTrigger(trigger);
}
void Obstacle::modify(Particle& particle,float deltaTime) const
{
Vector3D& velocity = particle.velocity();
velocity = particle.position();
velocity -= particle.oldPosition();
if (deltaTime != 0.0f)
velocity *= 1.0f / deltaTime;
else
velocity.set(0.0f,0.0f,0.0f);
float dist = dotProduct(velocity,normal);
normal *= dist;
velocity -= normal; // tangent component
velocity *= friction;
normal *= bouncingRatio; // normal component
velocity -= normal;
particle.position() = intersection;
}
}

View File

@ -0,0 +1,49 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_PointMass.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
PointMass::PointMass(Zone* zone,ModifierTrigger trigger,float mass,float minDistance) :
Modifier(ALWAYS | INSIDE_ZONE | OUTSIDE_ZONE,ALWAYS,false,false,zone),
position(),
tPosition(),
mass(mass)
{
setTrigger(trigger);
setMinDistance(minDistance);
}
void PointMass::modify(Particle& particle,float deltaTime) const
{
Vector3D force = tPosition;
if (getZone() != NULL)
force += getZone()->getTransformedPosition();
force -= particle.position();
force *= mass * deltaTime / std::max(sqrMinDistance,force.getSqrNorm());
particle.velocity() += force;
}
}

View File

@ -0,0 +1,84 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Vortex.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Vortex::Vortex(const Vector3D& position,const Vector3D& direction,float rotationSpeed,float attractionSpeed) :
Modifier(ALWAYS | INSIDE_ZONE |OUTSIDE_ZONE,ALWAYS,false,false,NULL),
rotationSpeed(rotationSpeed),
attractionSpeed(attractionSpeed),
angularSpeedEnabled(false),
linearSpeedEnabled(false),
killingParticleEnabled(false),
eyeRadius(0.0f)
{
setPosition(position);
setDirection(direction);
}
void Vortex::modify(Particle& particle,float deltaTime) const
{
// Distance of the projection point from the position of the vortex
float dist = dotProduct(tDirection,particle.position() - tPosition);
// Position of the rotation center (orthogonal projection of the particle)
Vector3D rotationCenter = tDirection;
rotationCenter *= dist;
rotationCenter += tPosition;
// Distance of the particle from the eye of the vortex
dist = getDist(rotationCenter,particle.position());
if (dist <= eyeRadius)
{
if (killingParticleEnabled)
particle.kill();
return;
}
float angle = angularSpeedEnabled ? rotationSpeed * deltaTime : rotationSpeed * deltaTime / dist;
// Computes ortho base
Vector3D normal = (particle.position() - rotationCenter) / dist;
Vector3D tangent = crossProduct(tDirection,normal);
float endRadius = linearSpeedEnabled ? dist * (1.0f - attractionSpeed * deltaTime) : dist - attractionSpeed * deltaTime;
if (endRadius <= eyeRadius)
{
endRadius = eyeRadius;
if (killingParticleEnabled)
particle.kill();
}
particle.position() = rotationCenter + normal * endRadius * std::cos(angle) + tangent * endRadius * std::sin(angle);
}
void Vortex::innerUpdateTransform()
{
Modifier::innerUpdateTransform();
transformPos(tPosition,position);
transformDir(tDirection,direction);
tDirection.normalize();
}
}

View File

@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Renderers/SPK_Oriented3DRendererInterface.h"
namespace SPK
{
Oriented3DRendererInterface::Oriented3DRendererInterface() :
lookOrientation(LOOK_CAMERA_PLANE),
upOrientation(UP_CAMERA),
lockedAxis(LOCK_UP)
{
lookVector.set(0.0f,0.0f,1.0f);
upVector.set(0.0f,1.0f,0.0f);
}
void Oriented3DRendererInterface::setOrientation(LookOrientation lookOrientation,UpOrientation upOrientation,LockedAxis lockedAxis)
{
this->lookOrientation = lookOrientation;
this->upOrientation = upOrientation;
this->lockedAxis = lockedAxis;
}
void Oriented3DRendererInterface::setOrientation(OrientationPreset orientation)
{
this->lookOrientation = static_cast<LookOrientation>((orientation >> 0x8) & 0xFF);
this->upOrientation = static_cast<UpOrientation>(orientation & 0xFF);
this->lockedAxis = static_cast<LockedAxis>((orientation >> 0x10) & 0xFF);
}
}

View File

@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Renderers/SPK_QuadRendererInterface.h"
namespace SPK
{
QuadRendererInterface::QuadRendererInterface(float scaleX,float scaleY) :
scaleX(scaleX),
scaleY(scaleY),
texturingMode(TEXTURE_NONE),
textureAtlasNbX(1),
textureAtlasNbY(1),
textureAtlasW(1.0f),
textureAtlasH(1.0f)
{}
void QuadRendererInterface::setAtlasDimensions(size_t nbX,size_t nbY)
{
textureAtlasNbX = nbX;
textureAtlasNbY = nbY;
textureAtlasW = 1.0f / nbX;
textureAtlasH = 1.0f / nbY;
}
}

View File

@ -0,0 +1,160 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_AABox.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
AABox::AABox(const Vector3D& position,const Vector3D& dimension) :
Zone(position)
{
setDimension(dimension);
}
void AABox::setDimension(const Vector3D& dimension)
{
this->dimension.set(std::max(0.0f,dimension.x),std::max(0.0f,dimension.y),std::max(0.0f,dimension.z));
}
void AABox::generatePosition(Particle& particle,bool full) const
{
particle.position().x = getTransformedPosition().x + random(-dimension.x * 0.5f,dimension.x * 0.5f);
particle.position().y = getTransformedPosition().y + random(-dimension.y * 0.5f,dimension.y * 0.5f);
particle.position().z = getTransformedPosition().z + random(-dimension.z * 0.5f,dimension.z * 0.5f);
if (!full)
{
int axis = random(0,3);
int sens = (random(0,2) << 1) - 1;
switch(axis)
{
case 0 :
particle.position().x = getTransformedPosition().x + sens * dimension.x * 0.5f;
break;
case 1 :
particle.position().y = getTransformedPosition().y + sens * dimension.y * 0.5f;
break;
default :
particle.position().z = getTransformedPosition().z + sens * dimension.z * 0.5f;
break;
}
}
}
bool AABox::contains(const Vector3D& v) const
{
if ((v.x >= getTransformedPosition().x - dimension.x * 0.5f)&&(v.x <= getTransformedPosition().x + dimension.x * 0.5f)
&&(v.y >= getTransformedPosition().y - dimension.y * 0.5f)&&(v.y <= getTransformedPosition().y + dimension.y * 0.5f)
&&(v.z >= getTransformedPosition().z - dimension.z * 0.5f)&&(v.z <= getTransformedPosition().z + dimension.z * 0.5f))
return true;
return false;
}
bool AABox::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float tEnter = 0.0f;
float tExit = 1.0f;
int axis;
if (!slabIntersects(v0.x,v1.x,getTransformedPosition().x - dimension.x * 0.5f,getTransformedPosition().x + dimension.x * 0.5f,tEnter,tExit,axis,0))
return false;
if (!slabIntersects(v0.y,v1.y,getTransformedPosition().y - dimension.y * 0.5f,getTransformedPosition().y + dimension.y * 0.5f,tEnter,tExit,axis,1))
return false;
if (!slabIntersects(v0.z,v1.z,getTransformedPosition().z - dimension.z * 0.5f,getTransformedPosition().z + dimension.z * 0.5f,tEnter,tExit,axis,2))
return false;
if ((tEnter <= 0.0f)&&(tExit >= 1.0f))
return false;
if (intersection != NULL)
{
if (tEnter <= 0.0f)
{
tEnter = tExit;
axis = (axis & 0xF0) >> 4;
}
else
axis &= 0x0F;
Vector3D vDir = v1 - v0;
float norm = vDir.getNorm() * tEnter;
tEnter = norm < APPROXIMATION_VALUE ? 0.0f : tEnter * (norm - APPROXIMATION_VALUE) / norm;
vDir *= tEnter;
*intersection = v0 + vDir;
if (normal != NULL)
{
switch(axis)
{
case 0 :
*normal = Vector3D(-1.0f,0.0f,0.0f);
break;
case 1 :
*normal = Vector3D(0.0f,-1.0f,0.0f);
break;
case 2 :
*normal = Vector3D(0.0f,0.0f,-1.0f);
break;
case 3 :
*normal = Vector3D(1.0f,0.0f,0.0f);
break;
case 4 :
*normal = Vector3D(0.0f,1.0f,0.0f);
break;
case 5 :
*normal = Vector3D(0.0f,0.0f,1.0f);
break;
}
}
}
return true;
}
void AABox::moveAtBorder(Vector3D& v,bool inside) const
{
if (inside)
{
Vector3D rayEnd(v - getTransformedPosition());
float maxDim = getTransformedPosition().x + getTransformedPosition().y + getTransformedPosition().z;
rayEnd *= maxDim * maxDim / rayEnd.getSqrNorm();
intersects(getTransformedPosition() + rayEnd,getTransformedPosition(),&v,NULL);
}
else
intersects(getTransformedPosition(),v,&v,NULL);
}
Vector3D AABox::computeNormal(const Vector3D& point) const
{
// TO DO
Vector3D normal(point - getTransformedPosition());
normalizeOrRandomize(normal);
return normal;
}
}

View File

@ -0,0 +1,92 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Line.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Line::Line(const Vector3D& p0,const Vector3D& p1) :
Zone(Vector3D())
{
setBounds(p0,p1);
}
void Line::setPosition(const Vector3D& v)
{
Vector3D displacement = v - getPosition();
bounds[0] = tBounds[0] += displacement;
bounds[1] = tBounds[1] += displacement;
computeDist();
Zone::setPosition(v);
}
void Line::setBounds(const Vector3D& p0,const Vector3D& p1)
{
bounds[0] = tBounds[0] = p0;
bounds[1] = tBounds[1] = p1;
computeDist();
computePosition();
}
void Line::pushBound(const Vector3D& bound)
{
bounds[0] = tBounds[0] = bounds[1];
bounds[1] = tBounds[1] = bound;
computeDist();
computePosition();
}
void Line::generatePosition(Particle& particle,bool full) const
{
float ratio = random(0.0f,1.0f);
particle.position() = tBounds[0] + tDist * ratio;
}
Vector3D Line::computeNormal(const Vector3D& point) const
{
float d = -dotProduct(tDist,point);
float sqrNorm = tDist.getSqrNorm();
float t = 0.0f;
if (sqrNorm > 0.0f)
{
t = -(dotProduct(tDist,tBounds[0]) + d) / sqrNorm;
// t is clamped to the segment
if (t < 0.0f) t = 0.0f;
else if (t > 1.0f) t = 1.0f;
}
Vector3D normal = point;
normal -= tBounds[0] + t * tDist;
normalizeOrRandomize(normal);
return normal;
}
void Line::innerUpdateTransform()
{
Zone::innerUpdateTransform();
transformPos(tBounds[0],bounds[0]);
transformPos(tBounds[1],bounds[1]);
computeDist();
}
}

View File

@ -0,0 +1,84 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Plane.h"
namespace SPK
{
Plane::Plane(const Vector3D& position,const Vector3D& normal) :
Zone(position)
{
setNormal(normal);
}
bool Plane::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float dist0 = dotProduct(tNormal,v0 - getTransformedPosition());
float dist1 = dotProduct(tNormal,v1 - getTransformedPosition());
if ((dist0 <= 0.0f) == (dist1 <= 0.0f)) // both points are on the same side
return false;
if (intersection != NULL)
{
if (dist0 <= 0.0f)
dist0 = -dist0;
else
dist1 = -dist1;
if (normal != NULL)
*normal = tNormal;
float ti = dist0 / (dist0 + dist1);
Vector3D vDir = v1 - v0;
float norm = vDir.getNorm();
norm *= ti;
ti = norm < APPROXIMATION_VALUE ? 0.0f : ti * (norm - APPROXIMATION_VALUE) / norm;
vDir *= ti;
*intersection = v0 + vDir;
}
return true;
}
void Plane::moveAtBorder(Vector3D& v,bool inside) const
{
float dist = dotProduct(tNormal,v - getTransformedPosition());
if ((dist <= 0.0f) == inside)
inside ? dist += APPROXIMATION_VALUE : dist -= APPROXIMATION_VALUE;
else
inside ? dist -= APPROXIMATION_VALUE : dist += APPROXIMATION_VALUE;
v += tNormal * -dist;
}
void Plane::innerUpdateTransform()
{
Zone::innerUpdateTransform();
transformDir(tNormal,normal);
tNormal.normalize();
}
}

View File

@ -0,0 +1,38 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Point.h"
namespace SPK
{
Point::Point(const Vector3D& position) :
Zone(position)
{}
Vector3D Point::computeNormal(const Vector3D& point) const
{
Vector3D normal(point - getTransformedPosition());
normalizeOrRandomize(normal);
return normal;
}
}

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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Ring.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Ring::Ring(const Vector3D& position,const Vector3D& normal,float minRadius,float maxRadius) :
Zone(position)
{
setNormal(normal);
setRadius(minRadius,maxRadius);
}
inline void Ring::setRadius(float minRadius,float maxRadius)
{
if (minRadius < 0.0f) minRadius = -minRadius;
if (maxRadius < 0.0f) maxRadius = -maxRadius;
if (minRadius > maxRadius) std::swap(minRadius,maxRadius);
this->minRadius = minRadius;
this->maxRadius = maxRadius;
sqrMinRadius = minRadius * minRadius;
sqrMaxRadius = maxRadius * maxRadius;
}
void Ring::generatePosition(Particle& particle,bool full) const
{
Vector3D tmp;
do tmp = Vector3D(random(-1.0f,1.0f),random(-1.0f,1.0f),random(-1.0f,1.0f));
while (tmp.getSqrNorm() > 1.0f);
crossProduct(tNormal,tmp,particle.position());
normalizeOrRandomize(particle.position());
particle.position() *= std::sqrt(random(sqrMinRadius,sqrMaxRadius)); // to have a uniform distribution
particle.position() += getTransformedPosition();
}
bool Ring::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float dist0 = dotProduct(tNormal,v0 - getTransformedPosition());
float dist1 = dotProduct(tNormal,v1 - getTransformedPosition());
if ((dist0 <= 0.0f) == (dist1 <= 0.0f)) // both points are on the same side
return false;
if (dist0 <= 0.0f)
dist0 = -dist0;
else
dist1 = -dist1;
float ti = dist0 / (dist0 + dist1);
Vector3D vDir(v1 - v0);
float norm = vDir.getNorm();
norm *= ti;
ti = norm < APPROXIMATION_VALUE ? 0.0f : ti * (norm - APPROXIMATION_VALUE) / norm;
vDir *= ti;
Vector3D inter(v0 + vDir);
float distFromCenter = getSqrDist(inter,getTransformedPosition());
if (distFromCenter > sqrMaxRadius || distFromCenter < sqrMinRadius) // intersection is not in the ring
return false;
if (intersection != NULL)
{
*intersection = inter;
if (normal != NULL)
*normal = tNormal;
}
return true;
}
void Ring::moveAtBorder(Vector3D& v,bool inside) const
{
float dist = dotProduct(tNormal,v - getTransformedPosition());
v += tNormal * -dist;
float distFromCenter = getSqrDist(v,getTransformedPosition());
if (distFromCenter > sqrMaxRadius)
{
distFromCenter = std::sqrt(distFromCenter);
Vector3D vDir(v - getTransformedPosition());
vDir *= maxRadius / distFromCenter;
v = getTransformedPosition() + vDir;
}
else if (distFromCenter < sqrMinRadius)
{
distFromCenter = std::sqrt(distFromCenter);
Vector3D vDir(v - getTransformedPosition());
vDir *= minRadius / distFromCenter;
v = getTransformedPosition() + vDir;
}
}
void Ring::innerUpdateTransform()
{
Zone::innerUpdateTransform();
transformDir(tNormal,normal);
tNormal.normalize();
}
}

View File

@ -0,0 +1,116 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Sphere.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Sphere::Sphere(const Vector3D& position,float radius) :
Zone(position)
{
setRadius(radius);
}
void Sphere::generatePosition(Particle& particle,bool full) const
{
do particle.position() = Vector3D(random(-radius,radius),random(-radius,radius),random(-radius,radius));
while (particle.position().getSqrNorm() > radius * radius);
if ((!full)&&(radius > 0.0f))
particle.position() *= radius / particle.position().getNorm();
particle.position() += getTransformedPosition();
}
bool Sphere::contains(const Vector3D& v) const
{
return getSqrDist(getTransformedPosition(),v) <= radius * radius;
}
bool Sphere::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float r2 = radius * radius;
float dist0 = getSqrDist(getTransformedPosition(),v0);
float dist1 = getSqrDist(getTransformedPosition(),v1);
if ((dist0 <= r2) == (dist1 <= r2))
return false;
if (intersection != NULL)
{
Vector3D vDir = v1 - v0;
float norm = vDir.getNorm();
float d = dotProduct(vDir,getTransformedPosition() - v0) / norm;
float a = std::sqrt(r2 - dist0 + d * d);
float ti;
if (dist0 <= r2)
ti = d - a;
else
ti = d + a;
ti /= norm;
if (ti < 0.0f) ti = 0.0f;
if (ti > 1.0f) ti = 1.0f;
norm *= ti;
ti = norm < APPROXIMATION_VALUE ? 0.0f : ti * (norm - APPROXIMATION_VALUE) / norm;
vDir *= ti;
*intersection = v0 + vDir;
if (normal != NULL)
{
if (dist0 <= r2)
*normal = getTransformedPosition() - *intersection;
else
*normal = *intersection - getTransformedPosition();
normal->normalize();
}
}
return true;
}
void Sphere::moveAtBorder(Vector3D& v,bool inside) const
{
Vector3D vDir = v - getTransformedPosition();
float norm = vDir.getNorm();
if (inside)
vDir *= (radius + APPROXIMATION_VALUE) / norm;
else
vDir *= (radius - APPROXIMATION_VALUE) / norm;
v = getTransformedPosition() + vDir;
}
Vector3D Sphere::computeNormal(const Vector3D& point) const
{
Vector3D normal(point - getTransformedPosition());
normalizeOrRandomize(normal);
return normal;
}
}

View File

@ -0,0 +1,326 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLExtHandler.h"
#if defined(__APPLE__) || defined(macintosh)
// Necessary includes to get GL functions pointers from MAC
#include <mach-o/dyld.h>
#include <stdlib.h>
#include <string.h>
#endif
namespace SPK
{
namespace GL
{
GLExtHandler::GLExtension GLExtHandler::pointSpriteGLExt = UNCHECKED;
GLExtHandler::GLExtension GLExtHandler::pointParameterGLExt = UNCHECKED;
GLExtHandler::GLExtension GLExtHandler::texture3DGLExt = UNCHECKED;
GLExtHandler::GLExtension GLExtHandler::shaderGLExt = UNCHECKED;
GLExtHandler::SPK_PFNGLPOINTPARAMETERFPROC GLExtHandler::SPK_glPointParameterf = NULL;
GLExtHandler::SPK_PFNGLPOINTPARAMETERFVPROC GLExtHandler::SPK_glPointParameterfv = NULL;
GLExtHandler::SPK_PFNGLTEXIMAGE3DPROC GLExtHandler::SPK_glTexImage3D = NULL;
GLExtHandler::SPK_PFNGLCREATESHADERPROC GLExtHandler::SPK_glCreateShader = NULL;
GLExtHandler::SPK_PFNGLDELETESHADERPROC GLExtHandler::SPK_glDeleteShader = NULL;
GLExtHandler::SPK_PFNGLSHADERSOURCEPROC GLExtHandler::SPK_glShaderSource = NULL;
GLExtHandler::SPK_PFNGLCOMPILESHADERPROC GLExtHandler::SPK_glCompileShader = NULL;
GLExtHandler::SPK_PFNGLCREATEPROGRAMPROC GLExtHandler::SPK_glCreateProgram = NULL;
GLExtHandler::SPK_PFNGLDELETEPROGRAMPROC GLExtHandler::SPK_glDeleteProgram = NULL;
GLExtHandler::SPK_PFNGLATTACHSHADERPROC GLExtHandler::SPK_glAttachShader = NULL;
GLExtHandler::SPK_PFNGLDETACHSHADERPROC GLExtHandler::SPK_glDetachShader = NULL;
GLExtHandler::SPK_PFNGLLINKPROGRAMPROC GLExtHandler::SPK_glLinkProgram = NULL;
GLExtHandler::SPK_PFNGLUSEPROGRAMPROC GLExtHandler::SPK_glUseProgram = NULL;
const float GLExtHandler::QUADRATIC_SCREEN[3] = {1.0f,0.0f,0.0f};
float GLExtHandler::pixelPerUnit = 1024.0f;
const float GLExtHandler::POINT_SIZE_CURRENT = 32.0f;
const float GLExtHandler::POINT_SIZE_MIN = 1.0f;
const float GLExtHandler::POINT_SIZE_MAX = 1024.0f;
#ifdef SPK_NO_GLEXT
bool GLExtHandler::loadGLExtPointSprite()
{
pointSpriteGLExt = UNSUPPORTED;
return false;
}
bool GLExtHandler::loadGLExtPointParameter()
{
pointParameterGLExt = UNSUPPORTED;
return false;
}
bool GLExtHandler::loadGLExtTexture3D()
{
texture3DGLExt = UNSUPPORTED;
return false;
}
bool GLExtHandler::loadGLExtShader()
{
shaderGLExt = UNSUPPORTED;
return false;
}
#else
bool GLExtHandler::loadGLExtPointSprite()
{
if (pointSpriteGLExt == UNCHECKED)
{
pointSpriteGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
// openGL 2.0 and higher
if (int(version[0] - '0') >= 2)
pointSpriteGLExt = SUPPORTED;
else
{
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if ((extensions.find("GL_ARB_point_sprites") != std::string::npos)
||(extensions.find("GL_NV_point_sprites") != std::string::npos))
pointSpriteGLExt = SUPPORTED;
}
}
return pointSpriteGLExt == SUPPORTED;
}
bool GLExtHandler::loadGLExtPointParameter()
{
if (pointParameterGLExt == UNCHECKED)
{
pointParameterGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
// openGL 1.4 and higher
if (((int(version[0] - '0') == 1)&&(int(version[2] - '0') >= 4))
||(int(version[0] - '0') > 1))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterf");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfv");
}
// point parameter ARB
if (((SPK_glPointParameterf == NULL)||(SPK_glPointParameterfv == NULL))
&&(extensions.find("GL_ARB_point_parameters") != std::string::npos))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterfARB");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfvARB");
}
// point parameter EXT
if (((SPK_glPointParameterf == NULL)||(SPK_glPointParameterfv == NULL))
&&(extensions.find("GL_EXT_point_parameters") != std::string::npos))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterfEXT");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfvEXT");
}
// point parameter SGIS
if (((SPK_glPointParameterf == NULL)||(SPK_glPointParameterfv == NULL))
&&(extensions.find("GL_SGIS_point_parameters") != std::string::npos))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterfSGIS");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfvSGIS");
}
if ((SPK_glPointParameterf != NULL)&&(SPK_glPointParameterfv != NULL))
pointParameterGLExt = SUPPORTED;
}
return pointParameterGLExt == SUPPORTED;
}
bool GLExtHandler::loadGLExtTexture3D()
{
if (texture3DGLExt == UNCHECKED)
{
texture3DGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
// openGL 1.2 and higher
if (((int(version[0] - '0') == 1)&&(int(version[2] - '0') >= 4))
||(int(version[0] - '0') > 1))
SPK_glTexImage3D = (SPK_PFNGLTEXIMAGE3DPROC)glGetProcAddress("glTexImage3D");
// texture 3D EXT
if ((SPK_glTexImage3D == NULL)&&(extensions.find("GL_EXT_texture3D") != std::string::npos))
SPK_glTexImage3D = (SPK_PFNGLTEXIMAGE3DPROC)glGetProcAddress("glTexImage3DEXT");
if (SPK_glTexImage3D != NULL)
texture3DGLExt = SUPPORTED;
}
return texture3DGLExt == SUPPORTED;
}
bool GLExtHandler::loadGLExtShader()
{
if (shaderGLExt == UNCHECKED)
{
shaderGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
// openGL 2.0 and higher
if (int(version[0] - '0') >= 2)
{
bool ok = true;
if (ok && ((SPK_glCreateShader = (SPK_PFNGLCREATESHADERPROC)glGetProcAddress("glCreateShader")) == NULL)) ok = false;
if (ok && ((SPK_glDeleteShader = (SPK_PFNGLDELETESHADERPROC)glGetProcAddress("glDeleteShader")) == NULL)) ok = false;
if (ok && ((SPK_glShaderSource = (SPK_PFNGLSHADERSOURCEPROC)glGetProcAddress("glShaderSource")) == NULL)) ok = false;
if (ok && ((SPK_glCompileShader = (SPK_PFNGLCOMPILESHADERPROC)glGetProcAddress("glCompileShader")) == NULL)) ok = false;
if (ok && ((SPK_glCreateProgram = (SPK_PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram")) == NULL)) ok = false;
if (ok && ((SPK_glDeleteProgram = (SPK_PFNGLDELETEPROGRAMPROC)glGetProcAddress("glDeleteProgram")) == NULL)) ok = false;
if (ok && ((SPK_glAttachShader = (SPK_PFNGLATTACHSHADERPROC)glGetProcAddress("glAttachShader")) == NULL)) ok = false;
if (ok && ((SPK_glDetachShader = (SPK_PFNGLDETACHSHADERPROC)glGetProcAddress("glDetachShader")) == NULL)) ok = false;
if (ok && ((SPK_glLinkProgram = (SPK_PFNGLLINKPROGRAMPROC)glGetProcAddress("glLinkProgram")) == NULL)) ok = false;
if (ok && ((SPK_glUseProgram = (SPK_PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram")) == NULL)) ok = false;
if (ok) shaderGLExt = SUPPORTED;
}
if (shaderGLExt == UNSUPPORTED)
{
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if ((extensions.find("GL_ARB_shading_language_100") != std::string::npos)&&
(extensions.find("GL_ARB_shader_objects") != std::string::npos)&&
(extensions.find("GL_ARB_vertex_shader") != std::string::npos)&&
(extensions.find("GL_ARB_fragment_shader") != std::string::npos))
{
bool ok = true;
if (ok && ((SPK_glCreateShader = (SPK_PFNGLCREATESHADERPROC)glGetProcAddress("glCreateShaderObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glDeleteShader = SPK_glDeleteProgram = (SPK_PFNGLDELETESHADERPROC)glGetProcAddress("glDeleteObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glShaderSource = (SPK_PFNGLSHADERSOURCEPROC)glGetProcAddress("glShaderSourceARB")) == NULL)) ok = false;
if (ok && ((SPK_glCompileShader = (SPK_PFNGLCOMPILESHADERPROC)glGetProcAddress("glCompileShaderARB")) == NULL)) ok = false;
if (ok && ((SPK_glCreateProgram = (SPK_PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgramObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glAttachShader = (SPK_PFNGLATTACHSHADERPROC)glGetProcAddress("glAttachObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glDetachShader = (SPK_PFNGLDETACHSHADERPROC)glGetProcAddress("glDetachObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glLinkProgram = (SPK_PFNGLLINKPROGRAMPROC)glGetProcAddress("glLinkProgramARB")) == NULL)) ok = false;
if (ok && ((SPK_glUseProgram = (SPK_PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgramObjectARB")) == NULL)) ok = false;
if (ok) shaderGLExt = SUPPORTED;
}
}
}
return shaderGLExt == SUPPORTED;
}
#endif
#if defined(__APPLE__) || defined(macintosh)
void* GLExtHandler::SPK_NSGLGetProcAddress(const char* name)
{
NSSymbol symbol;
char *symbolName;
symbolName = (char*)malloc (strlen (name) + 2);
strcpy(symbolName + 1, name);
symbolName[0] = '_';
symbol = NULL;
if (NSIsSymbolNameDefined (symbolName))
symbol = NSLookupAndBindSymbol (symbolName);
free (symbolName);
return symbol ? NSAddressOfSymbol (symbol) : NULL;
}
#endif
void GLExtHandler::setPixelPerUnit(float fovy,int screenHeight)
{
// the pixel per unit is computed for a distance from the camera of screenHeight
pixelPerUnit = screenHeight / (2.0f * tan(fovy * 0.5f));
}
void GLExtHandler::glTexImage3D(GLenum target,
GLint level,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
const GLvoid* pixels)
{
if (loadGLExtTexture3D())
SPK_glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels);
}
GLExtHandler::GLExtension GLExtHandler::getPointSpriteGLExt()
{
return pointSpriteGLExt;
}
GLExtHandler::GLExtension GLExtHandler::getPointParameterGLExt()
{
return pointParameterGLExt;
}
void GLExtHandler::enablePointParameterGLExt(float size,bool distance)
{
// derived size = size * sqrt(1 / (A + B * distance + C * distance²))
if (distance)
{
const float sqrtC = POINT_SIZE_CURRENT / (size * pixelPerUnit);
const float QUADRATIC_WORLD[3] = {0.0f,0.0f,sqrtC * sqrtC}; // A = 0; B = 0; C = (POINT_SIZE_CURRENT / (size * pixelPerUnit))²
SPK_glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION,QUADRATIC_WORLD);
}
else
{
const float sqrtA = POINT_SIZE_CURRENT / size;
const float QUADRATIC_WORLD[3] = {sqrtA * sqrtA,0.0f,0.0f}; // A = (POINT_SIZE_CURRENT / size)²; B = 0; C = 0
SPK_glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION,QUADRATIC_WORLD);
}
glPointSize(POINT_SIZE_CURRENT);
SPK_glPointParameterf(GL_POINT_SIZE_MIN,POINT_SIZE_MIN);
SPK_glPointParameterf(GL_POINT_SIZE_MAX,POINT_SIZE_MAX);
}
void GLExtHandler::disablePointParameterGLExt()
{
SPK_glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION,QUADRATIC_SCREEN);
}
GLExtHandler::GLExtension GLExtHandler::getTexture3DGLExt()
{
return texture3DGLExt;
}
GLExtHandler::GLExtension GLExtHandler::getShaderGLExt()
{
return shaderGLExt;
}
}}

View File

@ -0,0 +1,107 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLLineRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_ArrayBuffer.h"
namespace SPK
{
namespace GL
{
const std::string GLLineRenderer::GPU_BUFFER_NAME("SPK_GLLineRenderer_GPU");
float* GLLineRenderer::gpuBuffer = NULL;
float* GLLineRenderer::gpuIterator = NULL;
GLLineRenderer::GLLineRenderer(float length,float width) :
GLRenderer(),
LineRendererInterface(length,width)
{}
bool GLLineRenderer::checkBuffers(const Group& group)
{
FloatBuffer* fBuffer;
if ((fBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(GPU_BUFFER_NAME))) == NULL)
return false;
gpuIterator = gpuBuffer = fBuffer->getData();
return true;
}
void GLLineRenderer::createBuffers(const Group& group)
{
FloatBuffer* fBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(GPU_BUFFER_NAME,FloatBufferCreator(14),0,false));
gpuIterator = gpuBuffer = fBuffer->getData();
}
void GLLineRenderer::destroyBuffers(const Group& group)
{
group.destroyBuffer(GPU_BUFFER_NAME);
}
void GLLineRenderer::render(const Group& group)
{
if (!prepareBuffers(group))
return;
initBlending();
initRenderingHints();
glLineWidth(width);
glDisable(GL_TEXTURE_2D);
glShadeModel(GL_FLAT);
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
*(gpuIterator++) = particle.position().x;
*(gpuIterator++) = particle.position().y;
*(gpuIterator++) = particle.position().z;
gpuIterator += 4; // skips the first vertex color data as GL_FLAT was forced
*(gpuIterator++) = particle.position().x + particle.velocity().x * length;
*(gpuIterator++) = particle.position().y + particle.velocity().y * length;
*(gpuIterator++) = particle.position().z + particle.velocity().z * length;
*(gpuIterator++) = particle.getR();
*(gpuIterator++) = particle.getG();
*(gpuIterator++) = particle.getB();
*(gpuIterator++) = particle.getParamCurrentValue(PARAM_ALPHA);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
// interleaves vertex and color data
glVertexPointer(3,GL_FLOAT,7 * sizeof(float),gpuBuffer);
glColorPointer(4,GL_FLOAT,7 * sizeof(float),gpuBuffer + 3);
glDrawArrays(GL_LINES,0,group.getNbParticles() << 1);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}}

View File

@ -0,0 +1,204 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLLineTrailRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_ArrayBuffer.h"
namespace SPK
{
namespace GL
{
const std::string GLLineTrailRenderer::VERTEX_BUFFER_NAME("SPK_GLLineTrailRenderer_Vertex");
const std::string GLLineTrailRenderer::COLOR_BUFFER_NAME("SPK_GLLineTrailRenderer_Color");
const std::string GLLineTrailRenderer::VALUE_BUFFER_NAME("SPK_GLLineTrailRenderer_Value");
float* GLLineTrailRenderer::vertexBuffer = NULL;
float* GLLineTrailRenderer::vertexIterator = NULL;
float* GLLineTrailRenderer::colorBuffer = NULL;
float* GLLineTrailRenderer::colorIterator = NULL;
float* GLLineTrailRenderer::valueBuffer = NULL;
float* GLLineTrailRenderer::valueIterator = NULL;
GLLineTrailRenderer::GLLineTrailRenderer() :
GLRenderer(),
nbSamples(8),
width(1.0f),
duration(1.0f),
degeneratedR(0.0f),
degeneratedG(0.0f),
degeneratedB(0.0f),
degeneratedA(0.0f)
{
enableBlending(true);
}
void GLLineTrailRenderer::setDegeneratedLines(float r,float g,float b,float a)
{
degeneratedR = r;
degeneratedG = g;
degeneratedB = b;
degeneratedA = a;
}
bool GLLineTrailRenderer::checkBuffers(const Group& group)
{
FloatBuffer* fVertexBuffer;
FloatBuffer* fColorBuffer;
FloatBuffer* fValueBuffer;
if ((fVertexBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(VERTEX_BUFFER_NAME,nbSamples))) == NULL)
return false;
if ((fColorBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(COLOR_BUFFER_NAME,nbSamples))) == NULL)
return false;
if ((fValueBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(VALUE_BUFFER_NAME,nbSamples))) == NULL)
return false;
vertexIterator = vertexBuffer = fVertexBuffer->getData();
colorIterator = colorBuffer = fColorBuffer->getData();
valueIterator = valueBuffer = fValueBuffer->getData();
return true;
}
void GLLineTrailRenderer::createBuffers(const Group& group)
{
FloatBuffer* fVertexBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(VERTEX_BUFFER_NAME,FloatBufferCreator((nbSamples + 2) * 3),nbSamples,true));
FloatBuffer* fColorBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(COLOR_BUFFER_NAME,FloatBufferCreator((nbSamples + 2) << 2),nbSamples,true));
FloatBuffer* fValueBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(VALUE_BUFFER_NAME,FloatBufferCreator(nbSamples),nbSamples,true));
vertexIterator = vertexBuffer = fVertexBuffer->getData();
colorIterator = colorBuffer = fColorBuffer->getData();
valueIterator = valueBuffer = fValueBuffer->getData();
// Fills the buffers with correct values
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
init(particle,particle.getAge());
}
// Resets the iterators at the beginning after the init
vertexIterator = vertexBuffer;
colorIterator = colorBuffer;
valueIterator = valueBuffer;
}
void GLLineTrailRenderer::destroyBuffers(const Group& group)
{
group.destroyBuffer(VERTEX_BUFFER_NAME);
group.destroyBuffer(COLOR_BUFFER_NAME);
group.destroyBuffer(VALUE_BUFFER_NAME);
}
void GLLineTrailRenderer::init(const Group& group)
{
if (!prepareBuffers(group))
return;
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
init(particle,particle.getAge());
}
}
void GLLineTrailRenderer::render(const Group& group)
{
if (!prepareBuffers(group))
return;
initBlending();
initRenderingHints();
// Inits lines' parameters
glLineWidth(width);
glDisable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
float age = particle.getAge();
float oldAge = *valueIterator;
if ((age == 0.0f)||(age < *valueIterator)) // If the particle is new, buffers for it are reinitialized
init(particle,0.0f);
else
{
if (age - *(valueIterator + 1) >= duration / (nbSamples - 1)) // shifts the data by one
{
memmove(vertexIterator + 6,vertexIterator + 3,(nbSamples - 1) * 3 * sizeof(float));
memmove(colorIterator + 8,colorIterator + 4,((nbSamples - 1) << 2) * sizeof(float));
memmove(valueIterator + 1,valueIterator,(nbSamples - 1) * sizeof(float));
// post degenerated vertex copy
memcpy(vertexIterator + (nbSamples + 1) * 3,vertexIterator + nbSamples * 3,3 * sizeof(float));
}
// Updates the current sample
const Vector3D& pos = particle.position();
*(vertexIterator++) = pos.x;
*(vertexIterator++) = pos.y;
*(vertexIterator++) = pos.z;
memcpy(vertexIterator,vertexIterator - 3,3 * sizeof(float));
vertexIterator += (nbSamples + 1) * 3;
colorIterator += 4; // skips post degenerated vertex color
*(colorIterator++) = particle.getR();
*(colorIterator++) = particle.getG();
*(colorIterator++) = particle.getB();
*(colorIterator++) = particle.getParamCurrentValue(PARAM_ALPHA);
colorIterator += 3;
*(valueIterator++) = age;
//valueIterator += nbSamples;
// Updates alpha
for (size_t i = 0; i < nbSamples - 1; ++i)
{
float ratio = (age - oldAge) / (duration - age + *valueIterator);
if (ratio > 0.0f)
*colorIterator *= ratio < 1.0f ? 1.0f - ratio : 0.0f;
colorIterator += 4;
++valueIterator;
}
++colorIterator;
}
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4,GL_FLOAT,0,colorBuffer);
glVertexPointer(3,GL_FLOAT,0,vertexBuffer);
glDrawArrays(GL_LINE_STRIP,0,group.getNbParticles() * (nbSamples + 2));
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}}

View File

@ -0,0 +1,104 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLPointRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
namespace SPK
{
namespace GL
{
GLPointRenderer::GLPointRenderer(float size) :
GLRenderer(),
PointRendererInterface(POINT_SQUARE,size),
GLExtHandler(),
textureIndex(0),
worldSize(false)
{}
bool GLPointRenderer::setType(PointType type)
{
if ((type == POINT_SPRITE)&&(!loadGLExtPointSprite()))
return false;
this->type = type;
return true;
}
bool GLPointRenderer::enableWorldSize(bool worldSizeEnabled)
{
worldSize = ((worldSizeEnabled)&&(loadGLExtPointParameter()));
return worldSize;
}
void GLPointRenderer::render(const Group& group)
{
initBlending();
initRenderingHints();
switch(type)
{
case POINT_SQUARE :
glDisable(GL_TEXTURE_2D);
glDisable(GL_POINT_SMOOTH);
if (getPointSpriteGLExt() == SUPPORTED)
disablePointSpriteGLExt();
break;
case POINT_SPRITE :
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureIndex);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,getTextureBlending());
enablePointSpriteGLExt();
break;
case POINT_CIRCLE :
glDisable(GL_TEXTURE_2D);
glEnable(GL_POINT_SMOOTH);
if (getPointSpriteGLExt() == SUPPORTED)
disablePointSpriteGLExt();
break;
}
if (worldSize)
enablePointParameterGLExt(size,true);
else
{
glPointSize(size);
if (getPointParameterGLExt() == SUPPORTED)
disablePointParameterGLExt();
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(group.getModel()->isEnabled(PARAM_ALPHA) ? 4 : 3,GL_FLOAT,group.getParamStride(),group.getParamAddress(PARAM_RED));
glVertexPointer(3,GL_FLOAT,group.getPositionStride(),group.getPositionAddress());
glDrawArrays(GL_POINTS,0,group.getNbParticles());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}}

View File

@ -0,0 +1,279 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLQuadRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_ArrayBuffer.h"
namespace SPK
{
namespace GL
{
const std::string GLQuadRenderer::GPU_BUFFER_NAME("SPK_GLQuadRenderer_GPU");
const std::string GLQuadRenderer::TEXTURE_BUFFER_NAME("SPK_GLQuadRenderer_Texture");
float* GLQuadRenderer::gpuBuffer = NULL;
float* GLQuadRenderer::gpuIterator = NULL;
float* GLQuadRenderer::textureBuffer = NULL;
float* GLQuadRenderer::textureIterator = NULL;
void (GLQuadRenderer::*GLQuadRenderer::renderParticle)(const Particle&) const = NULL;
GLQuadRenderer::GLQuadRenderer(float scaleX,float scaleY) :
GLRenderer(),
QuadRendererInterface(scaleX,scaleY),
Oriented3DRendererInterface(),
GLExtHandler(),
textureIndex(0)
{}
bool GLQuadRenderer::checkBuffers(const Group& group)
{
FloatBuffer* fGpuBuffer;
if ((fGpuBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(GPU_BUFFER_NAME))) == NULL)
return false;
if (texturingMode != TEXTURE_NONE)
{
FloatBuffer* fTextureBuffer;
if ((fTextureBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(TEXTURE_BUFFER_NAME,texturingMode))) == NULL)
textureBuffer = createTextureBuffer(group);
textureIterator = textureBuffer = fTextureBuffer->getData();
}
gpuIterator = gpuBuffer = fGpuBuffer->getData();
return true;
}
void GLQuadRenderer::createBuffers(const Group& group)
{
FloatBuffer* fBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(GPU_BUFFER_NAME,FloatBufferCreator(28),0,false));
gpuIterator = gpuBuffer = fBuffer->getData();
if (texturingMode != TEXTURE_NONE)
textureIterator = textureBuffer = createTextureBuffer(group);
}
void GLQuadRenderer::destroyBuffers(const Group& group)
{
group.destroyBuffer(GPU_BUFFER_NAME);
group.destroyBuffer(TEXTURE_BUFFER_NAME);
}
float* GLQuadRenderer::createTextureBuffer(const Group& group) const
{
FloatBuffer* fbuffer = NULL;
switch(texturingMode)
{
case TEXTURE_2D :
fbuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(TEXTURE_BUFFER_NAME,FloatBufferCreator(8),TEXTURE_2D,false));
if (!group.getModel()->isEnabled(PARAM_TEXTURE_INDEX))
{
float t[8] = {1.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f};
for (size_t i = 0; i < group.getParticles().getNbReserved() << 3; ++i)
fbuffer->getData()[i] = t[i & 7];
}
break;
case TEXTURE_3D :
fbuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(TEXTURE_BUFFER_NAME,FloatBufferCreator(12),TEXTURE_3D,false));
float t[12] = {1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f,1.0f,1.0f,0.0f};
for (size_t i = 0; i < group.getParticles().getNbReserved() * 12; ++i)
fbuffer->getData()[i] = t[i % 12];
break;
}
return fbuffer->getData();
}
bool GLQuadRenderer::setTexturingMode(TexturingMode mode)
{
if ((mode == TEXTURE_3D)&&(!loadGLExtTexture3D()))
return false;
texturingMode = mode;
return true;
}
void GLQuadRenderer::render(const Group& group)
{
if (!prepareBuffers(group))
return;
float oldModelView[16];
for (int i = 0; i < 16; ++i)
oldModelView[i] = modelView[i];
glGetFloatv(GL_MODELVIEW_MATRIX,modelView);
for (int i = 0; i < 16; ++i)
if (oldModelView[i] != modelView[i])
{
invertModelView();
break;
}
initBlending();
initRenderingHints();
glShadeModel(GL_FLAT);
switch(texturingMode)
{
case TEXTURE_2D :
if (getTexture3DGLExt() == SUPPORTED)
glDisable(GL_TEXTURE_3D);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureIndex);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,getTextureBlending());
if (!group.getModel()->isEnabled(PARAM_TEXTURE_INDEX))
{
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render2D;
else
renderParticle = &GLQuadRenderer::render2DRot;
}
else
{
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render2DAtlas;
else
renderParticle = &GLQuadRenderer::render2DAtlasRot;
}
break;
case TEXTURE_3D :
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D,textureIndex);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,getTextureBlending());
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render3D;
else
renderParticle = &GLQuadRenderer::render3DRot;
break;
case TEXTURE_NONE :
glDisable(GL_TEXTURE_2D);
if (getTexture3DGLExt() == SUPPORTED)
glDisable(GL_TEXTURE_3D);
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render2D;
else
renderParticle = &GLQuadRenderer::render2DRot;
break;
}
bool globalOrientation = precomputeOrientation3D(
group,
Vector3D(-invModelView[8],-invModelView[9],-invModelView[10]),
Vector3D(invModelView[4],invModelView[5],invModelView[6]),
Vector3D(invModelView[12],invModelView[13],invModelView[14]));
if (globalOrientation)
{
computeGlobalOrientation3D();
for (size_t i = 0; i < group.getNbParticles(); ++i)
(this->*renderParticle)(group.getParticle(i));
}
else
{
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
computeSingleOrientation3D(particle);
(this->*renderParticle)(particle);
}
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
if (texturingMode == TEXTURE_2D)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2,GL_FLOAT,0,textureBuffer);
}
else if (texturingMode == TEXTURE_3D)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(3,GL_FLOAT,0,textureBuffer);
}
// interleaves vertex and color data
glVertexPointer(3,GL_FLOAT,7 * sizeof(float),gpuBuffer);
glColorPointer(4,GL_FLOAT,7 * sizeof(float),gpuBuffer + 3);
glDrawArrays(GL_QUADS,0,group.getNbParticles() << 2);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
if (texturingMode != TEXTURE_NONE)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void GLQuadRenderer::render2D(const Particle& particle) const
{
scaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
}
void GLQuadRenderer::render2DRot(const Particle& particle) const
{
rotateAndScaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
}
void GLQuadRenderer::render3D(const Particle& particle) const
{
scaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture3D(particle);
}
void GLQuadRenderer::render3DRot(const Particle& particle) const
{
rotateAndScaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture3D(particle);
}
void GLQuadRenderer::render2DAtlas(const Particle& particle) const
{
scaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture2DAtlas(particle);
}
void GLQuadRenderer::render2DAtlasRot(const Particle& particle) const
{
rotateAndScaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture2DAtlas(particle);
}
}}

View File

@ -0,0 +1,80 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.h"
namespace SPK
{
namespace GL
{
GLRenderer::GLRenderer() :
Renderer(),
blendingEnabled(false),
srcBlending(GL_SRC_ALPHA),
destBlending(GL_ONE_MINUS_SRC_ALPHA),
textureBlending(GL_MODULATE)
{}
GLRenderer::~GLRenderer() {}
void GLRenderer::setBlending(BlendingMode blendMode)
{
switch(blendMode)
{
case BLENDING_NONE :
srcBlending = GL_ONE;
destBlending = GL_ZERO;
blendingEnabled = false;
break;
case BLENDING_ADD :
srcBlending = GL_SRC_ALPHA;
destBlending = GL_ONE;
blendingEnabled = true;
break;
case BLENDING_ALPHA :
srcBlending = GL_SRC_ALPHA;
destBlending = GL_ONE_MINUS_SRC_ALPHA;
blendingEnabled = true;
break;
}
}
void GLRenderer::saveGLStates()
{
glPushAttrib(GL_POINT_BIT |
GL_LINE_BIT |
GL_ENABLE_BIT |
GL_COLOR_BUFFER_BIT |
GL_CURRENT_BIT |
GL_TEXTURE_BIT |
GL_DEPTH_BUFFER_BIT |
GL_LIGHTING_BIT |
GL_POLYGON_BIT);
}
void GLRenderer::restoreGLStates()
{
glPopAttrib();
}
}}

Some files were not shown because too many files have changed in this diff Show More