/// <summary> /// Reloads the specified asset. /// </summary> /// <typeparam name="T">The Type of asset to reload</typeparam> /// <param name="assetName">Name of the asset to load</param> /// <returns>The new reference to the reloaded asset</returns> public T Reload <T>(string assetName) { if (loadedAssets.ContainsKey(assetName)) { AssetTracker oldAssetTracker = loadedAssets[assetName]; // Remove tracker so Load<T>() will create a new one loadedAssets.Remove(assetName); loadedAssetNames.Remove(assetName); // Load it again T asset = Load <T>(assetName); // Invoke AssetChanged event oldAssetTracker.OnAssetChanged(asset); // Destroy previous tracker DisposeAssetTracker(oldAssetTracker, true); return(asset); } else { return(Load <T>(assetName)); } }
/// <summary> /// Constructor for convenience /// </summary> internal LoadAsyncParams(Type type, string name, AssetLoaded loadedMethod) { AssetType = type; ItemLoadedMethods.Add(loadedMethod); Tracker = new AssetTracker(); Tracker.AssetName = name; Tracker.RefCount = 1; Tracker.Status = AssetStatus.Loading; }
/// <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 (assetName != null && loadedAssets.ContainsKey(assetName)) { AssetTracker tracker = loadedAssets[assetName]; // Fire changed event tracker.OnAssetChanged(null); // Destroy disposables DisposeAssetTracker(tracker, releaseChildren); // Remove from dictionary loadedAssets.Remove(assetName); loadedAssetNames.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 (assetName != null && loadedAssets.ContainsKey(assetName)) { AssetTracker tracker = loadedAssets[assetName]; tracker.RefCount--; if (tracker.RefCount == 0) { tracker.OnAssetChanged(null); DisposeAssetTracker(tracker, true); // Remove from dictionary loadedAssets.Remove(assetName); loadedAssetNames.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(null); // Mark tracker as disposed tracker.Status = AssetStatus.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 (loadedAssets.ContainsKey(childAsset)) { // Maintain child reference list loadedAssets[childAsset].ReferredToBy.Remove(tracker.AssetName); // release child assets if requested if (releaseChildren) { Release(childAsset); } } } }
/// <summary> /// Asyncronously loads the specified asset /// </summary> /// <typeparam name="T">Generic type parameter</typeparam> /// <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 /// users to poll the asset status if desired</returns> public AssetTracker LoadAsync <T>(string assetName, AssetLoaded itemLoadedMethod) { AssetTracker tracker = null; // Check if asset is already loaded if (loadedAssets.ContainsKey(assetName)) { tracker = loadedAssets[assetName]; // Increment reference count tracker.RefCount++; // Call the specified item loaded method if (itemLoadedMethod != null) { itemLoadedMethod(tracker.Asset); } } else { if (loadThread == null) { // First time LoadAsync has been called so // initialise thread, reset event and queue loadThread = new Thread(new ThreadStart(LoadingThreadWorker)); loadThread.Name = "File Loading Worker"; loadItemsQueue = new Queue <LoadAsyncParams>(); loadResetEvent = new AutoResetEvent(false); //reset the request flag to close the thread mCloseRequested = false; // Start thread. It will wait once queue is empty loadThread.Start(); } // Create the async argument structure and enqueue it for async load. lock (loadItemsQueue) { // first check if this item is already enqueued Queue <LoadAsyncParams> .Enumerator enumer = loadItemsQueue.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(typeof(T), assetName, itemLoadedMethod); tracker = args.Tracker; loadItemsQueue.Enqueue(args); } } // Tell loading thread to stop waiting loadResetEvent.Set(); } // Return tracker. Allows async caller to poll loaded status return(tracker); }
/// <summary> /// Return the specified asset. Read it from disk if not available /// </summary> /// <typeparam name="T">The Type of asset to load</typeparam> /// <param name="assetName">Name of the asset to load</param> /// <param name="tracker">An AssetTracker to use when loading this asset. May be null</param> /// <param name="forceReadAsset">if set to <c>true</c> [force read asset].</param> /// <returns> /// A reference to the loaded asset /// </returns> public T LoadToTracker <T>(string assetName, AssetTracker tracker, bool forceReadAsset) { // Return asset if currently loaded if (!forceReadAsset && loadedAssets.ContainsKey(assetName)) { // Get asset tracker AssetTracker trackerExisting = loadedAssets[assetName]; // Get asset as correct type T asset = (T)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 (loadingAssetsStack.Count > 0) { loadingAssetsStack.Peek().RefersTo.Add(assetName); trackerExisting.ReferredToBy.Add(loadingAssetsStack.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 (loadingAssetsStack.Count > 0) { // Maintain the reference lists // The asset on the top of the stack refers to this asset loadingAssetsStack.Peek().RefersTo.Add(assetName); // This asset was loaded by the asset on the top of the stack tracker.ReferredToBy.Add(loadingAssetsStack.Peek().AssetName); } // Put current asset tracker on top of the stack // for next call to Load<T> loadingAssetsStack.Push(tracker); try { // Preparation complete. Now finally read the asset from disk. // This is where the internal magic happens. #if WINDOWS string fileName; if (UseSourceAssets && TrySearchForValidAssetSource <T>(assetName, out fileName)) { tracker.Asset = SourceAssetLoaders[typeof(T)].loadAssetDelegate(fileName); } else #endif tracker.Asset = ReadAsset <T>(assetName, tracker.TrackDisposableAsset); // 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)); }); } finally { // Asset has been loaded so the top tracker is not needed on the stack loadingAssetsStack.Pop(); } // Store the asset and it's disposables list if (forceReadAsset) { untrackedAssets.Add(tracker); } else { loadedAssets.Add(assetName, tracker); loadedAssetNames.Add(assetName); } // Mark tracker as ready to use tracker.Status = AssetStatus.Active; // Return loaded asset return((T)tracker.Asset); }