public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Color4) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var colField = pool.GetField(ParticleFields.Color4);
            var rndField = pool.GetField(ParticleFields.RandomSeed);
            
            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var color = Color4.Lerp(ColorMin, ColorMax, randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset));

                // Premultiply alpha
                // This can't be done in advance for ColorMin and ColorMax because it will change the math
                color.R *= color.A;
                color.G *= color.A;
                color.B *= color.A;

                (*((Color4*)particle[colField])) = color;

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 2
0
        public void AddEmitter(ParticleEmitter emitter)
        {
            emitters.Add(emitter);

            ParticlePool pool = new ParticlePool(this, maxParticlesPerEmitter);
            CollectionUtils.Put(particlesByEmitter, emitter, pool);
        }
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Order))
                return;

            var orderField = pool.GetField(ParticleFields.Order);
            var childOrderField = pool.GetField(ParticleFields.ChildOrder);

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);

                (*((uint*)particle[orderField])) = spawnOrder++; // Will loop every so often, but the loop condition should be unreachable for normal games

                if (childOrderField.IsValid())
                    (*((uint*)particle[childOrderField])) = 0;

                i = (i + 1) % maxCapacity;
            }

            // Increase the group by one
            spawnOrder = (spawnOrder >> SpawnOrderConst.GroupBitOffset);
            spawnOrder++;
            spawnOrder = (spawnOrder << SpawnOrderConst.GroupBitOffset);
        }
Esempio n. 4
0
 public ParticleFactory(int limit, int particlePerCreate, IParticleSetting setting, params TextureRegion[] regions)
 {
     this.pool = new ParticlePool(regions);
     particles = new List<Particle>();
     this.limit = limit;
     this.particlePerCreate = particlePerCreate;
     if (setting == null)
     {
         throw new Exception("setting must be not null");
     }
     particleSetting = setting;
 }
        /// <inheritdoc />
        public override void Update(float dt, ParticlePool pool)
        {
            if (!pool.FieldExists(ParticleFields.Angle) || !pool.FieldExists(ParticleFields.Life))
                return;

            if (SamplerOptional == null)
            {
                UpdateSingleSampler(pool);
                return;
            }

            UpdateDoubleSampler(pool);
        }
Esempio n. 6
0
        /// <summary>
        /// Updates the field by sampling a single value over the particle's lifetime
        /// </summary>
        /// <param name="pool">Target <see cref="ParticlePool"/></param>
        private unsafe void UpdateSingleSampler(ParticlePool pool)
        {
            var sizeField = pool.GetField(ParticleFields.Size);
            var lifeField = pool.GetField(ParticleFields.Life);

            SamplerMain.UpdateChanges();

            foreach (var particle in pool)
            {
                var life = 1f - (*((float*)particle[lifeField]));   // The Life field contains remaining life, so for sampling we take (1 - life)

                (*((float*)particle[sizeField])) = WorldScale.X * SamplerMain.Evaluate(life);
            }
        }
Esempio n. 7
0
        static void Main(string[] args)
        {
            ParticlePool particlePool = new ParticlePool();

            particlePool.Create(5,1,3,2,1);
            particlePool.Create(5,1,3,2,6);
            particlePool.Create(5,1,3,2,2);

            particlePool.Animate();
            particlePool.Animate();
            particlePool.Animate();
            particlePool.Animate();

            Console.ReadLine();

            // (I didn't test it with the ParticlePoolWithFreeList ...)
        }
        public override unsafe void Update(float dt, ParticlePool pool)
        {
            if (dt <= MathUtil.ZeroTolerance)
                return;

            if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.OldPosition) || !pool.FieldExists(ParticleFields.Direction))
                return;

            var posField = pool.GetField(ParticleFields.Position);
            var oldField = pool.GetField(ParticleFields.OldPosition);
            var dirField = pool.GetField(ParticleFields.Direction);

            foreach (var particle in pool)
            {
                (*((Vector3*)particle[dirField])) = ((*((Vector3*)particle[posField])) - (*((Vector3*)particle[oldField]))) / dt;
            }
        }
        public override unsafe void Update(float dt, ParticlePool pool)
        {
            if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.Velocity))
                return;

            var posField = pool.GetField(ParticleFields.Position);
            var velField = pool.GetField(ParticleFields.Velocity);

            var deltaVel = GravitationalAcceleration * dt;
            var deltaPos = deltaVel * (dt * 0.5f);

            foreach (var particle in pool)
            {
                (*((Vector3*)particle[posField])) += deltaPos;
                (*((Vector3*)particle[velField])) += deltaVel;
            }
        }
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Angle) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var rotField = pool.GetField(ParticleFields.Angle);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                (*((float*)particle[rotField])) = angularRotationStart + angularRotationStep * randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                i = (i + 1) % maxCapacity;
            }
        }
        public override unsafe void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.Velocity) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var posField = pool.GetField(ParticleFields.Position);
            var velField = pool.GetField(ParticleFields.Velocity);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var range = (float)(Angle * Math.PI / 180f);
            var magnitude = WorldScale.X;

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var x = (randSeed.GetFloat(RandomOffset.Offset2A + SeedOffset) - 0.5f) * range;
                var z = (randSeed.GetFloat(RandomOffset.Offset2B + SeedOffset) - 0.5f) * range;

                var u = (randSeed.GetFloat(RandomOffset.Offset2A + SeedOffset) - 0.5f) * range;
                var v = (randSeed.GetFloat(RandomOffset.Offset2B + SeedOffset) - 0.5f) * Math.PI;

                //                var particleRandPos = new Vector3(x, 1, z);

                var xz = (float)Math.Sin(u);
                var particleRandPos = new Vector3((float)Math.Cos(v) * xz, (float)Math.Sqrt(1 - u * u), (float)Math.Sin(v) * xz);
                particleRandPos.Normalize();


                particleRandPos *= magnitude;
                WorldRotation.Rotate(ref particleRandPos);

                (*((Vector3*)particle[posField])) = particleRandPos + WorldPosition;

                (*((Vector3*)particle[velField])) = particleRandPos * Strength;

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Updates the field by sampling a single value over the particle's lifetime
        /// </summary>
        /// <param name="pool">Target <see cref="ParticlePool"/></param>
        private unsafe void UpdateSingleSampler(ParticlePool pool)
        {
            var colorField = pool.GetField(ParticleFields.Color);
            var lifeField  = pool.GetField(ParticleFields.Life);

            SamplerMain.UpdateChanges();

            foreach (var particle in pool)
            {
                var life = 1f - (*((float*)particle[lifeField]));   // The Life field contains remaining life, so for sampling we take (1 - life)

                var color = SamplerMain.Evaluate(life);

                // Premultiply alpha
                color.R *= color.A;
                color.G *= color.A;
                color.B *= color.A;

                (*((Color4*)particle[colorField])) = color;
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Updates the field by interpolating between two sampled values over the particle's lifetime
        /// </summary>
        /// <param name="pool">Target <see cref="ParticlePool"/></param>
        private unsafe void UpdateDoubleSampler(ParticlePool pool)
        {
            var sizeField = pool.GetField(ParticleFields.Size);
            var lifeField = pool.GetField(ParticleFields.Life);
            var randField = pool.GetField(ParticleFields.RandomSeed);

            SamplerMain.UpdateChanges();
            SamplerOptional.UpdateChanges();

            foreach (var particle in pool)
            {
                var life = 1f - (*((float *)particle[lifeField]));   // The Life field contains remaining life, so for sampling we take (1 - life)

                var randSeed = particle.Get(randField);
                var lerp     = randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                var size1 = SamplerMain.Evaluate(life);
                var size2 = SamplerOptional.Evaluate(life);

                (*((float *)particle[sizeField])) = WorldScale.X * (size1 + (size2 - size1) * lerp);
            }
        }
Esempio n. 14
0
 public void ReleaseAll(ParticleEmitter emitter)
 {
     if (particlesByEmitter.Count != 0)
     {
         IEnumerator <ParticlePool> it = particlesByEmitter.Values.GetEnumerator();
         while (it.MoveNext())
         {
             ParticlePool pool = it.Current;
             for (int i = 0; i < pool.particles.Length; i++)
             {
                 if (pool.particles[i].InUse())
                 {
                     if (pool.particles[i].GetEmitter() == emitter)
                     {
                         pool.particles[i].SetLife(-1);
                         Release(pool.particles[i]);
                     }
                 }
             }
         }
     }
 }
Esempio n. 15
0
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Angle) || !pool.FieldExists(ParticleFields.RandomSeed))
            {
                return;
            }

            var rotField = pool.GetField(ParticleFields.Angle);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var i = startIdx;

            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                (*((float *)particle[rotField])) = angularRotationStart + angularRotationStep * randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 16
