add sparkle explosions
This commit is contained in:
3
libs/spark/src/Core/.directory
Normal file
3
libs/spark/src/Core/.directory
Normal file
@@ -0,0 +1,3 @@
|
||||
[Dolphin]
|
||||
Timestamp=2011,1,5,19,24,26
|
||||
ViewMode=1
|
53
libs/spark/src/Core/SPK_BufferHandler.cpp
Normal file
53
libs/spark/src/Core/SPK_BufferHandler.cpp
Normal 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;
|
||||
}
|
||||
}
|
28
libs/spark/src/Core/SPK_DEF.cpp
Normal file
28
libs/spark/src/Core/SPK_DEF.cpp
Normal 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;
|
||||
}
|
131
libs/spark/src/Core/SPK_Emitter.cpp
Normal file
131
libs/spark/src/Core/SPK_Emitter.cpp
Normal 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);
|
||||
}
|
||||
}
|
214
libs/spark/src/Core/SPK_Factory.cpp
Normal file
214
libs/spark/src/Core/SPK_Factory.cpp
Normal 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;
|
||||
}
|
||||
}
|
746
libs/spark/src/Core/SPK_Group.cpp
Normal file
746
libs/spark/src/Core/SPK_Group.cpp
Normal 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;
|
||||
}
|
||||
}
|
148
libs/spark/src/Core/SPK_Interpolator.cpp
Normal file
148
libs/spark/src/Core/SPK_Interpolator.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
299
libs/spark/src/Core/SPK_Model.cpp
Normal file
299
libs/spark/src/Core/SPK_Model.cpp
Normal 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];
|
||||
}
|
||||
}
|
100
libs/spark/src/Core/SPK_Modifier.cpp
Normal file
100
libs/spark/src/Core/SPK_Modifier.cpp
Normal 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
|
||||
}
|
||||
}
|
237
libs/spark/src/Core/SPK_Particle.cpp
Normal file
237
libs/spark/src/Core/SPK_Particle.cpp
Normal 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);
|
||||
}
|
||||
}
|
118
libs/spark/src/Core/SPK_Registerable.cpp
Normal file
118
libs/spark/src/Core/SPK_Registerable.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
37
libs/spark/src/Core/SPK_Renderer.cpp
Normal file
37
libs/spark/src/Core/SPK_Renderer.cpp
Normal 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(){}
|
||||
}
|
330
libs/spark/src/Core/SPK_System.cpp
Normal file
330
libs/spark/src/Core/SPK_System.cpp
Normal 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);
|
||||
}
|
||||
}
|
239
libs/spark/src/Core/SPK_Transformable.cpp
Normal file
239
libs/spark/src/Core/SPK_Transformable.cpp
Normal 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
|
||||
}
|
||||
}
|
177
libs/spark/src/Core/SPK_Vector3D.cpp
Normal file
177
libs/spark/src/Core/SPK_Vector3D.cpp
Normal 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;
|
||||
}
|
||||
}
|
35
libs/spark/src/Core/SPK_Zone.cpp
Normal file
35
libs/spark/src/Core/SPK_Zone.cpp
Normal 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user