4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Collections.Specialized;
8 using System.Runtime.InteropServices;
9 using SiliconStudio.Paradox.Games;
10 using SiliconStudio.Core;
11 using SiliconStudio.Core.Collections;
12 using SiliconStudio.Core.Mathematics;
14 namespace SiliconStudio.
Paradox.Particles
21 private bool disposed =
false;
22 private const int particleDefaultCapacity = 256;
23 private int particleCount;
24 private int particleCapacity;
25 private int particleSize;
26 private IntPtr particleData;
29 private IntPtr particleDefaultValue;
34 private Dictionary<ParticleFieldDescription, ParticleField> fields =
new Dictionary<ParticleFieldDescription, ParticleField>(8);
43 public TrackingCollection<IParticlePlugin> Plugins {
get;
private set; }
67 public int ParticleCount
69 get {
return particleCount; }
78 Plugins =
new TrackingCollection<IParticlePlugin>();
84 EnsureCapacity(particleDefaultCapacity);
86 Plugins.CollectionChanged += Plugins_CollectionChanged;
101 GC.SuppressFinalize(
this);
108 protected virtual void Dispose(
bool disposing)
112 if (particleData != IntPtr.Zero)
114 Utilities.FreeMemory(particleData);
115 particleData = IntPtr.Zero;
117 if (particleDefaultValue != IntPtr.Zero)
119 Utilities.FreeMemory(particleDefaultValue);
120 particleDefaultValue = IntPtr.Zero;
140 case NotifyCollectionChangedAction.Add:
141 if (particlePluginListener != null)
142 particlePluginListener.OnAddPlugin(
this);
144 case NotifyCollectionChangedAction.Remove:
145 if (particlePluginListener != null)
146 particlePluginListener.OnRemovePlugin(
this);
162 if (!fields.TryGetValue(fieldDesc, out field))
179 if (!fields.TryGetValue(fieldDesc, out field))
181 field = AddField(fieldDesc);
198 if (!fields.TryGetValue(fieldDesc, out field))
200 field = AddField(fieldDesc);
202 SetDefaultValue(field, defaultValue);
212 internal void SetDefaultValue<T>(ParticleField particleField, T defaultValue) where T :
struct
214 if (particleDefaultValue == IntPtr.Zero)
215 throw new InvalidOperationException();
218 Utilities.Write(particleDefaultValue + particleField.Offset, ref defaultValue);
228 internal ParticleField AddField<T>(ParticleFieldDescription<T> fieldDesc) where T :
struct
230 ParticleField existingField;
231 if (fields.TryGetValue(fieldDesc, out existingField))
232 return existingField;
234 var
size = Utilities.SizeOf<T>();
238 throw new ArgumentException(
"Particle field size must be a multiple of 4",
"size");
240 var newParticleSize = particleSize +
size;
243 var newParticleDefaultValue = Utilities.AllocateMemory(newParticleSize);
244 if (particleDefaultValue != IntPtr.Zero)
246 Utilities.CopyMemory(newParticleDefaultValue, particleDefaultValue, particleSize);
247 Utilities.FreeMemory(particleDefaultValue);
250 particleDefaultValue = newParticleDefaultValue;
253 var defaultValue = fieldDesc.DefaultValue;
254 Utilities.Write(newParticleDefaultValue + particleSize, ref defaultValue);
258 if (particleData != IntPtr.Zero && particleCapacity * particleSize < newParticleSize * particleCount)
269 var particleSizeInDword = particleSize / 4;
272 var particleEnd = (
int*)(particleData + particleCount * particleSize);
273 var newParticleEnd = (
int*)(particleData + particleCount * newParticleSize - size);
274 for (
int i = particleCount - 1; i >= 0; --i)
277 for (
int j = 0; j < particleSizeInDword; ++j)
279 *--newParticleEnd = *--particleEnd;
282 newParticleEnd -=
size;
285 Utilities.Write((IntPtr)newParticleEnd, ref defaultValue);
290 particleCapacity = particleCapacity * particleSize / newParticleSize;
292 else if (particleCapacity > 0)
294 var newParticleData = Utilities.AllocateMemory(particleCapacity * newParticleSize);
297 if (particleData != IntPtr.Zero)
299 var newParticleDataPtr = newParticleData;
300 var particleDataPtr = particleData;
301 for (
int i = 0; i < particleCount; ++i)
304 Utilities.CopyMemory(newParticleDataPtr, particleDataPtr, particleSize);
306 Utilities.Write(newParticleDataPtr + particleSize, ref defaultValue);
307 particleDataPtr += particleSize;
308 newParticleDataPtr += newParticleSize;
310 Utilities.FreeMemory(particleData);
313 particleData = newParticleData;
317 var field =
new ParticleField { Offset = particleSize, Size = size };
318 fields.Add(fieldDesc, field);
321 particleSize = newParticleSize;
330 foreach (var plugin
in Plugins)
332 plugin.Update(
this, dt);
343 if (ParticleCount == particleCapacity)
344 EnsureCapacity(ParticleCount + 1);
347 var particle =
new Particle(particleData + particleSize * particleCount);
350 Utilities.CopyMemory(particle.Pointer, particleDefaultValue, particleSize);
363 var lastParticleIndex = ParticleCount - 1;
364 if (particleIndex != lastParticleIndex)
366 Utilities.CopyMemory(particleData + particleIndex * particleSize, particleData + lastParticleIndex * particleSize, particleSize);
369 particleCount = ParticleCount - 1;
372 private void EnsureCapacity(
int min)
374 if (ParticleCount < min)
376 int newCapacity = (particleCapacity == 0) ? particleDefaultCapacity : (particleCapacity * 2);
377 if (newCapacity < min)
380 if (newCapacity != particleCapacity)
383 var newParticleData = Utilities.AllocateMemory(newCapacity * particleSize);
385 if (particleData != IntPtr.Zero)
388 Utilities.CopyMemory(newParticleData, particleData, particleSize * particleCount);
391 Utilities.FreeMemory(particleData);
395 particleData = newParticleData;
396 particleCapacity = newCapacity;
408 private int particleSize;
409 private IntPtr particleData;
417 this.particleSystem = particleSystem;
418 this.particleSize = particleSystem.particleSize;
420 this.particleData = IntPtr.Zero;
431 get {
return index; }
438 particleData = particleSystem.particleData + particleSize * index;
449 particleSystem.RemoveParticleAt(Index--);
457 return ++Index < particleSystem.ParticleCount;
469 particleData = IntPtr.Zero;
473 object IEnumerator.Current
475 get {
return Current; }
481 get {
return new Particle(particleData); }
Describes a field for a particle, which can store specific data for every particle.
static readonly ParticleFieldDescription< float > Angle
A particle field description for the particle Orientation (for billboard only).
A particle system, containing particles and their updaters.
Enumerator(ParticleSystem particleSystem)
Initializes a new instance of the Enumerator struct.
Specifies how to access a ParticleFieldDescription in a given ParticleSystem instance.
static readonly ParticleFieldDescription< Vector3 > Position
A particle field description for the particle position.
virtual void Dispose(bool disposing)
Releases unmanaged and - optionally - managed resources.
void Update(float dt)
Updates this instance.
Enumerator GetEnumerator()
Gets the Particle enumerator.
Listeners that can react on addition or removal to a ParticleSystem.
NotifyCollectionChangedAction Action
Gets the type of action performed. Allowed values are NotifyCollectionChangedAction.Add and NotifyCollectionChangedAction.Remove.
A particle in the particle system.
Specifies how to access a ParticleFieldDescription{T} in a given ParticleSystem instance.
Particle AddParticle()
Adds the particle.
void RemoveParticle()
Removes the current particle from the particle system. The iterator will be placed at the previous pa...
_In_ size_t _In_ size_t size
ParticleSystem()
Initializes a new instance of the ParticleSystem class.
void RemoveParticleAt(int particleIndex)
Removes the particle at the specified index.