add sparkle explosions

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

View File

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

View File

@@ -0,0 +1,53 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_BufferHandler.h"
namespace SPK
{
bool BufferHandler::bufferCreation = true;
void BufferHandler::enableBuffersCreation(bool creation)
{
bufferCreation = creation;
}
bool BufferHandler::isBuffersCreationEnabled()
{
return bufferCreation;
}
bool BufferHandler::prepareBuffers(const Group& group)
{
if (!checkBuffers(group))
{
if (isBuffersCreationEnabled())
{
destroyBuffers(group);
createBuffers(group);
return true;
}
return false;
}
return true;
}
}

View File

@@ -0,0 +1,28 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_DEF.h"
namespace SPK
{
unsigned int randomSeed = 1;
}

View File

@@ -0,0 +1,131 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Emitter.h"
#include "Extensions/Zones/SPK_Point.h"
namespace SPK
{
Emitter::Emitter() :
Registerable(),
Transformable(),
zone(&getDefaultZone()),
full(true),
tank(-1),
flow(0.0f),
forceMin(0.0f),
forceMax(0.0f),
fraction(random(0.0f,1.0f)),
active(true)
{}
void Emitter::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
registerChild(zone,registerAll);
}
void Emitter::copyChildren(const Emitter& emitter,bool createBase)
{
Registerable::copyChildren(emitter,createBase);
zone = dynamic_cast<Zone*>(copyChild(emitter.zone,createBase));
}
void Emitter::destroyChildren(bool keepChildren)
{
destroyChild(zone,keepChildren);
Registerable::destroyChildren(keepChildren);
}
Registerable* Emitter::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if (object != NULL)
return object;
return zone->findByName(name);
}
void Emitter::changeTank(int deltaTank)
{
if (tank >= 0)
{
tank += deltaTank;
if (tank < 0)
tank = 0;
}
}
void Emitter::changeFlow(float deltaFlow)
{
if (flow >= 0.0f)
{
flow += deltaFlow;
if (flow < 0.0f)
flow = 0.0f;
}
}
void Emitter::setZone(Zone* zone,bool full)
{
decrementChildReference(this->zone);
incrementChildReference(zone);
if (zone == NULL)
zone = &getDefaultZone();
this->zone = zone;
this->full = full;
}
Zone& Emitter::getDefaultZone()
{
static Point defaultZone;
return defaultZone;
}
unsigned int Emitter::updateNumber(float deltaTime)
{
int nbBorn;
if (flow < 0.0f)
{
nbBorn = std::max(0,tank);
tank = 0;
}
else if (tank != 0)
{
fraction += flow * deltaTime;
nbBorn = static_cast<int>(fraction);
if (tank >= 0)
{
nbBorn = std::min(tank,nbBorn);
tank -= nbBorn;
}
fraction -= nbBorn;
}
else
nbBorn = 0;
return static_cast<unsigned int>(nbBorn);
}
}

View File

@@ -0,0 +1,214 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Factory.h"
namespace SPK
{
SPKFactory* SPKFactory::instance = NULL;
SPK_ID SPKFactory::currentID = NO_ID;
SPKFactory& SPKFactory::getInstance()
{
if (instance == NULL)
instance = new SPKFactory;
return *instance;
}
void SPKFactory::destroyInstance()
{
if (instance != NULL)
{
delete instance;
instance = NULL;
}
}
SPK_ID SPKFactory::create(const Registerable& base)
{
// Clears the adresses set
SPKAdresses.clear();
// clones the reference
Registerable* innerBase = base.clone(true);
// registers the base
registerObject(innerBase);
return innerBase->ID;
}
Registerable* SPKFactory::get(SPK_ID ID)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
return it->second;
return NULL; // the ID is not registered
}
Registerable* SPKFactory::copy(SPK_ID ID)
{
// Clears the adresses set
SPKAdresses.clear();
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
return registerObject(it->second->clone(false)); // registers a copy
return NULL; // the ID is not registered
}
Registerable* SPKFactory::copy(const Registerable* registerable)
{
// Clears the adresses set
SPKAdresses.clear();
if (registerable->isRegistered())
return registerObject(registerable->clone(false)); // registers a copy
return NULL;
}
bool SPKFactory::destroy(SPK_ID ID,bool checkNbReferences)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if ((it != SPKRegister.end())&& // the ID was found
((!checkNbReferences)||
(it->second->getNbReferences() == 0)))
{
unregisterObject(it,false);
return true;
}
return false; // the ID is not registered
}
bool SPKFactory::destroy(Registerable* object,bool checkNbReferences)
{
if (object == NULL)
return false;
return destroy(object->getSPKID(),checkNbReferences);
}
void SPKFactory::destroyAll()
{
std::map<SPK_ID,Registerable*>::iterator it;
while((it = SPKRegister.begin()) != SPKRegister.end())
unregisterObject(it,true);
}
Registerable* SPKFactory::findByName(const std::string& name)
{
for (std::map<SPK_ID,Registerable*>::const_iterator it = SPKRegister.begin(); it != SPKRegister.end(); ++it)
if (it->second->getName().compare(name) == 0)
return it->second;
return NULL;
}
void SPKFactory::trace(SPK_ID ID)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
traceObject(it,true);
else // the ID is not registered
std::cout << "No object registered in the SPKFactory with this ID";
}
void SPKFactory::trace(const Registerable* registerable)
{
trace(registerable->getSPKID());
}
void SPKFactory::traceAll()
{
std::cout << "Nb of objects in the SPKFactory : " << getNbObjects() << std::endl;
for (std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.begin(); it != SPKRegister.end(); ++it)
traceObject(it,true);
}
void SPKFactory::traceObject(const std::map<SPK_ID,Registerable*>::iterator& it,bool nextLine)
{
SPK_ID ID = it->first;
Registerable* object = it->second;
std::cout << object
<< " ID:" << ID
<< " type:" << object->getClassName().c_str()
<< " nbRef:" << object->getNbReferences()
<< " flag:";
if (object->isShared()) std::cout << "S";
if (object->isDestroyable()) std::cout << "D";
if (object->getName().length() > 0) std::cout << " \"" << object->getName() << "\"";
if (nextLine) std::cout << std::endl;
}
Registerable* SPKFactory::registerObject(Registerable* object)
{
object->onRegister();
object->ID = ++currentID;
// optimisation at the insertion to get an amortized constant complexity instead of a logarithmic complexity
SPKRegister.insert(SPKRegister.size() != 0 ? --SPKRegister.end() : SPKRegister.begin(),
std::pair<SPK_ID,Registerable*>(object->ID,object));
// Traces allocations
#ifdef SPK_DEBUG
++nbAlloc;
std::cout << "REGISTER ";
traceObject(SPKRegister.find(object->ID),false);
std::cout << " nbAlloc:" << nbAlloc << " nbObj:" << getNbObjects() << std::endl;
#endif
return object;
}
void SPKFactory::unregisterObject(std::map<SPK_ID,Registerable*>::iterator& it,bool keepChildren)
{
Registerable* object = it->second;
object->onUnregister();
// traces desallocations
#ifdef SPK_DEBUG
++nbDesalloc;
std::cout << "UNREGISTER ";
traceObject(it,false);
std::cout << " nbDesalloc:" << nbDesalloc << " nbObj:" << getNbObjects() - 1 << std::endl;
#endif
SPKRegister.erase(it); // unregister object
object->ID = NO_ID;
object->destroyChildren(keepChildren); // unregister and destroy registered children
delete object; // destroy object
}
bool SPKFactory::unregisterObject(SPK_ID ID,bool keepChildren)
{
std::map<SPK_ID,Registerable*>::iterator it = SPKRegister.find(ID);
if (it != SPKRegister.end()) // the ID was found
{
unregisterObject(it,keepChildren);
return true;
}
return false;
}
}

View File

