using System; using System.Collections.Generic; using System.ComponentModel; namespace libsecondlife { /// /// 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 at 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 sourc 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; /// Maximimum age (in seconds) particle will be displayed (max 30 seconds) public float MaxAge; /// 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; /// Area in radians that specify where particles will not be created public float InnerAngle; /// Area in radians that will be filled with particles public float OuterAngle; /// How often particle burts will occur in seconds public float BurstRate; /// Number of meters from center of sourcewhere particles are created public float BurstRadius; /// Minimum speed of particle creation public float BurstSpeedMin; /// Maximum speed of particle creation public float BurstSpeedMax; /// How many particles are generated per burst public byte BurstPartCount; /// X/Y/Z Velocity in which particles are emitted public LLVector3 AngularVelocity; /// X/Y/Z Acceleration in which particles are emitted public LLVector3 PartAcceleration; /// Key of texture used in particle public LLUUID Texture; /// Key of target public LLUUID Target; /// Flags of particle from public ParticleDataFlags PartDataFlags; /// Max Age particle system will emit particles for public float PartMaxAge; /// Starting color of particles public LLColor PartStartColor; /// Ending color of particles public LLColor PartEndColor; /// Starting X size of particle (Min 0, Max 4) public float PartStartScaleX; /// Starting Y size of particle (Min 0, Max 4) public float PartStartScaleY; /// Ending X size of particle (Min 0, Max 4) public float PartEndScaleX; /// Ending Y size of particle (Min 0, Max 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 LLVector3(x, y, z); x = pack.UnpackFixed(true, 8, 7); y = pack.UnpackFixed(true, 8, 7); z = pack.UnpackFixed(true, 8, 7); PartAcceleration = new LLVector3(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 LLColor(r, g, b, a); r = pack.UnpackByte(); g = pack.UnpackByte(); b = pack.UnpackByte(); a = pack.UnpackByte(); PartEndColor = new LLColor(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 = LLVector3.Zero; Texture = Target = LLUUID.Zero; PartDataFlags = ParticleDataFlags.None; PartMaxAge = 0.0f; PartStartColor = PartEndColor = LLColor.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(MaxAge, 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; } } } }