0
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Size) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var sizeField = pool.GetField(ParticleFields.Size);
            var rndField = pool.GetField(ParticleFields.RandomSeed);
            
            var minSize = WorldScale.X * RandomSize.X;
            var sizeGap = WorldScale.X * RandomSize.Y - minSize;

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                (*((float*)particle[sizeField])) = minSize + sizeGap * randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 17
0
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Color4) || !pool.FieldExists(ParticleFields.RandomSeed))
            {
                return;
            }

            var colField = pool.GetField(ParticleFields.Color4);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var i = startIdx;

            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                (*((Color4 *)particle[colField])) = Color4.Lerp(ColorMin, ColorMax, randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset));

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 18
0
        /**
         * Init pool
         */
        private void initPool(ParticlePool particle)
        {
            //check there was no same name for particle
            if (m_ParticleDictionary.ContainsKey(particle.name))
            {
                Debug.LogWarning("A particle with name '" + particle.name + "' has already been added");
            }
            else
            {
                //add to dictionary
                m_ParticleDictionary.Add(particle.name, particle);

                //initialize the GameObjects for pooling later
                List <ParticleClip> list = new List <ParticleClip>();
                for (int i = 0; i < particle.poolNum; i++)
                {
                    SpawnForPool(particle.particlePrefab, list);
                }

                //add to particle pool
                m_ParticlePool.Add(particle.name, list);
            }
        }
Esempio n. 19
0
        /// <summary>
        /// Updates the field by sampling a single value over the particle's lifetime
        /// </summary>
        /// <param name="pool">Target <see cref="ParticlePool"/></param>
        private unsafe void UpdateSingleSampler(ParticlePool pool)
        {
            var sizeField = pool.GetField(ParticleFields.Size);
            var lifeField = pool.GetField(ParticleFields.Life);

            int count = pool.NextFreeIndex;

            for (int i = 0; i < count; i++)
            {
                Particle particle = pool.FromIndex(i);

                var life = 1f - (*((float *)particle[lifeField]));   // The Life field contains remaining life, so for sampling we take (1 - life)

                if (pool.SpecificSizes != null)
                {
                    (*((float *)particle[sizeField])) = WorldScale.X * SamplerMain.Evaluate(life) * pool.SpecificSizes[i];
                }
                else
                {
                    (*((float *)particle[sizeField])) = WorldScale.X * SamplerMain.Evaluate(life);
                }
            }
        }
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Direction) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var dirField = pool.GetField(ParticleFields.Direction);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var leftCorner = DirectionMin * WorldScale;
            var xAxis = new Vector3(DirectionMax.X * WorldScale.X - leftCorner.X, 0, 0);
            var yAxis = new Vector3(0, DirectionMax.Y * WorldScale.Y - leftCorner.Y, 0);
            var zAxis = new Vector3(0, 0, DirectionMax.Z * WorldScale.Z - leftCorner.Z);

            if (!WorldRotation.IsIdentity)
            {
                WorldRotation.Rotate(ref leftCorner);
                WorldRotation.Rotate(ref xAxis);
                WorldRotation.Rotate(ref yAxis);
                WorldRotation.Rotate(ref zAxis);
            }

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var particleRandDir = leftCorner;
                particleRandDir += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                particleRandDir += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                particleRandDir += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                (*((Vector3*)particle[dirField])) = particleRandDir;

                i = (i + 1) % maxCapacity;
            }
        }
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Quaternion) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var rotField = pool.GetField(ParticleFields.Quaternion);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var randomRotation = Quaternion.Slerp(RotationQuaternionMin, RotationQuaternionMax, randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset));
                
                // Results in errors ("small" quaternion) when interpolation -90 to +90 degree rotations, so we have to normalize it
                randomRotation.Normalize();
            
                (*((Quaternion*)particle[rotField])) = randomRotation * WorldRotation;

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 22
0
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Order))
            {
                return;
            }

            // Collect the total number of living particles in the parent pool which have a Order field
            var parentPool           = Parent?.Pool;
            var parentParticlesCount = parentPool?.LivingParticles ?? 0;
            var orderFieldParent     = parentPool?.GetField(ParticleFields.Order) ?? ParticleFieldAccessor <uint> .Invalid();

            var childOrderFieldParent = parentPool?.GetField(ParticleFields.ChildOrder) ?? ParticleFieldAccessor <uint> .Invalid();

            if (!orderFieldParent.IsValid())
            {
                parentParticlesCount = 0;
            }

            var spawnControlField = GetSpawnControlField();

            var orderField  = pool.GetField(ParticleFields.Order);
            var randomField = pool.GetField(ParticleFields.RandomSeed);

            var sequentialParentIndex     = 0;
            var sequentialParentParticles = 0;
            var parentIndex = 0;

            var i = startIdx;

            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);

                // Will loop every so often, but the loop condition should be unreachable for normal games
                uint particleOrder = spawnOrder++;

                if (parentParticlesCount > 0)
                {
                    uint parentParticleOrder = 0;

                    // Spawn is fixed - parent particles have spawned a very specific number of children each
                    if (spawnControlField.IsValid())
                    {
                        while (sequentialParentParticles == 0)
                        {
                            // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally
                            if (sequentialParentIndex >= parentParticlesCount)
                            {
                                return;
                            }

                            parentIndex = sequentialParentIndex;
                            var tempParentParticle = parentPool.FromIndex(parentIndex);
                            sequentialParentIndex++;

                            var childrenAttribute = (*((ParticleChildrenAttribute *)tempParentParticle[spawnControlField]));

                            sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit;
                        }

                        sequentialParentParticles--;

                        var parentParticle = parentPool.FromIndex(parentIndex);
                        parentParticleOrder = (*((uint *)parentParticle[orderFieldParent]));

                        if (childOrderFieldParent.IsValid())
                        {
                            particleOrder = (*((uint *)parentParticle[childOrderFieldParent]));
                            (*((uint *)parentParticle[childOrderFieldParent])) = (particleOrder + 1);

                            particleOrder = (particleOrder & 0x0000FFFF) | ((parentParticleOrder << 16) & 0xFFFF0000);
                        }
                        else
                        {
                            particleOrder = (particleOrder & 0x000FFFFF) | ((parentParticleOrder << 20) & 0xFFF00000);
                        }
                    }

                    // Spawn is not fixed - pick a parent at random
                    else
                    {
                        var randSeed = particle.Get(randomField);

                        parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset));

                        var parentParticle = parentPool.FromIndex(parentIndex);
                        parentParticleOrder = (*((uint *)parentParticle[orderFieldParent]));

                        if (childOrderFieldParent.IsValid())
                        {
                            particleOrder = (*((uint *)parentParticle[childOrderFieldParent]));
                            (*((uint *)parentParticle[childOrderFieldParent])) = (particleOrder + 1);

                            particleOrder = (particleOrder & 0x0000FFFF) | ((parentParticleOrder << 16) & 0xFFFF0000);
                        }
                        else
                        {
                            particleOrder = (particleOrder & 0x000FFFFF) | ((parentParticleOrder << 20) & 0xFFF00000);
                        }
                    }
                }

                (*((uint *)particle[orderField])) = particleOrder;

                i = (i + 1) % maxCapacity;
            }
        }
 void Start()
 {
     // 0 = Normal crate
     // 1 = TNT crate
     particlePool = new ParticlePool(effects[0], effects[1], 5);
 }
Esempio n. 24
0
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed))
            {
                return;
            }

            var posField = pool.GetField(ParticleFields.Position);
            var oldField = pool.GetField(ParticleFields.OldPosition);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var leftCorner = PositionMin * WorldScale;
            var xAxis      = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0);
            var yAxis      = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0);
            var zAxis      = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z);

            if (!WorldRotation.IsIdentity)
            {
                WorldRotation.Rotate(ref leftCorner);
                WorldRotation.Rotate(ref xAxis);
                WorldRotation.Rotate(ref yAxis);
                WorldRotation.Rotate(ref zAxis);
            }

            leftCorner += WorldPosition;

            var i = startIdx;

            if (Interpolate)
            {
                // Interpolate positions between the old and the new one

                var positionDistance = (hasBegun) ? oldPosition - WorldPosition : Vector3.Zero;
                oldPosition = WorldPosition;
                hasBegun    = true;

                var totalCountLessOne = (startIdx < endIdx) ? (endIdx - startIdx - 1) : (endIdx - startIdx + maxCapacity - 1);
                var stepF             = (totalCountLessOne > 1) ? (1f / totalCountLessOne) : 1f;
                var step = 0f;

                while (i != endIdx)
                {
                    var particle = pool.FromIndex(i);
                    var randSeed = particle.Get(rndField);

                    var particleRandPos = leftCorner;

                    particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                    particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                    particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                    particleRandPos += positionDistance * step;
                    step            += stepF;

                    (*((Vector3 *)particle[posField])) = particleRandPos;

                    if (oldField.IsValid())
                    {
                        (*((Vector3 *)particle[oldField])) = particleRandPos;
                    }

                    i = (i + 1) % maxCapacity;
                }
            }
            else
            {
                // Do not interpolate position
                while (i != endIdx)
                {
                    var particle = pool.FromIndex(i);
                    var randSeed = particle.Get(rndField);

                    var particleRandPos = leftCorner;

                    particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                    particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                    particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                    (*((Vector3 *)particle[posField])) = particleRandPos;

                    if (oldField.IsValid())
                    {
                        (*((Vector3 *)particle[oldField])) = particleRandPos;
                    }

                    i = (i + 1) % maxCapacity;
                }
            }
        }