@@ -0,0 +1,746 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Group.h"
#include "Core/SPK_Emitter.h"
#include "Core/SPK_Modifier.h"
#include "Core/SPK_Renderer.h"
#include "Core/SPK_Factory.h"
#include "Core/SPK_Buffer.h"
namespace SPK
{
bool Group::bufferManagement = true;
Group::Group(Model* m,size_t capacity) :
Registerable(),
Transformable(),
model(m != NULL ? m : &getDefaultModel()),
renderer(NULL),
friction(0.0f),
gravity(Vector3D()),
pool(Pool<Particle>(capacity)),
particleData(new Particle::ParticleData[capacity]),
particleCurrentParams(new float[capacity * model->getSizeOfParticleCurrentArray()]),
particleExtendedParams(new float[capacity * model->getSizeOfParticleExtendedArray()]),
sortingEnabled(false),
distanceComputationEnabled(false),
creationBuffer(),
nbBufferedParticles(0),
fupdate(NULL),
fbirth(NULL),
fdeath(NULL),
boundingBoxEnabled(false),
emitters(),
modifiers(),
activeModifiers(),
additionalBuffers(),
swappableBuffers()
{}
Group::Group(const Group& group) :
Registerable(group),
Transformable(group),
model(group.model),
renderer(group.renderer),
friction(group.friction),
gravity(group.gravity),
pool(group.pool),
sortingEnabled(group.sortingEnabled),
distanceComputationEnabled(group.distanceComputationEnabled),
creationBuffer(group.creationBuffer),
nbBufferedParticles(group.nbBufferedParticles),
fupdate(group.fupdate),
fbirth(group.fbirth),
fdeath(group.fdeath),
boundingBoxEnabled(group.boundingBoxEnabled),
emitters(group.emitters),
modifiers(group.modifiers),
activeModifiers(group.activeModifiers.capacity()),
additionalBuffers(),
swappableBuffers()
{
particleData = new Particle::ParticleData[pool.getNbReserved()];
particleCurrentParams = new float[pool.getNbReserved() * model->getSizeOfParticleCurrentArray()];
particleExtendedParams = new float[pool.getNbReserved() * model->getSizeOfParticleExtendedArray()];
memcpy(particleData,group.particleData,pool.getNbTotal() * sizeof(Particle::ParticleData));
memcpy(particleCurrentParams,group.particleCurrentParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleCurrentArray());
memcpy(particleExtendedParams,group.particleExtendedParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleExtendedArray());
for (Pool<Particle>::iterator it = pool.begin(); it != pool.endInactive(); ++it)
{
it->group = this;
it->data = particleData + it->index;
it->currentParams = particleCurrentParams + it->index * model->getSizeOfParticleCurrentArray();
it->extendedParams = particleExtendedParams + it->index * model->getSizeOfParticleExtendedArray();
}
}
Group::~Group()
{
delete[] particleData;
delete[] particleCurrentParams;
delete[] particleExtendedParams;
// destroys additional buffers
destroyAllBuffers();
}
void Group::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
registerChild(model,registerAll);
registerChild(renderer,registerAll);
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != emitters.end(); ++it)
registerChild(*it,registerAll);
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
registerChild(*it,registerAll);
}
void Group::copyChildren(const Group& group,bool createBase)
{
Registerable::copyChildren(group,createBase);
model = dynamic_cast<Model*>(copyChild(group.model,createBase));
renderer = dynamic_cast<Renderer*>(copyChild(group.renderer,createBase));
// we clear the copies of pointers pushed in the vectors by the copy constructor
emitters.clear();
modifiers.clear();
for (std::vector<Emitter*>::const_iterator it = group.emitters.begin(); it != group.emitters.end(); ++it)
emitters.push_back(dynamic_cast<Emitter*>(copyChild(*it,createBase)));
for (std::vector<Modifier*>::const_iterator it = group.modifiers.begin(); it != group.modifiers.end(); ++it)
modifiers.push_back(dynamic_cast<Modifier*>(copyChild(*it,createBase)));
}
void Group::destroyChildren(bool keepChildren)
{
destroyChild(model,keepChildren);
destroyChild(renderer,keepChildren);
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != emitters.end(); ++it)
destroyChild(*it,keepChildren);
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
destroyChild(*it,keepChildren);
Registerable::destroyChildren(keepChildren);
}
Registerable* Group::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if (object != NULL)
return object;
object = model->findByName(name);
if (object != NULL)
return object;
if (renderer != NULL)
{
object = renderer->findByName(name);
if (object != NULL)
return object;
}
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != emitters.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
return NULL;
}
void Group::setModel(Model* newmodel)
{
if(!newmodel) newmodel = &getDefaultModel();
if(model == newmodel) return;
// empty and change model
empty();
decrementChildReference(model);
incrementChildReference(newmodel);
model = newmodel;
// recreate data
delete[] particleData;
delete[] particleCurrentParams;
delete[] particleExtendedParams;
particleData = new Particle::ParticleData[pool.getNbReserved()];
particleCurrentParams = new float[pool.getNbReserved() * model->getSizeOfParticleCurrentArray()];
particleExtendedParams = new float[pool.getNbReserved() * model->getSizeOfParticleExtendedArray()];
pool.clear();
// Destroys all the buffers
destroyAllBuffers();
}
void Group::setRenderer(Renderer* renderer)
{
decrementChildReference(this->renderer);
incrementChildReference(renderer);
if ((bufferManagement)&&(renderer != this->renderer))
{
if (this->renderer != NULL) this->renderer->destroyBuffers(*this);
if (renderer != NULL) renderer->createBuffers(*this);
}
this->renderer = renderer;
}
void Group::addEmitter(Emitter* emitter)
{
if (emitter == NULL)
return;
// Checks if the emitter is already in the group (since 1.03.03)
std::vector<Emitter*>::const_iterator it = std::find(emitters.begin(),emitters.end(),emitter);
if (it != emitters.end())
return;
incrementChildReference(emitter);
emitters.push_back(emitter);
}
void Group::removeEmitter(Emitter* emitter)
{
std::vector<Emitter*>::iterator it = std::find(emitters.begin(),emitters.end(),emitter);
if (it != emitters.end())
{
decrementChildReference(emitter);
emitters.erase(it);
}
}
void Group::addModifier(Modifier* modifier)
{
if (modifier == NULL)
return;
incrementChildReference(modifier);
if (bufferManagement)
modifier->createBuffers(*this);
modifiers.push_back(modifier);
}
void Group::removeModifier(Modifier* modifier)
{
std::vector<Modifier*>::iterator it = std::find(modifiers.begin(),modifiers.end(),modifier);
if (it != modifiers.end())
{
decrementChildReference(modifier);
if (bufferManagement)
(*it)->createBuffers(*this);
modifiers.erase(it);
}
}
bool Group::update(float deltaTime)
{
unsigned int nbManualBorn = nbBufferedParticles;
unsigned int nbAutoBorn = 0;
bool hasActiveEmitters = false;
// Updates emitters
activeEmitters.clear();
std::vector<Emitter*>::const_iterator endIt = emitters.end();
for (std::vector<Emitter*>::const_iterator it = emitters.begin(); it != endIt; ++it)
{
if ((*it)->isActive())
{
int nb = (*it)->updateNumber(deltaTime);
if (nb > 0)
{
EmitterData data = {*it,nb};
activeEmitters.push_back(data);
nbAutoBorn += nb;
}
}
hasActiveEmitters |= !((*it)->isSleeping());
}
std::vector<EmitterData>::iterator emitterIt = activeEmitters.begin();
unsigned int nbBorn = nbAutoBorn + nbManualBorn;
// Inits bounding box
if (boundingBoxEnabled)
{
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
}
// Prepare modifiers for processing
activeModifiers.clear();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != modifiers.end(); ++it)
{
(*it)->beginProcess(*this);
if ((*it)->isActive())
activeModifiers.push_back(*it);
}
// Updates particles
for (size_t i = 0; i < pool.getNbActive(); ++i)
{
if ((pool[i].update(deltaTime))||((fupdate != NULL)&&((*fupdate)(pool[i],deltaTime))))
{
if (fdeath != NULL)
(*fdeath)(pool[i]);
if (nbBorn > 0)
{
pool[i].init();
launchParticle(pool[i],emitterIt,nbManualBorn);
--nbBorn;
}
else
{
particleData[i].sqrDist = 0.0f;
pool.makeInactive(i);
--i;
}
}
else
{
if (boundingBoxEnabled)
updateAABB(pool[i]);
if (distanceComputationEnabled)
pool[i].computeSqrDist();
}
}
// Terminates modifiers processing
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != modifiers.end(); ++it)
(*it)->endProcess(*this);
// Emits new particles if some left
for (int i = nbBorn; i > 0; --i)
pushParticle(emitterIt,nbManualBorn);
// Sorts particles if enabled
if ((sortingEnabled)&&(pool.getNbActive() > 1))
sortParticles(0,pool.getNbActive() - 1);
if ((!boundingBoxEnabled)||(pool.getNbActive() == 0))
{
AABBMin.set(0.0f,0.0f,0.0f);
AABBMax.set(0.0f,0.0f,0.0f);
}
return (hasActiveEmitters)||(pool.getNbActive() > 0);
}
void Group::pushParticle(std::vector<EmitterData>::iterator& emitterIt,unsigned int& nbManualBorn)
{
Particle* ptr = pool.makeActive();
if (ptr == NULL)
{
if (pool.getNbEmpty() > 0)
{
Particle p(this,pool.getNbActive());
launchParticle(p,emitterIt,nbManualBorn);
pool.pushActive(p);
}
else if (nbManualBorn > 0)
popNextManualAdding(nbManualBorn);
}
else
{
ptr->init();
launchParticle(*ptr,emitterIt,nbManualBorn);
}
}
void Group::launchParticle(Particle& p,std::vector<EmitterData>::iterator& emitterIt,unsigned int& nbManualBorn)
{
if (nbManualBorn == 0)
{
emitterIt->emitter->emit(p);
if (--emitterIt->nbParticles == 0)
++emitterIt;
}
else
{
CreationData creationData = creationBuffer.front();
if (creationData.zone != NULL)
creationData.zone->generatePosition(p,creationData.full);
else
p.position() = creationData.position;
if (creationData.emitter != NULL)
creationData.emitter->generateVelocity(p);
else
p.velocity() = creationData.velocity;
popNextManualAdding(nbManualBorn);
}
// Resets old position (fix 1.04.00)
p.oldPosition() = p.position();
// first parameter interpolation
// must be here so that the velocity has already been initialized
p.interpolateParameters();
if (fbirth != NULL)
(*fbirth)(p);
if (boundingBoxEnabled)
updateAABB(p);
if (distanceComputationEnabled)
p.computeSqrDist();
}
void Group::render()
{
if ((renderer == NULL)||(!renderer->isActive()))
return;
renderer->render(*this);
}
void Group::empty()
{
for (size_t i = 0; i < pool.getNbActive(); ++i)
particleData[i].sqrDist = 0.0f;
pool.makeAllInactive();
creationBuffer.clear();
nbBufferedParticles = 0;
}
void Group::flushAddedParticles()
{
unsigned int nbManualBorn = nbBufferedParticles;
std::vector<EmitterData>::iterator emitterIt; // dummy emitterIt because we dont care
while(nbManualBorn > 0)
pushParticle(emitterIt,nbManualBorn);
}
float Group::addParticles(const Vector3D& start,const Vector3D& end,Emitter* emitter,float step,float offset)
{
if ((step <= 0.0f)||(offset < 0.0f))
return 0.0f;
Vector3D displacement = end - start;
float totalDist = displacement.getNorm();
while(offset < totalDist)
{
Vector3D position = start;
position += displacement * offset / totalDist;
addParticles(1,position,Vector3D(),NULL,emitter);
offset += step;
}
return offset - totalDist;
}
float Group::addParticles(const Vector3D& start,const Vector3D& end,const Vector3D& velocity,float step,float offset)
{
if ((step <= 0.0f)||(offset < 0.0f))
return 0.0f;
Vector3D displacement = end - start;
float totalDist = displacement.getNorm();
while(offset < totalDist)
{
Vector3D position = start;
position += displacement * (offset / totalDist);
addParticles(1,position,velocity,NULL,NULL);
offset += step;
}
return offset - totalDist;
}
void Group::addParticles(unsigned int nb,const Vector3D& position,const Vector3D& velocity,const Zone* zone,Emitter* emitter,bool full)
{
if (nb == 0)
return;
CreationData data = {nb,position,velocity,zone,emitter,full};
creationBuffer.push_back(data);
nbBufferedParticles += nb;
}
void Group::addParticles(unsigned int nb,Emitter* emitter)
{
addParticles(nb,Vector3D(),Vector3D(),emitter->getZone(),emitter,emitter->isFullZone());
}
void Group::addParticles(const Zone* zone,Emitter* emitter,float deltaTime,bool full)
{
addParticles(emitter->updateNumber(deltaTime),Vector3D(),Vector3D(),zone,emitter,full);
}
void Group::addParticles(const Vector3D& position,Emitter* emitter,float deltaTime)
{
addParticles(emitter->updateNumber(deltaTime),position,Vector3D(),NULL,emitter);
}
void Group::addParticles(Emitter* emitter,float deltaTime)
{
addParticles(emitter->updateNumber(deltaTime),Vector3D(),Vector3D(),emitter->getZone(),emitter,emitter->isFullZone());
}
void Group::sortParticles()
{
computeDistances();
if (sortingEnabled)
sortParticles(0,pool.getNbActive() - 1);
}
void Group::computeDistances()
{
if (!distanceComputationEnabled)
return;
Pool<Particle>::const_iterator endIt = pool.end();
for (Pool<Particle>::iterator it = pool.begin(); it != endIt; ++it)
it->computeSqrDist();
}
void Group::computeAABB()
{
if ((!boundingBoxEnabled)||(pool.getNbActive() == 0))
{
AABBMin.set(0.0f,0.0f,0.0f);
AABBMax.set(0.0f,0.0f,0.0f);
return;
}
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
Pool<Particle>::iterator endIt = pool.end();
for (Pool<Particle>::iterator it = pool.begin(); it != endIt; ++it)
updateAABB(*it);
}
void Group::reallocate(size_t capacity)
{
if (capacity > pool.getNbReserved())
{
pool.reallocate(capacity);
Particle::ParticleData* newData = new Particle::ParticleData[pool.getNbReserved()];
float* newCurrentParams = new float[pool.getNbReserved() * model->getSizeOfParticleCurrentArray()];
float* newExtendedParams = new float[pool.getNbReserved() * model->getSizeOfParticleExtendedArray()];
memcpy(newData,particleData,pool.getNbTotal() * sizeof(Particle::ParticleData));
memcpy(newCurrentParams,particleCurrentParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleCurrentArray());
memcpy(newExtendedParams,particleExtendedParams,pool.getNbTotal() * sizeof(float) * model->getSizeOfParticleExtendedArray());
delete[] particleData;
delete[] particleCurrentParams;
delete[] particleExtendedParams;
particleData = newData;
particleCurrentParams = newCurrentParams;
particleExtendedParams = newExtendedParams;
for (Pool<Particle>::iterator it = pool.begin(); it != pool.endInactive(); ++it)
{
it->group = this;
it->data = particleData + it->index;
it->currentParams = particleCurrentParams + it->index * model->getSizeOfParticleCurrentArray();
it->extendedParams = particleExtendedParams + it->index * model->getSizeOfParticleExtendedArray();
}
// Destroys all the buffers
destroyAllBuffers();
}
}
void Group::popNextManualAdding(unsigned int& nbManualBorn)
{
--creationBuffer.front().nb;
--nbManualBorn;
--nbBufferedParticles;
if (creationBuffer.front().nb <= 0)
creationBuffer.pop_front();
}
void Group::updateAABB(const Particle& particle)
{
const Vector3D& position = particle.position();
if (AABBMin.x > position.x)
AABBMin.x = position.x;
if (AABBMin.y > position.y)
AABBMin.y = position.y;
if (AABBMin.z > position.z)
AABBMin.z = position.z;
if (AABBMax.x < position.x)
AABBMax.x = position.x;
if (AABBMax.y < position.y)
AABBMax.y = position.y;
if (AABBMax.z < position.z)
AABBMax.z = position.z;
}
const void* Group::getParamAddress(ModelParam param) const
{
return particleCurrentParams + model->getParameterOffset(param);
}
size_t Group::getParamStride() const
{
return model->getSizeOfParticleCurrentArray() * sizeof(float);
}
Buffer* Group::createBuffer(const std::string& ID,const BufferCreator& creator,unsigned int flag,bool swapEnabled) const
{
destroyBuffer(ID);
Buffer* buffer = creator.createBuffer(pool.getNbReserved(),*this);
buffer->flag = flag;
buffer->swapEnabled = swapEnabled;
additionalBuffers.insert(std::pair<std::string,Buffer*>(ID,buffer));
if (swapEnabled)
swappableBuffers.insert(buffer);
return buffer;
}
void Group::destroyBuffer(const std::string& ID) const
{
std::map<std::string,Buffer*>::iterator it = additionalBuffers.find(ID);
if (it != additionalBuffers.end())
{
if (it->second->isSwapEnabled())
swappableBuffers.erase(it->second);
delete it->second;
additionalBuffers.erase(it);
}
}
void Group::destroyAllBuffers() const
{
for (std::map<std::string,Buffer*>::const_iterator it = additionalBuffers.begin(); it != additionalBuffers.end(); ++it)
delete it->second;
additionalBuffers.clear();
swappableBuffers.clear();
}
Buffer* Group::getBuffer(const std::string& ID,unsigned int flag) const
{
Buffer* buffer = getBuffer(ID);
if ((buffer != NULL)&&(buffer->flag == flag))
return buffer;
return NULL;
}
Buffer* Group::getBuffer(const std::string& ID) const
{
std::map<std::string,Buffer*>::const_iterator it = additionalBuffers.find(ID);
if (it != additionalBuffers.end())
return it->second;
return NULL;
}
void Group::enableBuffersManagement(bool manage)
{
bufferManagement = manage;
}
bool Group::isBuffersManagementEnabled()
{
return bufferManagement;
}
void Group::sortParticles(int start,int end)
{
if (start < end)
{
int i = start - 1;
int j = end + 1;
float pivot = particleData[(start + end) >> 1].sqrDist;
while (true)
{
do ++i;
while (particleData[i].sqrDist > pivot);
do --j;
while (particleData[j].sqrDist < pivot);
if (i < j)
swapParticles(pool[i],pool[j]);
else break;
}
sortParticles(start,j);
sortParticles(j + 1,end);
}
}
void Group::propagateUpdateTransform()
{
for (std::vector<Emitter*>::const_iterator emitterIt = emitters.begin(); emitterIt != emitters.end(); ++emitterIt)
(*emitterIt)->updateTransform(this);
for (std::vector<Modifier*>::const_iterator modifierIt = modifiers.begin(); modifierIt != modifiers.end(); ++modifierIt)
if ((*modifierIt)->isLocalToSystem())
(*modifierIt)->updateTransform(this);
}
Model& Group::getDefaultModel()
{
static Model defaultModel;
return defaultModel;
}
}

View File

@@ -0,0 +1,148 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Interpolator.h"
#include "Core/SPK_Model.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Interpolator::computeXFn Interpolator::COMPUTE_X_FN[4] =
{
&Interpolator::computeXLifeTime,
&Interpolator::computeXAge,
&Interpolator::computeXParam,
&Interpolator::computeXVelocity,
};
Interpolator::Interpolator() :
graph(),
type(INTERPOLATOR_LIFETIME),
param(PARAM_SIZE),
scaleXVariation(0.0f),
offsetXVariation(0.0f),
loopingEnabled(false)
{}
float Interpolator::computeXLifeTime(const Particle& particle) const
{
return particle.getAge() / (particle.getAge() + particle.getLifeLeft());
}
float Interpolator::computeXAge(const Particle& particle) const
{
return particle.getAge();
}
float Interpolator::computeXParam(const Particle& particle) const
{
return particle.getParamCurrentValue(param);
}
float Interpolator::computeXVelocity(const Particle& particle) const
{
return particle.velocity().getSqrNorm();
}
float Interpolator::interpolate(const Particle& particle,ModelParam interpolatedParam,float ratioY,float offsetX,float scaleX)
{
// First finds the current X of the particle
InterpolatorEntry currentKey((this->*Interpolator::COMPUTE_X_FN[type])(particle));
currentKey.x += offsetX; // Offsets it
currentKey.x *= scaleX; // Scales it
if (loopingEnabled)
{
// If the graph has les than 2 entries, we cannot loop
if (graph.size() < 2)
{
if (graph.empty())
return Model::getDefaultValue(interpolatedParam);
else
return interpolateY(*(graph.begin()),ratioY);
}
// Else finds the current X in the range
float newX = (currentKey.x - graph.begin()->x) / (graph.rbegin()->x - graph.begin()->x);
newX -= static_cast<int>(newX);
if (newX < 0.0f)
newX = 1.0f + newX;
currentKey.x = graph.begin()->x + newX * (graph.rbegin()->x - graph.begin()->x);
}
// Gets the entry that is immediatly after the current X
std::set<InterpolatorEntry>::const_iterator nextIt = graph.upper_bound(currentKey);
// If the current X is higher than the one of the last entry
if (nextIt == graph.end())
{
if (graph.empty()) // If the graph has no entry, sets the default value
return Model::getDefaultValue(interpolatedParam);
else // Else sets the value of the last entry
return interpolateY(*(--nextIt),ratioY);
}
else if (nextIt == graph.begin()) // If the current X is lower than the first entry, sets the value to the first entry
{
return interpolateY(*nextIt,ratioY);
}
else // Else interpolated between the entries before and after the current X
{
const InterpolatorEntry& nextEntry = *nextIt;
const InterpolatorEntry& previousEntry = *(--nextIt);
float y0 = interpolateY(previousEntry,ratioY);
float y1 = interpolateY(nextEntry,ratioY);
float ratioX = (currentKey.x - previousEntry.x) / (nextEntry.x - previousEntry.x);
return y0 + ratioX * (y1 - y0);
}
}
void Interpolator::generateSinCurve(float period,float amplitudeMin,float amplitudeMax,float offsetX,float offsetY,float startX,unsigned int length,unsigned int nbSamples)
{
// First clear any previous entry
clearGraph();
const float PI = 3.1415926535897932384626433832795f;
for (size_t i = 0; i < nbSamples; ++i)
{
float x = startX + i * period * length / (nbSamples - 1);
float sin = std::sin((x + offsetX) * 2 * PI / period);
addEntry(x,amplitudeMin * sin + offsetY,amplitudeMax * sin + offsetY);
}
}
void Interpolator::generatePolyCurve(float constant,float linear,float quadratic,float cubic,float startX,float endX,unsigned int nbSamples)
{
// First clear any previous entry
clearGraph();
for (size_t i = 0; i < nbSamples; ++i)
{
float x = startX + i * (endX - startX) / (nbSamples - 1);
float x2 = x * x;
float x3 = x2 * x;
addEntry(x,constant + x * linear + x2 * quadratic + x3 * cubic);
}
}
}

View File

