/* * Copyright (c) 2007-2008, openmetaverse.org * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the openmetaverse.org nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections.Generic; using System.ComponentModel; namespace OpenMetaverse { /// /// Particle system specific enumerators, flags and methods. /// public partial class Primitive { /// /// Complete structure for the particle system /// public struct ParticleSystem { /// /// Particle source pattern /// public enum SourcePattern : byte { /// None None = 0, /// Drop particles from source position with no force Drop = 0x01, /// "Explode" particles in all directions Explode = 0x02, /// Particles shoot across a 2D area Angle = 0x04, /// Particles shoot across a 3D Cone AngleCone = 0x08, /// Inverse of AngleCone (shoot particles everywhere except the 3D cone defined AngleConeEmpty = 0x10 } /// /// Particle Data Flags /// [Flags] public enum ParticleDataFlags : uint { /// None None = 0, /// Interpolate color and alpha from start to end InterpColor = 0x001, /// Interpolate scale from start to end InterpScale = 0x002, /// Bounce particles off particle sources Z height Bounce = 0x004, /// velocity of particles is dampened toward the simulators wind Wind = 0x008, /// Particles follow the source FollowSrc = 0x010, /// Particles point towards the direction of source's velocity FollowVelocity = 0x020, /// Target of the particles TargetPos = 0x040, /// Particles are sent in a straight line TargetLinear = 0x080, /// Particles emit a glow Emissive = 0x100, /// used for point/grab/touch Beam = 0x200 } /// /// Particle Flags Enum /// [Flags] public enum ParticleFlags : uint { /// None None = 0, /// Acceleration and velocity for particles are /// relative to the object rotation ObjectRelative = 0x01, /// Particles use new 'correct' angle parameters UseNewAngle = 0x02 } public uint CRC; /// Particle Flags /// There appears to be more data packed in to this area /// for many particle systems. It doesn't appear to be flag values /// and serialization breaks unless there is a flag for every /// possible bit so it is left as an unsigned integer public uint PartFlags; /// pattern of particles public SourcePattern Pattern; /// A representing the maximimum age (in seconds) particle will be displayed /// Maximum value is 30 seconds public float MaxAge; /// A representing the number of seconds, /// from when the particle source comes into view, /// or the particle system's creation, that the object will emits particles; /// after this time period no more particles are emitted public float StartAge; /// A in radians that specifies where particles will not be created public float InnerAngle; /// A in radians that specifies where particles will be created public float OuterAngle; /// A representing the number of seconds between burts. public float BurstRate; /// A representing the number of meters /// around the center of the source where particles will be created. public float BurstRadius; /// A representing in seconds, the minimum speed between bursts of new particles /// being emitted public float BurstSpeedMin; /// A representing in seconds the maximum speed of new particles being emitted. public float BurstSpeedMax; /// A representing the maximum number of particles emitted per burst public byte BurstPartCount; /// A which represents the velocity (speed) from the source which particles are emitted public Vector3 AngularVelocity; /// A which represents the Acceleration from the source which particles are emitted public Vector3 PartAcceleration; /// The Key of the texture displayed on the particle public UUID Texture; /// The Key of the specified target object or avatar particles will follow public UUID Target; /// Flags of particle from public ParticleDataFlags PartDataFlags; /// Max Age particle system will emit particles for public float PartMaxAge; /// The the particle has at the beginning of its lifecycle public Color4 PartStartColor; /// The the particle has at the ending of its lifecycle public Color4 PartEndColor; /// A that represents the starting X size of the particle /// Minimum value is 0, maximum value is 4 public float PartStartScaleX; /// A that represents the starting Y size of the particle /// Minimum value is 0, maximum value is 4 public float PartStartScaleY; /// A that represents the ending X size of the particle /// Minimum value is 0, maximum value is 4 public float PartEndScaleX; /// A that represents the ending Y size of the particle /// Minimum value is 0, maximum value is 4 public float PartEndScaleY; /// /// Decodes a byte[] array into a ParticleSystem Object /// /// ParticleSystem object /// Start position for BitPacker public ParticleSystem(byte[] data, int pos) { // TODO: Not sure exactly how many bytes we need here, so partial // (truncated) data will cause an exception to be thrown if (data.Length > 0) { BitPack pack = new BitPack(data, pos); CRC = pack.UnpackUBits(32); PartFlags = pack.UnpackUBits(32); Pattern = (SourcePattern)pack.UnpackByte(); MaxAge = pack.UnpackFixed(false, 8, 8); StartAge = pack.UnpackFixed(false, 8, 8); InnerAngle = pack.UnpackFixed(false, 3, 5); OuterAngle = pack.UnpackFixed(false, 3, 5); BurstRate = pack.UnpackFixed(false, 8, 8); BurstRadius = pack.UnpackFixed(false, 8, 8); BurstSpeedMin = pack.UnpackFixed(false, 8, 8); BurstSpeedMax = pack.UnpackFixed(false, 8, 8); BurstPartCount = pack.UnpackByte(); float x = pack.UnpackFixed(true, 8, 7); float y = pack.UnpackFixed(true, 8, 7); float z = pack.UnpackFixed(true, 8, 7); AngularVelocity = new Vector3(x, y, z); x = pack.UnpackFixed(true, 8, 7); y = pack.UnpackFixed(true, 8, 7); z = pack.UnpackFixed(true, 8, 7); PartAcceleration = new Vector3(x, y, z); Texture = pack.UnpackUUID(); Target = pack.UnpackUUID(); PartDataFlags = (ParticleDataFlags)pack.UnpackUBits(32); PartMaxAge = pack.UnpackFixed(false, 8, 8); byte r = pack.UnpackByte(); byte g = pack.UnpackByte(); byte b = pack.UnpackByte(); byte a = pack.UnpackByte(); PartStartColor = new Color4(r, g, b, a); r = pack.UnpackByte(); g = pack.UnpackByte(); b = pack.UnpackByte(); a = pack.UnpackByte(); PartEndColor = new Color4(r, g, b, a); PartStartScaleX = pack.UnpackFixed(false, 3, 5); PartStartScaleY = pack.UnpackFixed(false, 3, 5); PartEndScaleX = pack.UnpackFixed(false, 3, 5); PartEndScaleY = pack.UnpackFixed(false, 3, 5); } else { CRC = PartFlags = 0; Pattern = SourcePattern.None; MaxAge = StartAge = InnerAngle = OuterAngle = BurstRate = BurstRadius = BurstSpeedMin = BurstSpeedMax = 0.0f; BurstPartCount = 0; AngularVelocity = PartAcceleration = Vector3.Zero; Texture = Target = UUID.Zero; PartDataFlags = ParticleDataFlags.None; PartMaxAge = 0.0f; PartStartColor = PartEndColor = Color4.Black; PartStartScaleX = PartStartScaleY = PartEndScaleX = PartEndScaleY = 0.0f; } } /// /// Generate byte[] array from particle data /// /// Byte array public byte[] GetBytes() { byte[] bytes = new byte[86]; BitPack pack = new BitPack(bytes, 0); pack.PackBits(CRC, 32); pack.PackBits((uint)PartFlags, 32); pack.PackBits((uint)Pattern, 8); pack.PackFixed(MaxAge, false, 8, 8); pack.PackFixed(StartAge, false, 8, 8); pack.PackFixed(InnerAngle, false, 3, 5); pack.PackFixed(OuterAngle, false, 3, 5); pack.PackFixed(BurstRate, false, 8, 8); pack.PackFixed(BurstRadius, false, 8, 8); pack.PackFixed(BurstSpeedMin, false, 8, 8); pack.PackFixed(BurstSpeedMax, false, 8, 8); pack.PackBits(BurstPartCount, 8); pack.PackFixed(AngularVelocity.X, true, 8, 7); pack.PackFixed(AngularVelocity.Y, true, 8, 7); pack.PackFixed(AngularVelocity.Z, true, 8, 7); pack.PackFixed(PartAcceleration.X, true, 8, 7); pack.PackFixed(PartAcceleration.Y, true, 8, 7); pack.PackFixed(PartAcceleration.Z, true, 8, 7); pack.PackUUID(Texture); pack.PackUUID(Target); pack.PackBits((uint)PartDataFlags, 32); pack.PackFixed(PartMaxAge, false, 8, 8); pack.PackColor(PartStartColor); pack.PackColor(PartEndColor); pack.PackFixed(PartStartScaleX, false, 3, 5); pack.PackFixed(PartStartScaleY, false, 3, 5); pack.PackFixed(PartEndScaleX, false, 3, 5); pack.PackFixed(PartEndScaleY, false, 3, 5); return bytes; } } } }