Esempio n. 25
0
 public ParticleSorterDefault(ParticlePool pool)
 {
     ParticlePool = pool;
 }
Esempio n. 26
0
        public unsafe void ParticleGetSet(ParticlePool.ListPolicy policy)
        {
            const int maxParticles = 10;
            var pool = new ParticlePool(0, maxParticles, policy);

            // Spawn all particles
            for (var i = 0; i < maxParticles; i++)
            {
                pool.AddParticle();
            }

            const bool forceCreation = true;
            pool.FieldExists(ParticleFields.Position, forceCreation);
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation);
            pool.FieldExists(ParticleFields.Velocity, forceCreation);
            pool.FieldExists(ParticleFields.Size, forceCreation);

            var positionField = pool.GetField(ParticleFields.Position);
            var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
            var velocityField = pool.GetField(ParticleFields.Velocity);
            var sizeField     = pool.GetField(ParticleFields.Size);

            var vectorToSet = new Vector3(0, 0, 0);
            var scalarToSet = 0f;

            foreach (var particle in pool)
            {
                vectorToSet.Y = scalarToSet;

                *((Vector3*)particle[positionField]) = vectorToSet;

                *((float*)particle[lifetimeField])   = scalarToSet;

                *((Vector3*)particle[velocityField]) = vectorToSet;

                *((float*)particle[sizeField])       = scalarToSet;

                scalarToSet++;
            }

            // Assert the values are the same
            scalarToSet = 0f;
            foreach (var particle in pool)
            {
                Assert.That(*((Vector3*)particle[positionField]), Is.EqualTo(new Vector3(0, scalarToSet, 0)));

                Assert.That(*((float*)particle[lifetimeField]), Is.EqualTo(scalarToSet));

                Assert.That(*((Vector3*)particle[velocityField]), Is.EqualTo(new Vector3(0, scalarToSet, 0)));

                Assert.That(*((float*)particle[sizeField]), Is.EqualTo(scalarToSet));

                scalarToSet++;
            }

            // "Update" the values with delta time
            var dt = 0.033333f;
            foreach (var particle in pool)
            {
                var pos = ((Vector3*)particle[positionField]);
                var vel = ((Vector3*)particle[velocityField]);

                *pos += *vel * dt;

                *((float*)particle[lifetimeField]) += 1;
            }

            scalarToSet = 0f;
            foreach (var particle in pool)
            {
                Assert.That(*((Vector3*)particle[positionField]), Is.EqualTo(new Vector3(0, scalarToSet, 0) + *((Vector3*)particle[velocityField]) * dt));

                Assert.That(*((float*)particle[lifetimeField]), Is.EqualTo(scalarToSet + 1));

                scalarToSet++;
            }

        }
Esempio n. 27
0
 public void SetPool(ParticlePool p)
 {
     pool = p;
 }
Esempio n. 28
0
        /// <summary>
        /// The Update(...) step is called every frame for the particle pool, containing all particles
        /// Since this is a post-updater the Update(...) step is called *after* new particles have spawned for this frame
        /// Regular updaters are invoked *before* spawning new particles and avoid updating the particles on the frame they spawn
        /// </summary>
        public override void Update(float dt, ParticlePool pool)
        {
            // Make sure the fields we require exist, otherwise trying to access them will result in an invalid memory
            // The particle pool can check if the accessor is valid on each access, but that would be very inefficient so it skips the check
            if (!pool.FieldExists(ParticleFields.Life) || !pool.FieldExists(CustomParticleFields.RectangleXY))
            {
                return;
            }

            var lifeField = pool.GetField(ParticleFields.Life);
            var rectField = pool.GetField(CustomParticleFields.RectangleXY);

            // Instead of switching for each particle, we switch only once and then batch-update the particles to improve performance
            switch (Curve)
            {
            // X and Y sides both depend on cos(time)
            case AnimatedCurveEnum.CosCos:
            {
                foreach (var particle in pool)
                {
                    // Get the particle's remaining life. It's normalized between 0 and 1
                    var lifePi = particle.Get(lifeField) * MathUtil.Pi;

                    // Set the rectangle as a simple function over time
                    particle.Set(rectField, new Vector2((float)Math.Cos(lifePi), (float)Math.Cos(lifePi)));
                }
            }
            break;


            // X and Y sides both depend on sin(time)
            case AnimatedCurveEnum.SinSin:
            {
                foreach (var particle in pool)
                {
                    // Get the particle's remaining life. It's normalized between 0 and 1
                    var lifePi = particle.Get(lifeField) * MathUtil.Pi;

                    // Set the rectangle as a simple function over time
                    particle.Set(rectField, new Vector2((float)Math.Sin(lifePi), (float)Math.Sin(lifePi)));
                }
            }
            break;


            // X and Y sides depend on cos(time) and sin(time)
            case AnimatedCurveEnum.CosSin:
            {
                foreach (var particle in pool)
                {
                    // Get the particle's remaining life. It's normalized between 0 and 1
                    var lifePi = particle.Get(lifeField) * MathUtil.Pi;

                    // Set the rectangle as a simple function over time
                    particle.Set(rectField, new Vector2((float)Math.Cos(lifePi), (float)Math.Sin(lifePi)));
                }
            }
            break;


            // X and Y sides depend on sin(time) and cos(time)
            case AnimatedCurveEnum.SinCos:
            {
                foreach (var particle in pool)
                {
                    // Get the particle's remaining life. It's normalized between 0 and 1
                    var lifePi = particle.Get(lifeField) * MathUtil.Pi;

                    // Set the rectangle as a simple function over time
                    particle.Set(rectField, new Vector2((float)Math.Sin(lifePi), (float)Math.Cos(lifePi)));
                }
            }
            break;
            }
        }