@@ -0,0 +1,299 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Model.h"
#include "Core/SPK_Interpolator.h"
namespace SPK
{
const float Model::DEFAULT_VALUES[NB_PARAMS] =
{
1.0f, // RED
1.0f, // GREEN
1.0f, // BLUE
1.0f, // ALPHA
1.0f, // SIZE
1.0f, // MASS
0.0f, // ANGLE
0.0f, // TEXTURE_INDEX
0.0f, // ROTATION_SPEED
0.0f, // CUSTOM_0
0.0f, // CUSTOM_1
0.0f, // CUSTOM_2
};
Model::Model(int enableFlag,int mutableFlag,int randomFlag,int interpolatedFlag) :
Registerable(),
lifeTimeMin(1.0f),
lifeTimeMax(1.0f),
immortal(false),
paramsSize(0),
nbEnableParams(0),
nbMutableParams(0),
nbRandomParams(0),
nbInterpolatedParams(0)
{
enableFlag |= FLAG_RED | FLAG_GREEN | FLAG_BLUE; // Adds the color parameters to the enable flag
this->enableFlag = enableFlag & ((1 << (NB_PARAMS + 1)) - 1); // masks the enable flag with the existing parameters
this->interpolatedFlag = interpolatedFlag & this->enableFlag; // masks the interpolated flag with the enable flag
this->mutableFlag = mutableFlag & this->enableFlag; // masks the mutable flag with the enable flag
this->mutableFlag &= ~this->interpolatedFlag; // a param cannot be both interpolated and mutable
this->randomFlag = randomFlag & this->enableFlag; // masks the random flag with the enable flag
this->randomFlag &= ~this->interpolatedFlag; // a param cannot be both interpolated and random
int particleEnableParamsSize = 0;
int particleMutableParamsSize = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
{
ModelParam param = static_cast<ModelParam>(i);
int paramSize = 0;
if (isEnabled(param))
{
++nbEnableParams;
if (!isInterpolated(param))
{
interpolators[i] = NULL;
paramSize = 1;
if (isMutable(param))
{
paramSize = 2;
++nbMutableParams;
}
if (isRandom(param))
{
paramSize <<= 1;
++nbRandomParams;
}
}
else
{
interpolators[i] = new Interpolator(); // Creates the interpolator
++nbInterpolatedParams;
}
}
else
interpolators[i] = NULL;
particleEnableIndices[i] = particleEnableParamsSize;
particleMutableIndices[i] = particleMutableParamsSize;
particleEnableParamsSize += isEnabled(param) >> i;
particleMutableParamsSize += isMutable(param) >> i;
indices[i] = paramsSize;
paramsSize += paramSize;
}
// creates the array of params for this model
if (paramsSize > 0)
{
params = new float[paramsSize];
unsigned int currentParamIndex = 0;
unsigned int currentIndex = 0;
while (currentIndex < paramsSize)
{
unsigned int nbValues = getNbValues(static_cast<ModelParam>(currentParamIndex));
for (size_t i = 0; i < nbValues; ++i)
params[currentIndex + i] = DEFAULT_VALUES[currentParamIndex];
++currentParamIndex;
currentIndex += nbValues;
}
}
else
params = NULL;
if (nbEnableParams > 0)
{
enableParams = new int[nbEnableParams];
size_t index = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
if (isEnabled(static_cast<ModelParam>(i)))
enableParams[index++] = i;
}
else
enableParams = NULL;
if (nbMutableParams > 0)
{
mutableParams = new int[nbMutableParams];
size_t index = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
if (isMutable(static_cast<ModelParam>(i)))
mutableParams[index++] = i;
}
else
mutableParams = NULL;
if (nbInterpolatedParams > 0)
{
interpolatedParams = new int[nbInterpolatedParams];
size_t index = 0;
for (size_t i = 0; i < NB_PARAMS; ++i)
if (isInterpolated(static_cast<ModelParam>(i)))
interpolatedParams[index++] = i;
}
else
interpolatedParams = NULL;
}
Model::Model(const Model& model) :
Registerable(model),
lifeTimeMin(model.lifeTimeMin),
lifeTimeMax(model.lifeTimeMax),
immortal(model.immortal),
paramsSize(model.paramsSize),
nbEnableParams(model.nbEnableParams),
nbMutableParams(model.nbMutableParams),
nbRandomParams(model.nbRandomParams),
nbInterpolatedParams(model.nbInterpolatedParams),
enableFlag(model.enableFlag),
mutableFlag(model.mutableFlag),
randomFlag(model.randomFlag),
interpolatedFlag(model.interpolatedFlag),
params(NULL),
enableParams(NULL),
mutableParams(NULL),
interpolatedParams(NULL)
{
if (paramsSize > 0)
{
params = new float[paramsSize];
for (size_t i = 0; i < paramsSize; ++i)
params[i] = model.params[i];
}
if (nbEnableParams > 0)
{
enableParams = new int[nbEnableParams];
for (size_t i = 0; i < nbEnableParams; ++i)
enableParams[i] = model.enableParams[i];
}
if (nbMutableParams > 0)
{
mutableParams = new int[nbMutableParams];
for (size_t i = 0; i < nbMutableParams; ++i)
mutableParams[i] = model.mutableParams[i];
}
if (nbInterpolatedParams > 0)
{
interpolatedParams = new int[nbMutableParams];
for (size_t i = 0; i < nbInterpolatedParams; ++i)
interpolatedParams[i] = model.interpolatedParams[i];
}
for (size_t i = 0; i < NB_PARAMS; ++i)
{
indices[i] = model.indices[i];
particleEnableIndices[i] = model.particleEnableIndices[i];
particleMutableIndices[i] = model.particleMutableIndices[i];
if (model.interpolators[i] != NULL)
interpolators[i] = new Interpolator(*model.interpolators[i]);
else
interpolators[i] = NULL;
}
}
Model::~Model()
{
delete[] enableParams;
delete[] mutableParams;
delete[] interpolatedParams;
delete[] params;
for (size_t i = 0; i < NB_PARAMS; ++i)
delete interpolators[i];
}
bool Model::setParam(ModelParam type,float startMin,float startMax,float endMin,float endMax)
{
// if the given param doesnt have 4 values, return
if (getNbValues(type) != 4)
return false;
// Sets the values at the right position in params
float* ptr = params + indices[type];
*ptr++ = startMin;
*ptr++ = startMax;
*ptr++ = endMin;
*ptr = endMax;
return true;
}
bool Model::setParam(ModelParam type,float value0,float value1)
{
// if the given param doesnt have 2 values, return
if (getNbValues(type) != 2)
return false;
// Sets the values at the right position in params
float* ptr = params + indices[type];
*ptr++ = value0;
*ptr = value1;
return true;
}
bool Model::setParam(ModelParam type,float value)
{
// if the given param doesnt have 1 value, return
if (getNbValues(type) != 1)
return false;
// Sets the value at the right position in params
params[indices[type]] = value;
return true;
}
float Model::getParamValue(ModelParam type,size_t index) const
{
unsigned int nbValues = getNbValues(type);
if (index < nbValues)
return params[indices[type] + index];
return DEFAULT_VALUES[type];
}
unsigned int Model::getNbValues(ModelParam type) const
{
int value = 1 << type;
if (!(enableFlag & value) || (interpolatedFlag & value))
return 0;
if (!(mutableFlag & value) && !(randomFlag & value))
return 1;
if ((mutableFlag & value) && (randomFlag & value))
return 4;
return 2;
}
float Model::getDefaultValue(ModelParam param)
{
return DEFAULT_VALUES[param];
}
}

View File

@@ -0,0 +1,100 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Modifier.h"
namespace SPK
{
Vector3D Modifier::intersection;
Vector3D Modifier::normal;
Modifier::Modifier(int availableTriggers,ModifierTrigger trigger,bool needsIntersection,bool needsNormal,Zone* zone) :
Registerable(),
Transformable(),
BufferHandler(),
availableTriggers(availableTriggers),
trigger(trigger),
zone(zone),
needsIntersection(needsIntersection),
needsNormal(needsNormal),
full(false),
active(true),
local(false)
{}
void Modifier::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
registerChild(zone,registerAll);
}
void Modifier::copyChildren(const Modifier& modifier,bool createBase)
{
Registerable::copyChildren(modifier,createBase);
zone = dynamic_cast<Zone*>(copyChild(modifier.zone,createBase));
}
void Modifier::destroyChildren(bool keepChildren)
{
destroyChild(zone,keepChildren);
Registerable::destroyChildren(keepChildren);
}
Registerable* Modifier::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if ((object != NULL)||(zone == NULL))
return object;
return zone->findByName(name);
}
void Modifier::setZone(Zone* zone,bool full)
{
decrementChildReference(this->zone);
incrementChildReference(zone);
this->zone = zone;
this->full = full;
}
bool Modifier::setTrigger(ModifierTrigger trigger)
{
if ((trigger & availableTriggers) != 0)
{
this->trigger = trigger;
return true;
}
return false;
}
void Modifier::beginProcess(Group& group)
{
savedActive = active;
if (!active)
return;
if (!prepareBuffers(group))
active = false; // if buffers of the modifier in the group are not ready, the modifier is made incative for the frame
}
}

View File

@@ -0,0 +1,237 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_Modifier.h"
#include "Core/SPK_System.h"
#include "Core/SPK_Buffer.h"
#include "Core/SPK_Interpolator.h"
namespace SPK
{
Particle::Particle(Group* group,size_t index) :
group(group),
index(index),
data(group->particleData + index),
currentParams(group->particleCurrentParams + index * group->model->getSizeOfParticleCurrentArray()),
extendedParams(group->particleExtendedParams + index * group->model->getSizeOfParticleExtendedArray())
{
init();
}
void Particle::init()
{
const Model* model = group->getModel();
data->age = 0.0f;
data->life = random(model->lifeTimeMin,model->lifeTimeMax);
// creates pseudo-iterators to parse arrays
float* particleCurrentIt = currentParams;
float* particleMutableIt = extendedParams;
float* particleInterpolatedIt = extendedParams + model->nbMutableParams;
const int* paramIt = model->enableParams;
// initializes params
for (size_t i = model->nbEnableParams; i != 0; --i)
{
ModelParam param = static_cast<ModelParam>(*paramIt);
const float* templateIt = &model->params[model->indices[param]];
if (model->isInterpolated(param))
{
*particleCurrentIt++ = Model::DEFAULT_VALUES[param];
*particleInterpolatedIt++ = random(0.0f,1.0f); // ratioY
Interpolator* interpolator = model->interpolators[param];
float offsetVariation = interpolator->getOffsetXVariation();
float scaleVariation = interpolator->getScaleXVariation();
*particleInterpolatedIt++ = random(-offsetVariation,offsetVariation); // offsetX
*particleInterpolatedIt++ = 1.0f + random(-scaleVariation,scaleVariation); // scaleX
}
else if (model->isRandom(param))
{
*particleCurrentIt++ = random(*templateIt,*(templateIt + 1));
if (model->isMutable(param))
*particleMutableIt++ = random(*(templateIt + 2),*(templateIt + 3));
}
else
{
*particleCurrentIt++ = *templateIt;
if (model->isMutable(param))
*particleMutableIt++ = *(templateIt + 1);
}
++paramIt;
}
}
void Particle::interpolateParameters()
{
const Model* model = group->getModel();
float* interpolatedIt = extendedParams + model->nbMutableParams;
for (size_t i = 0; i < model->nbInterpolatedParams; ++i)
{
size_t index = model->interpolatedParams[i];
size_t enableIndex = model->particleEnableIndices[index];
currentParams[enableIndex] = model->interpolators[index]->interpolate(*this,static_cast<ModelParam>(index),interpolatedIt[0],interpolatedIt[1],interpolatedIt[2]);
interpolatedIt += 3;
}
}
bool Particle::update(float deltaTime)
{
const Model* model = group->getModel();
data->age += deltaTime;
if (!model->immortal)
{
// computes the ratio between the life of the particle and its lifetime
float ratio = std::min(1.0f,deltaTime / data->life);
data->life -= deltaTime;
// updates mutable parameters
for (size_t i = 0; i < model->nbMutableParams; ++i)
{
size_t index = model->mutableParams[i];
size_t enableIndex = model->particleEnableIndices[index];
currentParams[enableIndex] += (extendedParams[i] - currentParams[enableIndex]) * ratio;
}
}
// updates interpolated parameters
interpolateParameters();
// updates position
oldPosition() = position();
position() += velocity() * deltaTime;
// updates velocity
velocity() += group->getGravity() * deltaTime;
std::vector<Modifier*>::const_iterator end = group->activeModifiers.end();
for (std::vector<Modifier*>::const_iterator it = group->activeModifiers.begin(); it != end; ++it)
(*it)->process(*this,deltaTime);
if (group->getFriction() != 0.0f)
velocity() *= 1.0f - std::min(1.0f,group->getFriction() * deltaTime / getParamCurrentValue(PARAM_MASS));
return data->life <= 0.0f;
}
bool Particle::setParamCurrentValue(ModelParam type,float value)
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
{
currentParams[model->particleEnableIndices[type]] = value;
return true;
}
return false;
}
bool Particle::setParamFinalValue(ModelParam type,float value)
{
const Model* const model = group->getModel();
if (model->isMutable(type))
{
extendedParams[model->particleMutableIndices[type]] = value;
return true;
}
return false;
}
bool Particle::changeParamCurrentValue(ModelParam type,float delta)
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
{
currentParams[model->particleEnableIndices[type]] += delta;
return true;
}
return false;
}
bool Particle::changeParamFinalValue(ModelParam type,float delta)
{
const Model* const model = group->getModel();
if (model->isMutable(type))
{
extendedParams[model->particleMutableIndices[type]] += delta;
return true;
}
return false;
}
float Particle::getParamCurrentValue(ModelParam type) const
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
return currentParams[model->particleEnableIndices[type]];
return Model::DEFAULT_VALUES[type];
}
float Particle::getParamFinalValue(ModelParam type) const
{
const Model* const model = group->getModel();
if (model->isEnabled(type))
{
if (model->isMutable(type))
return extendedParams[model->particleMutableIndices[type] + 1];
return currentParams[model->particleEnableIndices[type]];
}
return Model::DEFAULT_VALUES[type];
}
Model* Particle::getModel() const
{
return group->getModel();
}
void Particle::computeSqrDist()
{
data->sqrDist = getSqrDist(position(),System::getCameraPosition());
}
extern void swapParticles(Particle& a,Particle& b)
{
//std::swap(a.index,b.index);
std::swap(*a.data,*b.data);
for (size_t i = 0; i < a.getModel()->getSizeOfParticleCurrentArray(); ++i)
std::swap(a.currentParams[i],b.currentParams[i]);
for (size_t i = 0; i < a.getModel()->getSizeOfParticleExtendedArray(); ++i)
std::swap(a.extendedParams[i],b.extendedParams[i]);
// swap additional data (groups are assumed to be the same)
for (std::set<Buffer*>::iterator it = a.group->swappableBuffers.begin(); it != a.group->swappableBuffers.end(); ++it)
(*it)->swap(a.index,b.index);
}
}

View File

@@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Registerable.h"
#include "Core/SPK_Factory.h"
namespace SPK
{
const SPK_ID NO_ID(0);
const std::string NO_NAME;
Registerable::Registerable() :
ID(NO_ID),
nbReferences(0),
shared(false),
destroyable(true),
name(NO_NAME)
{}
Registerable::Registerable(const Registerable& registerable) :
ID(NO_ID),
nbReferences(0),
shared(registerable.shared),
destroyable(registerable.destroyable),
name(registerable.name)
{}
Registerable::~Registerable(){}
Registerable* Registerable::copyChild(Registerable* child,bool createBase)
{
if (child == NULL)
return NULL;
if (((child->isRegistered())&&(!child->isShared()))||(createBase))
{
if (SPKFactory::getInstance().isAlreadyProcessed(child))
{
Registerable* processedClone = SPKFactory::getInstance().getProcessedObject(child);
processedClone->incrementReference();
return processedClone;
}
Registerable* cloneChild = child->clone(createBase);
SPKFactory::getInstance().registerObject(cloneChild);
cloneChild->incrementReference();
SPKFactory::getInstance().markAsProcessed(child,cloneChild);
return cloneChild;
}
child->incrementReference();
return child;
}
bool Registerable::destroyChild(Registerable* child,bool keepChildren)
{
if ((child == NULL)||(keepChildren))
return false;
child->decrementReference();
if ((child->isRegistered())&&
(child->isDestroyable())&&
(child->getNbReferences() == 0))
{
SPKFactory::getInstance().unregisterObject(child->getSPKID());
return true;
}
return false;
}
void Registerable::registerChild(Registerable* child,bool registerAll)
{
if (child == NULL)
return;
if (child->isRegistered())
{
child->incrementReference();
child->registerChildren(registerAll);
}
else if (registerAll)
{
SPKFactory::getInstance().registerObject(child);
child->incrementReference();
child->registerChildren(registerAll);
}
}
void Registerable::registerObject(Registerable* obj,bool registerAll)
{
if ((obj != NULL)&&(!obj->isRegistered()))
{
SPKFactory::getInstance().registerObject(obj);
obj->registerChildren(registerAll);
}
}
}

View File

@@ -0,0 +1,37 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Renderer.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Renderer::Renderer() :
Registerable(),
BufferHandler(),
active(true),
renderingHintsMask(DEPTH_TEST | DEPTH_WRITE),
alphaThreshold(1.0f)
{}
Renderer::~Renderer(){}
}

View File

