• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 
17 package com.badlogic.gdx.assets;
18 
19 import com.badlogic.gdx.assets.loaders.AssetLoader;
20 import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader;
21 import com.badlogic.gdx.assets.loaders.SynchronousAssetLoader;
22 import com.badlogic.gdx.files.FileHandle;
23 import com.badlogic.gdx.utils.Array;
24 import com.badlogic.gdx.utils.GdxRuntimeException;
25 import com.badlogic.gdx.utils.Logger;
26 import com.badlogic.gdx.utils.TimeUtils;
27 import com.badlogic.gdx.utils.async.AsyncExecutor;
28 import com.badlogic.gdx.utils.async.AsyncResult;
29 import com.badlogic.gdx.utils.async.AsyncTask;
30 
31 /** Responsible for loading an asset through an {@link AssetLoader} based on an {@link AssetDescriptor}.
32  *
33  * @author mzechner */
34 class AssetLoadingTask implements AsyncTask<Void> {
35 	AssetManager manager;
36 	final AssetDescriptor assetDesc;
37 	final AssetLoader loader;
38 	final AsyncExecutor executor;
39 	final long startTime;
40 
41 	volatile boolean asyncDone = false;
42 	volatile boolean dependenciesLoaded = false;
43 	volatile Array<AssetDescriptor> dependencies;
44 	volatile AsyncResult<Void> depsFuture = null;
45 	volatile AsyncResult<Void> loadFuture = null;
46 	volatile Object asset = null;
47 
48 	int ticks = 0;
49 	volatile boolean cancel = false;
50 
AssetLoadingTask(AssetManager manager, AssetDescriptor assetDesc, AssetLoader loader, AsyncExecutor threadPool)51 	public AssetLoadingTask (AssetManager manager, AssetDescriptor assetDesc, AssetLoader loader, AsyncExecutor threadPool) {
52 		this.manager = manager;
53 		this.assetDesc = assetDesc;
54 		this.loader = loader;
55 		this.executor = threadPool;
56 		startTime = manager.log.getLevel() == Logger.DEBUG ? TimeUtils.nanoTime() : 0;
57 	}
58 
59 	/** Loads parts of the asset asynchronously if the loader is an {@link AsynchronousAssetLoader}. */
60 	@Override
call()61 	public Void call () throws Exception {
62 		AsynchronousAssetLoader asyncLoader = (AsynchronousAssetLoader)loader;
63 		if (dependenciesLoaded == false) {
64 			dependencies = asyncLoader.getDependencies(assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
65 			if (dependencies != null) {
66 				removeDuplicates(dependencies);
67 				manager.injectDependencies(assetDesc.fileName, dependencies);
68 			} else {
69 				// if we have no dependencies, we load the async part of the task immediately.
70 				asyncLoader.loadAsync(manager, assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
71 				asyncDone = true;
72 			}
73 		} else {
74 			asyncLoader.loadAsync(manager, assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
75 		}
76 		return null;
77 	}
78 
79 	/** Updates the loading of the asset. In case the asset is loaded with an {@link AsynchronousAssetLoader}, the loaders
80 	 * {@link AsynchronousAssetLoader#loadAsync(AssetManager, String, FileHandle, AssetLoaderParameters)} method is first called on
81 	 * a worker thread. Once this method returns, the rest of the asset is loaded on the rendering thread via
82 	 * {@link AsynchronousAssetLoader#loadSync(AssetManager, String, FileHandle, AssetLoaderParameters)}.
83 	 * @return true in case the asset was fully loaded, false otherwise
84 	 * @throws GdxRuntimeException */
update()85 	public boolean update () {
86 		ticks++;
87 		if (loader instanceof SynchronousAssetLoader) {
88 			handleSyncLoader();
89 		} else {
90 			handleAsyncLoader();
91 		}
92 		return asset != null;
93 	}
94 
handleSyncLoader()95 	private void handleSyncLoader () {
96 		SynchronousAssetLoader syncLoader = (SynchronousAssetLoader)loader;
97 		if (!dependenciesLoaded) {
98 			dependenciesLoaded = true;
99 			dependencies = syncLoader.getDependencies(assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
100 			if (dependencies == null) {
101 				asset = syncLoader.load(manager, assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
102 				return;
103 			}
104 			removeDuplicates(dependencies);
105 			manager.injectDependencies(assetDesc.fileName, dependencies);
106 		} else {
107 			asset = syncLoader.load(manager, assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
108 		}
109 	}
110 
handleAsyncLoader()111 	private void handleAsyncLoader () {
112 		AsynchronousAssetLoader asyncLoader = (AsynchronousAssetLoader)loader;
113 		if (!dependenciesLoaded) {
114 			if (depsFuture == null) {
115 				depsFuture = executor.submit(this);
116 			} else {
117 				if (depsFuture.isDone()) {
118 					try {
119 						depsFuture.get();
120 					} catch (Exception e) {
121 						throw new GdxRuntimeException("Couldn't load dependencies of asset: " + assetDesc.fileName, e);
122 					}
123 					dependenciesLoaded = true;
124 					if (asyncDone) {
125 						asset = asyncLoader.loadSync(manager, assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
126 					}
127 				}
128 			}
129 		} else {
130 			if (loadFuture == null && !asyncDone) {
131 				loadFuture = executor.submit(this);
132 			} else {
133 				if (asyncDone) {
134 					asset = asyncLoader.loadSync(manager, assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
135 				} else if (loadFuture.isDone()) {
136 					try {
137 						loadFuture.get();
138 					} catch (Exception e) {
139 						throw new GdxRuntimeException("Couldn't load asset: " + assetDesc.fileName, e);
140 					}
141 					asset = asyncLoader.loadSync(manager, assetDesc.fileName, resolve(loader, assetDesc), assetDesc.params);
142 				}
143 			}
144 		}
145 	}
146 
resolve(AssetLoader loader, AssetDescriptor assetDesc)147 	private FileHandle resolve (AssetLoader loader, AssetDescriptor assetDesc) {
148 		if (assetDesc.file == null) assetDesc.file = loader.resolve(assetDesc.fileName);
149 		return assetDesc.file;
150 	}
151 
getAsset()152 	public Object getAsset () {
153 		return asset;
154 	}
155 
removeDuplicates(Array<AssetDescriptor> array)156 	private void removeDuplicates(Array<AssetDescriptor> array) {
157 		boolean ordered = array.ordered;
158 		array.ordered = true;
159 		for (int i = 0; i < array.size; ++i) {
160 			final String fn = array.get(i).fileName;
161 			final Class type = array.get(i).type;
162 			for (int j = array.size - 1; j > i; --j) {
163 				if (type == array.get(j).type && fn.equals(array.get(j).fileName))
164 					array.removeIndex(j);
165 			}
166 		}
167 		array.ordered = ordered;
168 	}
169 }
170