Esempio n. 29
0
 public void SetPool(ParticlePool p)
 {
     pool = p;
 }
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            // Collect the total number of living particles in the parent pool which have a Position field
            var parentPool = Parent?.Pool;
            var parentParticlesCount = parentPool?.LivingParticles ?? 0;
            var posFieldParent = parentPool?.GetField(ParticleFields.Position) ?? ParticleFieldAccessor<Vector3>.Invalid();
            if (!posFieldParent.IsValid())
            {
                parentParticlesCount = 0;
            }

            var oldPosFieldParent = parentPool?.GetField(ParticleFields.OldPosition) ?? ParticleFieldAccessor<Vector3>.Invalid();

            var spawnControlField = GetSpawnControlField();

            var posField = pool.GetField(ParticleFields.Position);
            var rndField = pool.GetField(ParticleFields.RandomSeed);
            var oldField = pool.GetField(ParticleFields.OldPosition);

            var leftCorner = PositionMin * WorldScale;
            var xAxis = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0);
            var yAxis = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0);
            var zAxis = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z);

            if (!WorldRotation.IsIdentity)
            {
                WorldRotation.Rotate(ref leftCorner);
                WorldRotation.Rotate(ref xAxis);
                WorldRotation.Rotate(ref yAxis);
                WorldRotation.Rotate(ref zAxis);
            }

            // Already inheriting from parent
            if (parentParticlesCount == 0)
                leftCorner += WorldPosition;

            var sequentialParentIndex = 0;
            var sequentialParentParticles = 0;
            var parentIndex = 0;

            // Interpolation - if parent particle has OldPosition field
            var stepF = 0f;
            var stepTotal = 0f;
            var positionDistance = new Vector3(0, 0, 0);

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var particleRandPos = leftCorner;

                particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                if (parentParticlesCount > 0)
                {
                    var parentParticlePosition = new Vector3(0, 0, 0);

                    // Spawn is fixed - parent particles have spawned a very specific number of children each
                    if (spawnControlField.IsValid())
                    {
                        // Interpolation - if parent particle has OldPosition field

                        while (sequentialParentParticles == 0)
                        {
                            // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally
                            if (sequentialParentIndex >= parentParticlesCount)
                                return;

                            parentIndex = sequentialParentIndex;
                            var tempParentParticle = parentPool.FromIndex(parentIndex);
                            sequentialParentIndex++;

                            var childrenAttribute = (*((ParticleChildrenAttribute*)tempParentParticle[spawnControlField]));

                            sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit;

                            if (oldPosFieldParent.IsValid())
                            {
                                stepF = (sequentialParentParticles > 0) ? (1f/(float)sequentialParentParticles) : 1;
                                stepTotal = 0f;
                                positionDistance = ((*((Vector3*)tempParentParticle[oldPosFieldParent])) - (*((Vector3*)tempParentParticle[posFieldParent])));
                            }
                        }

                        sequentialParentParticles--;

                        var parentParticle = parentPool.FromIndex(parentIndex);
                        parentParticlePosition = (*((Vector3*)parentParticle[posFieldParent]));
                        parentParticlePosition += positionDistance * stepTotal;
                        stepTotal += stepF;
                    }

                    // Spawn is not fixed - pick a parent at random
                    else
                    {
                        parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset));
                        var parentParticle = parentPool.FromIndex(parentIndex);

                        parentParticlePosition = (*((Vector3*)parentParticle[posFieldParent]));
                    }


                    // Convert from Local -> World space if needed
                    if (Parent.SimulationSpace == EmitterSimulationSpace.Local)
                    {
                        WorldRotation.Rotate(ref parentParticlePosition);
                        parentParticlePosition *= WorldScale.X;
                        parentParticlePosition += WorldPosition;
                    }

                    particleRandPos += parentParticlePosition;
                }


                (*((Vector3*)particle[posField])) = particleRandPos;

                if (oldField.IsValid())
                {
                    (*((Vector3*)particle[oldField])) = particleRandPos;
                }

                i = (i + 1) % maxCapacity;
            }
        }
        /// <summary>
        /// Updates the field by sampling a single value over the particle's lifetime
        /// </summary>
        /// <param name="pool">Target <see cref="ParticlePool"/></param>
        private unsafe void UpdateSingleSampler(ParticlePool pool)
        {
            var angleField = pool.GetField(ParticleFields.Angle);
            var lifeField = pool.GetField(ParticleFields.Life);

            foreach (var particle in pool)
            {
                var life = 1f - (*((float*)particle[lifeField]));   // The Life field contains remaining life, so for sampling we take (1 - life)

                (*((float*)particle[angleField])) = MathUtil.DegreesToRadians(SamplerMain.Evaluate(life));
            }
        }
        // TODO This will have to change at some point when we have better idea of how customizable the fields will be.
        //  Ideally no field should get initialized twice

        public unsafe void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            // Position - defaults to World position of the emitter
            var posField = pool.GetField(ParticleFields.Position);
            if (posField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3*)particle[posField])) = WorldPosition;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Old position - defaults to World position of the emitter
            var oldPosField = pool.GetField(ParticleFields.OldPosition);
            if (oldPosField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3*)particle[oldPosField])) = WorldPosition;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Direction - defaults to (0, 0, 0)
            var dirField = pool.GetField(ParticleFields.Direction);
            if (dirField.IsValid())
            {
                var zeroDirection = new Vector3(0, 0, 0);
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3*)particle[dirField])) = zeroDirection;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Quaternion rotation - defaults to World rotation of the emitter
            var quatField = pool.GetField(ParticleFields.Quaternion);
            if (quatField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Quaternion*)particle[quatField])) = WorldRotation;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Angular rotation - defaults to 0
            var rotField = pool.GetField(ParticleFields.Rotation);
            if (rotField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((float*)particle[rotField])) = 0;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Velocity - defaults to (0, 0, 0)
            var velField = pool.GetField(ParticleFields.Velocity);
            if (velField.IsValid())
            {
                var zeroVelocity = new Vector3(0, 0, 0);
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3*)particle[velField])) = zeroVelocity;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Size - defaults to the world scale of the emitter
            var sizeField = pool.GetField(ParticleFields.Size);
            if (sizeField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((float*)particle[sizeField])) = WorldScale;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Velocity - defaults to (0, 0, 0)
            var colField = pool.GetField(ParticleFields.Color);
            if (colField.IsValid())
            {
                var whiteColor = new Color4(1,1,1,1);
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Color4*)particle[colField])) = whiteColor;
                    i = (i + 1) % maxCapacity;
                }
            }

            // ChildrenFlags fields
            for (int j = 0; j < ParticleFields.ChildrenFlags.Length; j++)
            {
                var flagField = pool.GetField(ParticleFields.ChildrenFlags[j]);
                if (flagField.IsValid())
                {
                    for (var i = startIdx; i != endIdx;)
                    {
                        var particle = pool.FromIndex(i);
                        (*((uint*)particle[flagField])) = 0;
                        i = (i + 1) % maxCapacity;
                    }
                }

            }
        }
        /// <summary>
        /// Updates the field by interpolating between two sampled values over the particle's lifetime
        /// </summary>
        /// <param name="pool">Target <see cref="ParticlePool"/></param>
        private unsafe void UpdateDoubleSampler(ParticlePool pool)
        {
            var angleField = pool.GetField(ParticleFields.Angle);
            var lifeField = pool.GetField(ParticleFields.Life);
            var randField = pool.GetField(ParticleFields.RandomSeed);

            foreach (var particle in pool)
            {
                var life = 1f - (*((float*)particle[lifeField]));   // The Life field contains remaining life, so for sampling we take (1 - life)

                var randSeed = particle.Get(randField);
                var lerp = randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                var angle1 = SamplerMain.Evaluate(life);
                var angle2 = SamplerOptional.Evaluate(life);

                (*((float*)particle[angleField])) = MathUtil.DegreesToRadians(angle1 + (angle2 - angle1) * lerp);
            }
        }
Esempio n. 34
0
 public ParticleSorterDefault(ParticlePool pool) : base(pool) 
 {           
 }
Esempio n. 35
0
 public ParticleSorterLiving(ParticlePool pool) : base(pool)
 {
     particleList = new SortedParticle[pool.ParticleCapacity];
     currentLivingParticles = 0;
 }
Esempio n. 36
0
 /// <summary>
 /// Updates all particles in the <see cref="ParticlePool"/> using this updater
 /// </summary>
 /// <param name="dt">Delta time in seconds which has passed since the last update call</param>
 /// <param name="pool">The target <see cref="ParticlePool"/> which needs to be updated</param>
 public abstract void Update(float dt, ParticlePool pool);
Esempio n. 37
0
        public void Sorting()
        {
            var customFieldDesc = new ParticleFieldDescription <UInt32>("SomeField", 0);

            const int maxParticles = 4;
            var       pool         = new ParticlePool(0, maxParticles);

            const bool forceCreation = true;

            pool.FieldExists(ParticleFields.Position, forceCreation);      // Force creation of the position field
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation); // Force creation of the life field
            pool.FieldExists(customFieldDesc, forceCreation);              // Force creation of the custom field we just declared

            // We can extract them before the tight loop on all living particles
            var posField    = pool.GetField(ParticleFields.Position);
            var lifeField   = pool.GetField(ParticleFields.RemainingLife);
            var customField = pool.GetField(customFieldDesc);

            // Ad 4 particles
            var particle1 = pool.AddParticle();
            var particle2 = pool.AddParticle();
            var particle3 = pool.AddParticle();
            var particle4 = pool.AddParticle();

            particle1.Set(customField, (uint)1);
            particle2.Set(customField, (uint)2);
            particle3.Set(customField, (uint)3);
            particle4.Set(customField, (uint)4);

            particle1.Set(lifeField, 0.4f);
            particle2.Set(lifeField, 0.8f);
            particle3.Set(lifeField, 0.2f);
            particle4.Set(lifeField, 0.6f);

            particle1.Set(posField, new Vector3(0, 0, 3));
            particle2.Set(posField, new Vector3(0, 0, 9));
            particle3.Set(posField, new Vector3(0, 0, 5));
            particle4.Set(posField, new Vector3(0, 0, 1));

            // Don't sort
            uint[] sortedNone = { 1, 2, 3, 4 }; // List of expected values
            {
                var i = 0;
                foreach (var particle in pool)
                {
                    Assert.Equal(sortedNone[i++], particle.Get(customField));
                }
            }

            // Sort by depth
            uint[] sortedDepth = { 4, 1, 3, 2 }; // List of expected values
            {
                var depthSorter = new ParticleSorterDepth(pool);
                var sortedList  = depthSorter.GetSortedList(new Vector3(0, 0, 1));

                var i = 0;
                foreach (var particle in sortedList)
                {
                    Assert.Equal(sortedDepth[i++], particle.Get(customField));
                }
            }

            // Sort by age
            uint[] sortedAge = { 2, 4, 1, 3 }; // List of expected values
            {
                var ageSorter  = new ParticleSorterAge(pool);
                var sortedList = ageSorter.GetSortedList(new Vector3(0, 0, 1));

                var i = 0;
                foreach (var particle in sortedList)
                {
                    Assert.Equal(sortedAge[i++], particle.Get(customField));
                }
            }
        }
Esempio n. 38
0
 protected ParticleSorterCustom(ParticlePool pool, ParticleFieldDescription <T> fieldDesc)
 {
     ParticlePool   = pool;
     this.fieldDesc = fieldDesc;
 }
