* 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; |
package com.jme3.asset; |
||||||
|
|
||||||
|
import com.jme3.asset.cache.AssetCache; |
||||||
|
import com.jme3.asset.cache.WeakRefCloneAssetCache; |
||||||
import com.jme3.material.Material; |
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 |
* @author Kirill Vainer |
||||||
*/ |
*/ |
||||||
public class MaterialKey extends AssetKey { |
public class MaterialKey extends AssetKey<Material> { |
||||||
public MaterialKey(String name){ |
|
||||||
|
public MaterialKey(String name) { |
||||||
super(name); |
super(name); |
||||||
} |
} |
||||||
|
|
||||||
public MaterialKey(){ |
public MaterialKey() { |
||||||
super(); |
super(); |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public boolean useSmartCache(){ |
public Class<? extends AssetCache> getCacheType() { |
||||||
return true; |
return WeakRefCloneAssetCache.class; |
||||||
} |
} |
||||||
|
|
||||||
@Override |
@Override |
||||||
public Object createClonedInstance(Object asset){ |
public Class<? extends AssetProcessor> getProcessorType() { |
||||||
Material mat = (Material) asset; |
return CloneableAssetProcessor.class; |
||||||
return mat.clone(); |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -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