#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; using Microsoft.Xna.Framework.Graphics; using Nuclex.Graphics.Batching; using Nuclex.Support; namespace Nuclex.Graphics.SpecialEffects.Particles.HighLevel { partial class ParticleSystemManager { #region class PruneAsyncResult /// Asynchronous result handle for the pruning process private class PruneAsyncResult : IAsyncResult, IDisposable { /// /// Initializes a new asynchronous result for particle system prunes /// /// Particle system manager being pruned public PruneAsyncResult(ParticleSystemManager manager) { this.manager = manager; this.completed = true; this.stepCompletedDelegate = new AsyncCallback(stepCompleted); } /// Immediately releases all resources owned by the instance public void Dispose() { if(this.doneEvent != null) { this.doneEvent.Close(); this.doneEvent = null; } } /// Initializes a new result for asynchronous pruning /// /// Callback that will be invoked when pruning has finished /// /// /// User-defined state that will be passed to the callback /// public void Start(AsyncCallback callback, object state) { lock(this) { this.completed = false; if(this.doneEvent != null) { this.doneEvent.Reset(); } } this.exception = null; this.particleSystemCount = this.manager.particleSystems.Count; Interlocked.Exchange(ref this.currentParticleSystem, -1); this.callback = callback; this.state = state; stepCompleted(null); } /// User-defined state provided in the BeginPrune() method public object AsyncState { get { return this.state; } } /// Exception that occured during asynchronous processing public Exception AsyncException { get { return this.exception; } } /// WaitHandle that can be used to wait for pruning to finish public WaitHandle AsyncWaitHandle { get { if(this.doneEvent == null) { lock(this) { if(this.doneEvent == null) { this.doneEvent = new ManualResetEvent(this.completed); } } } return this.doneEvent; } } /// Whether the pruning process has completed synchronously public bool CompletedSynchronously { get { return false; } } /// Whether the pruning process has already finished public bool IsCompleted { get { return this.completed; } } /// Called when a single particle system has finished updating /// /// Asynchronous result handle of the pruning process /// private void stepCompleted(IAsyncResult asyncResult) { int current = Interlocked.Increment(ref this.currentParticleSystem); if(asyncResult != null) { try { this.manager.particleSystemHolders[current - 1].EndPrune( asyncResult ); } catch(Exception exception) { this.exception = exception; reportCompletion(); return; } } if(current == this.particleSystemCount) { reportCompletion(); } else { this.stepAsyncResult = this.manager.particleSystemHolders[ current ].BeginPrune(this.stepCompletedDelegate, null); } } /// Reports the completion of the pruning process to the caller private void reportCompletion() { AsyncCallback callbackCopy; lock(this) { callbackCopy = this.callback; this.completed = true; if(this.doneEvent != null) { this.doneEvent.Set(); } } if(callbackCopy != null) { callbackCopy(this); } } /// Index of the particle system being currently pruned private int currentParticleSystem; /// Number of particles systems that will be pruned private int particleSystemCount; /// Asynchronous result of the currently pruning particle sytem private volatile IAsyncResult stepAsyncResult; /// Delegate for the stepCompleted() method private AsyncCallback stepCompletedDelegate; /// Particle system manager the async result belongs to private ParticleSystemManager manager; /// Callback that will be invoked after pruning has finished private AsyncCallback callback; /// User-defined state that will be passed to the callback private object state; /// Wait handle that can be used to wait for pruning to finish private volatile ManualResetEvent doneEvent; /// Whether pruning has already finished private volatile bool completed; /// Exception that occured during asynchronous processing private volatile Exception exception; } #endregion // class PruneAsyncResult #region class UpdateAsyncResult /// Asynchronous result handle for the update process private class UpdateAsyncResult : IAsyncResult, IDisposable { /// /// Initializes a new asynchronous result for particle system updates /// /// Particle system manager being updated public UpdateAsyncResult(ParticleSystemManager manager) { this.manager = manager; this.completed = true; this.stepCompletedDelegate = new AsyncCallback(stepCompleted); } /// Immediateyl releases all resources owned by the instance public void Dispose() { if(this.doneEvent != null) { this.doneEvent.Close(); this.doneEvent = null; } } /// Initializes a new result for an asynchronous update /// /// Number of updates that will be performed on the particle systems /// /// Number of threads that will be used /// /// Callback that will be invoked when updating has finished /// /// /// User-defined state that will be passed to the callback /// public void Start(int updates, int threads, AsyncCallback callback, object state) { lock(this) { this.completed = false; if(this.doneEvent != null) { this.doneEvent.Reset(); } } this.exception = null; this.particleSystemCount = this.manager.particleSystems.Count; this.currentParticleSystem = -1; this.updates = updates; this.threads = threads; this.callback = callback; this.state = state; stepCompleted(null); } /// User-defined state provided in the BeginUpdate() method public object AsyncState { get { return this.state; } } /// Exception that occured during asynchronous processing public Exception AsyncException { get { return this.exception; } } /// WaitHandle that can be used to wait for updating to finish public WaitHandle AsyncWaitHandle { get { if(this.doneEvent == null) { lock(this) { if(this.doneEvent == null) { this.doneEvent = new ManualResetEvent(this.completed); } } } return this.doneEvent; } } /// Whether the updating process has completed synchronously public bool CompletedSynchronously { get { return false; } } /// Whether the updating process has already finished public bool IsCompleted { get { return this.completed; } } /// Called when a single particle system has finished updating /// /// Asynchronous result handle of the update process /// private void stepCompleted(IAsyncResult asyncResult) { int current = Interlocked.Increment(ref this.currentParticleSystem); if(asyncResult != null) { try { this.manager.particleSystemHolders[current - 1].EndUpdate( asyncResult ); } catch(Exception exception) { this.exception = exception; reportCompletion(); return; } } if(current == this.particleSystemCount) { reportCompletion(); } else { this.stepAsyncResult = this.manager.particleSystemHolders[ current ].BeginUpdate(this.updates, this.threads, this.stepCompletedDelegate, null); } } /// Reports the completion of the update to the caller private void reportCompletion() { AsyncCallback callbackCopy; lock(this) { callbackCopy = this.callback; this.completed = true; if(this.doneEvent != null) { this.doneEvent.Set(); } } if(callbackCopy != null) { callbackCopy(this); } } /// Index of the particle system being currently updated private int currentParticleSystem; /// Number of particles systems that will be updated private int particleSystemCount; /// Number of updates to perform on the particle systems private int updates; /// Number of threads to use for the updates private int threads; /// Asynchronous result of the currently updating particle sytem private volatile IAsyncResult stepAsyncResult; /// Delegate for the stepCompleted() method private AsyncCallback stepCompletedDelegate; /// Particle system manager the async result belongs to private ParticleSystemManager manager; /// Callback that will be invoked after updating has finished private AsyncCallback callback; /// User-defined state that will be passed to the callback private object state; /// Wait handle that can be used to wait for pruning to finish private volatile ManualResetEvent doneEvent; /// Whether the update has already completed private volatile bool completed; /// Exception that occured during asynchronous processing private volatile Exception exception; } #endregion // class UpdateAsyncResult } } // namespace Nuclex.Graphics.SpecialEffects.Particles.HighLevel