Esempio n. 39
0
        public unsafe void PoolCapacity(ParticlePool.ListPolicy policy)
        {
            const int maxParticles = 10;
            var pool = new ParticlePool(0, maxParticles, policy);

            const bool forceCreation = true;
            pool.FieldExists(ParticleFields.Position,       forceCreation);
            pool.FieldExists(ParticleFields.RemainingLife,  forceCreation);
            pool.FieldExists(ParticleFields.Velocity,       forceCreation);
            pool.FieldExists(ParticleFields.Size,           forceCreation);

            var testPos = new Vector3(1, 2, 3);
            var testVel = new Vector3(5, 6, 7);
            var testLife = 5f;
            var testSize = 4f;

            // Spawn all particles
            for (int i = 0; i < maxParticles; i++)
            {
                pool.AddParticle();
            }


            {
                // Field accessors break every time there is a change in the pool, so we need to exract them every time
                // We can extract them before the tight loop on all living particles
                var positionField   = pool.GetField(ParticleFields.Position);
                var lifetimeField   = pool.GetField(ParticleFields.RemainingLife);
                var velocityField   = pool.GetField(ParticleFields.Velocity);
                var sizeField       = pool.GetField(ParticleFields.Size);

                foreach (var particle in pool)
                {
                    *((Vector3*)particle[positionField]) = testPos;

                    *((float*)particle[lifetimeField]) = testLife;

                    *((Vector3*)particle[velocityField]) = testVel;

                    *((float*)particle[sizeField]) = testSize;
                }
            }

            // Double the pool capacity and assert that the first half of particles still have the same fields
            pool.SetCapacity(2 * maxParticles);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField = pool.GetField(ParticleFields.Size);

                var sorter = new ParticleSorterLiving(pool);
                sorter.Sort();

                var i = 0;
                foreach (var particle in sorter)
                {
                    Assert.That(*((Vector3*)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float*)particle[lifetimeField]), Is.EqualTo(testLife));

                    Assert.That(*((Vector3*)particle[velocityField]), Is.EqualTo(testVel));

                    Assert.That(*((float*)particle[sizeField]), Is.EqualTo(testSize));

                    i++;
                }

                // Assert that the number of living particles is still maxParticles, not maxParticles x2
                Assert.That(i, Is.EqualTo(maxParticles));
            }

            // Halve the pool capacity from its original size. Now all the particles should still have the same fields
            pool.SetCapacity(maxParticles / 2);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField = pool.GetField(ParticleFields.Size);

                var sorter = new ParticleSorterLiving(pool);
                sorter.Sort();

                var i = 0;
                foreach (var particle in sorter)
                {
                    Assert.That(*((Vector3*)particle[positionField]), Is.EqualTo(testPos));

                    Assert.That(*((float*)particle[lifetimeField]), Is.EqualTo(testLife));

                    Assert.That(*((Vector3*)particle[velocityField]), Is.EqualTo(testVel));

                    Assert.That(*((float*)particle[sizeField]), Is.EqualTo(testSize));

                    i++;
                }

                // Assert that the number of living particles is still maxParticles /2, not maxParticles x2
                Assert.That(i, Is.EqualTo(maxParticles / 2));
            }

        }
Esempio n. 40
0
 public ParticleSorterOrder(ParticlePool pool) : base(pool, ParticleFields.Order)
 {
 }
Esempio n. 41
0
 public void SetPool(ObjectPool objPool)
 {
     pool = (ParticlePool)objPool;
 }
Esempio n. 42
0
 /// <summary>
 /// Updates all particles in the <see cref="ParticlePool"/> using this updater
 /// </summary>
 /// <param name="dt">Delta time in seconds which has passed since the last update call</param>
 /// <param name="pool">The target <see cref="ParticlePool"/> which needs to be updated</param>
 public abstract void Update(float dt, ParticlePool pool);
Esempio n. 43
0
//        internal List<ParticleFieldDescription> RequiredFields = new List<ParticleFieldDescription>(ParticlePool.DefaultMaxFielsPerPool);

        /// <summary>
        /// Override Initialize if your module acts as an Initializer and change its type to Initializer
        /// </summary>
        /// <param name="pool">Particle pool to target</param>
        /// <param name="startIdx">Starting index (included from the array)</param>
        /// <param name="endIdx">End index (excluded from the array)</param>
        /// <param name="maxCapacity">Max pool capacity (loops after this point) so that it's possible for (endIdx < startIdx)</param>
        public abstract void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity);
Esempio n. 44
0
        /// <summary>
        /// Updates the field by interpolating between two sampled values over the particle's lifetime
        /// </summary>
        /// <param name="pool">Target <see cref="ParticlePool"/></param>
        private unsafe void UpdateDoubleSampler(ParticlePool pool)
        {
            var sizeField = pool.GetField(ParticleFields.Size);
            var lifeField = pool.GetField(ParticleFields.Life);
            var randField = pool.GetField(ParticleFields.RandomSeed);

            SamplerMain.UpdateChanges();
            SamplerOptional.UpdateChanges();

            foreach (var particle in pool)
            {
                var life = 1f - (*((float*)particle[lifeField]));   // The Life field contains remaining life, so for sampling we take (1 - life)

                var randSeed = particle.Get(randField);
                var lerp = randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                var size1 = SamplerMain.Evaluate(life);
                var size2 = SamplerOptional.Evaluate(life);

                (*((float*)particle[sizeField])) = WorldScale.X * (size1 + (size2 - size1) * lerp);
            }
        }
Esempio n. 45
0
 public ParticleSorterAge(ParticlePool pool) : base(pool, ParticleFields.Life)
 {
 }
Esempio n. 46
0
 /// <summary>
 /// Prepares fields accessors before the
 /// </summary>
 /// <param name="pool"></param>
 public abstract void PrepareFromPool(ParticlePool pool);
Esempio n. 47
0
        // TODO This will have to change at some point when we have better idea of how customizable the fields will be.
        //  Ideally no field should get initialized twice

        public unsafe void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            // Position - defaults to World position of the emitter
            var posField = pool.GetField(ParticleFields.Position);

            if (posField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3 *)particle[posField])) = WorldPosition;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Old position - defaults to World position of the emitter
            var oldPosField = pool.GetField(ParticleFields.OldPosition);

            if (oldPosField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3 *)particle[oldPosField])) = WorldPosition;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Direction - defaults to (0, 0, 0)
            var dirField = pool.GetField(ParticleFields.Direction);

            if (dirField.IsValid())
            {
                var zeroDirection = new Vector3(0, 0, 0);
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3 *)particle[dirField])) = zeroDirection;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Quaternion rotation - defaults to World rotation of the emitter
            var quatField = pool.GetField(ParticleFields.Quaternion);

            if (quatField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Quaternion *)particle[quatField])) = WorldRotation;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Angular rotation - defaults to 0
            var rotField = pool.GetField(ParticleFields.Rotation);

            if (rotField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((float *)particle[rotField])) = 0;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Velocity - defaults to (0, 0, 0)
            var velField = pool.GetField(ParticleFields.Velocity);

            if (velField.IsValid())
            {
                var zeroVelocity = new Vector3(0, 0, 0);
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Vector3 *)particle[velField])) = zeroVelocity;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Size - defaults to the world scale of the emitter
            var sizeField = pool.GetField(ParticleFields.Size);

            if (sizeField.IsValid())
            {
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((float *)particle[sizeField])) = WorldScale;
                    i = (i + 1) % maxCapacity;
                }
            }

            // Velocity - defaults to (0, 0, 0)
            var colField = pool.GetField(ParticleFields.Color);

            if (colField.IsValid())
            {
                var whiteColor = new Color4(1, 1, 1, 1);
                for (var i = startIdx; i != endIdx;)
                {
                    var particle = pool.FromIndex(i);
                    (*((Color4 *)particle[colField])) = whiteColor;
                    i = (i + 1) % maxCapacity;
                }
            }

            // ChildrenFlags fields
            for (int j = 0; j < ParticleFields.ChildrenFlags.Length; j++)
            {
                var flagField = pool.GetField(ParticleFields.ChildrenFlags[j]);
                if (flagField.IsValid())
                {
                    for (var i = startIdx; i != endIdx;)
                    {
                        var particle = pool.FromIndex(i);
                        (*((uint *)particle[flagField])) = 0;
                        i = (i + 1) % maxCapacity;
                    }
                }
            }
        }
