Пример #1
0
        /// <summary>
        /// Sets the default value for the specified field.
        /// </summary>
        /// <typeparam name="T">The field type.</typeparam>
        /// <param name="particleField">The field.</param>
        /// <param name="defaultValue">The new field default value.</param>
        internal void SetDefaultValue <T>(ParticleField particleField, T defaultValue) where T : struct
        {
            if (particleDefaultValue == IntPtr.Zero)
            {
                throw new InvalidOperationException();
            }

            // Write new default value for the field
            Utilities.Write(particleDefaultValue + particleField.Offset, ref defaultValue);
        }
Пример #2
0
        /// <summary>
        /// Adds a new field to the particle system.
        /// </summary>
        /// <typeparam name="T">The field type.</typeparam>
        /// <param name="fieldDesc">The field description.</param>
        /// <returns>The field.</returns>
        /// <exception cref="System.ArgumentException">Particle field size must be a multiple of 4;size</exception>
        internal ParticleField AddField <T>(ParticleFieldDescription <T> fieldDesc) where T : struct
        {
            ParticleField existingField;

            if (fields.TryGetValue(fieldDesc, out existingField))
            {
                return(existingField);
            }

            var size = Utilities.SizeOf <T>();

            // Only accept 4-byte multiples.
            if (size % 4 != 0)
            {
                throw new ArgumentException("Particle field size must be a multiple of 4", "size");
            }

            var newParticleSize = particleSize + size;

            // Update default value
            var newParticleDefaultValue = Utilities.AllocateMemory(newParticleSize);

            if (particleDefaultValue != IntPtr.Zero)
            {
                Utilities.CopyMemory(newParticleDefaultValue, particleDefaultValue, particleSize);
                Utilities.FreeMemory(particleDefaultValue);
            }

            particleDefaultValue = newParticleDefaultValue;

            // Write default value for new field
            var defaultValue = fieldDesc.DefaultValue;

            Utilities.Write(newParticleDefaultValue + particleSize, ref defaultValue);


            // Check if there is enough space to do the conversion in-place
            if (particleData != IntPtr.Zero && particleCapacity * particleSize < newParticleSize * particleCount)
            {
                // Copy in-place, particles from back to front (so that there is no memory overlap)
                // i.e.
                // AAABBBCCCDDD gets copied that way:
                // --------------D-
                // -------------DD-
                // ------------DDD-
                // ----------C-DDD-
                // ................
                // AAA-BBB-CCC-DDD-
                var particleSizeInDword = particleSize / 4;
                unsafe
                {
                    var particleEnd    = (int *)(particleData + particleCount * particleSize);
                    var newParticleEnd = (int *)(particleData + particleCount * newParticleSize - size);
                    for (int i = particleCount - 1; i >= 0; --i)
                    {
                        // Copy one particle, from back to end (no overlap)
                        for (int j = 0; j < particleSizeInDword; ++j)
                        {
                            *--newParticleEnd = *--particleEnd;
                        }
                        // Leave space for the newly added field.
                        newParticleEnd -= size;

                        // Write default value for new field
                        Utilities.Write((IntPtr)newParticleEnd, ref defaultValue);
                    }
                }

                // Update capacity
                particleCapacity = particleCapacity * particleSize / newParticleSize;
            }
            else if (particleCapacity > 0)
            {
                var newParticleData = Utilities.AllocateMemory(particleCapacity * newParticleSize);

                // Copy previous data to the new buffer, interleaved with space for the new field
                if (particleData != IntPtr.Zero)
                {
                    var newParticleDataPtr = newParticleData;
                    var particleDataPtr    = particleData;
                    for (int i = 0; i < particleCount; ++i)
                    {
                        // Copy particle values
                        Utilities.CopyMemory(newParticleDataPtr, particleDataPtr, particleSize);
                        // Write default value for new field
                        Utilities.Write(newParticleDataPtr + particleSize, ref defaultValue);
                        particleDataPtr    += particleSize;
                        newParticleDataPtr += newParticleSize;
                    }
                    Utilities.FreeMemory(particleData);
                }

                particleData = newParticleData;
            }

            // Add the field
            var field = new ParticleField {
                Offset = particleSize, Size = size
            };

            fields.Add(fieldDesc, field);

            // Update particle size
            particleSize = newParticleSize;
            return(field);
        }