@@ -0,0 +1,330 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_System.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_Vector3D.h"
#include "Core/SPK_Emitter.h"
#include "Core/SPK_Modifier.h"
namespace SPK
{
Vector3D System::cameraPosition;
StepMode System::stepMode(STEP_REAL);
float System::constantStep(0.0f);
float System::minStep(0.0f);
float System::maxStep(0.0f);
bool System::clampStepEnabled(false);
float System::clampStep(1.0f);
System::System() :
Registerable(),
Transformable(),
groups(),
nbParticles(0),
boundingBoxEnabled(false),
AABBMin(),
AABBMax(),
deltaStep(0.0f)
{}
void System::registerChildren(bool registerAll)
{
Registerable::registerChildren(registerAll);
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
registerChild(*it,registerAll);
}
void System::copyChildren(const System& system,bool createBase)
{
Registerable::copyChildren(system,createBase);
// we clear the copies of pointers pushed in the vectors by the copy constructor
groups.clear();
for (std::vector<Group*>::const_iterator it = system.groups.begin(); it != system.groups.end(); ++it)
groups.push_back(dynamic_cast<Group*>(copyChild(*it,createBase)));
}
void System::destroyChildren(bool keepChildren)
{
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
destroyChild(*it,keepChildren);
Registerable::destroyChildren(keepChildren);
}
void System::addGroup(Group* group)
{
incrementChildReference(group);
groups.push_back(group);
nbParticles += group->getNbParticles();
}
void System::removeGroup(Group* group)
{
std::vector<Group*>::iterator it = std::find(groups.begin(),groups.end(),group);
if (it != groups.end())
{
decrementChildReference(group);
groups.erase(it);
}
}
size_t System::computeNbParticles()
{
nbParticles = 0;
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
nbParticles += (*it)->getNbParticles();
return nbParticles;
}
bool System::innerUpdate(float deltaTime)
{
nbParticles = 0;
bool isAlive = false;
bool hasGroupsWithAABB = false;
if (boundingBoxEnabled)
{
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
}
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
{
isAlive |= (*it)->update(deltaTime);
nbParticles += (*it)->getNbParticles();
if ((boundingBoxEnabled)&&((*it)->isAABBComputingEnabled()))
{
Vector3D groupMin = (*it)->getAABBMin();
Vector3D groupMax = (*it)->getAABBMax();
if (AABBMin.x > groupMin.x)
AABBMin.x = groupMin.x;
if (AABBMin.y > groupMin.y)
AABBMin.y = groupMin.y;
if (AABBMin.z > groupMin.z)
AABBMin.z = groupMin.z;
if (AABBMax.x < groupMax.x)
AABBMax.x = groupMax.x;
if (AABBMax.y < groupMax.y)
AABBMax.y = groupMax.y;
if (AABBMax.z < groupMax.z)
AABBMax.z = groupMax.z;
hasGroupsWithAABB = true;
}
}
if ((!boundingBoxEnabled)||(!hasGroupsWithAABB))
{
AABBMin.set(0.0f,0.0f,0.0f);
AABBMax.set(0.0f,0.0f,0.0f);
}
return isAlive;
}
bool System::update(float deltaTime)
{
if ((clampStepEnabled)&&(deltaTime > clampStep))
deltaTime = clampStep;
if (stepMode != STEP_REAL)
{
deltaTime += deltaStep;
float updateStep;
if (stepMode == STEP_ADAPTIVE)
{
if (deltaTime > maxStep)
updateStep = maxStep;
else if (deltaTime < minStep)
updateStep = minStep;
else
{
deltaStep = 0.0f;
return innerUpdate(deltaTime);
}
}
else
updateStep = constantStep;
bool isAlive = true;
while(deltaTime >= updateStep)
{
if ((isAlive)&&(!innerUpdate(updateStep)))
isAlive = false;
deltaTime -= updateStep;
}
deltaStep = deltaTime;
return isAlive;
}
else
return innerUpdate(deltaTime);
}
void System::render() const
{
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->render();
}
void System::grow(float time,float step)
{
if (step <= 0.0f)
step = time;
while (time > 0.0f)
{
float currentStep = time > step ? step : time;
update(currentStep);
time -= currentStep;
}
}
void System::empty()
{
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->empty();
nbParticles = 0;
}
void System::setCameraPosition(const Vector3D& cameraPosition)
{
System::cameraPosition = cameraPosition;
}
void System::setClampStep(bool enableClampStep,float clamp)
{
clampStepEnabled = enableClampStep;
clampStep = clamp;
}
void System::useConstantStep(float constantStep)
{
stepMode = STEP_CONSTANT;
System::constantStep = constantStep;
}
void System::useAdaptiveStep(float minStep,float maxStep)
{
stepMode = STEP_ADAPTIVE;
System::minStep = minStep;
System::maxStep = maxStep;
}
void System::useRealStep()
{
stepMode = STEP_REAL;
}
const Vector3D& System::getCameraPosition()
{
return cameraPosition;
}
StepMode System::getStepMode()
{
return stepMode;
}
void System::sortParticles()
{
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->sortParticles();
}
void System::computeDistances()
{
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->computeDistances();
}
void System::computeAABB()
{
if (boundingBoxEnabled)
{
const float maxFloat = std::numeric_limits<float>::max();
AABBMin.set(maxFloat,maxFloat,maxFloat);
AABBMax.set(-maxFloat,-maxFloat,-maxFloat);
}
bool hasGroupsWithAABB = false;
for (std::vector<Group*>::iterator it = groups.begin(); it != groups.end(); ++it)
{
(*it)->computeAABB();
if ((boundingBoxEnabled)&&((*it)->isAABBComputingEnabled()))
{
Vector3D groupMin = (*it)->getAABBMin();
Vector3D groupMax = (*it)->getAABBMax();
if (AABBMin.x > groupMin.x)
AABBMin.x = groupMin.x;
if (AABBMin.y > groupMin.y)
AABBMin.y = groupMin.y;
if (AABBMin.z > groupMin.z)
AABBMin.z = groupMin.z;
if (AABBMax.x < groupMax.x)
AABBMax.x = groupMax.x;
if (AABBMax.y < groupMax.y)
AABBMax.y = groupMax.y;
if (AABBMax.z < groupMax.z)
AABBMax.z = groupMax.z;
hasGroupsWithAABB = true;
}
}
if ((!boundingBoxEnabled)||(!hasGroupsWithAABB))
{
const Vector3D pos = getWorldTransformPos();
AABBMin = AABBMax = pos;
}
}
Registerable* System::findByName(const std::string& name)
{
Registerable* object = Registerable::findByName(name);
if (object != NULL)
return object;
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
return NULL;
}
void System::propagateUpdateTransform()
{
for (std::vector<Group*>::const_iterator it = groups.begin(); it != groups.end(); ++it)
(*it)->updateTransform(this);
}
}

View File

@@ -0,0 +1,239 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Transformable.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
const float Transformable::IDENTITY[] =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
Transformable::Transformable() :
currentUpdate(0),
lastUpdate(0),
lastParentUpdate(0),
parent(NULL),
localIdentity(true)
{
memcpy(local,IDENTITY,sizeof(float) * TRANSFORM_LENGTH);
memcpy(world,IDENTITY,sizeof(float) * TRANSFORM_LENGTH);
}
Transformable::Transformable(const Transformable& transformable) :
currentUpdate(0),
lastUpdate(0),
lastParentUpdate(0),
parent(NULL),
localIdentity(transformable.localIdentity)
{
memcpy(local,transformable.local,sizeof(float) * TRANSFORM_LENGTH);
memcpy(world,transformable.world,sizeof(float) * TRANSFORM_LENGTH);
}
void Transformable::setTransformNC(const float* transform)
{
for (size_t i = 0; i < TRANSFORM_LENGTH; ++i)
local[i] = transform[(i >> 2) + ((i & 3) << 2)]; // conversion
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformPosition(const Vector3D& pos)
{
local[12] = pos.x;
local[13] = pos.y;
local[14] = pos.z;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationRH(Vector3D look,Vector3D up)
{
look.normalize();
up.normalize();
Vector3D side = crossProduct(look,up);
side.normalize();
up = crossProduct(side,look);
local[0] = side.x;
local[1] = side.y;
local[2] = side.z;
local[4] = up.x;
local[5] = up.y;
local[6] = up.z;
local[8] = -look.x;
local[9] = -look.y;
local[10] = -look.z;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationLH(Vector3D look,Vector3D up)
{
look.normalize();
Vector3D side = crossProduct(look,up);
side.normalize();
up = crossProduct(side,look);
local[0] = side.x;
local[1] = side.y;
local[2] = side.z;
local[4] = up.x;
local[5] = up.y;
local[6] = up.z;
local[8] = look.x;
local[9] = look.y;
local[10] = look.z;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientation(Vector3D axis,float angle)
{
axis.normalize();
float c = std::cos(angle);
float s = std::sin(angle);
float a = 1 - c;
Vector3D axis2(axis.x * axis.x,axis.y * axis.y,axis.z * axis.z);
local[0] = axis2.x + (1 - axis2.x) * c;
local[1] = axis.x * axis.y * a + axis.z * s;
local[2] = axis.x * axis.z * a - axis.y * s;
local[4] = axis.x * axis.y * a - axis.z * s;
local[5] = axis2.y + (1 - axis2.y) * c;
local[6] = axis.y * axis.z * a + axis.x * s;
local[8] = axis.x * axis.z * a + axis.y * s;
local[9] = axis.y * axis.z * a - axis.x * s;
local[10] = axis2.z + (1 - axis2.z) * c;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationX(float angle)
{
float cosA = std::cos(angle);
float sinA = std::sin(angle);
local[0] = 1.0f;
local[1] = 0.0f;
local[2] = 0.0f;
local[4] = 0.0f;
local[5] = cosA;
local[6] = sinA;
local[8] = 0.0f;
local[9] = -sinA;
local[10] = cosA;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationY(float angle)
{
float cosA = std::cos(angle);
float sinA = std::sin(angle);
local[0] = cosA;
local[1] = 0.0f;
local[2] = -sinA;
local[4] = 0.0f;
local[5] = 1.0f;
local[6] = 0.0f;
local[8] = sinA;
local[9] = 0.0f;
local[10] = cosA;
localIdentity = false;
notifyForUpdate();
}
void Transformable::setTransformOrientationZ(float angle)
{
float cosA = std::cos(angle);
float sinA = std::sin(angle);
local[0] = cosA;
local[1] = sinA;
local[2] = 0.0f;
local[4] = -sinA;
local[5] = cosA;
local[6] = 0.0f;
local[8] = 0.0f;
local[9] = 0.0f;
local[10] = 1.0f;
localIdentity = false;
notifyForUpdate();
}
void Transformable::updateTransform(const Transformable* parent)
{
if (isUpdateNotified() || // the local transform or instance param have been updated
parent != this->parent || // the parent has changed
(parent != NULL && lastParentUpdate != parent->currentUpdate)) // the parent transform has been modified
{
if (parent == NULL)
memcpy(world,local,sizeof(float) * TRANSFORM_LENGTH);
else if (isLocalIdentity())
{
memcpy(world,parent->world,sizeof(float) * TRANSFORM_LENGTH);
lastParentUpdate = parent->lastUpdate;
}
else
{
multiply(world,parent->world,local);
lastParentUpdate = parent->lastUpdate;
}
this->parent = parent;
lastUpdate = ++currentUpdate;
innerUpdateTransform();
}
propagateUpdateTransform();
}
void Transformable::transformPos(Vector3D& tPos,const Vector3D& pos)
{
multiply(tPos,pos,world);
}
void Transformable::transformDir(Vector3D& tDir,const Vector3D& dir)
{
rotate(tDir,dir,world); // To transform a direction, the translation is ignored
}
}

View File

@@ -0,0 +1,177 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Vector3D.h"
namespace SPK
{
Vector3D::Vector3D(float x,float y,float z) :
x(x),
y(y),
z(z) {}
Vector3D& Vector3D::operator+=(const Vector3D& v)
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
Vector3D& Vector3D::operator-=(const Vector3D& v)
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
Vector3D& Vector3D::operator+=(float f)
{
x += f;
y += f;
z += f;
return *this;
}
Vector3D& Vector3D::operator-=(float f)
{
x -= f;
y -= f;
z -= f;
return *this;
}
Vector3D& Vector3D::operator*=(float f)
{
x *= f;
y *= f;
z *= f;
return *this;
}
Vector3D& Vector3D::operator/=(float f)
{
f = 1.0f / f;
x *= f;
y *= f;
z *= f;
return *this;
}
float& Vector3D::operator[](size_t index)
{
switch(index)
{
case 0 : return x;
case 1 : return y;
default : return z;
}
}
const float& Vector3D::operator[](size_t index) const
{
switch(index)
{
case 0 : return x;
case 1 : return y;
default : return z;
}
}
void Vector3D::set(float x,float y,float z)
{
this->x = x;
this->y = y;
this->z = z;
}
bool Vector3D::normalize()
{
float norm = getNorm();
if (norm != 0.0f)
{
x /= norm;
y /= norm;
z /= norm;
return true;
}
return false;
}
void Vector3D::revert()
{
x = -x;
y = -y;
z = -z;
}
void Vector3D::abs()
{
if (x < 0.0f) x = -x;
if (y < 0.0f) y = -y;
if (z < 0.0f) z = -z;
}
void Vector3D::crossProduct(const Vector3D& v)
{
Vector3D result;
result.x = y * v.z - z * v.y;
result.y = z * v.x - x * v.z;
result.z = x * v.y - y * v.x;
*this = result;
}
float getSqrDist(const Vector3D& v0,const Vector3D& v1)
{
float dx = v0.x - v1.x;
float dy = v0.y - v1.y;
float dz = v0.z - v1.z;
return dx * dx + dy * dy + dz * dz;
}
float getDist(const Vector3D& v0,const Vector3D& v1)
{
return std::sqrt(getSqrDist(v0,v1));
}
Vector3D crossProduct(const Vector3D& v0,const Vector3D& v1)
{
Vector3D result;
result.x = v0.y * v1.z - v0.z * v1.y;
result.y = v0.z * v1.x - v0.x * v1.z;
result.z = v0.x * v1.y - v0.y * v1.x;
return result;
}
void crossProduct(const Vector3D& v0,const Vector3D& v1,Vector3D& result)
{
result.x = v0.y * v1.z - v0.z * v1.y;
result.y = v0.z * v1.x - v0.x * v1.z;
result.z = v0.x * v1.y - v0.y * v1.x;
}
}

View File

@@ -0,0 +1,35 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Core/SPK_Zone.h"
namespace SPK
{
const float Zone::APPROXIMATION_VALUE = 0.01f;
Zone::Zone(const Vector3D& position) :
Registerable(),
Transformable()
{
setPosition(position);
}
}

View File

@@ -0,0 +1,75 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_NormalEmitter.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
NormalEmitter::NormalEmitter(Zone* normalZone,bool inverted) :
Emitter(),
normalZone(normalZone),
inverted(inverted)
{}
void NormalEmitter::registerChildren(bool registerAll)
{
Emitter::registerChildren(registerAll);
registerChild(normalZone,registerAll);
}
void NormalEmitter::copyChildren(const NormalEmitter& emitter,bool createBase)
{
Emitter::copyChildren(emitter,createBase);
normalZone = dynamic_cast<Zone*>(copyChild(emitter.normalZone,createBase));
}
void NormalEmitter::destroyChildren(bool keepChildren)
{
destroyChild(normalZone,keepChildren);
Emitter::destroyChildren(keepChildren);
}
Registerable* NormalEmitter::findByName(const std::string& name)
{
Registerable* object = Emitter::findByName(name);
if ((object != NULL)||(normalZone == NULL))
return object;
return normalZone->findByName(name);
}
void NormalEmitter::setNormalZone(Zone* zone)
{
decrementChildReference(normalZone);
incrementChildReference(zone);
normalZone = zone;
}
void NormalEmitter::generateVelocity(Particle& particle,float speed) const
{
if (inverted) speed = -speed;
const Zone* zone = (normalZone == NULL ? getZone() : normalZone);
particle.velocity() = zone->computeNormal(particle.position()) * speed;
}
}

View File

@@ -0,0 +1,39 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_RandomEmitter.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
void RandomEmitter::generateVelocity(Particle& particle,float speed) const
{
float norm;
do
{
particle.velocity().set(random(-1.0f,1.0f),random(-1.0f,1.0f),random(-1.0f,1.0f));
norm = particle.velocity().getNorm();
}
while((norm > 1.0f) || (norm == 0.0f));
particle.velocity() *= speed / norm;
}
}

View File

@@ -0,0 +1,123 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_SphericEmitter.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
const float SphericEmitter::PI = 3.1415926535897932384626433832795f;
SphericEmitter::SphericEmitter(const Vector3D& direction,float angleA,float angleB) :
Emitter()
{
setDirection(direction);
setAngles(angleA,angleB);
}
void SphericEmitter::setDirection(const Vector3D& direction)
{
tDirection = direction;
computeMatrix();
this->direction = tDirection; // as tDirection was normalized in computeMatrix()
notifyForUpdate();
}
void SphericEmitter::setAngles(float angleA,float angleB)
{
if (angleB < angleA)
std::swap(angleA,angleB);
angleA = std::min(2.0f * PI,std::max(0.0f,angleA));
angleB = std::min(2.0f * PI,std::max(0.0f,angleB));
angleMin = angleA;
angleMax = angleB;
cosAngleMin = cos(angleMin * 0.5f);
cosAngleMax = cos(angleMax * 0.5f);
}
void SphericEmitter::computeMatrix()
{
tDirection.normalize();
if ((tDirection.x == 0.0f)&&(tDirection.y == 0.0f))
{
matrix[0] = tDirection.z;
matrix[1] = 0.0f;
matrix[2] = 0.0f;
matrix[3] = 0.0f;
matrix[4] = tDirection.z;
matrix[5] = 0.0f;
matrix[6] = 0.0f;
matrix[7] = 0.0f;
matrix[8] = tDirection.z;
}
else
{
Vector3D axis;
crossProduct(tDirection,Vector3D(0.0f,0.0f,1.0f),axis);
float cosA = tDirection.z;
float sinA = -axis.getNorm();
axis /= -sinA;
float x = axis.x;
float y = axis.y;
float z = axis.z;
matrix[0] = x * x + cosA * (1.0f - x * x);
matrix[1] = x * y * (1.0f - cosA) - z * sinA;
matrix[2] = tDirection.x;
matrix[3] = x * y * (1.0f - cosA) + z * sinA;
matrix[4] = y * y + cosA * (1.0f - y * y);
matrix[5] = tDirection.y;
matrix[6] = x * z * (1.0f - cosA) - y * sinA;
matrix[7] = y * z * (1.0f - cosA) + x * sinA;
matrix[8] = tDirection.z;
}
}
void SphericEmitter::generateVelocity(Particle& particle,float speed) const
{
float a = random(cosAngleMax,cosAngleMin);
float theta = acos(a);
float phi = random(0.0f,2.0f * PI);
float sinTheta = sin(theta);
float x = sinTheta * cos(phi);
float y = sinTheta * sin(phi);
float z = cos(theta);
particle.velocity().x = speed * (matrix[0] * x + matrix[1] * y + matrix[2] * z);
particle.velocity().y = speed * (matrix[3] * x + matrix[4] * y + matrix[5] * z);
particle.velocity().z = speed * (matrix[6] * x + matrix[7] * y + matrix[8] * z);
}
void SphericEmitter::innerUpdateTransform()
{
Emitter::innerUpdateTransform();
transformDir(tDirection,direction);
computeMatrix();
}
}

View File

@@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Emitters/SPK_StraightEmitter.h"
namespace SPK
{
StraightEmitter::StraightEmitter(const Vector3D& direction) :
Emitter()
{
setDirection(direction);
}
void StraightEmitter::setDirection(const Vector3D& direction)
{
this->direction = direction;
this->direction.normalize();
tDirection = this->direction;
notifyForUpdate();
}
void StraightEmitter::innerUpdateTransform()
{
Emitter::innerUpdateTransform();
transformDir(tDirection,direction);
tDirection.normalize();
}
}

View File

@@ -0,0 +1,122 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Collision.h"
#include "Core/SPK_Group.h"
namespace SPK
{
Collision::Collision(float scale,float elasticity) :
Modifier(),
scale(scale)
{
setElasticity(elasticity);
}
void Collision::modify(Particle& particle,float deltaTime) const
{
size_t index = particle.getIndex();
float radius1 = particle.getParamCurrentValue(PARAM_SIZE) * scale * 0.5f;
float m1 = particle.getParamCurrentValue(PARAM_MASS);
Group& group = *particle.getGroup();
// Tests collisions with all the particles that are stored before in the pool
for (size_t i = 0; i < index; ++i)
{
Particle& particle2 = group.getParticle(i);
float radius2 = particle2.getParamCurrentValue(PARAM_SIZE) * scale * 0.5f;
float sqrRadius = radius1 + radius2;
sqrRadius *= sqrRadius;
// Gets the normal of the collision plane
Vector3D normal = particle.position();
normal -= particle2.position();
float sqrDist = normal.getSqrNorm();
if (sqrDist < sqrRadius) // particles are intersecting each other
{
Vector3D delta = particle.velocity();
delta -= particle2.velocity();
if (dotProduct(normal,delta) < 0.0f) // particles are moving towards each other
{
float oldSqrDist = getSqrDist(particle.oldPosition(),particle2.oldPosition());
if (oldSqrDist > sqrDist)
{
// Disables the move from this frame
particle.position() = particle.oldPosition();
particle2.position() = particle2.oldPosition();
normal = particle.position();
normal -= particle2.position();
if (dotProduct(normal,delta) >= 0.0f)
continue;
}
normal.normalize();
// Gets the normal components of the velocities
Vector3D normal1(normal);
Vector3D normal2(normal);
normal1 *= dotProduct(normal,particle.velocity());
normal2 *= dotProduct(normal,particle2.velocity());
// Resolves collision
float m2 = particle2.getParamCurrentValue(PARAM_MASS);
if (oldSqrDist < sqrRadius && sqrDist < sqrRadius)
{
// Tweak to separate particles that intersects at both t - deltaTime and t
// In that case the collision is no more considered as punctual
if (dotProduct(normal,normal1) < 0.0f)
{
particle.velocity() -= normal1;
particle2.velocity() += normal1;
}
if (dotProduct(normal,normal2) > 0.0f)
{
particle2.velocity() -= normal2;
particle.velocity() += normal2;
}
}
else
{
// Else classic collision equations are applied
// Tangent components of the velocities are left untouched
particle.velocity() -= (1.0f + (elasticity * m2 - m1) / (m1 + m2)) * normal1;
particle2.velocity() -= (1.0f + (elasticity * m1 - m2) / (m1 + m2)) * normal2;
normal1 *= ((1.0f + elasticity) * m1) / (m1 + m2);
normal2 *= ((1.0f + elasticity) * m2) / (m1 + m2);
particle.velocity() += normal2;
particle2.velocity() += normal1;
}
}
}
}
}
}

View File

@@ -0,0 +1,51 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Destroyer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
Destroyer::Destroyer(Zone* zone,ModifierTrigger) :
Modifier(INSIDE_ZONE | OUTSIDE_ZONE | INTERSECT_ZONE | ENTER_ZONE | EXIT_ZONE,INSIDE_ZONE,true,false,zone)
{
setTrigger(trigger);
}
void Destroyer::modify(Particle& particle,float deltaTime) const
{
particle.kill();
if ((trigger != INSIDE_ZONE)||(trigger != OUTSIDE_ZONE))
particle.position() = intersection;
}
void Destroyer::modifyWrongSide(Particle& particle,bool inside) const
{
if (isFullZone())
{
getZone()->moveAtBorder(particle.position(),inside);
particle.kill();
}
}
}

View File

@@ -0,0 +1,50 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_LinearForce.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
LinearForce::LinearForce(Zone* zone,ModifierTrigger trigger,const Vector3D& force,ForceFactor type,ModelParam param) :
Modifier(ALWAYS | INSIDE_ZONE | OUTSIDE_ZONE,ALWAYS,false,false,zone),
force(force),
tForce(force),
factorType(type),
factorParam(param)
{}
void LinearForce::modify(Particle& particle,float deltaTime) const
{
float factor = deltaTime / particle.getParamCurrentValue(PARAM_MASS);
if (factorType != FACTOR_NONE)
{
float param = particle.getParamCurrentValue(factorParam);
factor *= param; // linearity function of the parameter
if (factorType == FACTOR_SQUARE)
factor *= param; // linearity function of the square of the parameter
}
particle.velocity() += tForce * factor;
}
}

