123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994 |
- /**
- * Copyright (c) 2006-2016 LOVE Development Team
- *
- * 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.
- **/
- //LOVE
- #include "common/config.h"
- #include "ParticleSystem.h"
- #include "common/math.h"
- #include "modules/math/RandomGenerator.h"
- // STD
- #include <algorithm>
- #include <cmath>
- #include <cstdlib>
- namespace love
- {
- namespace graphics
- {
- namespace
- {
- love::math::RandomGenerator rng;
- float calculate_variation(float inner, float outer, float var)
- {
- float low = inner - (outer/2.0f)*var;
- float high = inner + (outer/2.0f)*var;
- float r = (float) rng.random();
- return low*(1-r)+high*r;
- }
- } // anonymous namespace
- ParticleSystem::ParticleSystem(Texture *texture, uint32 size)
- : pMem(nullptr)
- , pFree(nullptr)
- , pHead(nullptr)
- , pTail(nullptr)
- , texture(texture)
- , active(true)
- , insertMode(INSERT_MODE_TOP)
- , maxParticles(0)
- , activeParticles(0)
- , emissionRate(0)
- , emitCounter(0)
- , areaSpreadDistribution(DISTRIBUTION_NONE)
- , lifetime(-1)
- , life(0)
- , particleLifeMin(0)
- , particleLifeMax(0)
- , direction(0)
- , spread(0)
- , speedMin(0)
- , speedMax(0)
- , linearAccelerationMin(0, 0)
- , linearAccelerationMax(0, 0)
- , radialAccelerationMin(0)
- , radialAccelerationMax(0)
- , tangentialAccelerationMin(0)
- , tangentialAccelerationMax(0)
- , linearDampingMin(0.0f)
- , linearDampingMax(0.0f)
- , sizeVariation(0)
- , rotationMin(0)
- , rotationMax(0)
- , spinStart(0)
- , spinEnd(0)
- , spinVariation(0)
- , offset(float(texture->getWidth())*0.5f, float(texture->getHeight())*0.5f)
- , defaultOffset(true)
- , relativeRotation(false)
- {
- if (size == 0 || size > MAX_PARTICLES)
- throw love::Exception("Invalid ParticleSystem size.");
- sizes.push_back(1.0f);
- colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
- setBufferSize(size);
- }
- ParticleSystem::ParticleSystem(const ParticleSystem &p)
- : pMem(nullptr)
- , pFree(nullptr)
- , pHead(nullptr)
- , pTail(nullptr)
- , texture(p.texture)
- , active(p.active)
- , insertMode(p.insertMode)
- , maxParticles(p.maxParticles)
- , activeParticles(0)
- , emissionRate(p.emissionRate)
- , emitCounter(0.0f)
- , position(p.position)
- , prevPosition(p.prevPosition)
- , areaSpreadDistribution(p.areaSpreadDistribution)
- , areaSpread(p.areaSpread)
- , lifetime(p.lifetime)
- , life(p.lifetime) // Initialize with the maximum life time.
- , particleLifeMin(p.particleLifeMin)
- , particleLifeMax(p.particleLifeMax)
- , direction(p.direction)
- , spread(p.spread)
- , speedMin(p.speedMin)
- , speedMax(p.speedMax)
- , linearAccelerationMin(p.linearAccelerationMin)
- , linearAccelerationMax(p.linearAccelerationMax)
- , radialAccelerationMin(p.radialAccelerationMin)
- , radialAccelerationMax(p.radialAccelerationMax)
- , tangentialAccelerationMin(p.tangentialAccelerationMin)
- , tangentialAccelerationMax(p.tangentialAccelerationMax)
- , linearDampingMin(p.linearDampingMin)
- , linearDampingMax(p.linearDampingMax)
- , sizes(p.sizes)
- , sizeVariation(p.sizeVariation)
- , rotationMin(p.rotationMin)
- , rotationMax(p.rotationMax)
- , spinStart(p.spinStart)
- , spinEnd(p.spinEnd)
- , spinVariation(p.spinVariation)
- , offset(p.offset)
- , defaultOffset(p.defaultOffset)
- , colors(p.colors)
- , quads(p.quads)
- , relativeRotation(p.relativeRotation)
- {
- setBufferSize(maxParticles);
- }
- ParticleSystem::~ParticleSystem()
- {
- deleteBuffers();
- }
- void ParticleSystem::resetOffset()
- {
- if (quads.empty())
- offset = love::Vector(float(texture->getWidth())*0.5f, float(texture->getHeight())*0.5f);
- else
- {
- Quad::Viewport v = quads[0]->getViewport();
- offset = love::Vector(v.x*0.5f, v.y*0.5f);
- }
- }
- void ParticleSystem::createBuffers(size_t size)
- {
- try
- {
- pFree = pMem = new Particle[size];
- maxParticles = (uint32) size;
- }
- catch (std::bad_alloc &)
- {
- deleteBuffers();
- throw love::Exception("Out of memory");
- }
- }
- void ParticleSystem::deleteBuffers()
- {
- // Clean up for great gracefulness!
- delete[] pMem;
- pMem = nullptr;
- maxParticles = 0;
- activeParticles = 0;
- }
- void ParticleSystem::setBufferSize(uint32 size)
- {
- if (size == 0 || size > MAX_PARTICLES)
- throw love::Exception("Invalid buffer size");
- deleteBuffers();
- createBuffers(size);
- reset();
- }
- uint32 ParticleSystem::getBufferSize() const
- {
- return maxParticles;
- }
- void ParticleSystem::addParticle(float t)
- {
- if (isFull())
- return;
- // Gets a free particle and updates the allocation pointer.
- Particle *p = pFree++;
- initParticle(p, t);
- switch (insertMode)
- {
- default:
- case INSERT_MODE_TOP:
- insertTop(p);
- break;
- case INSERT_MODE_BOTTOM:
- insertBottom(p);
- break;
- case INSERT_MODE_RANDOM:
- insertRandom(p);
- break;
- }
- activeParticles++;
- }
- void ParticleSystem::initParticle(Particle *p, float t)
- {
- float min,max;
- // Linearly interpolate between the previous and current emitter position.
- love::Vector pos = prevPosition + (position - prevPosition) * t;
- min = particleLifeMin;
- max = particleLifeMax;
- if (min == max)
- p->life = min;
- else
- p->life = (float) rng.random(min, max);
- p->lifetime = p->life;
- p->position = pos;
- float rand_x, rand_y;
- switch (areaSpreadDistribution)
- {
- case DISTRIBUTION_UNIFORM:
- p->position.x += (float) rng.random(-areaSpread.getX(), areaSpread.getX());
- p->position.y += (float) rng.random(-areaSpread.getY(), areaSpread.getY());
- break;
- case DISTRIBUTION_NORMAL:
- p->position.x += (float) rng.randomNormal(areaSpread.getX());
- p->position.y += (float) rng.randomNormal(areaSpread.getY());
- break;
- case DISTRIBUTION_ELLIPSE:
- rand_x = (float) rng.random(-1, 1);
- rand_y = (float) rng.random(-1, 1);
- p->position.x += areaSpread.getX() * (rand_x * sqrt(1 - 0.5f*pow(rand_y, 2)));
- p->position.y += areaSpread.getY() * (rand_y * sqrt(1 - 0.5f*pow(rand_x, 2)));
- break;
- case DISTRIBUTION_NONE:
- default:
- break;
- }
- p->origin = pos;
- min = speedMin;
- max = speedMax;
- float speed = (float) rng.random(min, max);
- min = direction - spread/2.0f;
- max = direction + spread/2.0f;
- float dir = (float) rng.random(min, max);
- p->velocity = love::Vector(cosf(dir), sinf(dir)) * speed;
- p->linearAcceleration.x = (float) rng.random(linearAccelerationMin.x, linearAccelerationMax.x);
- p->linearAcceleration.y = (float) rng.random(linearAccelerationMin.y, linearAccelerationMax.y);
- min = radialAccelerationMin;
- max = radialAccelerationMax;
- p->radialAcceleration = (float) rng.random(min, max);
- min = tangentialAccelerationMin;
- max = tangentialAccelerationMax;
- p->tangentialAcceleration = (float) rng.random(min, max);
- min = linearDampingMin;
- max = linearDampingMax;
- p->linearDamping = (float) rng.random(min, max);
- p->sizeOffset = (float) rng.random(sizeVariation); // time offset for size change
- p->sizeIntervalSize = (1.0f - (float) rng.random(sizeVariation)) - p->sizeOffset;
- p->size = sizes[(size_t)(p->sizeOffset - .5f) * (sizes.size() - 1)];
- min = rotationMin;
- max = rotationMax;
- p->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
- p->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
- p->rotation = (float) rng.random(min, max);
- p->angle = p->rotation;
- if (relativeRotation)
- p->angle += atan2f(p->velocity.y, p->velocity.x);
- p->color = colors[0];
- p->quadIndex = 0;
- }
- void ParticleSystem::insertTop(Particle *p)
- {
- if (pHead == nullptr)
- {
- pHead = p;
- p->prev = nullptr;
- }
- else
- {
- pTail->next = p;
- p->prev = pTail;
- }
- p->next = nullptr;
- pTail = p;
- }
- void ParticleSystem::insertBottom(Particle *p)
- {
- if (pTail == nullptr)
- {
- pTail = p;
- p->next = nullptr;
- }
- else
- {
- pHead->prev = p;
- p->next = pHead;
- }
- p->prev = nullptr;
- pHead = p;
- }
- void ParticleSystem::insertRandom(Particle *p)
- {
- // Nonuniform, but 64-bit is so large nobody will notice. Hopefully.
- uint64 pos = rng.rand() % ((int64) activeParticles + 1);
- // Special case where the particle gets inserted before the head.
- if (pos == activeParticles)
- {
- Particle *pA = pHead;
- if (pA)
- pA->prev = p;
- p->prev = nullptr;
- p->next = pA;
- pHead = p;
- return;
- }
- // Inserts the particle after the randomly selected particle.
- Particle *pA = pMem + pos;
- Particle *pB = pA->next;
- pA->next = p;
- if (pB)
- pB->prev = p;
- else
- pTail = p;
- p->prev = pA;
- p->next = pB;
- }
- ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p)
- {
- // The linked list is updated in this function and old pointers may be
- // invalidated. The returned pointer will inform the caller of the new
- // pointer to the next particle.
- Particle *pNext = nullptr;
- // Removes the particle from the linked list.
- if (p->prev)
- p->prev->next = p->next;
- else
- pHead = p->next;
- if (p->next)
- {
- p->next->prev = p->prev;
- pNext = p->next;
- }
- else
- pTail = p->prev;
- // The (in memory) last particle can now be moved into the free slot.
- // It will skip the moving if it happens to be the removed particle.
- pFree--;
- if (p != pFree)
- {
- *p = *pFree;
- if (pNext == pFree)
- pNext = p;
- if (p->prev)
- p->prev->next = p;
- else
- pHead = p;
- if (p->next)
- p->next->prev = p;
- else
- pTail = p;
- }
- activeParticles--;
- return pNext;
- }
- void ParticleSystem::setTexture(Texture *tex)
- {
- texture.set(tex);
- if (defaultOffset)
- resetOffset();
- }
- Texture *ParticleSystem::getTexture() const
- {
- return texture.get();
- }
- void ParticleSystem::setInsertMode(InsertMode mode)
- {
- insertMode = mode;
- }
- ParticleSystem::InsertMode ParticleSystem::getInsertMode() const
- {
- return insertMode;
- }
- void ParticleSystem::setEmissionRate(float rate)
- {
- if (rate < 0.0f)
- throw love::Exception("Invalid emission rate");
- emissionRate = rate;
- // Prevent an explosion when dramatically increasing the rate
- emitCounter = std::min(emitCounter, 1.0f/rate);
- }
- float ParticleSystem::getEmissionRate() const
- {
- return emissionRate;
- }
- void ParticleSystem::setEmitterLifetime(float life)
- {
- this->life = lifetime = life;
- }
- float ParticleSystem::getEmitterLifetime() const
- {
- return lifetime;
- }
- void ParticleSystem::setParticleLifetime(float min, float max)
- {
- particleLifeMin = min;
- if (max == 0)
- particleLifeMax = min;
- else
- particleLifeMax = max;
- }
- void ParticleSystem::getParticleLifetime(float &min, float &max) const
- {
- min = particleLifeMin;
- max = particleLifeMax;
- }
- void ParticleSystem::setPosition(float x, float y)
- {
- position = love::Vector(x, y);
- prevPosition = position;
- }
- const love::Vector &ParticleSystem::getPosition() const
- {
- return position;
- }
- void ParticleSystem::moveTo(float x, float y)
- {
- position = love::Vector(x, y);
- }
- void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
- {
- areaSpread = love::Vector(x, y);
- areaSpreadDistribution = distribution;
- }
- ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
- {
- return areaSpreadDistribution;
- }
- const love::Vector &ParticleSystem::getAreaSpreadParameters() const
- {
- return areaSpread;
- }
- void ParticleSystem::setDirection(float direction)
- {
- this->direction = direction;
- }
- float ParticleSystem::getDirection() const
- {
- return direction;
- }
- void ParticleSystem::setSpread(float spread)
- {
- this->spread = spread;
- }
- float ParticleSystem::getSpread() const
- {
- return spread;
- }
- void ParticleSystem::setSpeed(float speed)
- {
- speedMin = speedMax = speed;
- }
- void ParticleSystem::setSpeed(float min, float max)
- {
- speedMin = min;
- speedMax = max;
- }
- void ParticleSystem::getSpeed(float &min, float &max) const
- {
- min = speedMin;
- max = speedMax;
- }
- void ParticleSystem::setLinearAcceleration(float x, float y)
- {
- linearAccelerationMin.x = linearAccelerationMax.x = x;
- linearAccelerationMin.y = linearAccelerationMax.y = y;
- }
- void ParticleSystem::setLinearAcceleration(float xmin, float ymin, float xmax, float ymax)
- {
- linearAccelerationMin = love::Vector(xmin, ymin);
- linearAccelerationMax = love::Vector(xmax, ymax);
- }
- void ParticleSystem::getLinearAcceleration(love::Vector &min, love::Vector &max) const
- {
- min = linearAccelerationMin;
- max = linearAccelerationMax;
- }
- void ParticleSystem::setRadialAcceleration(float acceleration)
- {
- radialAccelerationMin = radialAccelerationMax = acceleration;
- }
- void ParticleSystem::setRadialAcceleration(float min, float max)
- {
- radialAccelerationMin = min;
- radialAccelerationMax = max;
- }
- void ParticleSystem::getRadialAcceleration(float &min, float &max) const
- {
- min = radialAccelerationMin;
- max = radialAccelerationMax;
- }
- void ParticleSystem::setTangentialAcceleration(float acceleration)
- {
- tangentialAccelerationMin = tangentialAccelerationMax = acceleration;
- }
- void ParticleSystem::setTangentialAcceleration(float min, float max)
- {
- tangentialAccelerationMin = min;
- tangentialAccelerationMax = max;
- }
- void ParticleSystem::getTangentialAcceleration(float &min, float &max) const
- {
- min = tangentialAccelerationMin;
- max = tangentialAccelerationMax;
- }
- void ParticleSystem::setLinearDamping(float min, float max)
- {
- linearDampingMin = min;
- linearDampingMax = max;
- }
- void ParticleSystem::getLinearDamping(float &min, float &max) const
- {
- min = linearDampingMin;
- max = linearDampingMax;
- }
- void ParticleSystem::setSize(float size)
- {
- sizes.resize(1);
- sizes[0] = size;
- }
- void ParticleSystem::setSizes(const std::vector<float> &newSizes)
- {
- sizes = newSizes;
- }
- const std::vector<float> &ParticleSystem::getSizes() const
- {
- return sizes;
- }
- void ParticleSystem::setSizeVariation(float variation)
- {
- sizeVariation = variation;
- }
- float ParticleSystem::getSizeVariation() const
- {
- return sizeVariation;
- }
- void ParticleSystem::setRotation(float rotation)
- {
- rotationMin = rotationMax = rotation;
- }
- void ParticleSystem::setRotation(float min, float max)
- {
- rotationMin = min;
- rotationMax = max;
- }
- void ParticleSystem::getRotation(float &min, float &max) const
- {
- min = rotationMin;
- max = rotationMax;
- }
- void ParticleSystem::setSpin(float spin)
- {
- spinStart = spin;
- spinEnd = spin;
- }
- void ParticleSystem::setSpin(float start, float end)
- {
- spinStart = start;
- spinEnd = end;
- }
- void ParticleSystem::getSpin(float &start, float &end) const
- {
- start = spinStart;
- end = spinEnd;
- }
- void ParticleSystem::setSpinVariation(float variation)
- {
- spinVariation = variation;
- }
- float ParticleSystem::getSpinVariation() const
- {
- return spinVariation;
- }
- void ParticleSystem::setOffset(float x, float y)
- {
- offset = love::Vector(x, y);
- defaultOffset = false;
- }
- love::Vector ParticleSystem::getOffset() const
- {
- return offset;
- }
- void ParticleSystem::setColor(const std::vector<Colorf> &newColors)
- {
- colors = newColors;
- for (Colorf &c : colors)
- {
- // We want to store the colors as [0, 1], rather than [0, 255].
- c.r /= 255.0f;
- c.g /= 255.0f;
- c.b /= 255.0f;
- c.a /= 255.0f;
- }
- }
- std::vector<Colorf> ParticleSystem::getColor() const
- {
- // The particle system stores colors in the range of [0, 1]...
- std::vector<Colorf> ncolors(colors);
- for (Colorf &c : ncolors)
- {
- c.r *= 255.0f;
- c.g *= 255.0f;
- c.b *= 255.0f;
- c.a *= 255.0f;
- }
- return ncolors;
- }
- void ParticleSystem::setQuads(const std::vector<Quad *> &newQuads)
- {
- std::vector<StrongRef<Quad>> quadlist;
- quadlist.reserve(newQuads.size());
- for (Quad *q : newQuads)
- quadlist.push_back(q);
- quads = quadlist;
- if (defaultOffset)
- resetOffset();
- }
- void ParticleSystem::setQuads()
- {
- quads.clear();
- }
- std::vector<Quad *> ParticleSystem::getQuads() const
- {
- std::vector<Quad *> quadlist;
- quadlist.reserve(quads.size());
- for (const StrongRef<Quad> &q : quads)
- quadlist.push_back(q.get());
- return quadlist;
- }
- void ParticleSystem::setRelativeRotation(bool enable)
- {
- relativeRotation = enable;
- }
- bool ParticleSystem::hasRelativeRotation() const
- {
- return relativeRotation;
- }
- uint32 ParticleSystem::getCount() const
- {
- return activeParticles;
- }
- void ParticleSystem::start()
- {
- active = true;
- }
- void ParticleSystem::stop()
- {
- active = false;
- life = lifetime;
- emitCounter = 0;
- }
- void ParticleSystem::pause()
- {
- active = false;
- }
- void ParticleSystem::reset()
- {
- if (pMem == nullptr)
- return;
- pFree = pMem;
- pHead = nullptr;
- pTail = nullptr;
- activeParticles = 0;
- life = lifetime;
- emitCounter = 0;
- }
- void ParticleSystem::emit(uint32 num)
- {
- if (!active)
- return;
- num = std::min(num, maxParticles - activeParticles);
- while (num--)
- addParticle(1.0f);
- }
- bool ParticleSystem::isActive() const
- {
- return active;
- }
- bool ParticleSystem::isPaused() const
- {
- return !active && life < lifetime;
- }
- bool ParticleSystem::isStopped() const
- {
- return !active && life >= lifetime;
- }
- bool ParticleSystem::isEmpty() const
- {
- return activeParticles == 0;
- }
- bool ParticleSystem::isFull() const
- {
- return activeParticles == maxParticles;
- }
- void ParticleSystem::update(float dt)
- {
- if (pMem == nullptr || dt == 0.0f)
- return;
- // Traverse all particles and update.
- Particle *p = pHead;
- while (p)
- {
- // Decrease lifespan.
- p->life -= dt;
- if (p->life <= 0)
- p = removeParticle(p);
- else
- {
- // Temp variables.
- love::Vector radial, tangential;
- love::Vector ppos = p->position;
- // Get vector from particle center to particle.
- radial = ppos - p->origin;
- radial.normalize();
- tangential = radial;
- // Resize radial acceleration.
- radial *= p->radialAcceleration;
- // Calculate tangential acceleration.
- {
- float a = tangential.getX();
- tangential.setX(-tangential.getY());
- tangential.setY(a);
- }
- // Resize tangential.
- tangential *= p->tangentialAcceleration;
- // Update velocity.
- p->velocity += (radial + tangential + p->linearAcceleration) * dt;
- // Apply damping.
- p->velocity *= 1.0f / (1.0f + p->linearDamping * dt);
- // Modify position.
- ppos += p->velocity * dt;
- p->position = ppos;
- const float t = 1.0f - p->life / p->lifetime;
- // Rotate.
- p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t) * dt;
- p->angle = p->rotation;
- if (relativeRotation)
- p->angle += atan2f(p->velocity.y, p->velocity.x);
- // Change size according to given intervals:
- // i = 0 1 2 3 n-1
- // |-------|-------|------|--- ... ---|
- // t = 0 1/(n-1) 3/(n-1) 1
- //
- // `s' is the interpolation variable scaled to the current
- // interval width, e.g. if n = 5 and t = 0.3, then the current
- // indices are 1,2 and s = 0.3 - 0.25 = 0.05
- float s = p->sizeOffset + t * p->sizeIntervalSize; // size variation
- s *= (float)(sizes.size() - 1); // 0 <= s < sizes.size()
- size_t i = (size_t)s;
- size_t k = (i == sizes.size() - 1) ? i : i + 1; // boundary check (prevents failing on t = 1.0f)
- s -= (float)i; // transpose s to be in interval [0:1]: i <= s < i + 1 ~> 0 <= s < 1
- p->size = sizes[i] * (1.0f - s) + sizes[k] * s;
- // Update color according to given intervals (as above)
- s = t * (float)(colors.size() - 1);
- i = (size_t)s;
- k = (i == colors.size() - 1) ? i : i + 1;
- s -= (float)i; // 0 <= s <= 1
- p->color = colors[i] * (1.0f - s) + colors[k] * s;
- // Update the quad index.
- k = quads.size();
- if (k > 0)
- {
- s = t * (float) k; // [0:numquads-1] (clamped below)
- i = (s > 0.0f) ? (size_t) s : 0;
- p->quadIndex = (int) ((i < k) ? i : k - 1);
- }
- // Next particle.
- p = p->next;
- }
- }
- // Make some more particles.
- if (active)
- {
- float rate = 1.0f / emissionRate; // the amount of time between each particle emit
- emitCounter += dt;
- float total = emitCounter - rate;
- while (emitCounter > rate)
- {
- addParticle(1.0f - (emitCounter - rate) / total);
- emitCounter -= rate;
- }
- life -= dt;
- if (lifetime != -1 && life < 0)
- stop();
- }
- prevPosition = position;
- }
- bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
- {
- return distributions.find(in, out);
- }
- bool ParticleSystem::getConstant(AreaSpreadDistribution in, const char *&out)
- {
- return distributions.find(in, out);
- }
- bool ParticleSystem::getConstant(const char *in, InsertMode &out)
- {
- return insertModes.find(in, out);
- }
- bool ParticleSystem::getConstant(InsertMode in, const char *&out)
- {
- return insertModes.find(in, out);
- }
- StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] =
- {
- { "none", DISTRIBUTION_NONE },
- { "uniform", DISTRIBUTION_UNIFORM },
- { "normal", DISTRIBUTION_NORMAL },
- { "ellipse", DISTRIBUTION_ELLIPSE },
- };
- StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM> ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries));
- StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM>::Entry ParticleSystem::insertModesEntries[] =
- {
- { "top", INSERT_MODE_TOP },
- { "bottom", INSERT_MODE_BOTTOM },
- { "random", INSERT_MODE_RANDOM },
- };
- StringMap<ParticleSystem::InsertMode, ParticleSystem::INSERT_MODE_MAX_ENUM> ParticleSystem::insertModes(ParticleSystem::insertModesEntries, sizeof(ParticleSystem::insertModesEntries));
- } // graphics
- } // love
|