/// <summary> /// Reloads the specified asset. /// </summary> /// <param name="assetName">Name of the asset to load</param> /// <returns>The new reference to the reloaded asset</returns> public object Reload(string assetName, AssetLoadedHandler Callback) { if (mCache.ContainsKey(assetName)) { AssetTracker oldAssetTracker = mCache[assetName]; // Remove tracker so Load<T>() will create a new one mCache.Remove(assetName); mCacheNames.Remove(assetName); // Load it again object asset = Load(assetName, Callback); // Invoke AssetChanged event oldAssetTracker.OnAssetChanged(new AssetChangedEventArgs(asset)); // Destroy previous tracker DisposeAssetTracker(oldAssetTracker, true); return(asset); } else { return(Load(assetName, Callback)); } }
/// <summary> /// Constructor for convenience /// </summary> internal LoadAsyncParams(string name, AssetLoaded loadedMethod) { ItemLoadedMethods.Add(loadedMethod); Tracker = new AssetTracker(); Tracker.AssetName = name; Tracker.RefCount = 1; Tracker.Status = EAssetStatus.Loading; }
/// <summary> /// Asyncronously loads the specified asset array /// </summary> /// <param name="assetNames">Names of assets to laod</param> /// <param name="itemLoadedMethod">Method to call once load is completed</param> /// <returns>AssetTracker array of assets to be loaded. Allows to poll the asset status if desired</returns> public AssetTracker[] LoadAsync(string[] assetNames, AssetLoaded itemLoadedMethod, AssetLoadedHandler Callback) { AssetTracker[] assets = new AssetTracker[assetNames.Length]; for (int i = 0; i < assets.Length; i++) { assets[i] = LoadAsync(assetNames[i], itemLoadedMethod, Callback); } return(assets); }
/// <summary> /// Force an asset to be disposed. Optionally releases child assets /// </summary> /// <param name="assetName">Name of asset to unload</param> /// <param name="releaseChildren">Release child assets</param> public void Unload(string assetName, bool releaseChildren) { if (mCache.ContainsKey(assetName)) { AssetTracker tracker = mCache[assetName]; // Fire changed event tracker.OnAssetChanged(new AssetChangedEventArgs(null)); // Destroy disposables DisposeAssetTracker(tracker, releaseChildren); // Remove from dictionary mCache.Remove(assetName); mCacheNames.Remove(assetName); } }
/// <summary> /// Release asset. Decrements the reference count and /// removes child assets when the count is zero /// </summary> /// <param name="assetName">Asset to release</param> public void Release(string assetName) { if (mCache.ContainsKey(assetName)) { AssetTracker tracker = mCache[assetName]; tracker.RefCount--; if (tracker.RefCount == 0) { tracker.OnAssetChanged(new AssetChangedEventArgs(null)); DisposeAssetTracker(tracker, true); // Remove from dictionary mCache.Remove(assetName); mCacheNames.Remove(assetName); } } }
/// <summary> /// Destroy IDisposables that were tracked by this asset but do not /// exist as assets in their own right. This will also dispose the /// unmanaged internals like vertex and index buffers /// </summary> /// <param name="tracker">AssetTracker to dispose</param> /// <param name="releaseChildren">If true, child assets will be released</param> private void DisposeAssetTracker(AssetTracker tracker, bool releaseChildren) { // Invoke asset changed event. tracker.OnAssetChanged(new AssetChangedEventArgs(null)); // Mark tracker as disposed tracker.Status = EAssetStatus.Disposed; // Destroy tracked disposables foreach (IDisposable disposable in tracker.Disposables) { disposable.Dispose(); } // Dispose the actual asset, if possible if (tracker.Asset is IDisposable) { ((IDisposable)tracker.Asset).Dispose(); } // Handle child assets foreach (string childAsset in tracker.RefersTo) { if (mCache.ContainsKey(childAsset)) { // Maintain child reference list mCache[childAsset].ReferredToBy.Remove(tracker.AssetName); // release child assets if requested if (releaseChildren) { Release(childAsset); } } } }
/// <summary> /// Asyncronously loads the specified asset array /// </summary> /// <param name="assetNames">Names of assets to laod</param> /// <param name="itemLoadedMethod">Method to call once load is completed</param> /// <returns>AssetTracker array of assets to be loaded. Allows to poll the asset status if desired</returns> public AssetTracker[] LoadAsync(string[] assetNames, AssetLoaded itemLoadedMethod, AssetLoadedHandler Callback) { AssetTracker[] assets = new AssetTracker[assetNames.Length]; for (int i = 0; i < assets.Length; i++) assets[i] = LoadAsync(assetNames[i], itemLoadedMethod, Callback); return assets; }
/// <summary> /// Asyncronously loads the specified asset /// </summary> /// <param name="assetName">Name of asset to laod</param> /// <param name="itemLoadedMethod">Method to call once load is completed</param> /// <returns>AssetTracker of asset to be loaded. Allows to poll the asset status if desired</returns> public AssetTracker LoadAsync(string assetName, AssetLoaded itemLoadedMethod, AssetLoadedHandler Callback) { AssetTracker tracker = null; // Check if asset is already loaded if (mCache.ContainsKey(assetName)) { tracker = mCache[assetName]; // Increment reference count tracker.RefCount++; // Call the specified item loaded method if (itemLoadedMethod != null) { itemLoadedMethod(tracker.Asset); } } else { if (mLoadThread == null) { // First time LoadAsync has been called so // initialise thread, reset event and queue mLoadThread = new Thread(new ThreadStart(LoadingThreadWorker)); mLoadItemsQueue = new Queue <LoadAsyncParams>(); mLoadResetEvent = new AutoResetEvent(false); // Start thread. It will wait once queue is empty mLoadThread.Start(); } // Create the async argument structure and enqueue it for async load. lock (mLoadItemsQueue) { // first check if this item is already enqueued Queue <LoadAsyncParams> .Enumerator enumer = mLoadItemsQueue.GetEnumerator(); while (enumer.MoveNext()) { if (enumer.Current.Tracker.AssetName == assetName) { // Register the itemLoaded method enumer.Current.ItemLoadedMethods.Add(itemLoadedMethod); tracker = enumer.Current.Tracker; tracker.RefCount++; break; } } // Item not already queued for loading if (tracker == null) { LoadAsyncParams args = new LoadAsyncParams(assetName, itemLoadedMethod); tracker = args.Tracker; mLoadItemsQueue.Enqueue(args); } } // Tell loading thread to stop waiting mLoadResetEvent.Set(); } tracker.OnAssetLoaded = Callback; // Return tracker. Allows async caller to poll loaded status return(tracker); }
private object Load(string assetName, AssetTracker tracker, AssetLoadedHandler Callback) { // Return asset if currently loaded if (mCache.ContainsKey(assetName)) { // Get asset tracker AssetTracker trackerExisting = mCache[assetName]; object asset = trackerExisting.Asset; // Increment tracker's reference count after the cast as the cast will // throw an exception if the incorrect generic type parameter is given trackerExisting.RefCount++; // Maintain the reference lists to show that this asset was loaded by // the asset on the top of the stack if (mCacheLoadingStack.Count > 0) { mCacheLoadingStack.Peek().RefersTo.Add(assetName); trackerExisting.ReferredToBy.Add(mCacheLoadingStack.Peek().AssetName); } return(asset); } // Need to load the asset. Create an AssetTracker to track it // unless we have been passed an existing AssetTracker if (tracker == null) { // Initialise tracker tracker = new AssetTracker(); tracker.RefCount = 1; tracker.AssetName = assetName; } // Stack count will be zero if called by user. // Otherwise, Load<T> was called internally by ReadAsset<T> if (mCacheLoadingStack.Count > 0) { // Maintain the reference lists // The asset on the top of the stack refers to this asset mCacheLoadingStack.Peek().RefersTo.Add(assetName); // This asset was loaded by the asset on the top of the stack tracker.ReferredToBy.Add(mCacheLoadingStack.Peek().AssetName); } // Put current asset tracker on top of the stack // for next call to Load<T> mCacheLoadingStack.Push(tracker); try { tracker.Asset = ReadAsset(assetName, tracker.TrackDisposableAsset); tracker.Asset = Callback(tracker); // Ensure the list of disposables doesn't refer to the // actual asset, or to any assets in the loadedAssets Dictionary. // Best to do this now to avoid multiple disposing later tracker.Disposables.RemoveAll(delegate(IDisposable d) { string tmp = ""; return(tracker.Asset == d || SearchForAsset(d, out tmp)); }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Asset.Load() Exception\n" + ex.ToString()); } finally { // Asset has been loaded so the top tracker is not needed on the stack mCacheLoadingStack.Pop(); } // Store the asset and it's disposables list mCache.Add(assetName, tracker); mCacheNames.Add(assetName); // Mark tracker as ready to use tracker.Status = EAssetStatus.Active; // Return loaded asset return(tracker.Asset); }
/// <summary> /// Destroy IDisposables that were tracked by this asset but do not /// exist as assets in their own right. This will also dispose the /// unmanaged internals like vertex and index buffers /// </summary> /// <param name="tracker">AssetTracker to dispose</param> /// <param name="releaseChildren">If true, child assets will be released</param> private void DisposeAssetTracker( AssetTracker tracker, bool releaseChildren ) { // Invoke asset changed event. tracker.OnAssetChanged( new AssetChangedEventArgs( null ) ); // Mark tracker as disposed tracker.Status = EAssetStatus.Disposed; // Destroy tracked disposables foreach( IDisposable disposable in tracker.Disposables ) { disposable.Dispose(); } // Dispose the actual asset, if possible if( tracker.Asset is IDisposable ) ( (IDisposable)tracker.Asset ).Dispose(); // Handle child assets foreach( string childAsset in tracker.RefersTo ) { if( mCache.ContainsKey( childAsset ) ) { // Maintain child reference list mCache[ childAsset ].ReferredToBy.Remove( tracker.AssetName ); // release child assets if requested if( releaseChildren ) Release( childAsset ); } } }
private object Load( string assetName, AssetTracker tracker, AssetLoadedHandler Callback ) { // Return asset if currently loaded if( mCache.ContainsKey( assetName ) ) { // Get asset tracker AssetTracker trackerExisting = mCache[ assetName ]; object asset = trackerExisting.Asset; // Increment tracker's reference count after the cast as the cast will // throw an exception if the incorrect generic type parameter is given trackerExisting.RefCount++; // Maintain the reference lists to show that this asset was loaded by // the asset on the top of the stack if( mCacheLoadingStack.Count > 0 ) { mCacheLoadingStack.Peek().RefersTo.Add( assetName ); trackerExisting.ReferredToBy.Add( mCacheLoadingStack.Peek().AssetName ); } return asset; } // Need to load the asset. Create an AssetTracker to track it // unless we have been passed an existing AssetTracker if( tracker == null ) { // Initialise tracker tracker = new AssetTracker(); tracker.RefCount = 1; tracker.AssetName = assetName; } // Stack count will be zero if called by user. // Otherwise, Load<T> was called internally by ReadAsset<T> if( mCacheLoadingStack.Count > 0 ) { // Maintain the reference lists // The asset on the top of the stack refers to this asset mCacheLoadingStack.Peek().RefersTo.Add( assetName ); // This asset was loaded by the asset on the top of the stack tracker.ReferredToBy.Add( mCacheLoadingStack.Peek().AssetName ); } // Put current asset tracker on top of the stack // for next call to Load<T> mCacheLoadingStack.Push( tracker ); try { tracker.Asset = ReadAsset( assetName, tracker.TrackDisposableAsset ); tracker.Asset = Callback( tracker ); // Ensure the list of disposables doesn't refer to the // actual asset, or to any assets in the loadedAssets Dictionary. // Best to do this now to avoid multiple disposing later tracker.Disposables.RemoveAll( delegate( IDisposable d ) { string tmp = ""; return tracker.Asset == d || SearchForAsset( d, out tmp ); } ); } catch( Exception ex ) { System.Diagnostics.Debug.WriteLine( "Asset.Load() Exception\n" + ex.ToString() ); } finally { // Asset has been loaded so the top tracker is not needed on the stack mCacheLoadingStack.Pop(); } // Store the asset and it's disposables list mCache.Add( assetName, tracker ); mCacheNames.Add( assetName ); // Mark tracker as ready to use tracker.Status = EAssetStatus.Active; // Return loaded asset return tracker.Asset; }