View File

@@ -0,0 +1,169 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_ModifierGroup.h"
namespace SPK
{
ModifierGroup::ModifierGroup(Zone* zone,ModifierTrigger trigger) :
Modifier(INSIDE_ZONE | OUTSIDE_ZONE | INTERSECT_ZONE | ENTER_ZONE | EXIT_ZONE,trigger,false,false,zone),
modifiers(),
globalZone(false),
handleWrongSide(false)
{}
void ModifierGroup::registerChildren(bool registerAll)
{
Modifier::registerChildren(registerAll);
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
registerChild(*it,registerAll);
}
void ModifierGroup::copyChildren(const ModifierGroup& modifier,bool createBase)
{
Modifier::copyChildren(modifier,createBase);
// we clear the copies of pointers pushed in the vectors by the copy constructor
modifiers.clear();
for (std::vector<Modifier*>::const_iterator it = modifier.modifiers.begin(); it != modifier.modifiers.end(); ++it)
modifiers.push_back(dynamic_cast<Modifier*>(copyChild(*it,createBase)));
}
void ModifierGroup::destroyChildren(bool keepChildren)
{
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
destroyChild(*it,keepChildren);
Modifier::destroyChildren(keepChildren);
}
Registerable* ModifierGroup::findByName(const std::string& name)
{
Registerable* object = Modifier::findByName(name);
if (object != NULL)
return object;
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != modifiers.end(); ++it)
{
object = (*it)->findByName(name);
if (object != NULL)
return object;
}
return NULL;
}
void ModifierGroup::addModifier(Modifier* modifier)
{
if (modifier == NULL)
return;
incrementChildReference(modifier);
modifiers.push_back(modifier);
}
bool ModifierGroup::removeModifier(const Modifier* modifier)
{
std::vector<Modifier*>::iterator it = std::find<std::vector<Modifier*>::iterator,const Modifier*>(modifiers.begin(),modifiers.end(),modifier);
if (it != modifiers.end())
{
decrementChildReference(*it);
modifiers.erase(it);
return true;
}
return false;
}
void ModifierGroup::clear()
{
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != modifiers.end(); ++it)
decrementChildReference(*it);
modifiers.clear();
}
void ModifierGroup::modify(Particle& particle,float deltaTime) const
{
std::vector<Modifier*>::const_iterator end = modifiers.end();
if (globalZone)
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
{
Zone* oldZone = (*it)->getZone();
(*it)->setZone(getZone());
(*it)->modify(particle,deltaTime);
(*it)->setZone(oldZone);
}
else
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
(*it)->process(particle,deltaTime);
}
void ModifierGroup::modifyWrongSide(Particle& particle,bool inside) const
{
if (globalZone)
{
std::vector<Modifier*>::const_iterator end = modifiers.end();
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
{
Zone* oldZone = (*it)->getZone();
(*it)->setZone(getZone());
(*it)->modifyWrongSide(particle,inside);
(*it)->setZone(oldZone);
}
}
else if (handleWrongSide)
{
std::vector<Modifier*>::const_iterator end = modifiers.end();
for (std::vector<Modifier*>::const_iterator it = modifiers.begin(); it != end; ++it)
if (((*it)->getZone() != NULL)&&((*it)->getTrigger() != INTERSECT_ZONE))
modifyWrongSide(particle,true);
}
}
void ModifierGroup::createBuffers(const Group& group)
{
std::vector<Modifier*>::iterator end = modifiers.end();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != end; ++it)
(*it)->createBuffers(group);
}
void ModifierGroup::destroyBuffers(const Group& group)
{
std::vector<Modifier*>::iterator end = modifiers.end();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != end; ++it)
(*it)->destroyBuffers(group);
}
bool ModifierGroup::checkBuffers(const Group& group)
{
std::vector<Modifier*>::iterator end = modifiers.end();
for (std::vector<Modifier*>::iterator it = modifiers.begin(); it != end; ++it)
if (!(*it)->checkBuffers(group))
return false;
return true;
}
}

View File

@@ -0,0 +1,57 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Obstacle.h"
namespace SPK
{
Obstacle::Obstacle(Zone* zone,ModifierTrigger trigger,float bouncingRatio,float friction) :
Modifier(INTERSECT_ZONE | ENTER_ZONE | EXIT_ZONE,INTERSECT_ZONE,true,true,zone),
bouncingRatio(bouncingRatio),
friction(friction)
{
setTrigger(trigger);
}
void Obstacle::modify(Particle& particle,float deltaTime) const
{
Vector3D& velocity = particle.velocity();
velocity = particle.position();
velocity -= particle.oldPosition();
if (deltaTime != 0.0f)
velocity *= 1.0f / deltaTime;
else
velocity.set(0.0f,0.0f,0.0f);
float dist = dotProduct(velocity,normal);
normal *= dist;
velocity -= normal; // tangent component
velocity *= friction;
normal *= bouncingRatio; // normal component
velocity -= normal;
particle.position() = intersection;
}
}

View File

@@ -0,0 +1,49 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_PointMass.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Zone.h"
namespace SPK
{
PointMass::PointMass(Zone* zone,ModifierTrigger trigger,float mass,float minDistance) :
Modifier(ALWAYS | INSIDE_ZONE | OUTSIDE_ZONE,ALWAYS,false,false,zone),
position(),
tPosition(),
mass(mass)
{
setTrigger(trigger);
setMinDistance(minDistance);
}
void PointMass::modify(Particle& particle,float deltaTime) const
{
Vector3D force = tPosition;
if (getZone() != NULL)
force += getZone()->getTransformedPosition();
force -= particle.position();
force *= mass * deltaTime / std::max(sqrMinDistance,force.getSqrNorm());
particle.velocity() += force;
}
}

View File

@@ -0,0 +1,84 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Modifiers/SPK_Vortex.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Vortex::Vortex(const Vector3D& position,const Vector3D& direction,float rotationSpeed,float attractionSpeed) :
Modifier(ALWAYS | INSIDE_ZONE |OUTSIDE_ZONE,ALWAYS,false,false,NULL),
rotationSpeed(rotationSpeed),
attractionSpeed(attractionSpeed),
angularSpeedEnabled(false),
linearSpeedEnabled(false),
killingParticleEnabled(false),
eyeRadius(0.0f)
{
setPosition(position);
setDirection(direction);
}
void Vortex::modify(Particle& particle,float deltaTime) const
{
// Distance of the projection point from the position of the vortex
float dist = dotProduct(tDirection,particle.position() - tPosition);
// Position of the rotation center (orthogonal projection of the particle)
Vector3D rotationCenter = tDirection;
rotationCenter *= dist;
rotationCenter += tPosition;
// Distance of the particle from the eye of the vortex
dist = getDist(rotationCenter,particle.position());
if (dist <= eyeRadius)
{
if (killingParticleEnabled)
particle.kill();
return;
}
float angle = angularSpeedEnabled ? rotationSpeed * deltaTime : rotationSpeed * deltaTime / dist;
// Computes ortho base
Vector3D normal = (particle.position() - rotationCenter) / dist;
Vector3D tangent = crossProduct(tDirection,normal);
float endRadius = linearSpeedEnabled ? dist * (1.0f - attractionSpeed * deltaTime) : dist - attractionSpeed * deltaTime;
if (endRadius <= eyeRadius)
{
endRadius = eyeRadius;
if (killingParticleEnabled)
particle.kill();
}
particle.position() = rotationCenter + normal * endRadius * std::cos(angle) + tangent * endRadius * std::sin(angle);
}
void Vortex::innerUpdateTransform()
{
Modifier::innerUpdateTransform();
transformPos(tPosition,position);
transformDir(tDirection,direction);
tDirection.normalize();
}
}

View File

@@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Renderers/SPK_Oriented3DRendererInterface.h"
namespace SPK
{
Oriented3DRendererInterface::Oriented3DRendererInterface() :
lookOrientation(LOOK_CAMERA_PLANE),
upOrientation(UP_CAMERA),
lockedAxis(LOCK_UP)
{
lookVector.set(0.0f,0.0f,1.0f);
upVector.set(0.0f,1.0f,0.0f);
}
void Oriented3DRendererInterface::setOrientation(LookOrientation lookOrientation,UpOrientation upOrientation,LockedAxis lockedAxis)
{
this->lookOrientation = lookOrientation;
this->upOrientation = upOrientation;
this->lockedAxis = lockedAxis;
}
void Oriented3DRendererInterface::setOrientation(OrientationPreset orientation)
{
this->lookOrientation = static_cast<LookOrientation>((orientation >> 0x8) & 0xFF);
this->upOrientation = static_cast<UpOrientation>(orientation & 0xFF);
this->lockedAxis = static_cast<LockedAxis>((orientation >> 0x10) & 0xFF);
}
}

View File

