Home | History | Annotate | Download | only in asset
      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 
     73     public DesktopAssetManager(){
     74         this(null);
     75     }
     76 
     77     @Deprecated
     78     public DesktopAssetManager(boolean loadDefaults){
     79         this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Desktop.cfg"));
     80     }
     81 
     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 
    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 
    110     public void removeClassLoader(ClassLoader loader){
    111         if(classLoaders != null) synchronized(classLoaders) {
    112                 classLoaders.remove(loader);
    113             }
    114     }
    115 
    116     public List<ClassLoader> getClassLoaders(){
    117         return classLoaders;
    118     }
    119 
    120     public void setAssetEventListener(AssetEventListener listener){
    121         eventListener = listener;
    122     }
    123 
    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 
    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 
    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 
    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 
    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 
    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      */
    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      */
    195     public void addToCache(AssetKey key, Object asset){
    196         cache.addToCache(key, asset);
    197     }
    198 
    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      */
    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 
    315     public Object loadAsset(String name){
    316         return loadAsset(new AssetKey(name));
    317     }
    318 
    319     /**
    320      * Loads a texture.
    321      *
    322      * @return
    323      */
    324     public Texture loadTexture(TextureKey key){
    325         return (Texture) loadAsset(key);
    326     }
    327 
    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      */
    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 
    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 
    355     public Texture loadTexture(String name){
    356         return loadTexture(name, true);
    357     }
    358 
    359     public AudioData loadAudio(AudioKey key){
    360         return (AudioData) loadAsset(key);
    361     }
    362 
    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      */
    373     public BitmapFont loadFont(String name){
    374         return (BitmapFont) loadAsset(new AssetKey(name));
    375     }
    376 
    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      */
    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 
    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      */
    417     public Spatial loadModel(String name){
    418         return loadModel(new ModelKey(name));
    419     }
    420 
    421 }
    422