summaryrefslogtreecommitdiff
path: root/src/particle/particle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/particle/particle.cpp')
-rw-r--r--src/particle/particle.cpp590
1 files changed, 0 insertions, 590 deletions
diff --git a/src/particle/particle.cpp b/src/particle/particle.cpp
deleted file mode 100644
index 40b1b7a5a..000000000
--- a/src/particle/particle.cpp
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * The ManaPlus Client
- * Copyright (C) 2006-2009 The Mana World Development Team
- * Copyright (C) 2009-2010 The Mana Developers
- * Copyright (C) 2011-2017 The ManaPlus Developers
- *
- * This file is part of The ManaPlus Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "particle/particle.h"
-
-#include "actormanager.h"
-#include "logger.h"
-
-#include "being/actorsprite.h"
-
-#include "particle/animationparticle.h"
-#include "particle/particleemitter.h"
-#include "particle/rotationalparticle.h"
-
-#include "resources/animation/simpleanimation.h"
-
-#include "resources/dye/dye.h"
-
-#include "resources/image/image.h"
-
-#include "resources/loaders/imageloader.h"
-#include "resources/loaders/xmlloader.h"
-
-#include "utils/delete2.h"
-#include "utils/dtor.h"
-#include "utils/foreach.h"
-#include "utils/likely.h"
-#include "utils/mathutils.h"
-#include "utils/mrand.h"
-
-#include "debug.h"
-
-static const float SIN45 = 0.707106781F;
-static const double PI = M_PI;
-static const float PI2 = 2 * M_PI;
-
-class Graphics;
-
-Particle::Particle() :
- Actor(),
- mAlpha(1.0F),
- mLifetimeLeft(-1),
- mLifetimePast(0),
- mFadeOut(0),
- mFadeIn(0),
- mVelocity(),
- mAlive(AliveStatus::ALIVE),
- mType(ParticleType::Normal),
- mAnimation(nullptr),
- mImage(nullptr),
- mActor(BeingId_zero),
- mChildEmitters(),
- mChildParticles(),
- mChildMoveParticles(),
- mDeathEffect(),
- mGravity(0.0F),
- mBounce(0.0F),
- mAcceleration(0.0F),
- mInvDieDistance(-1.0F),
- mMomentum(1.0F),
- mTarget(nullptr),
- mRandomness(0),
- mDeathEffectConditions(0x00),
- mAutoDelete(true),
- mAllowSizeAdjust(false),
- mFollow(false)
-{
- ParticleEngine::particleCount++;
-}
-
-Particle::~Particle()
-{
- if (mActor != BeingId_zero &&
- (actorManager != nullptr))
- {
- ActorSprite *const actor = actorManager->findActor(mActor);
- if (actor != nullptr)
- actor->controlParticleDeleted(this);
- }
- // Delete child emitters and child particles
- clear();
- delete2(mAnimation);
- if (mImage != nullptr)
- {
- if (mType == ParticleType::Image)
- {
- const std::string &restrict name = mImage->mIdPath;
- StringIntMapIter it
- = ImageParticle::imageParticleCountByName.find(name);
- if (it != ImageParticle::imageParticleCountByName.end())
- {
- int &cnt = (*it).second;
- if (cnt > 0)
- cnt --;
- }
- mImage->decRef();
- }
- mImage = nullptr;
- }
-
- ParticleEngine::particleCount--;
-}
-
-void Particle::draw(Graphics *restrict const graphics A_UNUSED,
- const int offsetX A_UNUSED,
- const int offsetY A_UNUSED) const restrict2
-{
-}
-
-void Particle::updateSelf() restrict2
-{
- // calculate particle movement
- if (A_LIKELY(mMomentum != 1.0F))
- mVelocity *= mMomentum;
-
- if ((mTarget != nullptr) && mAcceleration != 0.0F)
- {
- Vector dist = mPos - mTarget->mPos;
- dist.x *= SIN45;
- float invHypotenuse;
-
- switch (ParticleEngine::fastPhysics)
- {
- case ParticlePhysics::Normal:
- invHypotenuse = fastInvSqrt(
- dist.x * dist.x + dist.y * dist.y + dist.z * dist.z);
- break;
- case ParticlePhysics::Fast:
- if (dist.x == 0.0f)
- {
- invHypotenuse = 0;
- break;
- }
-
- invHypotenuse = 2.0F / (static_cast<float>(fabs(dist.x))
- + static_cast<float>(fabs(dist.y))
- + static_cast<float>(fabs(dist.z)));
- break;
- case ParticlePhysics::Best:
- default:
- invHypotenuse = 1.0F / static_cast<float>(sqrt(
- dist.x * dist.x + dist.y * dist.y + dist.z * dist.z));
- break;
- }
-
- if (invHypotenuse != 0.0f)
- {
- if (mInvDieDistance > 0.0F && invHypotenuse > mInvDieDistance)
- mAlive = AliveStatus::DEAD_IMPACT;
- const float accFactor = invHypotenuse * mAcceleration;
- mVelocity -= dist * accFactor;
- }
- }
-
- if (A_LIKELY(mRandomness >= 10)) // reduce useless calculations
- {
- const int rand2 = mRandomness * 2;
- mVelocity.x += static_cast<float>(mrand() % rand2 - mRandomness)
- / 1000.0F;
- mVelocity.y += static_cast<float>(mrand() % rand2 - mRandomness)
- / 1000.0F;
- mVelocity.z += static_cast<float>(mrand() % rand2 - mRandomness)
- / 1000.0F;
- }
-
- mVelocity.z -= mGravity;
-
- // Update position
- mPos.x += mVelocity.x;
- mPos.y += mVelocity.y * SIN45;
- mPos.z += mVelocity.z * SIN45;
-
- // Update other stuff
- if (A_LIKELY(mLifetimeLeft > 0))
- mLifetimeLeft--;
-
- mLifetimePast++;
-
- if (mPos.z < 0.0F)
- {
- if (mBounce > 0.0F)
- {
- mPos.z *= -mBounce;
- mVelocity *= mBounce;
- mVelocity.z = -mVelocity.z;
- }
- else
- {
- mAlive = AliveStatus::DEAD_FLOOR;
- }
- }
- else if (mPos.z > ParticleEngine::PARTICLE_SKY)
- {
- mAlive = AliveStatus::DEAD_SKY;
- }
-
- // Update child emitters
- if ((ParticleEngine::emitterSkip != 0) &&
- (mLifetimePast - 1) % ParticleEngine::emitterSkip == 0)
- {
- FOR_EACH (EmitterConstIterator, e, mChildEmitters)
- {
- STD_VECTOR<Particle*> newParticles;
- (*e)->createParticles(mLifetimePast, newParticles);
- FOR_EACH (STD_VECTOR<Particle*>::const_iterator,
- it,
- newParticles)
- {
- Particle *const p = *it;
- p->moveBy(mPos);
- mChildParticles.push_back(p);
- if (p->mFollow)
- mChildMoveParticles.push_back(p);
- }
- }
- }
-
- // create death effect when the particle died
- if (A_UNLIKELY(mAlive != AliveStatus::ALIVE &&
- mAlive != AliveStatus::DEAD_LONG_AGO))
- {
- if ((CAST_U32(mAlive) & mDeathEffectConditions)
- > 0x00 && !mDeathEffect.empty())
- {
- Particle *restrict const deathEffect = particleEngine->addEffect(
- mDeathEffect, 0, 0);
- if (deathEffect != nullptr)
- deathEffect->moveBy(mPos);
- }
- mAlive = AliveStatus::DEAD_LONG_AGO;
- }
-}
-
-bool Particle::update() restrict2
-{
- if (A_LIKELY(mAlive == AliveStatus::ALIVE))
- {
- if (A_UNLIKELY(mLifetimeLeft == 0))
- {
- mAlive = AliveStatus::DEAD_TIMEOUT;
- if (mChildParticles.empty())
- {
- if (mAutoDelete)
- return false;
- return true;
- }
- }
- else
- {
- if (mAnimation != nullptr)
- {
- if (mType == ParticleType::Animation)
- {
- // particle engine is updated every 10ms
- mAnimation->update(10);
- }
- else // ParticleType::Rotational
- {
- // TODO: cache velocities to avoid spamming atan2()
- const int size = mAnimation->getLength();
- if (size == 0)
- return false;
-
- float rad = static_cast<float>(atan2(mVelocity.x,
- mVelocity.y));
- if (rad < 0)
- rad = PI2 + rad;
-
- const float range = static_cast<float>(PI / size);
-
- // Determines which frame the particle should play
- if (A_UNLIKELY(rad < range || rad > PI2 - range))
- {
- mAnimation->setFrame(0);
- }
- else
- {
- const float range2 = 2 * range;
- // +++ need move condition outside of for
- for (int c = 1; c < size; c++)
- {
- const float cRange = static_cast<float>(c) *
- range2;
- if (cRange - range < rad &&
- rad < cRange + range)
- {
- mAnimation->setFrame(c);
- break;
- }
- }
- }
- }
- mImage = mAnimation->getCurrentImage();
- }
- const Vector oldPos = mPos;
-
- updateSelf();
-
- const Vector change = mPos - oldPos;
- if (mChildParticles.empty())
- {
- if (mAlive != AliveStatus::ALIVE &&
- mAutoDelete)
- {
- return false;
- }
- return true;
- }
- for (ParticleIterator p = mChildMoveParticles.begin(),
- fp2 = mChildMoveParticles.end(); p != fp2; )
- {
- // move particle with its parent if desired
- (*p)->moveBy(change);
- ++p;
- }
- }
-
- // Update child particles
- for (ParticleIterator p = mChildParticles.begin(),
- fp2 = mChildParticles.end(); p != fp2; )
- {
- Particle *restrict const particle = *p;
- // update particle
- if (A_LIKELY(particle->update()))
- {
- ++p;
- }
- else
- {
- mChildMoveParticles.remove(*p);
- delete particle;
- p = mChildParticles.erase(p);
- }
- }
- if (A_UNLIKELY(mAlive != AliveStatus::ALIVE &&
- mChildParticles.empty() &&
- mAutoDelete))
- {
- return false;
- }
- }
- else
- {
- if (mChildParticles.empty())
- {
- if (mAutoDelete)
- return false;
- return true;
- }
- // Update child particles
- for (ParticleIterator p = mChildParticles.begin(),
- fp2 = mChildParticles.end(); p != fp2; )
- {
- Particle *restrict const particle = *p;
- // update particle
- if (A_LIKELY(particle->update()))
- {
- ++p;
- }
- else
- {
- mChildMoveParticles.remove(*p);
- delete particle;
- p = mChildParticles.erase(p);
- }
- }
- if (A_UNLIKELY(mChildParticles.empty() &&
- mAutoDelete))
- {
- return false;
- }
- }
-
- return true;
-}
-
-void Particle::moveBy(const Vector &restrict change) restrict2
-{
- mPos += change;
- FOR_EACH (ParticleConstIterator, p, mChildMoveParticles)
- {
- (*p)->moveBy(change);
- }
-}
-
-void Particle::moveTo(const float x, const float y) restrict2
-{
- moveTo(Vector(x, y, mPos.z));
-}
-
-Particle *Particle::addEffect(const std::string &restrict particleEffectFile,
- const int pixelX, const int pixelY,
- const int rotation) restrict2
-{
- Particle *newParticle = nullptr;
-
- const size_t pos = particleEffectFile.find('|');
- const std::string dyePalettes = (pos != std::string::npos)
- ? particleEffectFile.substr(pos + 1) : "";
- XML::Document *doc = Loader::getXml(particleEffectFile.substr(0, pos),
- UseVirtFs_true,
- SkipError_false);
- if (doc == nullptr)
- return nullptr;
- XmlNodeConstPtrConst rootNode = doc->rootNode();
-
- if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "effect"))
- {
- logger->log("Error loading particle: %s", particleEffectFile.c_str());
- doc->decRef();
- return nullptr;
- }
-
- // Parse particles
- for_each_xml_child_node(effectChildNode, rootNode)
- {
- // We're only interested in particles
- if (!xmlNameEqual(effectChildNode, "particle"))
- continue;
-
- // Determine the exact particle type
- XmlNodePtr node;
-
- // Animation
- if ((node = XML::findFirstChildByName(effectChildNode, "animation")) !=
- nullptr)
- {
- newParticle = new AnimationParticle(node, dyePalettes);
- newParticle->setMap(mMap);
- }
- // Rotational
- else if ((node = XML::findFirstChildByName(
- effectChildNode, "rotation")) != nullptr)
- {
- newParticle = new RotationalParticle(node, dyePalettes);
- newParticle->setMap(mMap);
- }
- // Image
- else if ((node = XML::findFirstChildByName(effectChildNode,
- "image")) != nullptr)
- {
- std::string imageSrc;
- if (XmlHaveChildContent(node))
- imageSrc = XmlChildContent(node);
- if (!imageSrc.empty() && !dyePalettes.empty())
- Dye::instantiate(imageSrc, dyePalettes);
- Image *const img = Loader::getImage(imageSrc);
-
- newParticle = new ImageParticle(img);
- newParticle->setMap(mMap);
- }
- // Other
- else
- {
- newParticle = new Particle;
- newParticle->setMap(mMap);
- }
-
- // Read and set the basic properties of the particle
- const float offsetX = XML::getFloatProperty(
- effectChildNode, "position-x", 0);
- const float offsetY = XML::getFloatProperty(
- effectChildNode, "position-y", 0);
- const float offsetZ = XML::getFloatProperty(
- effectChildNode, "position-z", 0);
- const Vector position(mPos.x + static_cast<float>(pixelX) + offsetX,
- mPos.y + static_cast<float>(pixelY) + offsetY,
- mPos.z + offsetZ);
- newParticle->moveTo(position);
-
- const int lifetime = XML::getProperty(effectChildNode, "lifetime", -1);
- newParticle->setLifetime(lifetime);
- const bool resizeable = "false" != XML::getProperty(effectChildNode,
- "size-adjustable", "false");
-
- newParticle->setAllowSizeAdjust(resizeable);
-
- // Look for additional emitters for this particle
- for_each_xml_child_node(emitterNode, effectChildNode)
- {
- if (xmlNameEqual(emitterNode, "emitter"))
- {
- ParticleEmitter *restrict const newEmitter =
- new ParticleEmitter(
- emitterNode,
- newParticle,
- mMap,
- rotation,
- dyePalettes);
- newParticle->addEmitter(newEmitter);
- }
- else if (xmlNameEqual(emitterNode, "deatheffect"))
- {
- std::string deathEffect;
- if ((node != nullptr) && XmlHaveChildContent(node))
- deathEffect = XmlChildContent(emitterNode);
-
- char deathEffectConditions = 0x00;
- if (XML::getBoolProperty(emitterNode, "on-floor", true))
- {
- deathEffectConditions += CAST_S8(
- AliveStatus::DEAD_FLOOR);
- }
- if (XML::getBoolProperty(emitterNode, "on-sky", true))
- {
- deathEffectConditions += CAST_S8(
- AliveStatus::DEAD_SKY);
- }
- if (XML::getBoolProperty(emitterNode, "on-other", false))
- {
- deathEffectConditions += CAST_S8(
- AliveStatus::DEAD_OTHER);
- }
- if (XML::getBoolProperty(emitterNode, "on-impact", true))
- {
- deathEffectConditions += CAST_S8(
- AliveStatus::DEAD_IMPACT);
- }
- if (XML::getBoolProperty(emitterNode, "on-timeout", true))
- {
- deathEffectConditions += CAST_S8(
- AliveStatus::DEAD_TIMEOUT);
- }
- newParticle->setDeathEffect(
- deathEffect, deathEffectConditions);
- }
- }
-
- mChildParticles.push_back(newParticle);
- }
-
- doc->decRef();
- return newParticle;
-}
-
-void Particle::adjustEmitterSize(const int w, const int h) restrict2
-{
- if (mAllowSizeAdjust)
- {
- FOR_EACH (EmitterConstIterator, e, mChildEmitters)
- (*e)->adjustSize(w, h);
- }
-}
-
-void Particle::prepareToDie() restrict2
-{
- FOR_EACH (ParticleIterator, p, mChildParticles)
- {
- Particle *restrict const particle = *p;
- if (particle == nullptr)
- continue;
- particle->prepareToDie();
- if (particle->isAlive() &&
- particle->mLifetimeLeft == -1 &&
- particle->mAutoDelete)
- {
- particle->kill();
- }
- }
-}
-
-void Particle::clear() restrict2
-{
- delete_all(mChildEmitters);
- mChildEmitters.clear();
-
- delete_all(mChildParticles);
- mChildParticles.clear();
-
- mChildMoveParticles.clear();
-}