@@ -0,0 +1,43 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Renderers/SPK_QuadRendererInterface.h"
namespace SPK
{
QuadRendererInterface::QuadRendererInterface(float scaleX,float scaleY) :
scaleX(scaleX),
scaleY(scaleY),
texturingMode(TEXTURE_NONE),
textureAtlasNbX(1),
textureAtlasNbY(1),
textureAtlasW(1.0f),
textureAtlasH(1.0f)
{}
void QuadRendererInterface::setAtlasDimensions(size_t nbX,size_t nbY)
{
textureAtlasNbX = nbX;
textureAtlasNbY = nbY;
textureAtlasW = 1.0f / nbX;
textureAtlasH = 1.0f / nbY;
}
}

View File

@@ -0,0 +1,160 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_AABox.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
AABox::AABox(const Vector3D& position,const Vector3D& dimension) :
Zone(position)
{
setDimension(dimension);
}
void AABox::setDimension(const Vector3D& dimension)
{
this->dimension.set(std::max(0.0f,dimension.x),std::max(0.0f,dimension.y),std::max(0.0f,dimension.z));
}
void AABox::generatePosition(Particle& particle,bool full) const
{
particle.position().x = getTransformedPosition().x + random(-dimension.x * 0.5f,dimension.x * 0.5f);
particle.position().y = getTransformedPosition().y + random(-dimension.y * 0.5f,dimension.y * 0.5f);
particle.position().z = getTransformedPosition().z + random(-dimension.z * 0.5f,dimension.z * 0.5f);
if (!full)
{
int axis = random(0,3);
int sens = (random(0,2) << 1) - 1;
switch(axis)
{
case 0 :
particle.position().x = getTransformedPosition().x + sens * dimension.x * 0.5f;
break;
case 1 :
particle.position().y = getTransformedPosition().y + sens * dimension.y * 0.5f;
break;
default :
particle.position().z = getTransformedPosition().z + sens * dimension.z * 0.5f;
break;
}
}
}
bool AABox::contains(const Vector3D& v) const
{
if ((v.x >= getTransformedPosition().x - dimension.x * 0.5f)&&(v.x <= getTransformedPosition().x + dimension.x * 0.5f)
&&(v.y >= getTransformedPosition().y - dimension.y * 0.5f)&&(v.y <= getTransformedPosition().y + dimension.y * 0.5f)
&&(v.z >= getTransformedPosition().z - dimension.z * 0.5f)&&(v.z <= getTransformedPosition().z + dimension.z * 0.5f))
return true;
return false;
}
bool AABox::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float tEnter = 0.0f;
float tExit = 1.0f;
int axis;
if (!slabIntersects(v0.x,v1.x,getTransformedPosition().x - dimension.x * 0.5f,getTransformedPosition().x + dimension.x * 0.5f,tEnter,tExit,axis,0))
return false;
if (!slabIntersects(v0.y,v1.y,getTransformedPosition().y - dimension.y * 0.5f,getTransformedPosition().y + dimension.y * 0.5f,tEnter,tExit,axis,1))
return false;
if (!slabIntersects(v0.z,v1.z,getTransformedPosition().z - dimension.z * 0.5f,getTransformedPosition().z + dimension.z * 0.5f,tEnter,tExit,axis,2))
return false;
if ((tEnter <= 0.0f)&&(tExit >= 1.0f))
return false;
if (intersection != NULL)
{
if (tEnter <= 0.0f)
{
tEnter = tExit;
axis = (axis & 0xF0) >> 4;
}
else
axis &= 0x0F;
Vector3D vDir = v1 - v0;
float norm = vDir.getNorm() * tEnter;
tEnter = norm < APPROXIMATION_VALUE ? 0.0f : tEnter * (norm - APPROXIMATION_VALUE) / norm;
vDir *= tEnter;
*intersection = v0 + vDir;
if (normal != NULL)
{
switch(axis)
{
case 0 :
*normal = Vector3D(-1.0f,0.0f,0.0f);
break;
case 1 :
*normal = Vector3D(0.0f,-1.0f,0.0f);
break;
case 2 :
*normal = Vector3D(0.0f,0.0f,-1.0f);
break;
case 3 :
*normal = Vector3D(1.0f,0.0f,0.0f);
break;
case 4 :
*normal = Vector3D(0.0f,1.0f,0.0f);
break;
case 5 :
*normal = Vector3D(0.0f,0.0f,1.0f);
break;
}
}
}
return true;
}
void AABox::moveAtBorder(Vector3D& v,bool inside) const
{
if (inside)
{
Vector3D rayEnd(v - getTransformedPosition());
float maxDim = getTransformedPosition().x + getTransformedPosition().y + getTransformedPosition().z;
rayEnd *= maxDim * maxDim / rayEnd.getSqrNorm();
intersects(getTransformedPosition() + rayEnd,getTransformedPosition(),&v,NULL);
}
else
intersects(getTransformedPosition(),v,&v,NULL);
}
Vector3D AABox::computeNormal(const Vector3D& point) const
{
// TO DO
Vector3D normal(point - getTransformedPosition());
normalizeOrRandomize(normal);
return normal;
}
}

View File

@@ -0,0 +1,92 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Line.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Line::Line(const Vector3D& p0,const Vector3D& p1) :
Zone(Vector3D())
{
setBounds(p0,p1);
}
void Line::setPosition(const Vector3D& v)
{
Vector3D displacement = v - getPosition();
bounds[0] = tBounds[0] += displacement;
bounds[1] = tBounds[1] += displacement;
computeDist();
Zone::setPosition(v);
}
void Line::setBounds(const Vector3D& p0,const Vector3D& p1)
{
bounds[0] = tBounds[0] = p0;
bounds[1] = tBounds[1] = p1;
computeDist();
computePosition();
}
void Line::pushBound(const Vector3D& bound)
{
bounds[0] = tBounds[0] = bounds[1];
bounds[1] = tBounds[1] = bound;
computeDist();
computePosition();
}
void Line::generatePosition(Particle& particle,bool full) const
{
float ratio = random(0.0f,1.0f);
particle.position() = tBounds[0] + tDist * ratio;
}
Vector3D Line::computeNormal(const Vector3D& point) const
{
float d = -dotProduct(tDist,point);
float sqrNorm = tDist.getSqrNorm();
float t = 0.0f;
if (sqrNorm > 0.0f)
{
t = -(dotProduct(tDist,tBounds[0]) + d) / sqrNorm;
// t is clamped to the segment
if (t < 0.0f) t = 0.0f;
else if (t > 1.0f) t = 1.0f;
}
Vector3D normal = point;
normal -= tBounds[0] + t * tDist;
normalizeOrRandomize(normal);
return normal;
}
void Line::innerUpdateTransform()
{
Zone::innerUpdateTransform();
transformPos(tBounds[0],bounds[0]);
transformPos(tBounds[1],bounds[1]);
computeDist();
}
}

View File

@@ -0,0 +1,84 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Plane.h"
namespace SPK
{
Plane::Plane(const Vector3D& position,const Vector3D& normal) :
Zone(position)
{
setNormal(normal);
}
bool Plane::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float dist0 = dotProduct(tNormal,v0 - getTransformedPosition());
float dist1 = dotProduct(tNormal,v1 - getTransformedPosition());
if ((dist0 <= 0.0f) == (dist1 <= 0.0f)) // both points are on the same side
return false;
if (intersection != NULL)
{
if (dist0 <= 0.0f)
dist0 = -dist0;
else
dist1 = -dist1;
if (normal != NULL)
*normal = tNormal;
float ti = dist0 / (dist0 + dist1);
Vector3D vDir = v1 - v0;
float norm = vDir.getNorm();
norm *= ti;
ti = norm < APPROXIMATION_VALUE ? 0.0f : ti * (norm - APPROXIMATION_VALUE) / norm;
vDir *= ti;
*intersection = v0 + vDir;
}
return true;
}
void Plane::moveAtBorder(Vector3D& v,bool inside) const
{
float dist = dotProduct(tNormal,v - getTransformedPosition());
if ((dist <= 0.0f) == inside)
inside ? dist += APPROXIMATION_VALUE : dist -= APPROXIMATION_VALUE;
else
inside ? dist -= APPROXIMATION_VALUE : dist += APPROXIMATION_VALUE;
v += tNormal * -dist;
}
void Plane::innerUpdateTransform()
{
Zone::innerUpdateTransform();
transformDir(tNormal,normal);
tNormal.normalize();
}
}

View File

@@ -0,0 +1,38 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Point.h"
namespace SPK
{
Point::Point(const Vector3D& position) :
Zone(position)
{}
Vector3D Point::computeNormal(const Vector3D& point) const
{
Vector3D normal(point - getTransformedPosition());
normalizeOrRandomize(normal);
return normal;
}
}

View File

@@ -0,0 +1,125 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Ring.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Ring::Ring(const Vector3D& position,const Vector3D& normal,float minRadius,float maxRadius) :
Zone(position)
{
setNormal(normal);
setRadius(minRadius,maxRadius);
}
inline void Ring::setRadius(float minRadius,float maxRadius)
{
if (minRadius < 0.0f) minRadius = -minRadius;
if (maxRadius < 0.0f) maxRadius = -maxRadius;
if (minRadius > maxRadius) std::swap(minRadius,maxRadius);
this->minRadius = minRadius;
this->maxRadius = maxRadius;
sqrMinRadius = minRadius * minRadius;
sqrMaxRadius = maxRadius * maxRadius;
}
void Ring::generatePosition(Particle& particle,bool full) const
{
Vector3D tmp;
do tmp = Vector3D(random(-1.0f,1.0f),random(-1.0f,1.0f),random(-1.0f,1.0f));
while (tmp.getSqrNorm() > 1.0f);
crossProduct(tNormal,tmp,particle.position());
normalizeOrRandomize(particle.position());
particle.position() *= std::sqrt(random(sqrMinRadius,sqrMaxRadius)); // to have a uniform distribution
particle.position() += getTransformedPosition();
}
bool Ring::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float dist0 = dotProduct(tNormal,v0 - getTransformedPosition());
float dist1 = dotProduct(tNormal,v1 - getTransformedPosition());
if ((dist0 <= 0.0f) == (dist1 <= 0.0f)) // both points are on the same side
return false;
if (dist0 <= 0.0f)
dist0 = -dist0;
else
dist1 = -dist1;
float ti = dist0 / (dist0 + dist1);
Vector3D vDir(v1 - v0);
float norm = vDir.getNorm();
norm *= ti;
ti = norm < APPROXIMATION_VALUE ? 0.0f : ti * (norm - APPROXIMATION_VALUE) / norm;
vDir *= ti;
Vector3D inter(v0 + vDir);
float distFromCenter = getSqrDist(inter,getTransformedPosition());
if (distFromCenter > sqrMaxRadius || distFromCenter < sqrMinRadius) // intersection is not in the ring
return false;
if (intersection != NULL)
{
*intersection = inter;
if (normal != NULL)
*normal = tNormal;
}
return true;
}
void Ring::moveAtBorder(Vector3D& v,bool inside) const
{
float dist = dotProduct(tNormal,v - getTransformedPosition());
v += tNormal * -dist;
float distFromCenter = getSqrDist(v,getTransformedPosition());
if (distFromCenter > sqrMaxRadius)
{
distFromCenter = std::sqrt(distFromCenter);
Vector3D vDir(v - getTransformedPosition());
vDir *= maxRadius / distFromCenter;
v = getTransformedPosition() + vDir;
}
else if (distFromCenter < sqrMinRadius)
{
distFromCenter = std::sqrt(distFromCenter);
Vector3D vDir(v - getTransformedPosition());
vDir *= minRadius / distFromCenter;
v = getTransformedPosition() + vDir;
}
}
void Ring::innerUpdateTransform()
{
Zone::innerUpdateTransform();
transformDir(tNormal,normal);
tNormal.normalize();
}
}

View File

@@ -0,0 +1,116 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "Extensions/Zones/SPK_Sphere.h"
#include "Core/SPK_Particle.h"
namespace SPK
{
Sphere::Sphere(const Vector3D& position,float radius) :
Zone(position)
{
setRadius(radius);
}
void Sphere::generatePosition(Particle& particle,bool full) const
{
do particle.position() = Vector3D(random(-radius,radius),random(-radius,radius),random(-radius,radius));
while (particle.position().getSqrNorm() > radius * radius);
if ((!full)&&(radius > 0.0f))
particle.position() *= radius / particle.position().getNorm();
particle.position() += getTransformedPosition();
}
bool Sphere::contains(const Vector3D& v) const
{
return getSqrDist(getTransformedPosition(),v) <= radius * radius;
}
bool Sphere::intersects(const Vector3D& v0,const Vector3D& v1,Vector3D* intersection,Vector3D* normal) const
{
float r2 = radius * radius;
float dist0 = getSqrDist(getTransformedPosition(),v0);
float dist1 = getSqrDist(getTransformedPosition(),v1);
if ((dist0 <= r2) == (dist1 <= r2))
return false;
if (intersection != NULL)
{
Vector3D vDir = v1 - v0;
float norm = vDir.getNorm();
float d = dotProduct(vDir,getTransformedPosition() - v0) / norm;
float a = std::sqrt(r2 - dist0 + d * d);
float ti;
if (dist0 <= r2)
ti = d - a;
else
ti = d + a;
ti /= norm;
if (ti < 0.0f) ti = 0.0f;
if (ti > 1.0f) ti = 1.0f;
norm *= ti;
ti = norm < APPROXIMATION_VALUE ? 0.0f : ti * (norm - APPROXIMATION_VALUE) / norm;
vDir *= ti;
*intersection = v0 + vDir;
if (normal != NULL)
{
if (dist0 <= r2)
*normal = getTransformedPosition() - *intersection;
else
*normal = *intersection - getTransformedPosition();
normal->normalize();
}
}
return true;
}
void Sphere::moveAtBorder(Vector3D& v,bool inside) const
{
Vector3D vDir = v - getTransformedPosition();
float norm = vDir.getNorm();
if (inside)
vDir *= (radius + APPROXIMATION_VALUE) / norm;
else
vDir *= (radius - APPROXIMATION_VALUE) / norm;
v = getTransformedPosition() + vDir;
}
Vector3D Sphere::computeNormal(const Vector3D& point) const
{
Vector3D normal(point - getTransformedPosition());
normalizeOrRandomize(normal);
return normal;
}
}

View File

@@ -0,0 +1,326 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLExtHandler.h"
#if defined(__APPLE__) || defined(macintosh)
// Necessary includes to get GL functions pointers from MAC
#include <mach-o/dyld.h>
#include <stdlib.h>
#include <string.h>
#endif
namespace SPK
{
namespace GL
{
GLExtHandler::GLExtension GLExtHandler::pointSpriteGLExt = UNCHECKED;
GLExtHandler::GLExtension GLExtHandler::pointParameterGLExt = UNCHECKED;
GLExtHandler::GLExtension GLExtHandler::texture3DGLExt = UNCHECKED;
GLExtHandler::GLExtension GLExtHandler::shaderGLExt = UNCHECKED;
GLExtHandler::SPK_PFNGLPOINTPARAMETERFPROC GLExtHandler::SPK_glPointParameterf = NULL;
GLExtHandler::SPK_PFNGLPOINTPARAMETERFVPROC GLExtHandler::SPK_glPointParameterfv = NULL;
GLExtHandler::SPK_PFNGLTEXIMAGE3DPROC GLExtHandler::SPK_glTexImage3D = NULL;
GLExtHandler::SPK_PFNGLCREATESHADERPROC GLExtHandler::SPK_glCreateShader = NULL;
GLExtHandler::SPK_PFNGLDELETESHADERPROC GLExtHandler::SPK_glDeleteShader = NULL;
GLExtHandler::SPK_PFNGLSHADERSOURCEPROC GLExtHandler::SPK_glShaderSource = NULL;
GLExtHandler::SPK_PFNGLCOMPILESHADERPROC GLExtHandler::SPK_glCompileShader = NULL;
GLExtHandler::SPK_PFNGLCREATEPROGRAMPROC GLExtHandler::SPK_glCreateProgram = NULL;
GLExtHandler::SPK_PFNGLDELETEPROGRAMPROC GLExtHandler::SPK_glDeleteProgram = NULL;
GLExtHandler::SPK_PFNGLATTACHSHADERPROC GLExtHandler::SPK_glAttachShader = NULL;
GLExtHandler::SPK_PFNGLDETACHSHADERPROC GLExtHandler::SPK_glDetachShader = NULL;
GLExtHandler::SPK_PFNGLLINKPROGRAMPROC GLExtHandler::SPK_glLinkProgram = NULL;
GLExtHandler::SPK_PFNGLUSEPROGRAMPROC GLExtHandler::SPK_glUseProgram = NULL;
const float GLExtHandler::QUADRATIC_SCREEN[3] = {1.0f,0.0f,0.0f};
float GLExtHandler::pixelPerUnit = 1024.0f;
const float GLExtHandler::POINT_SIZE_CURRENT = 32.0f;
const float GLExtHandler::POINT_SIZE_MIN = 1.0f;
const float GLExtHandler::POINT_SIZE_MAX = 1024.0f;
#ifdef SPK_NO_GLEXT
bool GLExtHandler::loadGLExtPointSprite()
{
pointSpriteGLExt = UNSUPPORTED;
return false;
}
bool GLExtHandler::loadGLExtPointParameter()
{
pointParameterGLExt = UNSUPPORTED;
return false;
}
bool GLExtHandler::loadGLExtTexture3D()
{
texture3DGLExt = UNSUPPORTED;
return false;
}
bool GLExtHandler::loadGLExtShader()
{
shaderGLExt = UNSUPPORTED;
return false;
}
#else
bool GLExtHandler::loadGLExtPointSprite()
{
if (pointSpriteGLExt == UNCHECKED)
{
pointSpriteGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
// openGL 2.0 and higher
if (int(version[0] - '0') >= 2)
pointSpriteGLExt = SUPPORTED;
else
{
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if ((extensions.find("GL_ARB_point_sprites") != std::string::npos)
||(extensions.find("GL_NV_point_sprites") != std::string::npos))
pointSpriteGLExt = SUPPORTED;
}
}
return pointSpriteGLExt == SUPPORTED;
}
bool GLExtHandler::loadGLExtPointParameter()
{
if (pointParameterGLExt == UNCHECKED)
{
pointParameterGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
// openGL 1.4 and higher
if (((int(version[0] - '0') == 1)&&(int(version[2] - '0') >= 4))
||(int(version[0] - '0') > 1))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterf");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfv");
}
// point parameter ARB
if (((SPK_glPointParameterf == NULL)||(SPK_glPointParameterfv == NULL))
&&(extensions.find("GL_ARB_point_parameters") != std::string::npos))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterfARB");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfvARB");
}
// point parameter EXT
if (((SPK_glPointParameterf == NULL)||(SPK_glPointParameterfv == NULL))
&&(extensions.find("GL_EXT_point_parameters") != std::string::npos))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterfEXT");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfvEXT");
}
// point parameter SGIS
if (((SPK_glPointParameterf == NULL)||(SPK_glPointParameterfv == NULL))
&&(extensions.find("GL_SGIS_point_parameters") != std::string::npos))
{
SPK_glPointParameterf = (SPK_PFNGLPOINTPARAMETERFPROC)glGetProcAddress("glPointParameterfSGIS");
SPK_glPointParameterfv = (SPK_PFNGLPOINTPARAMETERFVPROC)glGetProcAddress("glPointParameterfvSGIS");
}
if ((SPK_glPointParameterf != NULL)&&(SPK_glPointParameterfv != NULL))
pointParameterGLExt = SUPPORTED;
}
return pointParameterGLExt == SUPPORTED;
}
bool GLExtHandler::loadGLExtTexture3D()
{
if (texture3DGLExt == UNCHECKED)
{
texture3DGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
// openGL 1.2 and higher
if (((int(version[0] - '0') == 1)&&(int(version[2] - '0') >= 4))
||(int(version[0] - '0') > 1))
SPK_glTexImage3D = (SPK_PFNGLTEXIMAGE3DPROC)glGetProcAddress("glTexImage3D");
// texture 3D EXT
if ((SPK_glTexImage3D == NULL)&&(extensions.find("GL_EXT_texture3D") != std::string::npos))
SPK_glTexImage3D = (SPK_PFNGLTEXIMAGE3DPROC)glGetProcAddress("glTexImage3DEXT");
if (SPK_glTexImage3D != NULL)
texture3DGLExt = SUPPORTED;
}
return texture3DGLExt == SUPPORTED;
}
bool GLExtHandler::loadGLExtShader()
{
if (shaderGLExt == UNCHECKED)
{
shaderGLExt = UNSUPPORTED;
std::string version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
// openGL 2.0 and higher
if (int(version[0] - '0') >= 2)
{
bool ok = true;
if (ok && ((SPK_glCreateShader = (SPK_PFNGLCREATESHADERPROC)glGetProcAddress("glCreateShader")) == NULL)) ok = false;
if (ok && ((SPK_glDeleteShader = (SPK_PFNGLDELETESHADERPROC)glGetProcAddress("glDeleteShader")) == NULL)) ok = false;
if (ok && ((SPK_glShaderSource = (SPK_PFNGLSHADERSOURCEPROC)glGetProcAddress("glShaderSource")) == NULL)) ok = false;
if (ok && ((SPK_glCompileShader = (SPK_PFNGLCOMPILESHADERPROC)glGetProcAddress("glCompileShader")) == NULL)) ok = false;
if (ok && ((SPK_glCreateProgram = (SPK_PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram")) == NULL)) ok = false;
if (ok && ((SPK_glDeleteProgram = (SPK_PFNGLDELETEPROGRAMPROC)glGetProcAddress("glDeleteProgram")) == NULL)) ok = false;
if (ok && ((SPK_glAttachShader = (SPK_PFNGLATTACHSHADERPROC)glGetProcAddress("glAttachShader")) == NULL)) ok = false;
if (ok && ((SPK_glDetachShader = (SPK_PFNGLDETACHSHADERPROC)glGetProcAddress("glDetachShader")) == NULL)) ok = false;
if (ok && ((SPK_glLinkProgram = (SPK_PFNGLLINKPROGRAMPROC)glGetProcAddress("glLinkProgram")) == NULL)) ok = false;
if (ok && ((SPK_glUseProgram = (SPK_PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram")) == NULL)) ok = false;
if (ok) shaderGLExt = SUPPORTED;
}
if (shaderGLExt == UNSUPPORTED)
{
std::string extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if ((extensions.find("GL_ARB_shading_language_100") != std::string::npos)&&
(extensions.find("GL_ARB_shader_objects") != std::string::npos)&&
(extensions.find("GL_ARB_vertex_shader") != std::string::npos)&&
(extensions.find("GL_ARB_fragment_shader") != std::string::npos))
{
bool ok = true;
if (ok && ((SPK_glCreateShader = (SPK_PFNGLCREATESHADERPROC)glGetProcAddress("glCreateShaderObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glDeleteShader = SPK_glDeleteProgram = (SPK_PFNGLDELETESHADERPROC)glGetProcAddress("glDeleteObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glShaderSource = (SPK_PFNGLSHADERSOURCEPROC)glGetProcAddress("glShaderSourceARB")) == NULL)) ok = false;
if (ok && ((SPK_glCompileShader = (SPK_PFNGLCOMPILESHADERPROC)glGetProcAddress("glCompileShaderARB")) == NULL)) ok = false;
if (ok && ((SPK_glCreateProgram = (SPK_PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgramObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glAttachShader = (SPK_PFNGLATTACHSHADERPROC)glGetProcAddress("glAttachObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glDetachShader = (SPK_PFNGLDETACHSHADERPROC)glGetProcAddress("glDetachObjectARB")) == NULL)) ok = false;
if (ok && ((SPK_glLinkProgram = (SPK_PFNGLLINKPROGRAMPROC)glGetProcAddress("glLinkProgramARB")) == NULL)) ok = false;
if (ok && ((SPK_glUseProgram = (SPK_PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgramObjectARB")) == NULL)) ok = false;
if (ok) shaderGLExt = SUPPORTED;
}
}
}
return shaderGLExt == SUPPORTED;
}
#endif
#if defined(__APPLE__) || defined(macintosh)
void* GLExtHandler::SPK_NSGLGetProcAddress(const char* name)
{
NSSymbol symbol;
char *symbolName;
symbolName = (char*)malloc (strlen (name) + 2);
strcpy(symbolName + 1, name);
symbolName[0] = '_';
symbol = NULL;
if (NSIsSymbolNameDefined (symbolName))
symbol = NSLookupAndBindSymbol (symbolName);
free (symbolName);
return symbol ? NSAddressOfSymbol (symbol) : NULL;
}
#endif
void GLExtHandler::setPixelPerUnit(float fovy,int screenHeight)
{
// the pixel per unit is computed for a distance from the camera of screenHeight
pixelPerUnit = screenHeight / (2.0f * tan(fovy * 0.5f));
}
void GLExtHandler::glTexImage3D(GLenum target,
GLint level,
GLenum internalFormat,
GLsizei width,
GLsizei height,
GLsizei depth,
GLint border,
GLenum format,
GLenum type,
const GLvoid* pixels)
{
if (loadGLExtTexture3D())
SPK_glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels);
}
GLExtHandler::GLExtension GLExtHandler::getPointSpriteGLExt()
{
return pointSpriteGLExt;
}
GLExtHandler::GLExtension GLExtHandler::getPointParameterGLExt()
{
return pointParameterGLExt;
}
void GLExtHandler::enablePointParameterGLExt(float size,bool distance)
{
// derived size = size * sqrt(1 / (A + B * distance + C * distance<63>))
if (distance)
{
const float sqrtC = POINT_SIZE_CURRENT / (size * pixelPerUnit);
const float QUADRATIC_WORLD[3] = {0.0f,0.0f,sqrtC * sqrtC}; // A = 0; B = 0; C = (POINT_SIZE_CURRENT / (size * pixelPerUnit))<29>
SPK_glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION,QUADRATIC_WORLD);
}
else
{
const float sqrtA = POINT_SIZE_CURRENT / size;
const float QUADRATIC_WORLD[3] = {sqrtA * sqrtA,0.0f,0.0f}; // A = (POINT_SIZE_CURRENT / size)<29>; B = 0; C = 0
SPK_glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION,QUADRATIC_WORLD);
}
glPointSize(POINT_SIZE_CURRENT);
SPK_glPointParameterf(GL_POINT_SIZE_MIN,POINT_SIZE_MIN);
SPK_glPointParameterf(GL_POINT_SIZE_MAX,POINT_SIZE_MAX);
}
void GLExtHandler::disablePointParameterGLExt()
{
SPK_glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION,QUADRATIC_SCREEN);
}
GLExtHandler::GLExtension GLExtHandler::getTexture3DGLExt()
{
return texture3DGLExt;
}
GLExtHandler::GLExtension GLExtHandler::getShaderGLExt()
{
return shaderGLExt;
}
}}

View File

@@ -0,0 +1,107 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLLineRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_ArrayBuffer.h"
namespace SPK
{
namespace GL
{
const std::string GLLineRenderer::GPU_BUFFER_NAME("SPK_GLLineRenderer_GPU");
float* GLLineRenderer::gpuBuffer = NULL;
float* GLLineRenderer::gpuIterator = NULL;
GLLineRenderer::GLLineRenderer(float length,float width) :
GLRenderer(),
LineRendererInterface(length,width)
{}
bool GLLineRenderer::checkBuffers(const Group& group)
{
FloatBuffer* fBuffer;
if ((fBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(GPU_BUFFER_NAME))) == NULL)
return false;
gpuIterator = gpuBuffer = fBuffer->getData();
return true;
}
void GLLineRenderer::createBuffers(const Group& group)
{
FloatBuffer* fBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(GPU_BUFFER_NAME,FloatBufferCreator(14),0,false));
gpuIterator = gpuBuffer = fBuffer->getData();
}
void GLLineRenderer::destroyBuffers(const Group& group)
{
group.destroyBuffer(GPU_BUFFER_NAME);
}
void GLLineRenderer::render(const Group& group)
{
if (!prepareBuffers(group))
return;
initBlending();
initRenderingHints();
glLineWidth(width);
glDisable(GL_TEXTURE_2D);
glShadeModel(GL_FLAT);
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
*(gpuIterator++) = particle.position().x;
*(gpuIterator++) = particle.position().y;
*(gpuIterator++) = particle.position().z;
gpuIterator += 4; // skips the first vertex color data as GL_FLAT was forced
*(gpuIterator++) = particle.position().x + particle.velocity().x * length;
*(gpuIterator++) = particle.position().y + particle.velocity().y * length;
*(gpuIterator++) = particle.position().z + particle.velocity().z * length;
*(gpuIterator++) = particle.getR();
*(gpuIterator++) = particle.getG();
*(gpuIterator++) = particle.getB();
*(gpuIterator++) = particle.getParamCurrentValue(PARAM_ALPHA);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
// interleaves vertex and color data
glVertexPointer(3,GL_FLOAT,7 * sizeof(float),gpuBuffer);
glColorPointer(4,GL_FLOAT,7 * sizeof(float),gpuBuffer + 3);
glDrawArrays(GL_LINES,0,group.getNbParticles() << 1);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}}

View File

@@ -0,0 +1,204 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLLineTrailRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_ArrayBuffer.h"
namespace SPK
{
namespace GL
{
const std::string GLLineTrailRenderer::VERTEX_BUFFER_NAME("SPK_GLLineTrailRenderer_Vertex");
const std::string GLLineTrailRenderer::COLOR_BUFFER_NAME("SPK_GLLineTrailRenderer_Color");
const std::string GLLineTrailRenderer::VALUE_BUFFER_NAME("SPK_GLLineTrailRenderer_Value");
float* GLLineTrailRenderer::vertexBuffer = NULL;
float* GLLineTrailRenderer::vertexIterator = NULL;
float* GLLineTrailRenderer::colorBuffer = NULL;
float* GLLineTrailRenderer::colorIterator = NULL;
float* GLLineTrailRenderer::valueBuffer = NULL;
float* GLLineTrailRenderer::valueIterator = NULL;
GLLineTrailRenderer::GLLineTrailRenderer() :
GLRenderer(),
nbSamples(8),
width(1.0f),
duration(1.0f),
degeneratedR(0.0f),
degeneratedG(0.0f),
degeneratedB(0.0f),
degeneratedA(0.0f)
{
enableBlending(true);
}
void GLLineTrailRenderer::setDegeneratedLines(float r,float g,float b,float a)
{
degeneratedR = r;
degeneratedG = g;
degeneratedB = b;
degeneratedA = a;
}
bool GLLineTrailRenderer::checkBuffers(const Group& group)
{
FloatBuffer* fVertexBuffer;
FloatBuffer* fColorBuffer;
FloatBuffer* fValueBuffer;
if ((fVertexBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(VERTEX_BUFFER_NAME,nbSamples))) == NULL)
return false;
if ((fColorBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(COLOR_BUFFER_NAME,nbSamples))) == NULL)
return false;
if ((fValueBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(VALUE_BUFFER_NAME,nbSamples))) == NULL)
return false;
vertexIterator = vertexBuffer = fVertexBuffer->getData();
colorIterator = colorBuffer = fColorBuffer->getData();
valueIterator = valueBuffer = fValueBuffer->getData();
return true;
}
void GLLineTrailRenderer::createBuffers(const Group& group)
{
FloatBuffer* fVertexBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(VERTEX_BUFFER_NAME,FloatBufferCreator((nbSamples + 2) * 3),nbSamples,true));
FloatBuffer* fColorBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(COLOR_BUFFER_NAME,FloatBufferCreator((nbSamples + 2) << 2),nbSamples,true));
FloatBuffer* fValueBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(VALUE_BUFFER_NAME,FloatBufferCreator(nbSamples),nbSamples,true));
vertexIterator = vertexBuffer = fVertexBuffer->getData();
colorIterator = colorBuffer = fColorBuffer->getData();
valueIterator = valueBuffer = fValueBuffer->getData();
// Fills the buffers with correct values
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
init(particle,particle.getAge());
}
// Resets the iterators at the beginning after the init
vertexIterator = vertexBuffer;
colorIterator = colorBuffer;
valueIterator = valueBuffer;
}
void GLLineTrailRenderer::destroyBuffers(const Group& group)
{
group.destroyBuffer(VERTEX_BUFFER_NAME);
group.destroyBuffer(COLOR_BUFFER_NAME);
group.destroyBuffer(VALUE_BUFFER_NAME);
}
void GLLineTrailRenderer::init(const Group& group)
{
if (!prepareBuffers(group))
return;
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
init(particle,particle.getAge());
}
}
void GLLineTrailRenderer::render(const Group& group)
{
if (!prepareBuffers(group))
return;
initBlending();
initRenderingHints();
// Inits lines' parameters
glLineWidth(width);
glDisable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
float age = particle.getAge();
float oldAge = *valueIterator;
if ((age == 0.0f)||(age < *valueIterator)) // If the particle is new, buffers for it are reinitialized
init(particle,0.0f);
else
{
if (age - *(valueIterator + 1) >= duration / (nbSamples - 1)) // shifts the data by one
{
memmove(vertexIterator + 6,vertexIterator + 3,(nbSamples - 1) * 3 * sizeof(float));
memmove(colorIterator + 8,colorIterator + 4,((nbSamples - 1) << 2) * sizeof(float));
memmove(valueIterator + 1,valueIterator,(nbSamples - 1) * sizeof(float));
// post degenerated vertex copy
memcpy(vertexIterator + (nbSamples + 1) * 3,vertexIterator + nbSamples * 3,3 * sizeof(float));
}
// Updates the current sample
const Vector3D& pos = particle.position();
*(vertexIterator++) = pos.x;
*(vertexIterator++) = pos.y;
*(vertexIterator++) = pos.z;
memcpy(vertexIterator,vertexIterator - 3,3 * sizeof(float));
vertexIterator += (nbSamples + 1) * 3;
colorIterator += 4; // skips post degenerated vertex color
*(colorIterator++) = particle.getR();
*(colorIterator++) = particle.getG();
*(colorIterator++) = particle.getB();
*(colorIterator++) = particle.getParamCurrentValue(PARAM_ALPHA);
colorIterator += 3;
*(valueIterator++) = age;
//valueIterator += nbSamples;
// Updates alpha
for (size_t i = 0; i < nbSamples - 1; ++i)
{
float ratio = (age - oldAge) / (duration - age + *valueIterator);
if (ratio > 0.0f)
*colorIterator *= ratio < 1.0f ? 1.0f - ratio : 0.0f;
colorIterator += 4;
++valueIterator;
}
++colorIterator;
}
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4,GL_FLOAT,0,colorBuffer);
glVertexPointer(3,GL_FLOAT,0,vertexBuffer);
glDrawArrays(GL_LINE_STRIP,0,group.getNbParticles() * (nbSamples + 2));
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}}

View File

@@ -0,0 +1,104 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLPointRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
namespace SPK
{
namespace GL
{
GLPointRenderer::GLPointRenderer(float size) :
GLRenderer(),
PointRendererInterface(POINT_SQUARE,size),
GLExtHandler(),
textureIndex(0),
worldSize(false)
{}
bool GLPointRenderer::setType(PointType type)
{
if ((type == POINT_SPRITE)&&(!loadGLExtPointSprite()))
return false;
this->type = type;
return true;
}
bool GLPointRenderer::enableWorldSize(bool worldSizeEnabled)
{
worldSize = ((worldSizeEnabled)&&(loadGLExtPointParameter()));
return worldSize;
}
void GLPointRenderer::render(const Group& group)
{
initBlending();
initRenderingHints();
switch(type)
{
case POINT_SQUARE :
glDisable(GL_TEXTURE_2D);
glDisable(GL_POINT_SMOOTH);
if (getPointSpriteGLExt() == SUPPORTED)
disablePointSpriteGLExt();
break;
case POINT_SPRITE :
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureIndex);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,getTextureBlending());
enablePointSpriteGLExt();
break;
case POINT_CIRCLE :
glDisable(GL_TEXTURE_2D);
glEnable(GL_POINT_SMOOTH);
if (getPointSpriteGLExt() == SUPPORTED)
disablePointSpriteGLExt();
break;
}
if (worldSize)
enablePointParameterGLExt(size,true);
else
{
glPointSize(size);
if (getPointParameterGLExt() == SUPPORTED)
disablePointParameterGLExt();
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(group.getModel()->isEnabled(PARAM_ALPHA) ? 4 : 3,GL_FLOAT,group.getParamStride(),group.getParamAddress(PARAM_RED));
glVertexPointer(3,GL_FLOAT,group.getPositionStride(),group.getPositionAddress());
glDrawArrays(GL_POINTS,0,group.getNbParticles());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
}}

View File

@@ -0,0 +1,279 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLQuadRenderer.h"
#include "Core/SPK_Particle.h"
#include "Core/SPK_Group.h"
#include "Core/SPK_ArrayBuffer.h"
namespace SPK
{
namespace GL
{
const std::string GLQuadRenderer::GPU_BUFFER_NAME("SPK_GLQuadRenderer_GPU");
const std::string GLQuadRenderer::TEXTURE_BUFFER_NAME("SPK_GLQuadRenderer_Texture");
float* GLQuadRenderer::gpuBuffer = NULL;
float* GLQuadRenderer::gpuIterator = NULL;
float* GLQuadRenderer::textureBuffer = NULL;
float* GLQuadRenderer::textureIterator = NULL;
void (GLQuadRenderer::*GLQuadRenderer::renderParticle)(const Particle&) const = NULL;
GLQuadRenderer::GLQuadRenderer(float scaleX,float scaleY) :
GLRenderer(),
QuadRendererInterface(scaleX,scaleY),
Oriented3DRendererInterface(),
GLExtHandler(),
textureIndex(0)
{}
bool GLQuadRenderer::checkBuffers(const Group& group)
{
FloatBuffer* fGpuBuffer;
if ((fGpuBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(GPU_BUFFER_NAME))) == NULL)
return false;
if (texturingMode != TEXTURE_NONE)
{
FloatBuffer* fTextureBuffer;
if ((fTextureBuffer = dynamic_cast<FloatBuffer*>(group.getBuffer(TEXTURE_BUFFER_NAME,texturingMode))) == NULL)
textureBuffer = createTextureBuffer(group);
textureIterator = textureBuffer = fTextureBuffer->getData();
}
gpuIterator = gpuBuffer = fGpuBuffer->getData();
return true;
}
void GLQuadRenderer::createBuffers(const Group& group)
{
FloatBuffer* fBuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(GPU_BUFFER_NAME,FloatBufferCreator(28),0,false));
gpuIterator = gpuBuffer = fBuffer->getData();
if (texturingMode != TEXTURE_NONE)
textureIterator = textureBuffer = createTextureBuffer(group);
}
void GLQuadRenderer::destroyBuffers(const Group& group)
{
group.destroyBuffer(GPU_BUFFER_NAME);
group.destroyBuffer(TEXTURE_BUFFER_NAME);
}
float* GLQuadRenderer::createTextureBuffer(const Group& group) const
{
FloatBuffer* fbuffer = NULL;
switch(texturingMode)
{
case TEXTURE_2D :
fbuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(TEXTURE_BUFFER_NAME,FloatBufferCreator(8),TEXTURE_2D,false));
if (!group.getModel()->isEnabled(PARAM_TEXTURE_INDEX))
{
float t[8] = {1.0f,0.0f,0.0f,0.0f,0.0f,1.0f,1.0f,1.0f};
for (size_t i = 0; i < group.getParticles().getNbReserved() << 3; ++i)
fbuffer->getData()[i] = t[i & 7];
}
break;
case TEXTURE_3D :
fbuffer = dynamic_cast<FloatBuffer*>(group.createBuffer(TEXTURE_BUFFER_NAME,FloatBufferCreator(12),TEXTURE_3D,false));
float t[12] = {1.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f,1.0f,1.0f,0.0f};
for (size_t i = 0; i < group.getParticles().getNbReserved() * 12; ++i)
fbuffer->getData()[i] = t[i % 12];
break;
}
return fbuffer->getData();
}
bool GLQuadRenderer::setTexturingMode(TexturingMode mode)
{
if ((mode == TEXTURE_3D)&&(!loadGLExtTexture3D()))
return false;
texturingMode = mode;
return true;
}
void GLQuadRenderer::render(const Group& group)
{
if (!prepareBuffers(group))
return;
float oldModelView[16];
for (int i = 0; i < 16; ++i)
oldModelView[i] = modelView[i];
glGetFloatv(GL_MODELVIEW_MATRIX,modelView);
for (int i = 0; i < 16; ++i)
if (oldModelView[i] != modelView[i])
{
invertModelView();
break;
}
initBlending();
initRenderingHints();
glShadeModel(GL_FLAT);
switch(texturingMode)
{
case TEXTURE_2D :
if (getTexture3DGLExt() == SUPPORTED)
glDisable(GL_TEXTURE_3D);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textureIndex);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,getTextureBlending());
if (!group.getModel()->isEnabled(PARAM_TEXTURE_INDEX))
{
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render2D;
else
renderParticle = &GLQuadRenderer::render2DRot;
}
else
{
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render2DAtlas;
else
renderParticle = &GLQuadRenderer::render2DAtlasRot;
}
break;
case TEXTURE_3D :
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_3D);
glBindTexture(GL_TEXTURE_3D,textureIndex);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,getTextureBlending());
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render3D;
else
renderParticle = &GLQuadRenderer::render3DRot;
break;
case TEXTURE_NONE :
glDisable(GL_TEXTURE_2D);
if (getTexture3DGLExt() == SUPPORTED)
glDisable(GL_TEXTURE_3D);
if (!group.getModel()->isEnabled(PARAM_ANGLE))
renderParticle = &GLQuadRenderer::render2D;
else
renderParticle = &GLQuadRenderer::render2DRot;
break;
}
bool globalOrientation = precomputeOrientation3D(
group,
Vector3D(-invModelView[8],-invModelView[9],-invModelView[10]),
Vector3D(invModelView[4],invModelView[5],invModelView[6]),
Vector3D(invModelView[12],invModelView[13],invModelView[14]));
if (globalOrientation)
{
computeGlobalOrientation3D();
for (size_t i = 0; i < group.getNbParticles(); ++i)
(this->*renderParticle)(group.getParticle(i));
}
else
{
for (size_t i = 0; i < group.getNbParticles(); ++i)
{
const Particle& particle = group.getParticle(i);
computeSingleOrientation3D(particle);
(this->*renderParticle)(particle);
}
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
if (texturingMode == TEXTURE_2D)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2,GL_FLOAT,0,textureBuffer);
}
else if (texturingMode == TEXTURE_3D)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(3,GL_FLOAT,0,textureBuffer);
}
// interleaves vertex and color data
glVertexPointer(3,GL_FLOAT,7 * sizeof(float),gpuBuffer);
glColorPointer(4,GL_FLOAT,7 * sizeof(float),gpuBuffer + 3);
glDrawArrays(GL_QUADS,0,group.getNbParticles() << 2);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
if (texturingMode != TEXTURE_NONE)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void GLQuadRenderer::render2D(const Particle& particle) const
{
scaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
}
void GLQuadRenderer::render2DRot(const Particle& particle) const
{
rotateAndScaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
}
void GLQuadRenderer::render3D(const Particle& particle) const
{
scaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture3D(particle);
}
void GLQuadRenderer::render3DRot(const Particle& particle) const
{
rotateAndScaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture3D(particle);
}
void GLQuadRenderer::render2DAtlas(const Particle& particle) const
{
scaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture2DAtlas(particle);
}
void GLQuadRenderer::render2DAtlasRot(const Particle& particle) const
{
rotateAndScaleQuadVectors(particle,scaleX,scaleY);
GLCallColorAndVertex(particle);
GLCallTexture2DAtlas(particle);
}
}}