Esempio n. 48
0
 private void Awake()
 {
     Instance = this;
     GrowPool();
 }
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Velocity) || !pool.FieldExists(ParticleFields.RandomSeed))
            {
                return;
            }

            // Collect the total number of living particles in the parent pool which have a Velocity field
            var parentPool           = Parent?.Pool;
            var parentParticlesCount = parentPool?.LivingParticles ?? 0;
            var velFieldParent       = parentPool?.GetField(ParticleFields.Velocity) ?? ParticleFieldAccessor <Vector3> .Invalid();

            if (!velFieldParent.IsValid())
            {
                parentParticlesCount = 0;
            }

            var spawnControlField = GetSpawnControlField();

            var velField = pool.GetField(ParticleFields.Velocity);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var leftCorner = VelocityMin * WorldScale;
            var xAxis      = new Vector3(VelocityMax.X * WorldScale.X - leftCorner.X, 0, 0);
            var yAxis      = new Vector3(0, VelocityMax.Y * WorldScale.Y - leftCorner.Y, 0);
            var zAxis      = new Vector3(0, 0, VelocityMax.Z * WorldScale.Z - leftCorner.Z);

            if (!WorldRotation.IsIdentity)
            {
                WorldRotation.Rotate(ref leftCorner);
                WorldRotation.Rotate(ref xAxis);
                WorldRotation.Rotate(ref yAxis);
                WorldRotation.Rotate(ref zAxis);
            }

            var sequentialParentIndex     = 0;
            var sequentialParentParticles = 0;
            var parentIndex = 0;

            var i = startIdx;

            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var particleRandVel = leftCorner;

                particleRandVel += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                particleRandVel += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                particleRandVel += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                if (parentParticlesCount > 0)
                {
                    var parentParticleVelocity = new Vector3(0, 0, 0);

                    // Spawn is fixed - parent particles have spawned a very specific number of children each
                    if (spawnControlField.IsValid())
                    {
                        while (sequentialParentParticles == 0)
                        {
                            // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally
                            if (sequentialParentIndex >= parentParticlesCount)
                            {
                                return;
                            }

                            parentIndex = sequentialParentIndex;
                            var tempParentParticle = parentPool.FromIndex(parentIndex);
                            sequentialParentIndex++;

                            var childrenAttribute = (*((ParticleChildrenAttribute *)tempParentParticle[spawnControlField]));

                            sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit;
                        }

                        sequentialParentParticles--;

                        var parentParticle = parentPool.FromIndex(parentIndex);
                        parentParticleVelocity = (*((Vector3 *)parentParticle[velFieldParent]));
                    }

                    // Spawn is not fixed - pick a parent at random
                    else
                    {
                        parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset));
                        var parentParticle = parentPool.FromIndex(parentIndex);

                        parentParticleVelocity = (*((Vector3 *)parentParticle[velFieldParent]));
                    }


                    // Convert from Local -> World space if needed
                    if (Parent.SimulationSpace == EmitterSimulationSpace.Local)
                    {
                        WorldRotation.Rotate(ref parentParticleVelocity);
                        parentParticleVelocity *= WorldScale.X;
                    }

                    particleRandVel += parentParticleVelocity * ParentVelocityFactor;
                }


                (*((Vector3 *)particle[velField])) = particleRandVel;

                i = (i + 1) % maxCapacity;
            }
        }
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var posField = pool.GetField(ParticleFields.Position);
            var oldField = pool.GetField(ParticleFields.OldPosition);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var leftCorner = PositionMin * WorldScale;
            var xAxis = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0);
            var yAxis = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0);
            var zAxis = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z);

            if (!WorldRotation.IsIdentity)
            {
                WorldRotation.Rotate(ref leftCorner);
                WorldRotation.Rotate(ref xAxis);
                WorldRotation.Rotate(ref yAxis);
                WorldRotation.Rotate(ref zAxis);
            }

            leftCorner += WorldPosition;

            var i = startIdx;

            if (Interpolate)
            {
                // Interpolate positions between the old and the new one

                var positionDistance = (hasBegun) ? oldPosition - WorldPosition : new Vector3(0, 0, 0);
                oldPosition = WorldPosition;
                hasBegun = true;

                var totalCountLessOne = (startIdx < endIdx) ? (endIdx - startIdx - 1) : (endIdx - startIdx + maxCapacity - 1);
                var stepF = (totalCountLessOne > 1) ? (1f/totalCountLessOne) : 1f;
                var step = 0f;

                while (i != endIdx)
                {
                    var particle = pool.FromIndex(i);
                    var randSeed = particle.Get(rndField);

                    var particleRandPos = leftCorner;

                    particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                    particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                    particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                    particleRandPos += positionDistance * step;
                    step += stepF;

                    (*((Vector3*)particle[posField])) = particleRandPos;

                    if (oldField.IsValid())
                    {
                        (*((Vector3*)particle[oldField])) = particleRandPos;
                    }

                    i = (i + 1) % maxCapacity;
                }
            }
            else
            {
                // Do not interpolate position
                while (i != endIdx)
                {
                    var particle = pool.FromIndex(i);
                    var randSeed = particle.Get(rndField);

                    var particleRandPos = leftCorner;

                    particleRandPos += xAxis*randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                    particleRandPos += yAxis*randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                    particleRandPos += zAxis*randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                    (*((Vector3*)particle[posField])) = particleRandPos;

                    if (oldField.IsValid())
                    {
                        (*((Vector3*)particle[oldField])) = particleRandPos;
                    }

                    i = (i + 1)%maxCapacity;
                }
            }
        }
Esempio n. 51
0
        public void Sorting()
        {
            var customFieldDesc = new ParticleFieldDescription<UInt32>("SomeField", 0);

            const int maxParticles = 4;
            var pool = new ParticlePool(0, maxParticles);

            const bool forceCreation = true;
            pool.FieldExists(ParticleFields.Position, forceCreation); // Force creation of the position field
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation); // Force creation of the life field
            pool.FieldExists(customFieldDesc, forceCreation); // Force creation of the custom field we just declared

            // We can extract them before the tight loop on all living particles
            var posField = pool.GetField(ParticleFields.Position);
            var lifeField = pool.GetField(ParticleFields.RemainingLife);
            var customField = pool.GetField(customFieldDesc);

            // Ad 4 particles
            var particle1 = pool.AddParticle();
            var particle2 = pool.AddParticle();
            var particle3 = pool.AddParticle();
            var particle4 = pool.AddParticle();

            particle1.Set(customField, (uint)1);
            particle2.Set(customField, (uint)2);
            particle3.Set(customField, (uint)3);
            particle4.Set(customField, (uint)4);

            particle1.Set(lifeField, 0.4f);
            particle2.Set(lifeField, 0.8f);
            particle3.Set(lifeField, 0.2f);
            particle4.Set(lifeField, 0.6f);

            particle1.Set(posField, new Vector3(0, 0, 3));
            particle2.Set(posField, new Vector3(0, 0, 9));
            particle3.Set(posField, new Vector3(0, 0, 5));
            particle4.Set(posField, new Vector3(0, 0, 1));

            // Don't sort
            uint[] sortedNone = { 1, 2, 3, 4 }; // List of expected values
            {
                var i = 0;
                foreach (var particle in pool)
                {
                    Assert.That(particle.Get(customField), Is.EqualTo(sortedNone[i++]));
                }
            }

            // Sort by depth
            uint[] sortedDepth = { 4, 1, 3, 2 }; // List of expected values
            {
                GetSortIndex<Vector3> sortByDepth = value => value.Z;

                var depthSorter = new ParticleSorterCustom<Vector3>(pool, ParticleFields.Position, sortByDepth);
                depthSorter.Sort();

                var i = 0;
                foreach (var particle in depthSorter)
                {
                    Assert.That(particle.Get(customField), Is.EqualTo(sortedDepth[i++]));
                }
            }

            // Sort by age
            uint[] sortedAge = { 3, 1, 4, 2 }; // List of expected values
            {
                GetSortIndex<float> sortByAge = value => { return value; };

                var ageSorter = new ParticleSorterCustom<float>(pool, ParticleFields.Life, sortByAge);
                ageSorter.Sort();

                var i = 0;
                foreach (var particle in ageSorter)
                {
                    Assert.That(particle.Get(customField), Is.EqualTo(sortedAge[i++]));
                }
            }

        }
Esempio n. 52
0
        public void Render(GLEx g, float x, float y)
        {
            if (!visible)
            {
                return;
            }

            if ((sprite == null) && (defaultImageName != null))
            {
                LoadSystemParticleImage();
            }


            g.Translate(x, y);

            if (blendingMode == BLEND_ADDITIVE)
            {
                //GLEx.self.setBlendMode(GL.MODE_ALPHA_ONE);
            }
            if (UsePoints())
            {
                //GLEx.gl10.glEnable(GL.GL_POINT_SMOOTH);
                //g.glTex2DDisable();
            }

            for (int emitterIdx = 0; emitterIdx < emitters.Count; emitterIdx++)
            {
                ParticleEmitter emitter = emitters[emitterIdx];

                if (!emitter.IsEnabled())
                {
                    continue;
                }

                if (emitter.UseAdditive())
                {
                    //g.setBlendMode(GL.MODE_ALPHA_ONE);
                }

                ParticlePool pool  = particlesByEmitter[emitter];
                LTexture     image = emitter.GetImage();
                if (image == null)
                {
                    image = this.sprite;
                }

                if (!emitter.IsOriented() && !emitter.UsePoints(this))
                {
                    image.GLBegin();
                }

                for (int i = 0; i < pool.particles.Length; i++)
                {
                    if (pool.particles[i].InUse())
                    {
                        pool.particles[i].Render();
                    }
                }

                if (!emitter.IsOriented() && !emitter.UsePoints(this))
                {
                    image.GLEnd();
                }

                if (emitter.UseAdditive())
                {
                    //g.setBlendMode(GL.MODE_NORMAL);
                }
            }

            if (UsePoints())
            {
                //GLEx.gl10.glDisable(GL.GL_POINT_SMOOTH);
            }
            if (blendingMode == BLEND_ADDITIVE)
            {
                //g.setBlendMode(GL.MODE_NORMAL);
            }

            g.ResetColor();
            g.Translate(-x, -y);
        }
