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