* AssetCache is now an interface and can be extended by user. Moved to com.jme3.asset.cache package.
* Added 3 implementations of AssetCache: SimpleAssetCache, WeakRefAssetCache and WeakRefCloneAssetCache * Added AssetProcessor interface that handles cloning and post processing of assets after they are loaded * AssetKey can now configure which cache/processor to use for a particular asset type * Added AssetManager unregisterLoader method * AssetManager now supports more than one AssetLoadListener * Javadoc improvements in AssetManager * Asset interface now renamed to CloneableSmartAsset (which more accurately describes its behavior and use case) * DesktopAssetManager now makes proper use of the new AssetProcessor/AssetCache classes when handling asset loading * Added proper equals/hashCode methods to many AssetKey subclasses, which is required for the new system to work properly * All AssetKeys were rewritten to work with the new asset system * loadAsset(AudioKey) now returns an AudioNode and not AudioData, similar to the behavior of loadAsset(TextureKey) returning a Texture and not an Image. Because of that, the key storage in AudioData has been removed. * Texture, Spatial, and Material are all cloneable smart assets now and will be cleared from the cache when all instances become unreachable * Improved the existing TestAssetCache test to make sure the new system works git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9309 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
0c37fc46e9
commit
bd4214f3bd
@ -1,131 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.asset; |
||||
|
||||
import java.lang.ref.WeakReference; |
||||
import java.util.HashMap; |
||||
import java.util.WeakHashMap; |
||||
|
||||
/** |
||||
* An <code>AssetCache</code> allows storage of loaded resources in order |
||||
* to improve their access time if they are requested again in a short period |
||||
* of time. The AssetCache stores weak references to the resources, allowing |
||||
* Java's garbage collector to request deletion of rarely used resources |
||||
* when heap memory is low. |
||||
*/ |
||||
public class AssetCache { |
||||
|
||||
public static final class SmartAssetInfo { |
||||
public WeakReference<AssetKey> smartKey; |
||||
public Asset asset; |
||||
} |
||||
|
||||
private final WeakHashMap<AssetKey, SmartAssetInfo> smartCache |
||||
= new WeakHashMap<AssetKey, SmartAssetInfo>(); |
||||
private final HashMap<AssetKey, Object> regularCache = new HashMap<AssetKey, Object>(); |
||||
|
||||
/** |
||||
* Adds a resource to the cache. |
||||
* <br/><br/> |
||||
* <font color="red">Thread-safe.</font> |
||||
* @see #getFromCache(java.lang.String) |
||||
*/ |
||||
public void addToCache(AssetKey key, Object obj){ |
||||
synchronized (regularCache){ |
||||
if (obj instanceof Asset && key.useSmartCache()){ |
||||
// put in smart cache
|
||||
Asset asset = (Asset) obj; |
||||
asset.setKey(null); // no circular references
|
||||
SmartAssetInfo smartInfo = new SmartAssetInfo(); |
||||
smartInfo.asset = asset; |
||||
// use the original key as smart key
|
||||
smartInfo.smartKey = new WeakReference<AssetKey>(key); |
||||
smartCache.put(key, smartInfo); |
||||
}else{ |
||||
// put in regular cache
|
||||
regularCache.put(key, obj); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Delete an asset from the cache, returns true if it was deleted successfuly. |
||||
* <br/><br/> |
||||
* <font color="red">Thread-safe.</font> |
||||
*/ |
||||
public boolean deleteFromCache(AssetKey key){ |
||||
synchronized (regularCache){ |
||||
if (key.useSmartCache()){ |
||||
return smartCache.remove(key) != null; |
||||
}else{ |
||||
return regularCache.remove(key) != null; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets an object from the cache given an asset key. |
||||
* <br/><br/> |
||||
* <font color="red">Thread-safe.</font> |
||||
* @param key |
||||
* @return the object matching the {@link AssetKey} |
||||
*/ |
||||
public Object getFromCache(AssetKey key){ |
||||
synchronized (regularCache){ |
||||
if (key.useSmartCache()) { |
||||
return smartCache.get(key).asset; |
||||
} else { |
||||
return regularCache.get(key); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Retrieves smart asset info from the cache. |
||||
* @param key |
||||
* @return |
||||
*/ |
||||
public SmartAssetInfo getFromSmartCache(AssetKey key){ |
||||
return smartCache.get(key); |
||||
} |
||||
|
||||
/** |
||||
* Deletes all the assets in the regular cache. |
||||
*/ |
||||
public void deleteAllAssets(){ |
||||
synchronized (regularCache){ |
||||
regularCache.clear(); |
||||
smartCache.clear(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.asset; |
||||
|
||||
import com.jme3.material.Material; |
||||
import com.jme3.shader.Shader; |
||||
|
||||
/** |
||||
* <code>AssetProcessor</code> is used to apply processing to assets |
||||
* after they have been loaded. They are assigned to a particular |
||||
* asset type (which is represented by a {@link Class} and any assets |
||||
* loaded that are of that class will be processed by the assigned |
||||
* processor. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public interface AssetProcessor { |
||||
/** |
||||
* Applies post processing to an asset. |
||||
* The method may return an object that is not the same |
||||
* instance as the parameter object, and it could be from a different class. |
||||
* |
||||
* @param obj The asset that was loaded from an {@link AssetLoader}. |
||||
* @return Either the same object with processing applied, or an instance |
||||
* of a new object. |
||||
*/ |
||||
public Object postProcess(AssetKey key, Object obj); |
||||
|
||||
/** |
||||
* Creates a clone of the given asset. |
||||
* If no clone is desired, then the same instance can be returned, |
||||
* otherwise, a clone should be created. |
||||
* For example, a clone of a {@link Material} should have its own set |
||||
* of unique parameters that can be changed just for that instance, |
||||
* but it may share certain other data if it sees fit (like the {@link Shader}). |
||||
* |
||||
* @param obj The asset to clone |
||||
* @return The cloned asset, or the same as the given argument if no |
||||
* clone is needed. |
||||
*/ |
||||
public Object createClone(Object obj); |
||||
} |
@ -0,0 +1,52 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.asset; |
||||
|
||||
/** |
||||
* <code>CloneableAssetProcessor</code> simply calls {@link Object#clone() } |
||||
* on assets to clone them. No processing is applied. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class CloneableAssetProcessor implements AssetProcessor { |
||||
|
||||
public Object postProcess(AssetKey key, Object obj) { |
||||
return obj; |
||||
} |
||||
|
||||
public Object createClone(Object obj) { |
||||
CloneableSmartAsset asset = (CloneableSmartAsset) obj; |
||||
return asset.clone(); |
||||
} |
||||
|
||||
} |
@ -1,29 +1,65 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package com.jme3.asset; |
||||
|
||||
import com.jme3.asset.cache.AssetCache; |
||||
import com.jme3.asset.cache.WeakRefCloneAssetCache; |
||||
import com.jme3.material.Material; |
||||
|
||||
/** |
||||
* Used for loading {@link Material materials} only (not material definitions). |
||||
* |
||||
* Used for loading {@link Material materials} only (not material definitions!). |
||||
* Material instances use cloneable smart asset management so that they and any |
||||
* referenced textures will be collected when all instances of the material |
||||
* become unreachable. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class MaterialKey extends AssetKey { |
||||
public MaterialKey(String name){ |
||||
public class MaterialKey extends AssetKey<Material> { |
||||
|
||||
public MaterialKey(String name) { |
||||
super(name); |
||||
} |
||||
|
||||
public MaterialKey(){ |
||||
public MaterialKey() { |
||||
super(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean useSmartCache(){ |
||||
return true; |
||||
public Class<? extends AssetCache> getCacheType() { |
||||
return WeakRefCloneAssetCache.class; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Object createClonedInstance(Object asset){ |
||||
Material mat = (Material) asset; |
||||
return mat.clone(); |
||||
public Class<? extends AssetProcessor> getProcessorType() { |
||||
return CloneableAssetProcessor.class; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,75 @@ |
||||
package com.jme3.asset.cache; |
||||
|
||||
import com.jme3.asset.AssetKey; |
||||
|
||||
/** |
||||
* <code>AssetCache</code> is an interface for asset caches. |
||||
* Allowing storage of loaded resources in order to improve their access time |
||||
* if they are requested again in a short period of time. |
||||
* Depending on the asset type and how it is used, a specialized |
||||
* caching method can be selected that is most appropriate for that asset type. |
||||
* The asset cache must be thread safe. |
||||
* <p> |
||||
* |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public interface AssetCache { |
||||
/** |
||||
* Adds an asset to the cache. |
||||
* Once added, it should be possible to retrieve the asset |
||||
* by using the {@link #getFromCache(com.jme3.asset.AssetKey) } method. |
||||
* However the caching criteria may at some point choose that the asset |
||||
* should be removed from the cache to save memory, in that case, |
||||
* {@link #getFromCache(com.jme3.asset.AssetKey) } will return null. |
||||
* <p><font color="red">Thread-Safe</font> |
||||
* |
||||
* @param <T> The type of the asset to cache. |
||||
* @param key The asset key that can be used to look up the asset. |
||||
* @param obj The asset data to cache. |
||||
*/ |
||||
public <T> void addToCache(AssetKey<T> key, T obj); |
||||
|
||||
/** |
||||
* This should be called by the asset manager when it has successfully |
||||
* acquired a cached asset (with {@link #getFromCache(com.jme3.asset.AssetKey) }) |
||||
* and cloned it for use. |
||||
* <p><font color="red">Thread-Safe</font> |
||||
* |
||||
* @param <T> The type of the asset to register. |
||||
* @param key The asset key of the loaded asset (used to retrieve from cache) |
||||
* @param clone The <strong>clone</strong> of the asset retrieved from |
||||
* the cache. |
||||
*/ |
||||
public <T> void registerAssetClone(AssetKey<T> key, T clone); |
||||
|
||||
/** |
||||
* Retrieves an asset from the cache. |
||||
* It is possible to add an asset to the cache using |
||||
* {@link #addToCache(com.jme3.asset.AssetKey, java.lang.Object) }. |
||||
* The asset may be removed from the cache automatically even if |
||||
* it was added previously, in that case, this method will return null. |
||||
* <p><font color="red">Thread-Safe</font> |
||||
* |
||||
* @param <T> The type of the asset to retrieve |
||||
* @param key The key used to lookup the asset. |
||||
* @return The asset that was previously cached, or null if not found. |
||||
*/ |
||||
public <T> T getFromCache(AssetKey<T> key); |
||||
|
||||
/** |
||||
* Deletes an asset from the cache. |
||||
* <p><font color="red">Thread-Safe</font> |
||||
* |
||||
* @param key The asset key to find the asset to delete. |
||||
* @return True if the asset was successfully found in the cache |
||||
* and removed. |
||||
*/ |
||||
public boolean deleteFromCache(AssetKey key); |
||||
|
||||
/** |
||||
* Deletes all assets from the cache. |
||||
* <p><font color="red">Thread-Safe</font> |
||||
*/ |
||||
public void clearCache(); |
||||
} |
@ -0,0 +1,41 @@ |
||||
/* |
||||
* To change this template, choose Tools | Templates |
||||
* and open the template in the editor. |
||||
*/ |
||||
package com.jme3.asset.cache; |
||||
|
||||
import com.jme3.asset.AssetKey; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
/** |
||||
* <code>SimpleAssetCache</code> is an asset cache |
||||
* that caches assets without any automatic removal policy. The user |
||||
* is expected to manually call {@link #deleteFromCache(com.jme3.asset.AssetKey) } |
||||
* to delete any assets. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class SimpleAssetCache implements AssetCache { |
||||
|
||||
private final ConcurrentHashMap<AssetKey, Object> keyToAssetMap = new ConcurrentHashMap<AssetKey, Object>(); |
||||
|
||||
public <T> void addToCache(AssetKey<T> key, T obj) { |
||||
keyToAssetMap.put(key, obj); |
||||
} |
||||
|
||||
public <T> void registerAssetClone(AssetKey<T> key, T clone) { |
||||
} |
||||
|
||||
public <T> T getFromCache(AssetKey<T> key) { |
||||
return (T) keyToAssetMap.get(key); |
||||
} |
||||
|
||||
public boolean deleteFromCache(AssetKey key) { |
||||
return keyToAssetMap.remove(key) != null; |
||||
} |
||||
|
||||
public void clearCache() { |
||||
keyToAssetMap.clear(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,88 @@ |
||||
package com.jme3.asset.cache; |
||||
|
||||
import com.jme3.asset.AssetKey; |
||||
import com.jme3.asset.AssetProcessor; |
||||
import java.lang.ref.ReferenceQueue; |
||||
import java.lang.ref.WeakReference; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
/** |
||||
* A garbage collector bound asset cache that handles non-clonable objects. |
||||
* This cache assumes that the asset given to the user is the same asset |
||||
* that has been stored in the cache, in other words, |
||||
* {@link AssetProcessor#createClone(java.lang.Object) } for that asset |
||||
* returns the same object as the argument. |
||||
* This implementation will remove the asset from the cache |
||||
* once the asset is no longer referenced in user code and memory is low, |
||||
* e.g. the VM feels like purging the weak references for that asset. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class WeakRefAssetCache implements AssetCache { |
||||
|
||||
private final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>(); |
||||
|
||||
private final ConcurrentHashMap<AssetKey, AssetRef> assetCache |
||||
= new ConcurrentHashMap<AssetKey, AssetRef>(); |
||||
|
||||
private static class AssetRef extends WeakReference<Object> { |
||||
|
||||
private final AssetKey assetKey; |
||||
|
||||
public AssetRef(AssetKey assetKey, Object originalAsset, ReferenceQueue<Object> refQueue){ |
||||
super(originalAsset, refQueue); |
||||
this.assetKey = assetKey; |
||||
} |
||||
} |
||||
|
||||
private void removeCollectedAssets(){ |
||||
int removedAssets = 0; |
||||
for (AssetRef ref; (ref = (AssetRef)refQueue.poll()) != null;){ |
||||
// Asset was collected, note that at this point the asset cache
|
||||
// might not even have this asset anymore, it is OK.
|
||||
if (assetCache.remove(ref.assetKey) != null){ |
||||
removedAssets ++; |
||||
//System.out.println("WeakRefAssetCache: The asset " + ref.assetKey + " was purged from the cache");
|
||||
} |
||||
} |
||||
if (removedAssets >= 1) { |
||||
// System.out.println("WeakRefAssetCache: " + removedAssets + " assets were purged from the cache.");
|
||||
} |
||||
} |
||||
|
||||
public <T> void addToCache(AssetKey<T> key, T obj) { |
||||
removeCollectedAssets(); |
||||
|
||||
// NOTE: Some thread issues can hapen if another
|
||||
// thread is loading an asset with the same key ..
|
||||
AssetRef ref = new AssetRef(key, obj, refQueue); |
||||
assetCache.put(key, ref); |
||||
|
||||
// Texture t = (Texture) obj;
|
||||
// Image i = t.getImage();
|
||||
// System.out.println("add to cache " + System.identityHashCode(i));
|
||||
} |
||||
|
||||
public <T> T getFromCache(AssetKey<T> key) { |
||||
AssetRef ref = assetCache.get(key); |
||||
if (ref != null){ |
||||
return (T) ref.get(); |
||||
}else{ |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public boolean deleteFromCache(AssetKey key) { |
||||
return assetCache.remove(key) != null; |
||||
} |
||||
|
||||
public void clearCache() { |
||||
assetCache.clear(); |
||||
} |
||||
|
||||
public <T> void registerAssetClone(AssetKey<T> key, T clone) { |
||||
// Texture t = (Texture) clone;
|
||||
// System.out.println("clonable asset " + System.identityHashCode(t.getImage()));
|
||||
//throw new UnsupportedOperationException("Cannot use this cache for cloneable assets");
|
||||
} |
||||
} |
@ -0,0 +1,116 @@ |
||||
package com.jme3.asset.cache; |
||||
|
||||
import com.jme3.asset.CloneableSmartAsset; |
||||
import com.jme3.asset.AssetKey; |
||||
import java.lang.ref.WeakReference; |
||||
import java.util.ArrayDeque; |
||||
import java.util.WeakHashMap; |
||||
|
||||
/** |
||||
* <codeWeakRefCloneAssetCache</code> caches cloneable assets in a weak-key |
||||
* cache, allowing them to be collected when memory is low. |
||||
* The cache stores weak references to the asset keys, so that |
||||
* when all clones of the original asset are collected, will cause the |
||||
* asset to be automatically removed from the cache. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class WeakRefCloneAssetCache implements AssetCache { |
||||
|
||||
private static final class SmartCachedAsset { |
||||
|
||||
WeakReference<AssetKey> key; |
||||
CloneableSmartAsset asset; |
||||
|
||||
public SmartCachedAsset(CloneableSmartAsset originalAsset, AssetKey originalKey) { |
||||
this.key = new WeakReference<AssetKey>(originalKey); |
||||
this.asset = originalAsset; |
||||
} |
||||
} |
||||
|
||||
private final WeakHashMap<AssetKey, SmartCachedAsset> smartCache |
||||
= new WeakHashMap<AssetKey, SmartCachedAsset>(); |
||||
|
||||
private final ThreadLocal<ArrayDeque<AssetKey>> assetLoadStack |
||||
= new ThreadLocal<ArrayDeque<AssetKey>>() { |
||||
@Override |
||||
protected ArrayDeque<AssetKey> initialValue() { |
||||
return new ArrayDeque<AssetKey>(); |
||||
} |
||||
}; |
||||
|
||||
public <T> void addToCache(AssetKey<T> key, T obj) { |
||||
CloneableSmartAsset asset = (CloneableSmartAsset) obj; |
||||
|
||||
// No circular references, since the original asset is
|
||||
// strongly referenced, we don't want the key strongly referenced.
|
||||
asset.setKey(null); |
||||
|
||||
// Place the asset in the cache with a weak ref to the key.
|
||||
synchronized (smartCache) { |
||||
smartCache.put(key, new SmartCachedAsset(asset, key)); |
||||
} |
||||
|
||||
// Push the original key used to load the asset
|
||||
// so that it can be set on the clone later
|
||||
ArrayDeque<AssetKey> loadStack = assetLoadStack.get(); |
||||
loadStack.push(key); |
||||
} |
||||
|
||||
public <T> void registerAssetClone(AssetKey<T> key, T clone) { |
||||
ArrayDeque<AssetKey> loadStack = assetLoadStack.get(); |
||||
((CloneableSmartAsset)clone).setKey(loadStack.pop()); |
||||
} |
||||
|
||||
public <T> T getFromCache(AssetKey<T> key) { |
||||
SmartCachedAsset smartInfo; |
||||
synchronized (smartCache){ |
||||
smartInfo = smartCache.get(key); |
||||
} |
||||
|
||||
if (smartInfo == null) { |
||||
return null; |
||||
} else { |
||||
// NOTE: Optimization so that registerAssetClone()
|
||||
// can check this and determine that the asset clone
|
||||
// belongs to the asset retrieved here.
|
||||
AssetKey keyForTheClone = smartInfo.key.get(); |
||||
if (keyForTheClone == null){ |
||||
// The asset was JUST collected by GC
|
||||
// (between here and smartCache.get)
|
||||
return null; |
||||
} |
||||
|
||||
// Prevent original key from getting collected
|
||||
// while an asset is loaded for it.
|
||||
ArrayDeque<AssetKey> loadStack = assetLoadStack.get(); |
||||
loadStack.push(keyForTheClone); |
||||
|
||||
return (T) smartInfo.asset; |
||||
} |
||||
} |
||||
|
||||
public boolean deleteFromCache(AssetKey key) { |
||||
ArrayDeque<AssetKey> loadStack = assetLoadStack.get(); |
||||
|
||||
if (!loadStack.isEmpty()){ |
||||
throw new UnsupportedOperationException("Cache cannot be modified" |
||||
+ "while assets are being loaded"); |
||||
} |
||||
synchronized (smartCache) { |
||||
return smartCache.remove(key) != null; |
||||
} |
||||
} |
||||
|
||||
public void clearCache() { |
||||
ArrayDeque<AssetKey> loadStack = assetLoadStack.get(); |
||||
|
||||
if (!loadStack.isEmpty()){ |
||||
throw new UnsupportedOperationException("Cache cannot be modified" |
||||
+ "while assets are being loaded"); |
||||
} |
||||
synchronized (smartCache) { |
||||
smartCache.clear(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,19 @@ |
||||
package com.jme3.audio; |
||||
|
||||
import com.jme3.asset.AssetKey; |
||||
import com.jme3.asset.AssetProcessor; |
||||
|
||||
public class AudioProcessor implements AssetProcessor{ |
||||
|
||||
public Object postProcess(AssetKey key, Object obj) { |
||||
AudioKey audioKey = (AudioKey) key; |
||||
AudioData audioData = (AudioData) obj; |
||||
return new AudioNode(audioData, audioKey); |
||||
} |
||||
|
||||
public Object createClone(Object obj) { |
||||
AudioNode node = (AudioNode) obj; |
||||
return node.clone(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,15 @@ |
||||
package com.jme3.material; |
||||
|
||||
import com.jme3.asset.AssetKey; |
||||
import com.jme3.asset.AssetProcessor; |
||||
|
||||
public class MaterialProcessor implements AssetProcessor { |
||||
|
||||
public Object postProcess(AssetKey key, Object obj) { |
||||
return null; |
||||
} |
||||
|
||||
public Object createClone(Object obj) { |
||||
return ((Material) obj).clone(); |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
package com.jme3.texture; |
||||
|
||||
import com.jme3.asset.AssetKey; |
||||
import com.jme3.asset.AssetProcessor; |
||||
import com.jme3.asset.TextureKey; |
||||
import java.nio.ByteBuffer; |
||||
|
||||
public class TextureProcessor implements AssetProcessor { |
||||
|
||||
public Object postProcess(AssetKey key, Object obj) { |
||||
TextureKey texKey = (TextureKey) key; |
||||
Image img = (Image) obj; |
||||
if (img == null) { |
||||
return null; |
||||
} |
||||
|
||||
Texture tex; |
||||
if (texKey.isAsCube()) { |
||||
if (texKey.isFlipY()) { |
||||
// also flip -y and +y image in cubemap
|
||||
ByteBuffer pos_y = img.getData(2); |
||||
img.setData(2, img.getData(3)); |
||||
img.setData(3, pos_y); |
||||
} |
||||
tex = new TextureCubeMap(); |
||||
} else if (texKey.isAsTexture3D()) { |
||||
tex = new Texture3D(); |
||||
} else { |
||||
tex = new Texture2D(); |
||||
} |
||||
|
||||
// enable mipmaps if image has them
|
||||
// or generate them if requested by user
|
||||
if (img.hasMipmaps() || texKey.isGenerateMips()) { |
||||
tex.setMinFilter(Texture.MinFilter.Trilinear); |
||||
} |
||||
|
||||
tex.setAnisotropicFilter(texKey.getAnisotropy()); |
||||
tex.setName(texKey.getName()); |
||||
tex.setImage(img); |
||||
return tex; |
||||
} |
||||
|
||||
public Object createClone(Object obj) { |
||||
Texture tex = (Texture) obj; |
||||
return tex.clone(); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue