#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2009 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
using Nuclex.Graphics.Batching;
using Nuclex.Support;
namespace Nuclex.Graphics.SpecialEffects.Particles.HighLevel {
partial class ParticleSystemManager {
#region interface IParticleSystemHolder
/// Interface for objects managing a single particle system
private interface IParticleSystemHolder {
/// Renders the particle system into its primitive batch
void Render();
/// Disposes the contained particle system
void Dispose();
/// Releases or destroys the referenced primitive batch
void ReleasePrimitiveBatch();
/// Updates the particles in the particle system
/// Number of updates that will be performed
void Update(int updates);
/// Begins an asynchronous update on the particle system
/// Number of updates that will be performed
/// Number of threads that will be used
///
/// Callback that will be invoked after the update has finished
///
/// User-defined state
///
/// An asynchronous result handle that can be used to wait for the operation
///
IAsyncResult BeginUpdate(
int updates, int threads, AsyncCallback callback, object state
);
/// Ends the asynchronous update
///
/// Asynchronous result handle obtained from the BeginUpdate() method
///
void EndUpdate(IAsyncResult asyncResult);
/// Prunes dead particles from the system
void Prune();
/// Begins asynchronously pruning dead particles from the system
///
/// Callback that will be invoked after pruning has finished
///
/// User-defined state
///
/// An asynchronous result handle that can be used to wait for the operation
///
IAsyncResult BeginPrune(AsyncCallback callback, object state);
/// Ends asynchronous pruning
///
/// Asynchronous result handle obtained from the BeginPrune() method
///
void EndPrune(IAsyncResult asyncResult);
}
#endregion // interface IParticleSystemHolder
#region class ParticleSystemHolder<>
/// Manages a particle system and its associated resources
///
/// Type of particles being simulated in the particle system
///
///
/// Type of vertices the particle system generates
///
private class ParticleSystemHolder : IParticleSystemHolder
where ParticleType : struct
where VertexType : struct, IVertexType {
/// Initializes a new particle system holder
/// Particle system the holder will manage
///
/// Renderer through which the particles are sent to the primitive batch
///
///
/// Method which will be used to detect dead particles
///
///
/// Primitive batch holder that manages the primitive batch used to
/// render the vertices generated by this particle system
///
public ParticleSystemHolder(
ParticleSystem particleSystem,
ParticleSystem.PrunePredicate pruneDelegate,
IParticleRenderer renderer,
PrimitiveBatchHolder primitiveBatchHolder
) {
if(renderer == null) {
throw new ArgumentException("You must specify a renderer", "renderer");
}
this.particleSystem = particleSystem;
this.pruneDelegate = pruneDelegate;
this.renderer = renderer;
this.primitiveBatchHolder = primitiveBatchHolder;
}
/// Renders the particle system into its primitive batch
public void Render() {
this.renderer.Render(
this.particleSystem.Particles, this.primitiveBatchHolder.PrimitiveBatch
);
}
/// Disposes the contained particle system
public void Dispose() {
this.particleSystem.Dispose();
}
/// Releases or destroys the referenced primitive batch
public void ReleasePrimitiveBatch() {
this.primitiveBatchHolder.Release();
}
/// Updates the particles in the particle system
/// Number of updates that will be performed
public void Update(int updates) {
this.particleSystem.Update(updates);
}
/// Begins an asynchronous update on the particle system
/// Number of updates that will be performed
/// Number of threads that will be used
///
/// Callback that will be invoked after the update has finished
///
/// User-defined state
///
/// An asynchronous result handle that can be used to wait for the operation
///
public IAsyncResult BeginUpdate(
int updates, int threads, AsyncCallback callback, object state
) {
return this.particleSystem.BeginUpdate(updates, threads, callback, state);
}
/// Ends the asynchronous update
///
/// Asynchronous result handle obtained from the BeginUpdate() method
///
public void EndUpdate(IAsyncResult asyncResult) {
this.particleSystem.EndUpdate(asyncResult);
}
/// Prunes dead particles from the system
public void Prune() {
this.particleSystem.Prune(this.pruneDelegate);
}
/// Begins asynchronously pruning dead particles from the system
///
/// Callback that will be invoked after pruning has finished
///
/// User-defined state
///
/// An asynchronous result handle that can be used to wait for the operation
///
public IAsyncResult BeginPrune(AsyncCallback callback, object state) {
return this.particleSystem.BeginPrune(this.pruneDelegate, callback, state);
}
/// Ends asynchronous pruning
///
/// Asynchronous result handle obtained from the BeginPrune() method
///
public void EndPrune(IAsyncResult asyncResult) {
this.particleSystem.EndPrune(asyncResult);
}
/// Particle system being managed by the holder
private ParticleSystem particleSystem;
/// Particle renderer used to generate vertices from particles
private IParticleRenderer renderer;
/// Manages the primitive batch used to draw particles
private PrimitiveBatchHolder primitiveBatchHolder;
/// Delegate for the method used to recognize dead particles
private ParticleSystem.PrunePredicate pruneDelegate;
}
#endregion // class ParticleSystemHolder<>
/// Adds a particle system to be processed by the manager
///
/// Type of particles being stored in the particle system
///
///
/// Type of vertices that will be generated from the particles
///
///
/// Particle system that will be added to the manager
///
/// Method used to detect dead particles
///
/// Particle renderer that will turn the particles into vertices and send
/// them to a primitive batch for rendering
///
public void AddParticleSystem(
ParticleSystem particleSystem,
ParticleSystem.PrunePredicate pruneDelegate,
IParticleRenderer renderer
)
where ParticleType : struct
where VertexType : struct, IVertexType {
PrimitiveBatchHolder holder;
holder = getOrCreatePrimitiveBatch();
try {
this.particleSystems.Add(
particleSystem,
new ParticleSystemHolder(
particleSystem,
pruneDelegate,
renderer,
holder
)
);
this.holderArraysDirty = true;
}
catch(Exception) {
holder.Release();
throw;
}
}
/// Removes a particle system from the manager
///
/// Type of particles being stored in the particle system
///
///
/// Particle system that will be removed from the manager
///
public void RemoveParticleSystem(
ParticleSystem particleSystem
) where ParticleType : struct, IVertexType {
IParticleSystemHolder holder;
if(!this.particleSystems.TryGetValue(particleSystem, out holder)) {
throw new ArgumentException(
"Particle system has not been added to this manager", "particleSystem"
);
}
// Get rid of the particle system and unreference the primitive batch
// it was using for rendering
holder.ReleasePrimitiveBatch();
this.particleSystems.Remove(particleSystem);
this.holderArraysDirty = true;
}
/// Particle systems that are being managed by this instance
private Dictionary