#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