/*
* SprayEmitter.cs
* Authors: Brian Murphy
* Copyright (c) 2007-2008 Cornell University
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 (at your option) 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Random=Util.Random;
namespace TACParticleEngine.Emitters
{
///
/// This class is an emitter that causes a "spray" effect within a box of specified height and width
///
public class SprayEmitter : Emitter
{
#region Fields
// Temporary vector for determining where a particle moves in two-dimensions
private Vector3 mTempVel;
// Temporary vector for determining where a particle spawns in two-dimensions
private Vector3 mTempPos;
// Temporary int used for storing how many particles were created every cycle
private int mTempAmount;
// Temporary integer for use in iterating over the particle heap
private int mTempIndex;
// Current index of the next available spot in the head for adding a particle to
private int mCurrentIndex;
// Float used for determining
private float mTotalElapsedTime;
#endregion
#region Form Fields
// Current position of the emitter
private Vector3 mEmitterPosition;
// Direction for particles to move in.
// *Note* if given with values < -1 or > 1, will just move randomly
private Vector3 mDirection;
// The box dimensions for determining where a particle spawns
// *Note* each dimension value implies -/+ the value with 0 as the origin
private Vector3 mSprayRange;
#endregion
#region Form Properties
///
/// Gets/Sets the current position of the emitter
///
public override Vector3 EmitterPosition {
get { return mEmitterPosition; }
set { mEmitterPosition = value; }
}
///
/// Gets/Sets the direction of the emitter
/// *Note* if given with values less than -1 or greater than 1, will just move randomly
///
public override Vector3 Direction {
get { return mDirection; }
set { mDirection = value; }
}
///
/// Gets/Sets the box dimensions for determining where a particle spawns
/// *Note* each dimension value implies -/+ the value with 0 as the origin
///
public Vector3 SprayRange
{
get { return mSprayRange; }
set { mSprayRange = value; }
}
#endregion
#region Creation
///
/// Default constructor for use in the Particle Editor
///
public SprayEmitter()
: base(SpriteBlendMode.AlphaBlend, "", 100, 1000, -1, 1, Vector2.One, Vector2.One, Vector2.One,
new Vector2(500,500), 0, 0, 0, 0, Vector4.One, Vector4.One, Vector4.Zero, Vector4.Zero)
{
mCurrentIndex = 0;
mEmitterPosition = Vector3.Zero;
mTotalElapsedTime = 0;
mSprayRange = Vector3.Zero;
mDirection = Vector3.Zero;
}
///
/// Constructor
///
/// Initial position to start at
/// Box range for point spraying
/// Direction for the particles to move in.
/// SpriteBlendMode to use
/// Name of the texture to draw with
/// How many particles per second are made
/// The max amount of particles available at one time
/// How long the emitter stays active for
/// How long the patrticle stays active for
/// How small a particle can start
/// How large a particle can start
/// How small a particle can end
/// How large a particle can end
/// How slow a particle can start
/// How fast a particle can start
/// How slow a particle can end
/// How fast a particle can end
/// Minimum values for color to start with
/// Maximum values for color to start with
/// Minimum values for color to end with
/// Maximum values for color to end with
public SprayEmitter(Vector3 position, Vector3 sprayRange, Vector3 direction, SpriteBlendMode blendEffect,
string textureName, float particlesPerSec, int particleAmount, float emitLifetime, float particleLifetime,
Vector2 minStartSize, Vector2 maxStartSize, Vector2 minEndSize, Vector2 maxEndSize,
float minStartSpeed, float maxStartSpeed, float minEndSpeed, float maxEndSpeed,
Vector4 minStartColor, Vector4 maxStartColor, Vector4 minEndColor, Vector4 maxEndColor)
: base(blendEffect, textureName, particlesPerSec, particleAmount, emitLifetime,
particleLifetime, minStartSize, maxStartSize, minEndSize, maxEndSize, minStartSpeed,
maxStartSpeed, minEndSpeed, maxEndSpeed, minStartColor, maxStartColor, minEndColor, maxEndColor)
{
mCurrentIndex = 0;
mEmitterPosition = position;
mTotalElapsedTime = 0;
mSprayRange = sprayRange;
mDirection = direction;
}
///
/// Returns a copy of the spray emitter
///
/// A cloned copy of this spray emitter
public override object Clone()
{
SprayEmitter retVal = new SprayEmitter(mEmitterPosition, mSprayRange, mDirection, base.mBlendEffect, base.mTextureName,
base.mParticlesPerSec, base.mParticleAmount, base.mEmitLifetime, base.mParticleLifetime, base.mMinStartSize,
base.mMaxStartSize, base.mMinEndSize, base.mMaxEndSize, base.mMinStartSpeed, base.mMaxStartSpeed,
base.mMinEndSpeed, base.mMaxEndSpeed, base.mMinStartColor, base.mMaxStartColor, base.mMinEndColor,
base.mMaxEndColor);
retVal.mTexture = mTexture;
return retVal;
}
#endregion
#region Update
///
/// Updates point emitter
///
/// The time elapsed since last tick in milliseconds
public override void Update(float elapsedTime)
{
if (base.mParticles != null)
{
base.Update(elapsedTime);
if (base.Alive && base.IsActive)
{
mTotalElapsedTime += elapsedTime;
mTempAmount = (int)(mTotalElapsedTime * base.mParticlesPerSec);
if (mTempAmount > 0)
{
mTempIndex = (mCurrentIndex + mTempAmount) % base.mParticles.Length;
if (mCurrentIndex + mTempAmount < base.mParticles.Length)
{
for (; mCurrentIndex < mTempIndex; mCurrentIndex++)
{
CalcPosition();
calcDirection();
base.InitializeParticle(mTempPos, mTempVel, mCurrentIndex);
}
}
else
{
for (; mCurrentIndex < base.mParticles.Length; mCurrentIndex++)
{
CalcPosition();
calcDirection();
base.InitializeParticle(mTempPos, mTempVel, mCurrentIndex);
}
mCurrentIndex = 0;
for (; mCurrentIndex < mTempIndex; mCurrentIndex++)
{
CalcPosition();
calcDirection();
base.InitializeParticle(mTempPos, mTempVel, mCurrentIndex);
}
}
mTotalElapsedTime = 0;
}
}
}
}
#endregion
#region Util
///
/// Determines a random position for the next particle to start at
///
private void CalcPosition()
{
mTempPos = mEmitterPosition + Random.RandomVector3(-mSprayRange, mSprayRange);
}
///
/// Determines a random direction for the next particle to go in
///
private void calcDirection()
{
if (mRandomDir || mDirection.X < -1 || mDirection.X > 1 || mDirection.Y < -1 || mDirection.Y > 1 || mDirection.Z < -1 || mDirection.Z > 1)
{
double tempXRot = Random.NextFloat(MathHelper.TwoPi);
double tempYRot = Random.NextFloat(MathHelper.TwoPi);
mTempVel.X = (float)Math.Cos(tempYRot);
mTempVel.Y = (float)Math.Sin(tempXRot);
mTempVel.Z = (float)(Math.Sqrt(Math.Pow(Math.Sin(tempYRot), 2.0) + Math.Pow(Math.Cos(tempXRot), 2.0)));
}
else
{
mTempVel = mDirection;
}
}
#endregion
}
}