/// <summary>
 ///     Applies this modifiers effect to the given particle node.
 /// </summary>
 /// <param name="node">Node to apply effect to.</param>
 /// <param name="deltaTime">Time elapsed since last frame.</param>
 public abstract void Apply(ParticleNode node, float deltaTime);
 /// <summary>
 ///     Gets or sets if this modifier is active on the give node.
 /// </summary>
 /// <param name="node">Node to check activity against.</param>
 protected bool Active(ParticleNode node)
 {
     float percent = (100.0f / (float)node.LifeTime) * (float)node.ExpiredLife;
     return (percent >= _effectDuration.Start && percent <= _effectDuration.Finish);
 }
        /// <summary>
        ///     Applies this modifiers effect to the given particle node.
        /// </summary>
        /// <param name="node">Node to apply effect to.</param>
        /// <param name="deltaTime">Time elapsed since last frame.</param>
        public override void Apply(ParticleNode node, float deltaTime)
        {
            // Check that we are active on this particle.
            if (Active(node) == false) return;

            // Couple of useful variables.
            float onePercent = (100.0f / (float)node.LifeTime);
            float duration = (_effectDuration.Finish - _effectDuration.Start);
            float expired = (onePercent * (float)node.ExpiredLife) - _effectDuration.Start;

            // Color the particle
            int rRand = _colorTintRedRandom.Minimum + (int)((_colorTintRedRandom.Maximum - _colorTintRedRandom.Minimum) * node.RandomNumbers[2]);
            int gRand = _colorTintGreenRandom.Minimum + (int)((_colorTintGreenRandom.Maximum - _colorTintGreenRandom.Minimum) * node.RandomNumbers[3]);
            int bRand = _colorTintBlueRandom.Minimum + (int)((_colorTintBlueRandom.Maximum - _colorTintBlueRandom.Minimum) * node.RandomNumbers[4]);
            int aRand = _colorTintAlphaRandom.Minimum + (int)((_colorTintAlphaRandom.Maximum - _colorTintAlphaRandom.Minimum) * node.RandomNumbers[5]);
            int r = (int)(_colorTint.Start.R + (((_colorTint.Finish.R - _colorTint.Start.R) / duration) * expired));
            int g = (int)(_colorTint.Start.G + (((_colorTint.Finish.G - _colorTint.Start.G) / duration) * expired));
            int b = (int)(_colorTint.Start.B + (((_colorTint.Finish.B - _colorTint.Start.B) / duration) * expired));
            int a = (int)(_colorTint.StartAlpha + (((_colorTint.FinishAlpha - _colorTint.StartAlpha) / duration) * expired));
            node.Color = ColorMethods.CombineColor(ColorFormats.A8R8G8B8, MathMethods.Restrict(r + rRand, 0, 255), MathMethods.Restrict(g + gRand, 0, 255), MathMethods.Restrict(b + bRand, 0, 255), MathMethods.Restrict(a + aRand, 0, 255));
        }
        /// <summary>
        ///     Applies this modifiers effect to the given particle node.
        /// </summary>
        /// <param name="node">Node to apply effect to.</param>
        /// <param name="deltaTime">Time elapsed since last frame.</param>
        public override void Apply(ParticleNode node, float deltaTime)
        {
            // Check that we are active on this particle.
            if (Active(node) == false) return;

            // Couple of useful variables.
            float onePercent = (100.0f / (float)node.LifeTime);
            float duration = (_effectDuration.Finish - _effectDuration.Start);
            float expired = (onePercent * (float)node.ExpiredLife) - _effectDuration.Start;

            if (_animationMode == AnimationModifierMode.Loop)
                node.Frame = _frames.Start + ((((int)expired) / _frameDelay) % (_frames.Finish - _frames.Start));
            else if (_animationMode == AnimationModifierMode.OneShot)
                node.Frame = _frames.Start + (int)(((_frames.Finish - _frames.Start) / duration) * expired);
        }
        /// <summary>
        ///     Applies this modifiers effect to the given particle node.
        /// </summary>
        /// <param name="node">Node to apply effect to.</param>
        /// <param name="deltaTime">Time elapsed since last frame.</param>
        public override void Apply(ParticleNode node, float deltaTime)
        {
            // Check that we are active on this particle.
            if (Active(node) == false) return;

            // Couple of useful variables.
            float onePercent = (100.0f / (float)node.LifeTime);
            float duration = (_effectDuration.Finish - _effectDuration.Start);
            float expired = (onePercent * (float)node.ExpiredLife) - _effectDuration.Start;
            float xRand = _xAccelerationRandom.Minimum + ((_xAccelerationRandom.Maximum - _xAccelerationRandom.Minimum) * node.RandomNumbers[0]);
            float yRand = _yAccelerationRandom.Minimum + ((_yAccelerationRandom.Maximum - _yAccelerationRandom.Minimum) * node.RandomNumbers[1]);

            // Move the particle.
            float accX = (float)(_xAcceleration.Start + (((_xAcceleration.Finish - _xAcceleration.Start) / duration) * expired));
            float accY = (float)(_yAcceleration.Start + (((_yAcceleration.Finish - _yAcceleration.Start) / duration) * expired));
            node.Move((accX + xRand) * deltaTime, (accY + yRand) * deltaTime, 0);
        }
        /// <summary>
        ///     Causes this particle type to update itself.
        /// </summary>
        /// <param name="deltaTime">Time elapsed since last frame.</param>
        public void Think(float deltaTime)
        {
            // Find any new dead particles.
            ArrayList removeList = new ArrayList();
            foreach (ParticleNode particle in _particles)
            {
                if (particle.IsDead == true)
                {
                    particle.IsVisible = false;
                    _deadParticles.Add(particle);
                    _emitter.Particles.Remove(particle);
                    removeList.Add(particle);
                }
            }
            foreach (ParticleNode particle in removeList)
                _particles.Remove(particle);

            // Remove dead particles from particle list.
            if (_deadCleanUpTimer.DurationMillisecond > 500)
            {
                _deadCleanUpTimer.Restart();
                _deadParticles.Clear();
            }

            // Create any new particles that need to be created.
            if (_emitTimer.DurationMillisecond > _cycleEmitRate && (_cycleCount < _maximumCycles || _maximumCycles == 0))
            {
                _cycleEmitRate = MathMethods.Random(_emitRate.Minimum, _emitRate.Maximum);
                _emitTimer.Restart();

                int emitCount = MathMethods.Random(_emitCount.Minimum, _emitCount.Maximum);
                for (int particleNumber = 0; particleNumber < emitCount; particleNumber++)
                {
                    ParticleNode particle = null;

                    // Recycle dead particle if we can.
                    if (_deadParticles.Count > 0)
                    {
                        particle = (ParticleNode)_deadParticles[0];
                        _deadParticles.Remove(particle);
                        particle.Reset();
                    }

                    // Create a new particle as we can't recycle.
                    if (particle == null)
                        particle = new ParticleNode();

                    // Position it according to emit shape.
                    float x = _emitter.Transformation.X;
                    float y = _emitter.Transformation.Y;
                    if (_emitShape == EmitShape.Circle)
                    {
                        float angle = MathMethods.Random(0, 360);
                        x += ((float)Math.Sin(angle) * MathMethods.Random(0, _emitter.BoundingRectangle.Width / 2)) + (_emitter.BoundingRectangle.Width / 2);
                        y += ((float)Math.Cos(angle) * MathMethods.Random(0, _emitter.BoundingRectangle.Height / 2)) + (_emitter.BoundingRectangle.Height / 2);
                    }
                    else if (_emitShape == EmitShape.Rectangle)
                    {
                        x += MathMethods.Random(0, _emitter.BoundingRectangle.Width);
                        y += MathMethods.Random(0, _emitter.BoundingRectangle.Height);
                    }

                    // Setup some basic settings.
                    particle.IsVisible = _emitter.IsVisible;
                    particle.LifeTime = MathMethods.Random(_particleLifeTimeRandom.Minimum, _particleLifeTimeRandom.Maximum);
                    particle.Position(x, y, _emitter.Transformation.Z);

                    // Add particle to lists.
                    _particles.Add(particle);
                    _emitter.Particles.Add(particle);
                }

                _cycleCount++;
            }

            // Apply modifiers to all alive particles.
            foreach (ParticleModifier modifier in _modifiers)
                foreach (ParticleNode particle in _particles)
                    modifier.Apply(particle, deltaTime);
        }
        /// <summary>
        ///     Applies this modifiers effect to the given particle node.
        /// </summary>
        /// <param name="node">Node to apply effect to.</param>
        /// <param name="deltaTime">Time elapsed since last frame.</param>
        public override void Apply(ParticleNode node, float deltaTime)
        {
            // Check that we are active on this particle.
            if (Active(node) == false) return;

            // Properties, properties :D.
            node.Image = _image;
            node.RenderMode = _renderMode;
            node.BlendMode = _blendMode;
            node.Text = _text;
            node.Font = _font;
            node.IsSolid = _isVisible;
            node.IsVisible = _isEnabled;
            node.Shader = _shader;
        }