View File

@@ -0,0 +1,80 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.h"
namespace SPK
{
namespace GL
{
GLRenderer::GLRenderer() :
Renderer(),
blendingEnabled(false),
srcBlending(GL_SRC_ALPHA),
destBlending(GL_ONE_MINUS_SRC_ALPHA),
textureBlending(GL_MODULATE)
{}
GLRenderer::~GLRenderer() {}
void GLRenderer::setBlending(BlendingMode blendMode)
{
switch(blendMode)
{
case BLENDING_NONE :
srcBlending = GL_ONE;
destBlending = GL_ZERO;
blendingEnabled = false;
break;
case BLENDING_ADD :
srcBlending = GL_SRC_ALPHA;
destBlending = GL_ONE;
blendingEnabled = true;
break;
case BLENDING_ALPHA :
srcBlending = GL_SRC_ALPHA;
destBlending = GL_ONE_MINUS_SRC_ALPHA;
blendingEnabled = true;
break;
}
}
void GLRenderer::saveGLStates()
{
glPushAttrib(GL_POINT_BIT |
GL_LINE_BIT |
GL_ENABLE_BIT |
GL_COLOR_BUFFER_BIT |
GL_CURRENT_BIT |
GL_TEXTURE_BIT |
GL_DEPTH_BUFFER_BIT |
GL_LIGHTING_BIT |
GL_POLYGON_BIT);
}
void GLRenderer::restoreGLStates()
{
glPopAttrib();
}
}}

View File

@@ -0,0 +1,78 @@
//////////////////////////////////////////////////////////////////////////////////
// SPARK particle engine //
// Copyright (C) 2008-2009 - Julien Fryer - julienfryer@gmail.com //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
// Note : //
// //
// This file is used to speed up the compilation of a module, lower the size //
// of the output library on certain compilers and allow deeper optimizations //
// by reunifying all compilation units into one (single compilation unit //
// method). //
// //
// Either only this file or all the files below should be compiled, not both or //
// some 'multiple definition of symbols' errors will occur. //
//////////////////////////////////////////////////////////////////////////////////
// Core
#include "Core/SPK_DEF.cpp"
#include "Core/SPK_Vector3D.cpp"
#include "Core/SPK_Registerable.cpp" // 1.03
#include "Core/SPK_Transformable.cpp" // 1.03
#include "Core/SPK_BufferHandler.cpp" // 1.04
#include "Core/SPK_Renderer.cpp"
#include "Core/SPK_System.cpp"
#include "Core/SPK_Particle.cpp"
#include "Core/SPK_Zone.cpp"
#include "Core/SPK_Interpolator.cpp" // 1.05
#include "Core/SPK_Model.cpp"
#include "Core/SPK_Emitter.cpp"
#include "Core/SPK_Modifier.cpp"
#include "Core/SPK_Group.cpp"
#include "Core/SPK_Factory.cpp" // 1.03
// Zones
#include "Extensions/Zones/SPK_AABox.cpp"
#include "Extensions/Zones/SPK_Point.cpp"
#include "Extensions/Zones/SPK_Sphere.cpp"
#include "Extensions/Zones/SPK_Plane.cpp"
#include "Extensions/Zones/SPK_Line.cpp" // 1.01
#include "Extensions/Zones/SPK_Ring.cpp" // 1.05
// Emitters
#include "Extensions/Emitters/SPK_StraightEmitter.cpp"
#include "Extensions/Emitters/SPK_SphericEmitter.cpp"
#include "Extensions/Emitters/SPK_NormalEmitter.cpp" // 1.02
#include "Extensions/Emitters/SPK_RandomEmitter.cpp" // 1.02
// Modifiers
#include "Extensions/Modifiers/SPK_Obstacle.cpp"
#include "Extensions/Modifiers/SPK_Destroyer.cpp"
#include "Extensions/Modifiers/SPK_PointMass.cpp"
#include "Extensions/Modifiers/SPK_ModifierGroup.cpp" // 1.02
#include "Extensions/Modifiers/SPK_LinearForce.cpp" // 1.03
#include "Extensions/Modifiers/SPK_Collision.cpp" // 1.04
#include "Extensions/Modifiers/SPK_Vortex.cpp" // 1.05
// Renderer Interfaces
#include "Extensions/Renderers/SPK_QuadRendererInterface.cpp" // 1.04
#include "Extensions/Renderers/SPK_Oriented3DRendererInterface.cpp" // 1.04

View File

@@ -0,0 +1,42 @@
//////////////////////////////////////////////////////////////////////////////////
// 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. //
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
// Note : //
// //
// This file is used to speed up the compilation of a module, lower the size //
// of the output library on certain compilers and allow deeper optimizations //
// by reunifying all compilation units into one (single compilation unit //
// method). //
// //
// Either only this file or all the files below should be compiled, not both or //
// some 'multiple definition of symbols' errors will occur. //
//////////////////////////////////////////////////////////////////////////////////
// GL
#include "RenderingAPIs/OpenGL/SPK_GLExtHandler.cpp" // 1.01
#include "RenderingAPIs/OpenGL/SPK_GLRenderer.cpp"
#include "RenderingAPIs/OpenGL/SPK_GLLineRenderer.cpp"
#include "RenderingAPIs/OpenGL/SPK_GLPointRenderer.cpp"
#include "RenderingAPIs/OpenGL/SPK_GLQuadRenderer.cpp"
#include "RenderingAPIs/OpenGL/SPK_GLLineTrailRenderer.cpp" // 1.03