add sparkle explosions

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

View File

@@ -0,0 +1,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);
}
}