• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.jme3.asset;
34 
35 import com.jme3.asset.AssetCache.SmartAssetInfo;
36 import com.jme3.audio.AudioData;
37 import com.jme3.audio.AudioKey;
38 import com.jme3.font.BitmapFont;
39 import com.jme3.material.Material;
40 import com.jme3.scene.Spatial;
41 import com.jme3.shader.Shader;
42 import com.jme3.shader.ShaderKey;
43 import com.jme3.texture.Texture;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.net.URL;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Collections;
50 import java.util.List;
51 import java.util.logging.Level;
52 import java.util.logging.Logger;
53 
54 /**
55  * <code>AssetManager</code> is the primary method for managing and loading
56  * assets inside jME.
57  *
58  * @author Kirill Vainer
59  */
60 public class DesktopAssetManager implements AssetManager {
61 
62     private static final Logger logger = Logger.getLogger(AssetManager.class.getName());
63 
64     private final AssetCache cache = new AssetCache();
65     private final ImplHandler handler = new ImplHandler(this);
66 
67     private AssetEventListener eventListener = null;
68     private List<ClassLoader> classLoaders;
69 
70 //    private final ThreadingManager threadingMan = new ThreadingManager(this);
71 //    private final Set<AssetKey> alreadyLoadingSet = new HashSet<AssetKey>();
72 
DesktopAssetManager()73     public DesktopAssetManager(){
74         this(null);
75     }
76 
77     @Deprecated
DesktopAssetManager(boolean loadDefaults)78     public DesktopAssetManager(boolean loadDefaults){
79         this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Desktop.cfg"));
80     }
81 
DesktopAssetManager(URL configFile)82     public DesktopAssetManager(URL configFile){
83         if (configFile != null){
84             InputStream stream = null;
85             try{
86                 AssetConfig cfg = new AssetConfig(this);
87                 stream = configFile.openStream();
88                 cfg.loadText(stream);
89             }catch (IOException ex){
90                 logger.log(Level.SEVERE, "Failed to load asset config", ex);
91             }finally{
92                 if (stream != null)
93                     try{
94                         stream.close();
95                     }catch (IOException ex){
96                     }
97             }
98         }
99         logger.info("DesktopAssetManager created.");
100     }
101 
addClassLoader(ClassLoader loader)102     public void addClassLoader(ClassLoader loader){
103         if(classLoaders == null)
104             classLoaders = Collections.synchronizedList(new ArrayList<ClassLoader>());
105         synchronized(classLoaders) {
106             classLoaders.add(loader);
107         }
108     }
109 
removeClassLoader(ClassLoader loader)110     public void removeClassLoader(ClassLoader loader){
111         if(classLoaders != null) synchronized(classLoaders) {
112                 classLoaders.remove(loader);
113             }
114     }
115 
getClassLoaders()116     public List<ClassLoader> getClassLoaders(){
117         return classLoaders;
118     }
119 
setAssetEventListener(AssetEventListener listener)120     public void setAssetEventListener(AssetEventListener listener){
121         eventListener = listener;
122     }
123 
registerLoader(Class<? extends AssetLoader> loader, String ... extensions)124     public void registerLoader(Class<? extends AssetLoader> loader, String ... extensions){
125         handler.addLoader(loader, extensions);
126         if (logger.isLoggable(Level.FINER)){
127             logger.log(Level.FINER, "Registered loader: {0} for extensions {1}",
128               new Object[]{loader.getSimpleName(), Arrays.toString(extensions)});
129         }
130     }
131 
registerLoader(String clsName, String ... extensions)132     public void registerLoader(String clsName, String ... extensions){
133         Class<? extends AssetLoader> clazz = null;
134         try{
135             clazz = (Class<? extends AssetLoader>) Class.forName(clsName);
136         }catch (ClassNotFoundException ex){
137             logger.log(Level.WARNING, "Failed to find loader: "+clsName, ex);
138         }catch (NoClassDefFoundError ex){
139             logger.log(Level.WARNING, "Failed to find loader: "+clsName, ex);
140         }
141         if (clazz != null){
142             registerLoader(clazz, extensions);
143         }
144     }
145 
registerLocator(String rootPath, Class<? extends AssetLocator> locatorClass)146     public void registerLocator(String rootPath, Class<? extends AssetLocator> locatorClass){
147         handler.addLocator(locatorClass, rootPath);
148         if (logger.isLoggable(Level.FINER)){
149             logger.log(Level.FINER, "Registered locator: {0}",
150                     locatorClass.getSimpleName());
151         }
152     }
153 
registerLocator(String rootPath, String clsName)154     public void registerLocator(String rootPath, String clsName){
155         Class<? extends AssetLocator> clazz = null;
156         try{
157             clazz = (Class<? extends AssetLocator>) Class.forName(clsName);
158         }catch (ClassNotFoundException ex){
159             logger.log(Level.WARNING, "Failed to find locator: "+clsName, ex);
160         }catch (NoClassDefFoundError ex){
161             logger.log(Level.WARNING, "Failed to find loader: "+clsName, ex);
162         }
163         if (clazz != null){
164             registerLocator(rootPath, clazz);
165         }
166     }
167 
unregisterLocator(String rootPath, Class<? extends AssetLocator> clazz)168     public void unregisterLocator(String rootPath, Class<? extends AssetLocator> clazz){
169         handler.removeLocator(clazz, rootPath);
170         if (logger.isLoggable(Level.FINER)){
171             logger.log(Level.FINER, "Unregistered locator: {0}",
172                     clazz.getSimpleName());
173         }
174     }
175 
clearCache()176     public void clearCache(){
177         cache.deleteAllAssets();
178     }
179 
180     /**
181      * Delete an asset from the cache, returns true if it was deleted
182      * successfully.
183      * <br/><br/>
184      * <font color="red">Thread-safe.</font>
185      */
deleteFromCache(AssetKey key)186     public boolean deleteFromCache(AssetKey key){
187         return cache.deleteFromCache(key);
188     }
189 
190     /**
191      * Adds a resource to the cache.
192      * <br/><br/>
193      * <font color="red">Thread-safe.</font>
194      */
addToCache(AssetKey key, Object asset)195     public void addToCache(AssetKey key, Object asset){
196         cache.addToCache(key, asset);
197     }
198 
locateAsset(AssetKey<?> key)199     public AssetInfo locateAsset(AssetKey<?> key){
200         if (handler.getLocatorCount() == 0){
201             logger.warning("There are no locators currently"+
202                            " registered. Use AssetManager."+
203                            "registerLocator() to register a"+
204                            " locator.");
205             return null;
206         }
207 
208         AssetInfo info = handler.tryLocate(key);
209         if (info == null){
210             logger.log(Level.WARNING, "Cannot locate resource: {0}", key);
211         }
212 
213         return info;
214     }
215 
216     /**
217      * <font color="red">Thread-safe.</font>
218      *
219      * @param <T>
220      * @param key
221      * @return
222      */
loadAsset(AssetKey<T> key)223       public <T> T loadAsset(AssetKey<T> key){
224         if (key == null)
225             throw new IllegalArgumentException("key cannot be null");
226 
227         if (eventListener != null)
228             eventListener.assetRequested(key);
229 
230         AssetKey smartKey = null;
231         Object o = null;
232         if (key.shouldCache()){
233             if (key.useSmartCache()){
234                 SmartAssetInfo smartInfo = cache.getFromSmartCache(key);
235                 if (smartInfo != null){
236                     smartKey = smartInfo.smartKey.get();
237                     if (smartKey != null){
238                         o = smartInfo.asset;
239                     }
240                 }
241             }else{
242                 o = cache.getFromCache(key);
243             }
244         }
245         if (o == null){
246             AssetLoader loader = handler.aquireLoader(key);
247             if (loader == null){
248                 throw new IllegalStateException("No loader registered for type \"" +
249                                                 key.getExtension() + "\"");
250             }
251 
252             if (handler.getLocatorCount() == 0){
253                 throw new IllegalStateException("There are no locators currently"+
254                                                 " registered. Use AssetManager."+
255                                                 "registerLocator() to register a"+
256                                                 " locator.");
257             }
258 
259             AssetInfo info = handler.tryLocate(key);
260             if (info == null){
261                 if (handler.getParentKey() != null && eventListener != null){
262                     // Inform event listener that an asset has failed to load.
263                     // If the parent AssetLoader chooses not to propagate
264                     // the exception, this is the only means of finding
265                     // that something went wrong.
266                     eventListener.assetDependencyNotFound(handler.getParentKey(), key);
267                 }
268                 throw new AssetNotFoundException(key.toString());
269             }
270 
271             try {
272                 handler.establishParentKey(key);
273                 o = loader.load(info);
274             } catch (IOException ex) {
275                 throw new AssetLoadException("An exception has occured while loading asset: " + key, ex);
276             } finally {
277                 handler.releaseParentKey(key);
278             }
279             if (o == null){
280                 throw new AssetLoadException("Error occured while loading asset \"" + key + "\" using" + loader.getClass().getSimpleName());
281             }else{
282                 if (logger.isLoggable(Level.FINER)){
283                     logger.log(Level.FINER, "Loaded {0} with {1}",
284                             new Object[]{key, loader.getClass().getSimpleName()});
285                 }
286 
287                 // do processing on asset before caching
288                 o = key.postProcess(o);
289 
290                 if (key.shouldCache())
291                     cache.addToCache(key, o);
292 
293                 if (eventListener != null)
294                     eventListener.assetLoaded(key);
295             }
296         }
297 
298         // object o is the asset
299         // create an instance for user
300         T clone = (T) key.createClonedInstance(o);
301 
302         if (key.useSmartCache()){
303             if (smartKey != null){
304                 // smart asset was already cached, use original key
305                 ((Asset)clone).setKey(smartKey);
306             }else{
307                 // smart asset was cached on this call, use our key
308                 ((Asset)clone).setKey(key);
309             }
310         }
311 
312         return clone;
313     }
314 
loadAsset(String name)315     public Object loadAsset(String name){
316         return loadAsset(new AssetKey(name));
317     }
318 
319     /**
320      * Loads a texture.
321      *
322      * @return
323      */
loadTexture(TextureKey key)324     public Texture loadTexture(TextureKey key){
325         return (Texture) loadAsset(key);
326     }
327 
loadMaterial(String name)328     public Material loadMaterial(String name){
329         return (Material) loadAsset(new MaterialKey(name));
330     }
331 
332     /**
333      * Loads a texture.
334      *
335      * @param name
336      * @param generateMipmaps Enable if applying texture to 3D objects, disable
337      * for GUI/HUD elements.
338      * @return
339      */
loadTexture(String name, boolean generateMipmaps)340     public Texture loadTexture(String name, boolean generateMipmaps){
341         TextureKey key = new TextureKey(name, true);
342         key.setGenerateMips(generateMipmaps);
343         key.setAsCube(false);
344         return loadTexture(key);
345     }
346 
loadTexture(String name, boolean generateMipmaps, boolean flipY, boolean asCube, int aniso)347     public Texture loadTexture(String name, boolean generateMipmaps, boolean flipY, boolean asCube, int aniso){
348         TextureKey key = new TextureKey(name, flipY);
349         key.setGenerateMips(generateMipmaps);
350         key.setAsCube(asCube);
351         key.setAnisotropy(aniso);
352         return loadTexture(key);
353     }
354 
loadTexture(String name)355     public Texture loadTexture(String name){
356         return loadTexture(name, true);
357     }
358 
loadAudio(AudioKey key)359     public AudioData loadAudio(AudioKey key){
360         return (AudioData) loadAsset(key);
361     }
362 
loadAudio(String name)363     public AudioData loadAudio(String name){
364         return loadAudio(new AudioKey(name, false));
365     }
366 
367     /**
368      * Loads a bitmap font with the given name.
369      *
370      * @param name
371      * @return
372      */
loadFont(String name)373     public BitmapFont loadFont(String name){
374         return (BitmapFont) loadAsset(new AssetKey(name));
375     }
376 
loadGLSLLibrary(AssetKey key)377     public InputStream loadGLSLLibrary(AssetKey key){
378         return (InputStream) loadAsset(key);
379     }
380 
381     /**
382      * Load a vertex/fragment shader combo.
383      *
384      * @param key
385      * @return
386      */
loadShader(ShaderKey key)387     public Shader loadShader(ShaderKey key){
388         // cache abuse in method
389         // that doesn't use loaders/locators
390         Shader s = (Shader) cache.getFromCache(key);
391         if (s == null){
392             String vertName = key.getVertName();
393             String fragName = key.getFragName();
394 
395             String vertSource = (String) loadAsset(new AssetKey(vertName));
396             String fragSource = (String) loadAsset(new AssetKey(fragName));
397 
398             s = new Shader(key.getLanguage());
399             s.addSource(Shader.ShaderType.Vertex,   vertName, vertSource, key.getDefines().getCompiled());
400             s.addSource(Shader.ShaderType.Fragment, fragName, fragSource, key.getDefines().getCompiled());
401 
402             cache.addToCache(key, s);
403         }
404         return s;
405     }
406 
loadModel(ModelKey key)407     public Spatial loadModel(ModelKey key){
408         return (Spatial) loadAsset(key);
409     }
410 
411     /**
412      * Load a model.
413      *
414      * @param name
415      * @return
416      */
loadModel(String name)417     public Spatial loadModel(String name){
418         return loadModel(new ModelKey(name));
419     }
420 
421 }
422