Esempio n. 53
0
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Size) || !pool.FieldExists(ParticleFields.RandomSeed))
            {
                return;
            }

            var parentPool           = Parent?.Pool;
            var parentParticlesCount = parentPool?.LivingParticles ?? 0;
            var sizeFieldParent      = parentPool?.GetField(ParticleFields.Size) ?? ParticleFieldAccessor <float> .Invalid();

            if (!sizeFieldParent.IsValid())
            {
                parentParticlesCount = 0;
            }

            var spawnControlField = GetSpawnControlField();

            var sizeField = pool.GetField(ParticleFields.Size);
            var rndField  = pool.GetField(ParticleFields.RandomSeed);

            var minSize = WorldScale.X * RandomSize.X;
            var sizeGap = WorldScale.X * RandomSize.Y - minSize;

            var sequentialParentIndex     = 0;
            var sequentialParentParticles = 0;
            var parentIndex = 0;

            var i = startIdx;

            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var particleRandomSize = minSize + sizeGap * randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                if (parentParticlesCount > 0)
                {
                    var parentParticleSize = 1f;

                    // Spawn is fixed - parent particles have spawned a very specific number of children each
                    if (spawnControlField.IsValid())
                    {
                        while (sequentialParentParticles == 0)
                        {
                            // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally
                            if (sequentialParentIndex >= parentParticlesCount)
                            {
                                return;
                            }

                            parentIndex = sequentialParentIndex;
                            var tempParentParticle = parentPool.FromIndex(parentIndex);
                            sequentialParentIndex++;

                            var childrenAttribute = (*((ParticleChildrenAttribute *)tempParentParticle[spawnControlField]));

                            sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit;
                        }

                        sequentialParentParticles--;

                        var parentParticle = parentPool.FromIndex(parentIndex);
                        parentParticleSize = (*((float *)parentParticle[sizeFieldParent]));
                    }

                    // Spawn is not fixed - pick a parent at random
                    else
                    {
                        parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset));
                        var parentParticle = parentPool.FromIndex(parentIndex);

                        parentParticleSize = (*((float *)parentParticle[sizeFieldParent]));
                    }


                    // Convert from Local -> World space if needed
                    if (Parent.SimulationSpace == EmitterSimulationSpace.Local)
                    {
                        parentParticleSize *= WorldScale.X;
                    }

                    particleRandomSize *= parentParticleSize;
                }


                (*((float *)particle[sizeField])) = particleRandomSize;

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 54
0
 private void Awake()
 {
     instance = this;
     Setup();
 }
Esempio n. 55
0
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Position) || !pool.FieldExists(ParticleFields.RandomSeed))
            {
                return;
            }

            // Collect the total number of living particles in the parent pool which have a Position field
            var parentPool           = Parent?.Pool;
            var parentParticlesCount = parentPool?.LivingParticles ?? 0;
            var posFieldParent       = parentPool?.GetField(ParticleFields.Position) ?? ParticleFieldAccessor <Vector3> .Invalid();

            if (!posFieldParent.IsValid())
            {
                parentParticlesCount = 0;
            }

            var oldPosFieldParent = parentPool?.GetField(ParticleFields.OldPosition) ?? ParticleFieldAccessor <Vector3> .Invalid();

            var spawnControlField = GetSpawnControlField();

            var posField = pool.GetField(ParticleFields.Position);
            var rndField = pool.GetField(ParticleFields.RandomSeed);
            var oldField = pool.GetField(ParticleFields.OldPosition);

            var leftCorner = PositionMin * WorldScale;
            var xAxis      = new Vector3(PositionMax.X * WorldScale.X - leftCorner.X, 0, 0);
            var yAxis      = new Vector3(0, PositionMax.Y * WorldScale.Y - leftCorner.Y, 0);
            var zAxis      = new Vector3(0, 0, PositionMax.Z * WorldScale.Z - leftCorner.Z);

            if (!WorldRotation.IsIdentity)
            {
                WorldRotation.Rotate(ref leftCorner);
                WorldRotation.Rotate(ref xAxis);
                WorldRotation.Rotate(ref yAxis);
                WorldRotation.Rotate(ref zAxis);
            }

            // Already inheriting from parent
            if (parentParticlesCount == 0)
            {
                leftCorner += WorldPosition;
            }

            var sequentialParentIndex     = 0;
            var sequentialParentParticles = 0;
            var parentIndex = 0;

            // Interpolation - if parent particle has OldPosition field
            var stepF            = 0f;
            var stepTotal        = 0f;
            var positionDistance = new Vector3(0, 0, 0);

            var i = startIdx;

            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var particleRandPos = leftCorner;

                particleRandPos += xAxis * randSeed.GetFloat(RandomOffset.Offset3A + SeedOffset);
                particleRandPos += yAxis * randSeed.GetFloat(RandomOffset.Offset3B + SeedOffset);
                particleRandPos += zAxis * randSeed.GetFloat(RandomOffset.Offset3C + SeedOffset);

                if (parentParticlesCount > 0)
                {
                    var parentParticlePosition = new Vector3(0, 0, 0);

                    // Spawn is fixed - parent particles have spawned a very specific number of children each
                    if (spawnControlField.IsValid())
                    {
                        // Interpolation - if parent particle has OldPosition field

                        while (sequentialParentParticles == 0)
                        {
                            // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally
                            if (sequentialParentIndex >= parentParticlesCount)
                            {
                                return;
                            }

                            parentIndex = sequentialParentIndex;
                            var tempParentParticle = parentPool.FromIndex(parentIndex);
                            sequentialParentIndex++;

                            var childrenAttribute = (*((ParticleChildrenAttribute *)tempParentParticle[spawnControlField]));

                            sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit;

                            if (oldPosFieldParent.IsValid())
                            {
                                stepF            = (sequentialParentParticles > 0) ? (1f / (float)sequentialParentParticles) : 1;
                                stepTotal        = 0f;
                                positionDistance = ((*((Vector3 *)tempParentParticle[oldPosFieldParent])) - (*((Vector3 *)tempParentParticle[posFieldParent])));
                            }
                        }

                        sequentialParentParticles--;

                        var parentParticle = parentPool.FromIndex(parentIndex);
                        parentParticlePosition  = (*((Vector3 *)parentParticle[posFieldParent]));
                        parentParticlePosition += positionDistance * stepTotal;
                        stepTotal += stepF;
                    }

                    // Spawn is not fixed - pick a parent at random
                    else
                    {
                        parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset));
                        var parentParticle = parentPool.FromIndex(parentIndex);

                        parentParticlePosition = (*((Vector3 *)parentParticle[posFieldParent]));
                    }


                    // Convert from Local -> World space if needed
                    if (Parent.SimulationSpace == EmitterSimulationSpace.Local)
                    {
                        WorldRotation.Rotate(ref parentParticlePosition);
                        parentParticlePosition *= WorldScale.X;
                        parentParticlePosition += WorldPosition;
                    }

                    particleRandPos += parentParticlePosition;
                }


                (*((Vector3 *)particle[posField])) = particleRandPos;

                if (oldField.IsValid())
                {
                    (*((Vector3 *)particle[oldField])) = particleRandPos;
                }

                i = (i + 1) % maxCapacity;
            }
        }
        /// <inheritdoc />
        public unsafe override void Initialize(ParticlePool pool, int startIdx, int endIdx, int maxCapacity)
        {
            if (!pool.FieldExists(ParticleFields.Size) || !pool.FieldExists(ParticleFields.RandomSeed))
                return;

            var parentPool = Parent?.Pool;
            var parentParticlesCount = parentPool?.LivingParticles ?? 0;
            var sizeFieldParent = parentPool?.GetField(ParticleFields.Size) ?? ParticleFieldAccessor<float>.Invalid();
            if (!sizeFieldParent.IsValid())
            {
                parentParticlesCount = 0;
            }

            var spawnControlField = GetSpawnControlField();

            var sizeField = pool.GetField(ParticleFields.Size);
            var rndField = pool.GetField(ParticleFields.RandomSeed);

            var minSize = WorldScale.X * RandomSize.X;
            var sizeGap = WorldScale.X * RandomSize.Y - minSize;

            var sequentialParentIndex = 0;
            var sequentialParentParticles = 0;
            var parentIndex = 0;

            var i = startIdx;
            while (i != endIdx)
            {
                var particle = pool.FromIndex(i);
                var randSeed = particle.Get(rndField);

                var particleRandomSize = minSize + sizeGap * randSeed.GetFloat(RandomOffset.Offset1A + SeedOffset);

                if (parentParticlesCount > 0)
                {
                    var parentParticleSize = 1f;

                    // Spawn is fixed - parent particles have spawned a very specific number of children each
                    if (spawnControlField.IsValid())
                    {
                        while (sequentialParentParticles == 0)
                        {
                            // Early out - no more fixed number children. Rest of the particles (if any) are skipped intentionally
                            if (sequentialParentIndex >= parentParticlesCount)
                                return;

                            parentIndex = sequentialParentIndex;
                            var tempParentParticle = parentPool.FromIndex(parentIndex);
                            sequentialParentIndex++;

                            var childrenAttribute = (*((ParticleChildrenAttribute*)tempParentParticle[spawnControlField]));

                            sequentialParentParticles = (int)childrenAttribute.ParticlesToEmit;
                        }

                        sequentialParentParticles--;

                        var parentParticle = parentPool.FromIndex(parentIndex);
                        parentParticleSize = (*((float*)parentParticle[sizeFieldParent]));
                    }

                    // Spawn is not fixed - pick a parent at random
                    else
                    {
                        parentIndex = (int)(parentParticlesCount * randSeed.GetFloat(RandomOffset.Offset1A + ParentSeedOffset));
                        var parentParticle = parentPool.FromIndex(parentIndex);

                        parentParticleSize = (*((float*)parentParticle[sizeFieldParent]));
                    }


                    // Convert from Local -> World space if needed
                    if (Parent.SimulationSpace == EmitterSimulationSpace.Local)
                    {
                        parentParticleSize *= WorldScale.X;
                    }

                    particleRandomSize *= parentParticleSize;
                }


                (*((float*)particle[sizeField])) = particleRandomSize;

                i = (i + 1) % maxCapacity;
            }
        }
