diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 2b6604dd2..47e4b6552 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -45,10 +45,18 @@ 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)); + float r = random(); return low*(1-r)+high*r; } +StringMap::Entry ParticleSystem::distributionsEntries[] = { + { "none", ParticleSystem::DISTRIBUTION_NONE }, + { "uniform", ParticleSystem::DISTRIBUTION_UNIFORM }, + { "normal", ParticleSystem::DISTRIBUTION_NORMAL }, +}; + +StringMap ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries)); + ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer) : pStart(0) @@ -57,6 +65,7 @@ ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer) , active(true) , emissionRate(0) , emitCounter(0) + , areaSpreadDistribution(DISTRIBUTION_NONE) , lifetime(-1) , life(0) , particleLifeMin(0) @@ -108,45 +117,60 @@ void ParticleSystem::add() 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 @@ void ParticleSystem::setPosition(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; +} + void ParticleSystem::setDirection(float direction) { this->direction = direction; @@ -349,6 +380,16 @@ const love::Vector &ParticleSystem::getPosition() const 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 @@ void ParticleSystem::update(float dt) } // 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 diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 186437ad4..64cb5c519 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -72,6 +72,16 @@ struct particle class ParticleSystem : public Drawable { public: + /** + * Type of distribution new particles are drawn from: None, uniform, normal. + */ + enum AreaSpreadDistribution + { + DISTRIBUTION_NONE, + DISTRIBUTION_UNIFORM, + DISTRIBUTION_NORMAL, + DISTRIBUTION_MAX_ENUM, + }; /** * Creates a particle system with the specified buffersize and sprite. @@ -122,6 +132,19 @@ public: **/ void setPosition(float x, float y); + /** + * Sets the emission area spread parameters and distribution type. The interpretation of + * the parameters depends on the distribution type: + * + * * None: Parameters are ignored. No area spread. + * * Uniform: Parameters denote maximal (symmetric) displacement from emitter position. + * * Normal: Parameters denote the standard deviation in x and y direction. x and y are assumed to be uncorrelated. + * @param x First parameter. Interpretation depends on distribution type. + * @param y Second parameter. Interpretation depends on distribution type. + * @param distribution Distribution type + * */ + void setAreaSpread(AreaSpreadDistribution distribution, float x, float y); + /** * Sets the direction and the spread of the particle emitter. * @param direction The direction (in degrees). @@ -285,6 +308,16 @@ public: **/ const love::Vector &getPosition() const; + /** + * Returns area spread distribution type. + */ + AreaSpreadDistribution getAreaSpreadDistribution() const; + + /** + * Returns area spread parameters. + */ + const love::Vector &getAreaSpreadParameters() const; + /** * Returns the direction of the emitter (in degrees). **/ @@ -357,6 +390,9 @@ public: * @param dt Time since last update. **/ void update(float dt); + + static bool getConstant(const char *in, AreaSpreadDistribution &out); + static bool getConstant(AreaSpreadDistribution in, const char *&out); protected: // The max amount of particles. @@ -386,6 +422,10 @@ protected: // The relative position of the particle emitter. love::Vector position; + // Emission area spread. + AreaSpreadDistribution areaSpreadDistribution; + love::Vector areaSpread; + // The lifetime of the particle emitter (-1 means infinite) and the life it has left. float lifetime; float life; @@ -439,6 +479,9 @@ protected: void add(); void remove(particle *p); + + static StringMap::Entry distributionsEntries[]; + static StringMap distributions; }; } // opengl diff --git a/src/modules/graphics/opengl/PixelEffect.cpp b/src/modules/graphics/opengl/PixelEffect.cpp index 9679dc5de..e9da1233d 100644 --- a/src/modules/graphics/opengl/PixelEffect.cpp +++ b/src/modules/graphics/opengl/PixelEffect.cpp @@ -172,7 +172,7 @@ std::string PixelEffect::getGLSLVersion() bool PixelEffect::isSupported() { - return GLEE_VERSION_2_0 && GLEE_ARB_shader_objects && GLEE_ARB_fragment_shader && getGLSLVersion() >= "1.2"; + return (GLEE_VERSION_2_0 || (GLEE_ARB_shader_objects && GLEE_ARB_fragment_shader)) && getGLSLVersion() >= "1.2"; } std::string PixelEffect::getWarnings() const diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 3054b32a5..69df1c67f 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -86,6 +86,24 @@ int w_ParticleSystem_setPosition(lua_State *L) return 0; } +int w_ParticleSystem_setAreaSpread(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + + ParticleSystem::AreaSpreadDistribution distribution; + const char *str = luaL_checkstring(L, 2); + if (!ParticleSystem::getConstant(str, distribution)) + return luaL_error(L, "Invalid distribution: '%s'", str); + + float x = (float)luaL_checknumber(L, 3); + float y = (float)luaL_checknumber(L, 4); + if (x < 0.0f || y < 0.0f) + return luaL_error(L, "Invalid area spread parameters (must be >= 0)"); + + t->setAreaSpread(distribution, x, y); + return 0; +} + int w_ParticleSystem_setDirection(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); @@ -273,6 +291,21 @@ int w_ParticleSystem_getPosition(lua_State *L) return 2; } +int w_ParticleSystem_getAreaSpread(lua_State *L) +{ + ParticleSystem *t = luax_checkparticlesystem(L, 1); + ParticleSystem::AreaSpreadDistribution distribution = t-> getAreaSpreadDistribution(); + const char *str; + ParticleSystem::getConstant(distribution, str); + const love::Vector &p = t->getAreaSpreadParameters(); + + lua_pushstring(L, str); + lua_pushnumber(L, p.x); + lua_pushnumber(L, p.y); + + return 3; +} + int w_ParticleSystem_getDirection(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); @@ -373,6 +406,7 @@ static const luaL_Reg functions[] = { "setLifetime", w_ParticleSystem_setLifetime }, { "setParticleLife", w_ParticleSystem_setParticleLife }, { "setPosition", w_ParticleSystem_setPosition }, + { "setAreaSpread", w_ParticleSystem_setAreaSpread }, { "setDirection", w_ParticleSystem_setDirection }, { "setSpread", w_ParticleSystem_setSpread }, { "setRelativeDirection", w_ParticleSystem_setRelativeDirection }, @@ -390,6 +424,7 @@ static const luaL_Reg functions[] = { "getX", w_ParticleSystem_getX }, { "getY", w_ParticleSystem_getY }, { "getPosition", w_ParticleSystem_getPosition }, + { "getAreaSpread", w_ParticleSystem_getAreaSpread }, { "getDirection", w_ParticleSystem_getDirection }, { "getSpread", w_ParticleSystem_getSpread }, { "getOffsetX", w_ParticleSystem_getOffsetX },