123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- /**
- * Copyright (c) 2006-2009 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.
- **/
- #include "ParticleSystem.h"
- #include <SDL_opengl.h>
- #include <cmath>
- #include <cstdlib>
- #include <cstring>
- namespace love
- {
- namespace graphics
- {
- namespace opengl
- {
- 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 = (rand() / (float(RAND_MAX)+1));
- return low*(1-r)+high*r;
- }
- ParticleSystem::ParticleSystem(Image * sprite, unsigned int buffer) : pStart(0), pLast(0), pEnd(0), active(true), emissionRate(0),
- emitCounter(0), lifetime(-1), life(0), particleLifeMin(0), particleLifeMax(0),
- direction(0), spread(0), relative(false), speedMin(0), speedMax(0), gravityMin(0),
- gravityMax(0), radialAccelerationMin(0), radialAccelerationMax(0),
- tangentialAccelerationMin(0), tangentialAccelerationMax(0),
- sizeStart(1), sizeEnd(1), sizeVariation(0), rotationMin(0), rotationMax(0),
- spinStart(0), spinEnd(0), spinVariation(0), offsetX(sprite->getWidth()*0.5f),
- offsetY(sprite->getHeight()*0.5f)
- {
- this->sprite = sprite;
- sprite->retain();
- memset(colorStart, 255, 4);
- memset(colorEnd, 255, 4);
- setBufferSize(buffer);
- }
- ParticleSystem::~ParticleSystem()
- {
- if(this->sprite != 0)
- {
- this->sprite->release();
- this->sprite = 0;
- }
- if(pStart != 0)
- delete [] pStart;
- }
- void ParticleSystem::add()
- {
- if(isFull()) return;
- float min,max;
- min = particleLifeMin;
- max = particleLifeMax;
- if(min == max)
- pLast->life = min;
- else
- pLast->life = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
- pLast->lifetime = pLast->life;
- pLast->position[0] = position.getX();
- pLast->position[1] = position.getY();
- min = direction - spread/2.0f;
- max = direction + spread/2.0f;
- pLast->direction = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
- min = speedMin;
- max = speedMax;
- float speed = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
- pLast->speed = love::Vector(cos(pLast->direction), sin(pLast->direction));
- pLast->speed *= speed;
- min = gravityMin;
- max = gravityMax;
- pLast->gravity = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
- min = radialAccelerationMin;
- max = radialAccelerationMax;
- pLast->radialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
- min = tangentialAccelerationMin;
- max = tangentialAccelerationMax;
- pLast->tangentialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
- pLast->sizeStart = calculate_variation(sizeStart, sizeEnd, sizeVariation);
- pLast->sizeEnd = calculate_variation(sizeEnd, sizeStart, sizeVariation);
- pLast->size = pLast->sizeStart;
- min = rotationMin;
- max = rotationMax;
- pLast->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
- pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
- pLast->rotation = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;;
- pLast->color[0] = (float)colorStart[0] / 255;
- pLast->color[1] = (float)colorStart[1] / 255;
- pLast->color[2] = (float)colorStart[2] / 255;
- pLast->color[3] = (float)colorStart[3] / 255;
- pLast++;
- }
- void ParticleSystem::remove(particle * p)
- {
- if(!isEmpty())
- {
- *p = *(--pLast);
- }
- }
- void ParticleSystem::setSprite(Image * image)
- {
- if(this->sprite != 0)
- {
- this->sprite->release();
- this->sprite = 0;
- }
- this->sprite = image;
- }
- void ParticleSystem::setBufferSize(unsigned int size)
- {
- // delete previous data
- delete [] pStart;
- pLast = pStart = new particle[size];
- pEnd = pStart + size;
- }
- void ParticleSystem::setEmissionRate(int rate)
- {
- emissionRate = rate;
- }
- void ParticleSystem::setLifetime(float life)
- {
- this->life = lifetime = life;
- }
- void ParticleSystem::setParticleLife(float min, float max)
- {
- particleLifeMin = min;
- if(max == 0)
- particleLifeMax = min;
- else
- particleLifeMax = max;
- }
- void ParticleSystem::setPosition(float x, float y)
- {
- position = love::Vector(x, y);
- }
- void ParticleSystem::setDirection(float direction)
- {
- this->direction = direction;
- }
- void ParticleSystem::setSpread(float spread)
- {
- this->spread = spread;
- }
- void ParticleSystem::setRelativeDirection(bool relative)
- {
- this->relative = relative;
- }
- void ParticleSystem::setSpeed(float speed)
- {
- speedMin = speedMax = speed;
- }
- void ParticleSystem::setSpeed(float min, float max)
- {
- speedMin = min;
- speedMax = max;
- }
- void ParticleSystem::setGravity(float gravity)
- {
- gravityMin = gravityMax = gravity;
- }
- void ParticleSystem::setGravity(float min, float max)
- {
- gravityMin = min;
- gravityMax = max;
- }
- void ParticleSystem::setRadialAcceleration(float acceleration)
- {
- radialAccelerationMin = radialAccelerationMax = acceleration;
- }
- void ParticleSystem::setRadialAcceleration(float min, float max)
- {
- radialAccelerationMin = min;
- radialAccelerationMax = max;
- }
- void ParticleSystem::setTangentialAcceleration(float acceleration)
- {
- tangentialAccelerationMin = tangentialAccelerationMax = acceleration;
- }
- void ParticleSystem::setTangentialAcceleration(float min, float max)
- {
- tangentialAccelerationMin = min;
- tangentialAccelerationMax = max;
- }
- void ParticleSystem::setSize(float size)
- {
- sizeStart = size;
- sizeEnd = size;
- }
- void ParticleSystem::setSize(float start, float end)
- {
- sizeStart = start;
- sizeEnd = end;
- }
- void ParticleSystem::setSize(float start, float end, float variation)
- {
- sizeStart = start;
- sizeEnd = end;
- sizeVariation = variation;
- }
- void ParticleSystem::setSizeVariation(float variation)
- {
- sizeVariation = variation;
- }
- void ParticleSystem::setRotation(float rotation)
- {
- rotationMin = rotationMax = rotation;
- }
- void ParticleSystem::setRotation(float min, float max)
- {
- rotationMin = min;
- rotationMax = max;
- }
- void ParticleSystem::setSpin(float spin)
- {
- spinStart = spin;
- spinEnd = spin;
- }
- void ParticleSystem::setSpin(float start, float end)
- {
- spinStart = start;
- spinEnd = end;
- }
- void ParticleSystem::setSpin(float start, float end, float variation)
- {
- spinStart = start;
- spinEnd = end;
- spinVariation = variation;
- }
- void ParticleSystem::setSpinVariation(float variation)
- {
- spinVariation = variation;
- }
- void ParticleSystem::setColor(unsigned char * color)
- {
- memcpy(colorStart, color, 4);
- memcpy(colorEnd, color, 4);
- }
- void ParticleSystem::setColor(unsigned char * start, unsigned char * end)
- {
- memcpy(colorStart, start, 4);
- memcpy(colorEnd, end, 4);
- }
- void ParticleSystem::setOffset(float x, float y)
- {
- offsetX = x;
- offsetY = y;
- }
- float ParticleSystem::getX() const
- {
- return position.getX();
- }
- float ParticleSystem::getY() const
- {
- return position.getY();
- }
- float ParticleSystem::getDirection() const
- {
- return direction;
- }
- float ParticleSystem::getSpread() const
- {
- return spread;
- }
- float ParticleSystem::getOffsetX() const
- {
- return offsetX;
- }
- float ParticleSystem::getOffsetY() const
- {
- return offsetY;
- }
- int ParticleSystem::count() const
- {
- return (int)(pLast - pStart);
- }
- void ParticleSystem::start()
- {
- active = true;
- }
- void ParticleSystem::stop()
- {
- active = false;
- life = lifetime;
- emitCounter = 0;
- }
- void ParticleSystem::pause()
- {
- active = false;
- }
- void ParticleSystem::reset()
- {
- pLast = pStart;
- life = lifetime;
- emitCounter = 0;
- }
- bool ParticleSystem::isActive() const
- {
- return active;
- }
- bool ParticleSystem::isEmpty() const
- {
- return pStart == pLast;
- }
- bool ParticleSystem::isFull() const
- {
- return pLast == pEnd;
- }
- void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy) const
- {
- if(sprite == 0) return; // just in case of failure
- glPushMatrix();
- glPushAttrib(GL_CURRENT_BIT);
- glTranslatef(x, y, 0);
- glRotatef(angle, 0, 0, 1.0f);
- glScalef(sx, sy, 1.0f);
- glTranslatef( ox, oy, 0);
- particle * p = pStart;
- while(p != pLast)
- {
- glPushMatrix();
- glColor4f(p->color[0],p->color[1],p->color[2],p->color[3]);
- glTranslatef(p->position[0],p->position[1],0.0f);
- glRotatef(p->rotation * 57.29578f, 0.0f, 0.0f, 1.0f); // rad * (180 / pi)
- glScalef(p->size,p->size,1.0f);
- glTranslatef(-offsetX,-offsetY,0.0f);
- sprite->draw(0,0, 0, 1, 1, 0, 0);
- glPopMatrix();
- p++;
- }
- glPopAttrib();
- glPopMatrix();
- }
- void ParticleSystem::update(float dt)
- {
- // Traverse all particles and update.
- particle * p = pStart;
- // Make some more particles.
- if(active)
- {
- float rate = 1.0f / emissionRate; // the amount of time between each particle emit
- emitCounter += dt;
- while(emitCounter > rate)
- {
- add();
- emitCounter -= rate;
- }
- /*int particles = (int)(emissionRate * dt);
- for(int i = 0; i != particles; i++)
- add();*/
- life -= dt;
- if(lifetime != -1 && life < 0)
- stop();
- }
- while(p != pLast)
- {
- // Decrease lifespan.
- p->life -= dt;
- if(p->life > 0)
- {
- // Temp variables.
- love::Vector radial, tangential, gravity(0, p->gravity);
- love::Vector ppos(p->position[0], p->position[1]);
- // Get vector from particle center to particle.
- radial = ppos - position;
- 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 position.
- p->speed += (radial+tangential+gravity)*dt;
- // Modify position.
- ppos += p->speed * dt;
- p->position[0] = ppos.getX();
- p->position[1] = ppos.getY();
- const float t = p->life / p->lifetime;
- // Change size.
- p->size = p->sizeEnd - ((p->sizeEnd - p->sizeStart) * t);
- // Rotate.
- p->rotation += (p->spinStart*(1-t) + p->spinEnd*t)*dt;
- // Update color.
- p->color[0] = (float)(colorEnd[0]*(1.0f-t) + colorStart[0] * t)/255.0f;
- p->color[1] = (float)(colorEnd[1]*(1.0f-t) + colorStart[1] * t)/255.0f;
- p->color[2] = (float)(colorEnd[2]*(1.0f-t) + colorStart[2] * t)/255.0f;
- p->color[3] = (float)(colorEnd[3]*(1.0f-t) + colorStart[3] * t)/255.0f;
- // Next particle.
- p++;
- }
- else
- {
- remove(p);
- if(p >= pLast)
- return;
- } // else
- } // while
- }
- } // opengl
- } // graphics
- } // love
|