Esempio n. 57
0
 public ParticleList(ParticlePool pool, int capacity, SortedParticle[] list = null)
 {
     this.pool         = pool;
     this.listCapacity = capacity;
     this.sortedList   = list;
 }
Esempio n. 58
0
        public unsafe void PoolCapacity(ParticlePool.ListPolicy policy)
        {
            const int maxParticles = 10;
            var       pool         = new ParticlePool(0, maxParticles, policy);

            const bool forceCreation = true;

            pool.FieldExists(ParticleFields.Position, forceCreation);
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation);
            pool.FieldExists(ParticleFields.Velocity, forceCreation);
            pool.FieldExists(ParticleFields.Size, forceCreation);

            var testPos  = new Vector3(1, 2, 3);
            var testVel  = new Vector3(5, 6, 7);
            var testLife = 5f;
            var testSize = 4f;

            // Spawn all particles
            for (int i = 0; i < maxParticles; i++)
            {
                pool.AddParticle();
            }


            {
                // Field accessors break every time there is a change in the pool, so we need to exract them every time
                // We can extract them before the tight loop on all living particles
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                foreach (var particle in pool)
                {
                    *((Vector3 *)particle[positionField]) = testPos;

                    *((float *)particle[lifetimeField]) = testLife;

                    *((Vector3 *)particle[velocityField]) = testVel;

                    *((float *)particle[sizeField]) = testSize;
                }
            }

            // Double the pool capacity and assert that the first half of particles still have the same fields
            pool.SetCapacity(2 * maxParticles);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                var sorter     = new ParticleSorterLiving(pool);
                var sortedList = sorter.GetSortedList(new Vector3(0, 0, -1));

                var i = 0;
                foreach (var particle in sortedList)
                {
                    Assert.Equal(testPos, *((Vector3 *)particle[positionField]));

                    Assert.Equal(testLife, *((float *)particle[lifetimeField]));

                    Assert.Equal(testVel, *((Vector3 *)particle[velocityField]));

                    Assert.Equal(testSize, *((float *)particle[sizeField]));

                    i++;
                }

                sorter.FreeSortedList(ref sortedList);

                // Assert that the number of living particles is still maxParticles, not maxParticles x2
                Assert.Equal(maxParticles, i);
            }

            // Halve the pool capacity from its original size. Now all the particles should still have the same fields
            pool.SetCapacity(maxParticles / 2);
            {
                // Field accessors break every time there is a change in the pool
                var positionField = pool.GetField(ParticleFields.Position);
                var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
                var velocityField = pool.GetField(ParticleFields.Velocity);
                var sizeField     = pool.GetField(ParticleFields.Size);

                var sorter     = new ParticleSorterLiving(pool);
                var sortedList = sorter.GetSortedList(new Vector3(0, 0, -1));

                var i = 0;
                foreach (var particle in sortedList)
                {
                    Assert.Equal(testPos, *((Vector3 *)particle[positionField]));

                    Assert.Equal(testLife, *((float *)particle[lifetimeField]));

                    Assert.Equal(testVel, *((Vector3 *)particle[velocityField]));

                    Assert.Equal(testSize, *((float *)particle[sizeField]));

                    i++;
                }

                sorter.FreeSortedList(ref sortedList);

                // Assert that the number of living particles is still maxParticles /2, not maxParticles x2
                Assert.Equal(maxParticles / 2, i);
            }
        }
Esempio n. 59
0
        /// <summary>
        /// Default constructor. Initializes the pool and all collections contained in the <see cref="ParticleEmitter"/>
        /// </summary>
        public ParticleEmitter()
        {
            pool = new ParticlePool(0, 0);
            PoolChangedNotification();
            requiredFields = new Dictionary<ParticleFieldDescription, int>();

            // For now all particles require Life and RandomSeed fields, always
            AddRequiredField(ParticleFields.RemainingLife);
            AddRequiredField(ParticleFields.RandomSeed);
            AddRequiredField(ParticleFields.Position);

            initialDefaultFields = new InitialDefaultFields();

            Initializers = new FastTrackingCollection<ParticleInitializer>();
            Initializers.CollectionChanged += ModulesChanged;

            Updaters = new FastTrackingCollection<ParticleUpdater>();
            Updaters.CollectionChanged += ModulesChanged;

            Spawners = new FastTrackingCollection<ParticleSpawner>();
            Spawners.CollectionChanged += SpawnersChanged;        
        }
Esempio n. 60
0
        public unsafe void ParticleGetSet(ParticlePool.ListPolicy policy)
        {
            const int maxParticles = 10;
            var       pool         = new ParticlePool(0, maxParticles, policy);

            // Spawn all particles
            for (var i = 0; i < maxParticles; i++)
            {
                pool.AddParticle();
            }

            const bool forceCreation = true;

            pool.FieldExists(ParticleFields.Position, forceCreation);
            pool.FieldExists(ParticleFields.RemainingLife, forceCreation);
            pool.FieldExists(ParticleFields.Velocity, forceCreation);
            pool.FieldExists(ParticleFields.Size, forceCreation);

            var positionField = pool.GetField(ParticleFields.Position);
            var lifetimeField = pool.GetField(ParticleFields.RemainingLife);
            var velocityField = pool.GetField(ParticleFields.Velocity);
            var sizeField     = pool.GetField(ParticleFields.Size);

            var vectorToSet = new Vector3(0, 0, 0);
            var scalarToSet = 0f;

            foreach (var particle in pool)
            {
                vectorToSet.Y = scalarToSet;

                *((Vector3 *)particle[positionField]) = vectorToSet;

                *((float *)particle[lifetimeField]) = scalarToSet;

                *((Vector3 *)particle[velocityField]) = vectorToSet;

                *((float *)particle[sizeField]) = scalarToSet;

                scalarToSet++;
            }

            // Assert the values are the same
            scalarToSet = 0f;
            foreach (var particle in pool)
            {
                Assert.Equal(new Vector3(0, scalarToSet, 0), *((Vector3 *)particle[positionField]));

                Assert.Equal(scalarToSet, *((float *)particle[lifetimeField]));

                Assert.Equal(new Vector3(0, scalarToSet, 0), *((Vector3 *)particle[velocityField]));

                Assert.Equal(scalarToSet, *((float *)particle[sizeField]));

                scalarToSet++;
            }

            // "Update" the values with delta time
            var dt = 0.033333f;

            foreach (var particle in pool)
            {
                var pos = ((Vector3 *)particle[positionField]);
                var vel = ((Vector3 *)particle[velocityField]);

                *pos += *vel * dt;

                *((float *)particle[lifetimeField]) += 1;
            }

            scalarToSet = 0f;
            foreach (var particle in pool)
            {
                Assert.Equal(*((Vector3 *)particle[positionField]), new Vector3(0, scalarToSet, 0) + *((Vector3 *)particle[velocityField]) * dt);

                Assert.Equal(scalarToSet + 1, *((float *)particle[lifetimeField]));

                scalarToSet++;
            }
        }