diff src/modules/graphics/opengl/ParticleSystem.cpp @ 1127:13e6ca38c28c

Fix issue #437: Area-based particle spawn. New particles are spawned around the particle emitter position according to a configurabe distribution. New functionality: particlesystem:setAreaSpread(distributon, x, y) distribution, x, y = particlesystem:getAreaSpread() Where `distribution' is one of "none", "uniform", "normal". `x' and `y' take different meaning based on the distribution: * none: no area spread - particles spawned at emitter position. * uniform: particle spawned at px,py in the rectangle around emitter position ex,ey, i.e.: ex - x < px < ex + x, ey - y < py < ey + y, * normal: particle position drawn from a normal/gaussian distribution with mean ex,ey and standard deviation x,y, i.e.: px \in N(ex, x²), py \in N(ey, y²).
author vrld <vrld@vrld.org>
date Mon, 10 Sep 2012 19:58:44 +0200
parents 86a44f2bc38f
children 7c7332becb70 77889bd62149
line wrap: on
line diff
--- a/src/modules/graphics/opengl/ParticleSystem.cpp	Mon Sep 10 19:45:54 2012 +0200
+++ b/src/modules/graphics/opengl/ParticleSystem.cpp	Mon Sep 10 19:58:44 2012 +0200
@@ -45,10 +45,18 @@
 {
 	float low = inner - (outer/2.0f)*var;
 	float high = inner + (outer/2.0f)*var;
-	float r = (rand() / (float(RAND_MAX)+1));
+	float r = random();
 	return low*(1-r)+high*r;
 }
 
+StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] = {
+	{ "none",     ParticleSystem::DISTRIBUTION_NONE },
+	{ "uniform",  ParticleSystem::DISTRIBUTION_UNIFORM },
+	{ "normal",   ParticleSystem::DISTRIBUTION_NORMAL },
+};
+
+StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM> ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries));
+
 
 ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer)
 	: pStart(0)
@@ -57,6 +65,7 @@
 	, active(true)
 	, emissionRate(0)
 	, emitCounter(0)
+	, areaSpreadDistribution(DISTRIBUTION_NONE)
 	, lifetime(-1)
 	, life(0)
 	, particleLifeMin(0)
@@ -108,45 +117,60 @@
 	if (min == max)
 		pLast->life = min;
 	else
-		pLast->life = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+		pLast->life = random(min, max);
 	pLast->lifetime = pLast->life;
 
 	pLast->position[0] = position.getX();
 	pLast->position[1] = position.getY();
 
+	switch (areaSpreadDistribution)
+	{
+		case DISTRIBUTION_UNIFORM:
+			pLast->position[0] += random(-areaSpread.getX(), areaSpread.getX());
+			pLast->position[1] += random(-areaSpread.getY(), areaSpread.getY());
+			break;
+		case DISTRIBUTION_NORMAL:
+			pLast->position[0] += random_normal(areaSpread.getX());
+			pLast->position[1] += random_normal(areaSpread.getY());
+			break;
+		case DISTRIBUTION_NONE:
+		default:
+			break;
+	}
+
 	min = direction - spread/2.0f;
 	max = direction + spread/2.0f;
-	pLast->direction = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	pLast->direction = random(min, max);
 
 	pLast->origin = position;
 
 	min = speedMin;
 	max = speedMax;
-	float speed = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	float speed = random(min, max);
 	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;
+	pLast->gravity = random(min, max);
 
 	min = radialAccelerationMin;
 	max = radialAccelerationMax;
-	pLast->radialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	pLast->radialAcceleration = random(min, max);
 
 	min = tangentialAccelerationMin;
 	max = tangentialAccelerationMax;
-	pLast->tangentialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
+	pLast->tangentialAcceleration = random(min, max);
 
-	pLast->sizeOffset       = (rand() / (float(RAND_MAX)+1)) * sizeVariation; // time offset for size change
-	pLast->sizeIntervalSize = (1.0f - (rand() / (float(RAND_MAX)+1)) * sizeVariation) - pLast->sizeOffset;
+	pLast->sizeOffset       = random(sizeVariation); // time offset for size change
+	pLast->sizeIntervalSize = (1.0f - random(sizeVariation)) - pLast->sizeOffset;
 	pLast->size = sizes[(size_t)(pLast->sizeOffset - .5f) * (sizes.size() - 1)];
 
 	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->rotation = random(min, max);
 
 	pLast->color = colors[0];
 
@@ -204,6 +228,13 @@
 	position = love::Vector(x, y);
 }
 
+
+void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
+{
+	areaSpread = love::Vector(x, y);
+	areaSpreadDistribution = distribution;
+}
+
 void ParticleSystem::setDirection(float direction)
 {
 	this->direction = direction;
@@ -349,6 +380,16 @@
 	return position;
 }
 
+ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
+{
+	return areaSpreadDistribution;
+}
+
+const love::Vector &ParticleSystem::getAreaSpreadParameters() const
+{
+	return areaSpread;
+}
+
 float ParticleSystem::getDirection() const
 {
 	return direction;
@@ -543,6 +584,16 @@
 	} // while
 }
 
+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);
+}
+
 } // opengl
 } // graphics
 } // love