diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index 189b34552..e3f5cbf30 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -65,9 +65,9 @@ ParticleSystem::ParticleSystem(Texture *texture, uint32 size) , activeParticles(0) , emissionRate(0) , emitCounter(0) - , areaSpreadDistribution(DISTRIBUTION_NONE) - , areaSpreadAngle(0) - , areaSpreadIsRelativeDirection(false) + , emissionAreaDistribution(DISTRIBUTION_NONE) + , emissionAreaAngle(0) + , directionRelativeToEmissionCenter(false) , lifetime(-1) , life(0) , particleLifeMin(0) @@ -122,10 +122,10 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p) , emitCounter(0.0f) , position(p.position) , prevPosition(p.prevPosition) - , areaSpreadDistribution(p.areaSpreadDistribution) - , areaSpread(p.areaSpread) - , areaSpreadAngle(p.areaSpreadAngle) - , areaSpreadIsRelativeDirection(p.areaSpreadIsRelativeDirection) + , emissionAreaDistribution(p.emissionAreaDistribution) + , emissionArea(p.emissionArea) + , emissionAreaAngle(p.emissionAreaAngle) + , directionRelativeToEmissionCenter(p.directionRelativeToEmissionCenter) , lifetime(p.lifetime) , life(p.lifetime) // Initialize with the maximum life time. , particleLifeMin(p.particleLifeMin) @@ -275,61 +275,67 @@ void ParticleSystem::initParticle(Particle *p, float t) // In this switch statement, variables 'rand_y', 'min', and 'max' // are sometimes reused as data stores for performance reasons float rand_x, rand_y; - switch (areaSpreadDistribution) + float c, s; + switch (emissionAreaDistribution) { case DISTRIBUTION_UNIFORM: - rand_x = (float) rng.random(-areaSpread.x, areaSpread.x); - rand_y = (float) rng.random(-areaSpread.y, areaSpread.y); - p->position.x += cosf(areaSpreadAngle) * rand_x - sinf(areaSpreadAngle) * rand_y; - p->position.y += sinf(areaSpreadAngle) * rand_x + cosf(areaSpreadAngle) * rand_y; + c = cosf(emissionAreaAngle); s = sinf(emissionAreaAngle); + rand_x = (float) rng.random(-emissionArea.x, emissionArea.x); + rand_y = (float) rng.random(-emissionArea.y, emissionArea.y); + p->position.x += c * rand_x - s * rand_y; + p->position.y += s * rand_x + c * rand_y; break; case DISTRIBUTION_NORMAL: - rand_x = (float) rng.randomNormal(areaSpread.x); - rand_y = (float) rng.randomNormal(areaSpread.y); - p->position.x += cosf(areaSpreadAngle) * rand_x - sinf(areaSpreadAngle) * rand_y; - p->position.y += sinf(areaSpreadAngle) * rand_x + cosf(areaSpreadAngle) * rand_y; + c = cosf(emissionAreaAngle); s = sinf(emissionAreaAngle); + rand_x = (float) rng.randomNormal(emissionArea.x); + rand_y = (float) rng.randomNormal(emissionArea.y); + p->position.x += c * rand_x - s * rand_y; + p->position.y += s * rand_x + c * rand_y; break; case DISTRIBUTION_ELLIPSE: + c = cosf(emissionAreaAngle); s = sinf(emissionAreaAngle); rand_x = (float) rng.random(-1, 1); rand_y = (float) rng.random(-1, 1); - min = areaSpread.x * (rand_x * sqrt(1 - 0.5f*pow(rand_y, 2))); - max = areaSpread.y * (rand_y * sqrt(1 - 0.5f*pow(rand_x, 2))); - p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * max; - p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * max; + min = emissionArea.x * (rand_x * sqrt(1 - 0.5f*pow(rand_y, 2))); + max = emissionArea.y * (rand_y * sqrt(1 - 0.5f*pow(rand_x, 2))); + p->position.x += c * min - s * max; + p->position.y += s * min + c * max; break; case DISTRIBUTION_BORDER_ELLIPSE: + c = cosf(emissionAreaAngle); s = sinf(emissionAreaAngle); rand_x = (float) rng.random(0, LOVE_M_PI * 2); - min = cosf(rand_x) * areaSpread.x; - max = sinf(rand_x) * areaSpread.y; - p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * max; - p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * max; + min = cosf(rand_x) * emissionArea.x; + max = sinf(rand_x) * emissionArea.y; + p->position.x += c * min - s * max; + p->position.y += s * min + c * max; break; case DISTRIBUTION_BORDER_RECTANGLE: - rand_x = (float) rng.random((areaSpread.x + areaSpread.y) * -2, (areaSpread.x + areaSpread.y) * 2); - rand_y = areaSpread.y * 2; + c = cosf(emissionAreaAngle); s = sinf(emissionAreaAngle); + rand_x = (float) rng.random((emissionArea.x + emissionArea.y) * -2, (emissionArea.x + emissionArea.y) * 2); + rand_y = emissionArea.y * 2; if (rand_x < -rand_y) { - min = rand_x + rand_y + areaSpread.x; - p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * -areaSpread.y; - p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * -areaSpread.y; + min = rand_x + rand_y + emissionArea.x; + p->position.x += c * min - s * -emissionArea.y; + p->position.y += s * min + c * -emissionArea.y; } else if (rand_x < 0) { - max = rand_x + areaSpread.y; - p->position.x += cosf(areaSpreadAngle) * -areaSpread.x - sinf(areaSpreadAngle) * max; - p->position.y += sinf(areaSpreadAngle) * -areaSpread.x + cosf(areaSpreadAngle) * max; + max = rand_x + emissionArea.y; + p->position.x += c * -emissionArea.x - s * max; + p->position.y += s * -emissionArea.x + c * max; } else if (rand_x < rand_y) { - max = rand_x - areaSpread.y; - p->position.x += cosf(areaSpreadAngle) * areaSpread.x - sinf(areaSpreadAngle) * max; - p->position.y += sinf(areaSpreadAngle) * areaSpread.x + cosf(areaSpreadAngle) * max; + max = rand_x - emissionArea.y; + p->position.x += c * emissionArea.x - s * max; + p->position.y += s * emissionArea.x + c * max; } else { - min = rand_x - rand_y - areaSpread.x; - p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * areaSpread.y; - p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * areaSpread.y; + min = rand_x - rand_y - emissionArea.x; + p->position.x += c * min - s * emissionArea.y; + p->position.y += s * min + c * emissionArea.y; } break; case DISTRIBUTION_NONE: @@ -338,7 +344,7 @@ void ParticleSystem::initParticle(Particle *p, float t) } // Determine if the origin of each particle is the center of the area - if (areaSpreadIsRelativeDirection) + if (directionRelativeToEmissionCenter) dir += atan2(p->position.y - pos.y, p->position.x - pos.x); p->origin = pos; @@ -571,40 +577,20 @@ void ParticleSystem::moveTo(float x, float y) position = love::Vector2(x, y); } -void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y) +void ParticleSystem::setEmissionArea(AreaSpreadDistribution distribution, float x, float y, float angle, bool directionRelativeToCenter) { - areaSpread = love::Vector2(x, y); - areaSpreadDistribution = distribution; + emissionArea = love::Vector2(x, y); + emissionAreaDistribution = distribution; + emissionAreaAngle = angle; + directionRelativeToEmissionCenter = directionRelativeToCenter; } -ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const +ParticleSystem::AreaSpreadDistribution ParticleSystem::getEmissionArea(love::Vector2 ¶ms, float &angle, bool &directionRelativeToCenter) const { - return areaSpreadDistribution; -} - -const love::Vector2 &ParticleSystem::getAreaSpreadParameters() const -{ - return areaSpread; -} - -void ParticleSystem::setAreaSpreadAngle(float angle) -{ - areaSpreadAngle = angle; -} - -float ParticleSystem::getAreaSpreadAngle() const -{ - return areaSpreadAngle; -} - -void ParticleSystem::setAreaSpreadIsRelativeDirection(bool isRelativeDirection) -{ - areaSpreadIsRelativeDirection = isRelativeDirection; -} - -bool ParticleSystem::getAreaSpreadIsRelativeDirection() const -{ - return areaSpreadIsRelativeDirection; + params = emissionArea; + angle = emissionAreaAngle; + directionRelativeToCenter = directionRelativeToEmissionCenter; + return emissionAreaDistribution; } void ParticleSystem::setDirection(float direction) diff --git a/src/modules/graphics/ParticleSystem.h b/src/modules/graphics/ParticleSystem.h index a80120620..ee069efe6 100644 --- a/src/modules/graphics/ParticleSystem.h +++ b/src/modules/graphics/ParticleSystem.h @@ -202,45 +202,19 @@ public: * * Normal: Parameters denote the standard deviation in x and y direction. x and y are assumed to be uncorrelated. * * borderellipse: Parameter causes particle distribution around outside of ellipse * * borderrectangle: Parameter causes particle distribution around outside of rectangle + * @param distribution Distribution type * @param x First parameter. Interpretation depends on distribution type. * @param y Second parameter. Interpretation depends on distribution type. - * @param distribution Distribution type + * @param angle The angle of the emission area (in radians). + * @param directionRelativeToCenter whether the initial direction of + * particles points away from the center of the emission area. **/ - void setAreaSpread(AreaSpreadDistribution distribution, float x, float y); - - /** - * Returns area spread distribution type. - **/ - AreaSpreadDistribution getAreaSpreadDistribution() const; + void setEmissionArea(AreaSpreadDistribution distribution, float x, float y, float angle, bool directionRelativeToCenter); /** * Returns area spread parameters. **/ - const love::Vector2 &getAreaSpreadParameters() const; - - /** - * Returns the angle of the area distribution (in radians). - **/ - float getAreaSpreadAngle() const; - - /** - * Sets the angle of the area distribution - * @param angle The angle (in radians). - **/ - void setAreaSpreadAngle(float angle); - - /** - * Returns true if particles spawn relative to the center of the - * shape area or false if they will use the setDirection parameter - **/ - bool getAreaSpreadIsRelativeDirection() const; - - /** - * Sets if particles starting direction is away from the center of the - * area spread or the setDirection parameter - * @param isRelativeDirection boolean use relative direction from center - **/ - void setAreaSpreadIsRelativeDirection(bool isRelativeDirection); + AreaSpreadDistribution getEmissionArea(love::Vector2 ¶ms, float &angle, bool &directionRelativeToCenter) const; /** * Sets the direction of the particle emitter. @@ -636,10 +610,10 @@ private: love::Vector2 prevPosition; // Emission area spread. - AreaSpreadDistribution areaSpreadDistribution; - love::Vector2 areaSpread; - float areaSpreadAngle; - bool areaSpreadIsRelativeDirection; + AreaSpreadDistribution emissionAreaDistribution; + love::Vector2 emissionArea; + float emissionAreaAngle; + bool directionRelativeToEmissionCenter; // The lifetime of the particle emitter (-1 means infinite) and the life it has left. float lifetime; diff --git a/src/modules/graphics/wrap_ParticleSystem.cpp b/src/modules/graphics/wrap_ParticleSystem.cpp index 73f313adf..8f9144dc2 100644 --- a/src/modules/graphics/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/wrap_ParticleSystem.cpp @@ -196,14 +196,16 @@ int w_ParticleSystem_moveTo(lua_State *L) return 0; } -int w_ParticleSystem_setAreaSpread(lua_State *L) +int w_ParticleSystem_setEmissionArea(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); ParticleSystem::AreaSpreadDistribution distribution = ParticleSystem::DISTRIBUTION_NONE; float x = 0.f, y = 0.f; + float angle = 0.0f; + bool directionRelativeToCenter = false; - const char *str = lua_isnoneornil(L, 2) ? 0 : luaL_checkstring(L, 2); + const char *str = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2); if (str && !ParticleSystem::getConstant(str, distribution)) return luax_enumerror(L, "particle distribution", ParticleSystem::getConstants(distribution), str); @@ -213,55 +215,32 @@ int w_ParticleSystem_setAreaSpread(lua_State *L) y = (float) luaL_checknumber(L, 4); if (x < 0.0f || y < 0.0f) return luaL_error(L, "Invalid area spread parameters (must be >= 0)"); + + angle = (float) luaL_optnumber(L, 5, 0.0f); + directionRelativeToCenter = luax_optboolean(L, 6, false); } - t->setAreaSpread(distribution, x, y); + t->setEmissionArea(distribution, x, y, angle, directionRelativeToCenter); return 0; } -int w_ParticleSystem_getAreaSpread(lua_State *L) +int w_ParticleSystem_getEmissionArea(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); - ParticleSystem::AreaSpreadDistribution distribution = t-> getAreaSpreadDistribution(); + love::Vector2 p; + float angle; + bool directionRelativeToCenter; + ParticleSystem::AreaSpreadDistribution distribution = t->getEmissionArea(p, angle, directionRelativeToCenter); const char *str; ParticleSystem::getConstant(distribution, str); - const love::Vector2 &p = t->getAreaSpreadParameters(); lua_pushstring(L, str); lua_pushnumber(L, p.x); lua_pushnumber(L, p.y); + lua_pushnumber(L, angle); + luax_pushboolean(L, directionRelativeToCenter); - return 3; -} - -int w_ParticleSystem_setAreaSpreadAngle(lua_State *L) -{ - ParticleSystem *t = luax_checkparticlesystem(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - t->setAreaSpreadAngle(arg1); - return 0; -} - -int w_ParticleSystem_getAreaSpreadAngle(lua_State *L) -{ - ParticleSystem *t = luax_checkparticlesystem(L, 1); - lua_pushnumber(L, t->getAreaSpreadAngle()); - return 1; -} - -int w_ParticleSystem_setAreaSpreadIsRelativeDirection(lua_State *L) -{ - ParticleSystem *t = luax_checkparticlesystem(L, 1); - bool arg1 = luax_checkboolean(L, 2); - t->setAreaSpreadIsRelativeDirection(arg1); - return 0; -} - -int w_ParticleSystem_getAreaSpreadIsRelativeDirection(lua_State *L) -{ - ParticleSystem *t = luax_checkparticlesystem(L, 1); - luax_pushboolean(L, t->getAreaSpreadIsRelativeDirection()); - return 1; + return 5; } int w_ParticleSystem_setDirection(lua_State *L) @@ -734,6 +713,52 @@ int w_ParticleSystem_update(lua_State *L) return 0; } +// Deprecated functions. + +int w_ParticleSystem_setAreaSpread(lua_State *L) +{ + luax_markdeprecated(L, "ParticleSystem:setAreaSpread", API_METHOD, DEPRECATED_REPLACED, "ParticleSystem:setEmissionArea"); + + ParticleSystem *t = luax_checkparticlesystem(L, 1); + + ParticleSystem::AreaSpreadDistribution distribution = ParticleSystem::DISTRIBUTION_NONE; + float x = 0.f, y = 0.f; + + const char *str = lua_isnoneornil(L, 2) ? 0 : luaL_checkstring(L, 2); + if (str && !ParticleSystem::getConstant(str, distribution)) + return luax_enumerror(L, "particle distribution", ParticleSystem::getConstants(distribution), str); + + if (distribution != ParticleSystem::DISTRIBUTION_NONE) + { + x = (float) luaL_checknumber(L, 3); + 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->setEmissionArea(distribution, x, y, 0.0f, false); + return 0; +} + +int w_ParticleSystem_getAreaSpread(lua_State *L) +{ + luax_markdeprecated(L, "ParticleSystem:getAreaSpread", API_METHOD, DEPRECATED_REPLACED, "ParticleSystem:getEmissionArea"); + + ParticleSystem *t = luax_checkparticlesystem(L, 1); + love::Vector2 p; + float angle; + bool unused; + ParticleSystem::AreaSpreadDistribution distribution = t->getEmissionArea(p, angle, unused); + const char *str; + ParticleSystem::getConstant(distribution, str); + + lua_pushstring(L, str); + lua_pushnumber(L, p.x); + lua_pushnumber(L, p.y); + + return 3; +} + static const luaL_Reg w_ParticleSystem_functions[] = { { "clone", w_ParticleSystem_clone }, @@ -752,12 +777,8 @@ static const luaL_Reg w_ParticleSystem_functions[] = { "setPosition", w_ParticleSystem_setPosition }, { "getPosition", w_ParticleSystem_getPosition }, { "moveTo", w_ParticleSystem_moveTo }, - { "setAreaSpread", w_ParticleSystem_setAreaSpread }, - { "getAreaSpread", w_ParticleSystem_getAreaSpread }, - { "setAreaSpreadAngle", w_ParticleSystem_setAreaSpreadAngle }, - { "getAreaSpreadAngle", w_ParticleSystem_getAreaSpreadAngle }, - { "setAreaSpreadIsRelativeDirection", w_ParticleSystem_setAreaSpreadIsRelativeDirection }, - { "getAreaSpreadIsRelativeDirection", w_ParticleSystem_getAreaSpreadIsRelativeDirection }, + { "setEmissionArea", w_ParticleSystem_setEmissionArea }, + { "getEmissionArea", w_ParticleSystem_getEmissionArea }, { "setDirection", w_ParticleSystem_setDirection }, { "getDirection", w_ParticleSystem_getDirection }, { "setSpread", w_ParticleSystem_setSpread }, @@ -800,6 +821,11 @@ static const luaL_Reg w_ParticleSystem_functions[] = { "isPaused", w_ParticleSystem_isPaused }, { "isStopped", w_ParticleSystem_isStopped }, { "update", w_ParticleSystem_update }, + + // Deprecated. + { "setAreaSpread", w_ParticleSystem_setAreaSpread }, + { "getAreaSpread", w_ParticleSystem_getAreaSpread }, + { 0, 0 } };