Răsfoiți Sursa

Merge branch 'master' of https://github.com/jMonkeyEngine/jmonkeyengine into GL4ShaderSupport

Conflicts:
	jme3-core/src/main/resources/com/jme3/asset/Desktop.cfg
michael 10 ani în urmă
părinte
comite
5b58bda23f
34 a modificat fișierele cu 714 adăugiri și 984 ștergeri
  1. 0 111
      jme3-android/src/main/java/com/jme3/asset/AndroidAssetManager.java
  2. 1 0
      jme3-android/src/main/java/com/jme3/asset/AndroidImageInfo.java
  3. 6 43
      jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java
  4. 1 0
      jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java
  5. 1 0
      jme3-android/src/main/java/com/jme3/texture/plugins/AndroidImageLoader.java
  6. 8 0
      jme3-android/src/main/resources/com/jme3/asset/Android.cfg
  7. 4 4
      jme3-core/src/main/java/com/jme3/animation/AnimControl.java
  8. 11 9
      jme3-core/src/main/java/com/jme3/app/Application.java
  9. 60 77
      jme3-core/src/main/java/com/jme3/asset/AssetConfig.java
  10. 99 63
      jme3-core/src/main/java/com/jme3/asset/AssetManager.java
  11. 117 74
      jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java
  12. 4 2
      jme3-core/src/main/java/com/jme3/asset/ImplHandler.java
  13. 26 5
      jme3-core/src/main/java/com/jme3/asset/StreamAssetInfo.java
  14. 0 5
      jme3-core/src/main/java/com/jme3/asset/cache/WeakRefAssetCache.java
  15. 1 1
      jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java
  16. 30 0
      jme3-core/src/main/java/com/jme3/asset/cache/package.html
  17. 6 4
      jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
  18. 10 0
      jme3-core/src/main/java/com/jme3/system/JmeSystem.java
  19. 18 6
      jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
  20. 3 2
      jme3-core/src/main/resources/com/jme3/asset/Desktop.cfg
  21. 26 0
      jme3-core/src/main/resources/com/jme3/asset/General.cfg
  22. 10 0
      jme3-core/src/plugins/java/com/jme3/asset/plugins/ClasspathLocator.java
  23. 1 0
      jme3-core/src/plugins/java/com/jme3/asset/plugins/FileLocator.java
  24. 17 0
      jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java
  25. 4 0
      jme3-core/src/plugins/java/com/jme3/asset/plugins/UrlLocator.java
  26. 7 1
      jme3-core/src/plugins/java/com/jme3/asset/plugins/ZipLocator.java
  27. 0 80
      jme3-core/src/tools/java/jme3tools/converters/FolderConverter.java
  28. 0 351
      jme3-core/src/tools/java/jme3tools/converters/model/FloatToFixed.java
  29. 3 14
      jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java
  30. 4 0
      jme3-ios/src/main/java/com/jme3/asset/IOS.cfg
  31. 0 109
      jme3-ios/src/main/java/com/jme3/system/ios/IosAssetManager.java
  32. 5 19
      jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java
  33. 224 0
      jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/file/FBXDump.java
  34. 7 4
      jme3-plugins/src/xml/java/com/jme3/export/xml/XMLImporter.java

+ 0 - 111
jme3-android/src/main/java/com/jme3/asset/AndroidAssetManager.java

@@ -1,111 +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 com.jme3.asset.plugins.AndroidLocator;
-import com.jme3.asset.plugins.ClasspathLocator;
-import com.jme3.audio.plugins.AndroidAudioLoader;
-import com.jme3.audio.plugins.NativeVorbisLoader;
-import com.jme3.audio.plugins.WAVLoader;
-import com.jme3.system.AppSettings;
-import com.jme3.system.android.JmeAndroidSystem;
-import com.jme3.texture.plugins.AndroidBufferImageLoader;
-import com.jme3.texture.plugins.AndroidNativeImageLoader;
-import java.net.URL;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * <code>AndroidAssetManager</code> is an implementation of DesktopAssetManager for Android
- *
- * @author larynx
- */
-public class AndroidAssetManager extends DesktopAssetManager {
-
-    private static final Logger logger = Logger.getLogger(AndroidAssetManager.class.getName());
-
-    private void registerLoaderSafe(String loaderClass, String ... extensions) {
-        try {
-            Class<? extends AssetLoader> loader = (Class<? extends AssetLoader>) Class.forName(loaderClass);
-            registerLoader(loader, extensions);
-        } catch (Exception e){
-            logger.log(Level.WARNING, "Failed to load AssetLoader", e);
-        }
-    }
-
-    /**
-     * AndroidAssetManager constructor
-     * If URL == null then a default list of locators and loaders for android is set
-     * @param configFile
-     */
-    public AndroidAssetManager(URL configFile) {
-        System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
-
-        // Set Default Android config
-        registerLocator("", AndroidLocator.class);
-        registerLocator("", ClasspathLocator.class);
-
-        registerLoader(AndroidNativeImageLoader.class, "jpg", "jpeg", "bmp", "gif", "png");
-        
-        if (JmeAndroidSystem.getAudioRendererType().equals(AppSettings.ANDROID_MEDIAPLAYER)) {
-            registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav");
-        } else if (JmeAndroidSystem.getAudioRendererType().equals(AppSettings.ANDROID_OPENAL_SOFT)) {
-            registerLoader(WAVLoader.class, "wav");
-            registerLoader(NativeVorbisLoader.class, "ogg");
-        } else {
-            throw new IllegalStateException("No Audio Renderer Type defined!");
-        }
-
-        registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
-        registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
-        registerLoader(com.jme3.material.plugins.ShaderNodeDefinitionLoader.class, "j3sn");
-        registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
-        registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o");
-        registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
-
-        // Less common loaders (especially on Android)
-        registerLoaderSafe("com.jme3.texture.plugins.DDSLoader", "dds");
-        registerLoaderSafe("com.jme3.texture.plugins.PFMLoader", "pfm");
-        registerLoaderSafe("com.jme3.texture.plugins.HDRLoader", "hdr");
-        registerLoaderSafe("com.jme3.texture.plugins.TGALoader", "tga");
-        registerLoaderSafe("com.jme3.scene.plugins.OBJLoader", "obj");
-        registerLoaderSafe("com.jme3.scene.plugins.MTLLoader", "mtl");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.MeshLoader", "mesh.xml");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.SkeletonLoader", "skeleton.xml");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.MaterialLoader", "material");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.SceneLoader", "scene");
-
-
-        logger.fine("AndroidAssetManager created.");
-    }
-
-}

+ 1 - 0
jme3-android/src/main/java/com/jme3/asset/AndroidImageInfo.java

@@ -20,6 +20,7 @@ import java.util.logging.Logger;
   *
   * @author Kirill Vainer
   */
+@Deprecated
 public class AndroidImageInfo extends ImageRaster {
     
     private static final Logger logger = Logger.getLogger(AndroidImageInfo.class.getName());

+ 6 - 43
jme3-android/src/main/java/com/jme3/system/android/JmeAndroidSystem.java

@@ -6,9 +6,6 @@ import android.graphics.Bitmap;
 import android.os.Environment;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
-import com.jme3.asset.AndroidAssetManager;
-import com.jme3.asset.AndroidImageInfo;
-import com.jme3.asset.AssetManager;
 import com.jme3.audio.AudioRenderer;
 import com.jme3.audio.android.AndroidAL;
 import com.jme3.audio.android.AndroidALC;
@@ -19,14 +16,10 @@ import com.jme3.audio.openal.ALC;
 import com.jme3.audio.openal.EFX;
 import com.jme3.system.*;
 import com.jme3.system.JmeContext.Type;
-import com.jme3.texture.Image;
-import com.jme3.texture.image.DefaultImageRaster;
-import com.jme3.texture.image.ImageRaster;
 import com.jme3.util.AndroidScreenshots;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.net.URL;
 import java.nio.ByteBuffer;
 import java.util.logging.Level;
 
@@ -41,6 +34,11 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
         } catch (UnsatisfiedLinkError e) {
         }
     }
+    
+    @Override
+    public String getPlatformAssetConfigPath() {
+        return "com/jme3/asset/Android.cfg";
+    }
 
     @Override
     public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
@@ -58,27 +56,6 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
         bitmapImage.recycle();
     }
 
-    @Override
-    public ImageRaster createImageRaster(Image image, int slice) {
-        if (image.getEfficentData() != null) {
-            return (AndroidImageInfo) image.getEfficentData();
-        } else {
-            return new DefaultImageRaster(image, slice);
-        }
-    }
-
-    @Override
-    public AssetManager newAssetManager(URL configFile) {
-        logger.log(Level.FINE, "Creating asset manager with config {0}", configFile);
-        return new AndroidAssetManager(configFile);
-    }
-
-    @Override
-    public AssetManager newAssetManager() {
-        logger.log(Level.FINE, "Creating asset manager with default config");
-        return new AndroidAssetManager(null);
-    }
-
     @Override
     public void showErrorDialog(String message) {
         final String finalMsg = message;
@@ -122,21 +99,6 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
         AL al = new AndroidAL();
         EFX efx = new AndroidEFX();
         return new ALAudioRenderer(al, alc, efx);
-/*
-        if (settings.getAudioRenderer().equals(AppSettings.ANDROID_MEDIAPLAYER)) {
-            logger.log(Level.INFO, "newAudioRenderer settings set to Android MediaPlayer / SoundPool");
-            audioRendererType = AppSettings.ANDROID_MEDIAPLAYER;
-            return new AndroidMediaPlayerAudioRenderer(activity);
-        } else if (settings.getAudioRenderer().equals(AppSettings.ANDROID_OPENAL_SOFT)) {
-            logger.log(Level.INFO, "newAudioRenderer settings set to Android OpenAL Soft");
-            audioRendererType = AppSettings.ANDROID_OPENAL_SOFT;
-            return new AndroidMediaPlayerAudioRenderer(activity);
-        } else {
-            logger.log(Level.INFO, "AudioRenderer not set. Defaulting to Android MediaPlayer / SoundPool");
-            audioRendererType = AppSettings.ANDROID_MEDIAPLAYER;
-            return new AndroidMediaPlayerAudioRenderer(activity);
-        }
-*/
     }
 
     @Override
@@ -145,6 +107,7 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
             return;
         }
         initialized = true;
+        System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
         logger.log(Level.INFO, getBuildInfo());
     }
 

+ 1 - 0
jme3-android/src/main/java/com/jme3/texture/plugins/AndroidBufferImageLoader.java

@@ -50,6 +50,7 @@ import java.nio.ByteBuffer;
  * 
  * @author Kirill Vainer
  */
+@Deprecated
 public class AndroidBufferImageLoader implements AssetLoader {
     
     private final byte[] tempData = new byte[16 * 1024];

+ 1 - 0
jme3-android/src/main/java/com/jme3/texture/plugins/AndroidImageLoader.java

@@ -8,6 +8,7 @@ import com.jme3.texture.Image;
 import com.jme3.texture.image.ColorSpace;
 import java.io.IOException;
 
+@Deprecated
 public class AndroidImageLoader implements AssetLoader {
 
     public Object load(AssetInfo info) throws IOException {

+ 8 - 0
jme3-android/src/main/resources/com/jme3/asset/Android.cfg

@@ -0,0 +1,8 @@
+INCLUDE com/jme3/asset/General.cfg
+
+# Android specific locators
+LOCATOR / com.jme3.asset.plugins.AndroidLocator
+
+# Android specific loaders
+LOADER com.jme3.texture.plugins.AndroidNativeImageLoader : jpg, bmp, gif, png, jpeg
+LOADER com.jme3.audio.plugins.NativeVorbisLoader : ogg

+ 4 - 4
jme3-core/src/main/java/com/jme3/animation/AnimControl.java

@@ -56,12 +56,12 @@ import java.util.Map.Entry;
  * 4) Animation event listeners
  * 5) Animated model cloning
  * 6) Animated model binary import/export
+ * 7) Hardware skinning
+ * 8) Attachments
+ * 9) Add/remove skins
  *
  * Planned:
- * 1) Hardware skinning
- * 2) Morph/Pose animation
- * 3) Attachments
- * 4) Add/remove skins
+ * 1) Morph/Pose animation
  *
  * @author Kirill Vainer
  */

+ 11 - 9
jme3-core/src/main/java/com/jme3/app/Application.java

@@ -174,28 +174,30 @@ public class Application implements SystemListener {
     }
 
     private void initAssetManager(){
+        URL assetCfgUrl = null;
+        
         if (settings != null){
             String assetCfg = settings.getString("AssetConfigURL");
             if (assetCfg != null){
-                URL url = null;
                 try {
-                    url = new URL(assetCfg);
+                    assetCfgUrl = new URL(assetCfg);
                 } catch (MalformedURLException ex) {
                 }
-                if (url == null) {
-                    url = Application.class.getClassLoader().getResource(assetCfg);
-                    if (url == null) {
+                if (assetCfgUrl == null) {
+                    assetCfgUrl = Application.class.getClassLoader().getResource(assetCfg);
+                    if (assetCfgUrl == null) {
                         logger.log(Level.SEVERE, "Unable to access AssetConfigURL in asset config:{0}", assetCfg);
                         return;
                     }
                 }
-                assetManager = JmeSystem.newAssetManager(url);
             }
         }
+        if (assetCfgUrl == null) {
+            String assetCfg = JmeSystem.getPlatformAssetConfigPath();
+            assetCfgUrl = Thread.currentThread().getContextClassLoader().getResource(assetCfg);
+        }
         if (assetManager == null){
-            assetManager = JmeSystem.newAssetManager(
-                    Thread.currentThread().getContextClassLoader()
-                    .getResource("com/jme3/asset/Desktop.cfg"));
+            assetManager = JmeSystem.newAssetManager(assetCfgUrl);
         }
     }
 

+ 60 - 77
jme3-core/src/main/java/com/jme3/asset/AssetConfig.java

@@ -33,6 +33,9 @@ package com.jme3.asset;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Locale;
 import java.util.Scanner;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -42,97 +45,77 @@ import java.util.logging.Logger;
  * <br/><br/>
  * The config file is specified with the following format:
  * <code>
+ * "INCLUDE" <path>
  * "LOADER" <class> : (<extension> ",")* <extension>
- * "LOCATOR" <path> <class> : (<extension> ",")* <extension>
+ * "LOCATOR" <path> <class>
  * </code>
  *
  * @author Kirill Vainer
  */
-public class AssetConfig {
+public final class AssetConfig {
 
-    private AssetManager manager;
-
-    public AssetConfig(AssetManager manager){
-        this.manager = manager;
-    }
-
-    public void loadText(InputStream in) throws IOException{
-        Scanner scan = new Scanner(in);
-        while (scan.hasNext()){
-            String cmd = scan.next();
-            if (cmd.equals("LOADER")){
-                String loaderClass = scan.next();
-                String colon = scan.next();
-                if (!colon.equals(":")){
-                    throw new IOException("Expected ':', got '"+colon+"'");
-                }
-                String extensionsList = scan.nextLine();
-                String[] extensions = extensionsList.split(",");
-                for (int i = 0; i < extensions.length; i++){
-                    extensions[i] = extensions[i].trim();
-                }
-                Class clazz = acquireClass(loaderClass);
-                if (clazz != null) {
-                    manager.registerLoader(clazz, extensions);
-                } else {
-                    Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot find loader {0}", loaderClass);
-                }
-            } else if (cmd.equals("LOCATOR")) {
-                String rootPath = scan.next();
-                String locatorClass = scan.nextLine().trim();
-                Class clazz = acquireClass(locatorClass);
-                if (clazz != null) {
-                    manager.registerLocator(rootPath, clazz);
-                } else {
-                    Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot find locator {0}", locatorClass);
-                }
-            } else {
-                throw new IOException("Expected command, got '" + cmd + "'");
-            }
-        }
-    }
+    private static final Logger logger = Logger.getLogger(AssetConfig.class.getName());
     
-    private Class acquireClass(String name) {
+    private AssetConfig() { }
+    
+    private static Class acquireClass(String name) {
         try {
-            Class clazz = Class.forName(name);
-            return clazz;
+            return Class.forName(name);
         } catch (ClassNotFoundException ex) {
             return null;
         }
     }
     
-    /*
-    private static String readString(DataInput dataIn) throws IOException{
-        int length = dataIn.readUnsignedShort();
-        char[] chrs = new char[length];
-        for (int i = 0; i < length; i++){
-            chrs[i] = (char) dataIn.readUnsignedByte();
-        }
-        return String.valueOf(chrs);
-    }
-
-    public void loadBinary(DataInput dataIn) throws IOException{
-        // read signature and version
-
-        // how many locator entries?
-        int locatorEntries = dataIn.readUnsignedShort();
-        for (int i = 0; i < locatorEntries; i++){
-            String locatorClazz = readString(dataIn);
-            String rootPath = readString(dataIn);
-            manager.registerLocator(rootPath, locatorClazz);
-        }
-
-        int loaderEntries = dataIn.readUnsignedShort();
-        for (int i = 0; i < loaderEntries; i++){
-            String loaderClazz = readString(dataIn);
-            int numExtensions = dataIn.readUnsignedByte();
-            String[] extensions = new String[numExtensions];
-            for (int j = 0; j < numExtensions; j++){
-                extensions[j] = readString(dataIn);
+    public static void loadText(AssetManager assetManager, URL configUrl) throws IOException{
+        InputStream in = configUrl.openStream();
+        try {
+            Scanner scan = new Scanner(in);
+            scan.useLocale(Locale.US); // Fix commas / periods ??
+            while (scan.hasNext()){
+                String cmd = scan.next();
+                if (cmd.equals("LOADER")){
+                    String loaderClass = scan.next();
+                    String colon = scan.next();
+                    if (!colon.equals(":")){
+                        throw new IOException("Expected ':', got '"+colon+"'");
+                    }
+                    String extensionsList = scan.nextLine();
+                    String[] extensions = extensionsList.split(",");
+                    for (int i = 0; i < extensions.length; i++){
+                        extensions[i] = extensions[i].trim();
+                    }
+                    Class clazz = acquireClass(loaderClass);
+                    if (clazz != null) {
+                        assetManager.registerLoader(clazz, extensions);
+                    } else {
+                        logger.log(Level.WARNING, "Cannot find loader {0}", loaderClass);
+                    }
+                } else if (cmd.equals("LOCATOR")) {
+                    String rootPath = scan.next();
+                    String locatorClass = scan.nextLine().trim();
+                    Class clazz = acquireClass(locatorClass);
+                    if (clazz != null) {
+                        assetManager.registerLocator(rootPath, clazz);
+                    } else {
+                        logger.log(Level.WARNING, "Cannot find locator {0}", locatorClass);
+                    }
+                } else if (cmd.equals("INCLUDE")) {
+                    String includedCfg = scan.nextLine().trim();
+                    URL includedCfgUrl = Thread.currentThread().getContextClassLoader().getResource(includedCfg);
+                    if (includedCfgUrl != null) {
+                        loadText(assetManager, includedCfgUrl);
+                    } else {
+                        logger.log(Level.WARNING, "Cannot find config include {0}", includedCfg);
+                    }
+                } else if (cmd.trim().startsWith("#")) {
+                    scan.nextLine();
+                    continue;
+                } else {
+                    throw new IOException("Expected command, got '" + cmd + "'");
+                }
             }
-
-            manager.registerLoader(loaderClazz, extensions);
+        } finally {
+            if (in != null) in.close();
         }
     }
-    */
 }

+ 99 - 63
jme3-core/src/main/java/com/jme3/asset/AssetManager.java

@@ -46,6 +46,8 @@ import com.jme3.shader.ShaderGenerator;
 import com.jme3.shader.ShaderKey;
 import com.jme3.texture.Texture;
 import com.jme3.texture.plugins.TGALoader;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.EnumSet;
 import java.util.List;
 
@@ -75,7 +77,15 @@ import java.util.List;
  * <li>{@link TGALoader} - Used to load Targa image files</li>
  * </ul>
  * <p>
- * Once the asset has been loaded, 
+ * Once the asset has been loaded, it will be 
+ * {@link AssetProcessor#postProcess(com.jme3.asset.AssetKey, java.lang.Object) 
+ * post-processed} by the {@link AssetKey#getProcessorType() key's processor}.
+ * If the key specifies a {@link AssetKey#getCacheType() cache type}, the asset
+ * will be cached in the specified cache. Next, the {@link AssetProcessor}
+ * will be requested to {@link AssetProcessor#createClone(java.lang.Object) } 
+ * generate a clone for the asset. Some assets do not require cloning,
+ * such as immutable or shared assets. Others, like models, must be cloned
+ * so that modifications to one instance do not leak onto others.
  */
 public interface AssetManager {
 
@@ -100,46 +110,13 @@ public interface AssetManager {
      */
     public List<ClassLoader> getClassLoaders();
     
-    /**
-     * Registers a loader for the given extensions.
-     * 
-     * @param loaderClassName
-     * @param extensions
-     * 
-     * @deprecated Please use {@link #registerLoader(java.lang.Class, java.lang.String[]) }
-     * together with {@link Class#forName(java.lang.String) } to find a class
-     * and then register it.
-     * 
-     * @deprecated Please use {@link #registerLoader(java.lang.Class, java.lang.String[]) }
-     * with {@link Class#forName(java.lang.String) } instead.
-     */
-    @Deprecated
-    public void registerLoader(String loaderClassName, String ... extensions);
-
-    /**
-     * Registers an {@link AssetLocator} by using a class name. 
-     * See the {@link AssetManager#registerLocator(java.lang.String, java.lang.Class) }
-     * method for more information.
-     *
-     * @param rootPath The root path from which to locate assets, this 
-     * depends on the implementation of the asset locator. 
-     * A URL based locator will expect a url folder such as "http://www.example.com/"
-     * while a File based locator will expect a file path (OS dependent).
-     * @param locatorClassName The full class name of the {@link AssetLocator}
-     * implementation.
-     * 
-     * @deprecated Please use {@link #registerLocator(java.lang.String, java.lang.Class)  }
-     * together with {@link Class#forName(java.lang.String) } to find a class
-     * and then register it.
-     */
-    @Deprecated
-    public void registerLocator(String rootPath, String locatorClassName);
-
     /**
      * Register an {@link AssetLoader} by using a class object.
      * 
-     * @param loaderClass
-     * @param extensions
+     * @param loaderClass The loader class to register.
+     * @param extensions Which extensions this loader is responsible for loading,
+     * if there are already other loaders registered for that extension, they
+     * will be overridden - there should only be one loader for each extension.
      */
     public void registerLoader(Class<? extends AssetLoader> loaderClass, String ... extensions);
     
@@ -161,7 +138,7 @@ public interface AssetManager {
      * to the {@link AssetLoader} to load the asset.
      * Once a locator is registered, it can be removed via
      * {@link #unregisterLocator(java.lang.String, java.lang.Class) }.
-     *
+     * 
      * @param rootPath Specifies the root path from which to locate assets
      * for the given {@link AssetLocator}. The purpose of this parameter
      * depends on the type of the {@link AssetLocator}.
@@ -206,18 +183,6 @@ public interface AssetManager {
      */
     public void clearAssetEventListeners();
     
-    /**
-     * Set an {@link AssetEventListener} to receive events from this
-     * <code>AssetManager</code>. Any currently added listeners are
-     * cleared and then the given listener is added.
-     * 
-     * @param listener The listener to set
-     * @deprecated Please use {@link #addAssetEventListener(com.jme3.asset.AssetEventListener) }
-     * to listen for asset events.
-     */
-    @Deprecated
-    public void setAssetEventListener(AssetEventListener listener);
-
     /**
      * Manually locates an asset with the given {@link AssetKey}. 
      * This method should be used for debugging or internal uses.
@@ -233,6 +198,23 @@ public interface AssetManager {
      */
     public AssetInfo locateAsset(AssetKey<?> key);
 
+    /**
+     * Load an asset from an {@link InputStream}. 
+     * In some cases it may be required to load an asset from memory 
+     * or arbitrary streams so that registering a custom locator and key
+     * type is not necessary. 
+     * 
+     * @param <T> The object type that will be loaded from the AssetKey instance.
+     * @param key The AssetKey. Note that the asset will not be cached - 
+     * following the same behavior as if {@link AssetKey#getCacheType()} returned null.
+     * @param inputStream The input stream from which the asset shall be loaded.
+     * @return The loaded asset.
+     * 
+     * @throws AssetLoadException If the {@link AssetLoader} has failed
+     * to load the asset due to an {@link IOException} or another error.
+     */
+    public <T> T loadAssetFromStream(AssetKey<T> key, InputStream inputStream);
+    
     /**
      * Load an asset from a key, the asset will be located
      * by one of the {@link AssetLocator} implementations provided in the
@@ -244,17 +226,18 @@ public interface AssetManager {
      *
      * @param <T> The object type that will be loaded from the AssetKey instance.
      * @param key The AssetKey
-     * @return The loaded asset, or null if it was failed to be located
-     * or loaded.
+     * @return The loaded asset.
+     * 
+     * @throws AssetNotFoundException If all registered locators have failed 
+     * to locate the asset.
+     * @throws AssetLoadException If the {@link AssetLoader} has failed
+     * to load the asset due to an {@link IOException} or another error.
      */
     public <T> T loadAsset(AssetKey<T> key);
 
     /**
-     * Load an asset by name, calling this method
-     * is the same as calling
-     * <code>
-     * loadAsset(new AssetKey(name)).
-     * </code>
+     * Load an asset by name, calling this method is the same as calling
+     * <code>loadAsset(new AssetKey(name))</code>.
      *
      * @param name The name of the asset to load.
      * @return The loaded asset, or null if failed to be loaded.
@@ -265,7 +248,7 @@ public interface AssetManager {
 
     /**
      * Loads texture file, supported types are BMP, JPG, PNG, GIF,
-     * TGA and DDS.
+     * TGA, DDS, PFM, and HDR.
      *
      * @param key The {@link TextureKey} to use for loading.
      * @return The loaded texture, or null if failed to be loaded.
@@ -276,8 +259,10 @@ public interface AssetManager {
 
     /**
      * Loads texture file, supported types are BMP, JPG, PNG, GIF,
-     * TGA and DDS.
+     * TGA, DDS, PFM, and HDR.
      *
+     * The texture will be loaded with mip-mapping enabled. 
+     * 
      * @param name The name of the texture to load.
      * @return The texture that was loaded
      *
@@ -306,7 +291,8 @@ public interface AssetManager {
 
     /**
      * Loads a 3D model with a ModelKey. 
-     * Models can be jME3 object files (J3O) or OgreXML/OBJ files.
+     * Models can be jME3 object files (J3O), OgreXML (mesh.xml), BLEND, FBX 
+     * and OBJ files.
      * @param key Asset key of the model to load
      * @return The model that was loaded
      *
@@ -315,8 +301,9 @@ public interface AssetManager {
     public Spatial loadModel(ModelKey key);
 
     /**
-     * Loads a 3D model. Models can be jME3 object files (J3O) or
-     * OgreXML/OBJ files.
+     * Loads a 3D model. Models can be jME3 object files (J3O),
+     * OgreXML (mesh.xml), BLEND, FBX and OBJ files.
+     * 
      * @param name Asset name of the model to load
      * @return The model that was loaded
      *
@@ -381,4 +368,53 @@ public interface AssetManager {
      */
     public ShaderGenerator getShaderGenerator(EnumSet<Caps> caps);
     
+    /**
+     * Retrieve an asset from the asset cache.
+     * 
+     * <b>NOTE:</b> Do <em>not</em> modify the returned asset! 
+     * It is the same reference as what is stored in the cache, therefore any 
+     * modifications to it will leak onto assets loaded from the same key in the future.
+     * 
+     * @param <T> The object type that will be retrieved from the AssetKey instance.
+     * @param key The AssetKey to get from the cache.
+     * @return The cached asset, if found. Otherwise, <code>null</code>.
+     * 
+     * @throws IllegalArgumentException If {@link AssetKey#getCacheType() caching}
+     * is disabled for the key.
+     */
+    public <T> T getFromCache(AssetKey<T> key);
+    
+    /**
+     * Inject an asset into the asset cache.
+     * 
+     * <b>NOTE:</b> Do <em>not</em> modify the cached asset after storing!
+     * It is the same reference as what is stored in the cache, therefore any 
+     * modifications to it will leak onto assets loaded from the same key in the future.
+     * 
+     * @param <T> The object type of the asset.
+     * @param key The key where the asset shall be stored.
+     * @param asset The asset to inject into the cache.
+     * 
+     * @throws IllegalArgumentException If {@link AssetKey#getCacheType() caching}
+     * is disabled for the key.
+     */
+    public <T> void addToCache(AssetKey<T> key, T asset);
+    
+    /**
+     * Delete an asset from the asset cache.
+     * 
+     * @param <T> The object type of the AssetKey instance.
+     * @param key The asset key to remove from the cache.
+     * @return True if the asset key was found in the cache and was removed
+     * successfully. False if the asset key was not present in the cache.
+     * 
+     * @throws IllegalArgumentException If {@link AssetKey#getCacheType() caching}
+     * is disabled for the key.
+     */
+    public <T> boolean deleteFromCache(AssetKey<T> key);
+    
+    /**
+     * Clears the asset cache.
+     */
+    public void clearCache();
 }

+ 117 - 74
jme3-core/src/main/java/com/jme3/asset/DesktopAssetManager.java

@@ -81,11 +81,6 @@ public class DesktopAssetManager implements AssetManager {
         this(null);
     }
 
-    @Deprecated
-    public DesktopAssetManager(boolean loadDefaults){
-        this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Desktop.cfg"));
-    }
-
     public DesktopAssetManager(URL configFile){
         if (configFile != null){
             loadConfigFile(configFile);
@@ -93,20 +88,11 @@ public class DesktopAssetManager implements AssetManager {
         logger.fine("DesktopAssetManager created.");
     }
 
-    private void loadConfigFile(URL configFile){
-        InputStream stream = null;
-        try{
-            AssetConfig cfg = new AssetConfig(this);
-            stream = configFile.openStream();
-            cfg.loadText(stream);
-        }catch (IOException ex){
+    private void loadConfigFile(URL configFile) {
+        try {
+            AssetConfig.loadText(this, configFile);
+        } catch (IOException ex) {
             logger.log(Level.SEVERE, "Failed to load asset config", ex);
-        }finally{
-            if (stream != null)
-                try{
-                    stream.close();
-                }catch (IOException ex){
-                }
         }
     }
     
@@ -207,6 +193,7 @@ public class DesktopAssetManager implements AssetManager {
         return info;
     }
     
+    @Override
     public <T> T getFromCache(AssetKey<T> key) {
         AssetCache cache = handler.getCache(key.getCacheType());
         if (cache != null) {
@@ -221,6 +208,7 @@ public class DesktopAssetManager implements AssetManager {
         }
     }
     
+    @Override
     public <T> void addToCache(AssetKey<T> key, T asset) {
         AssetCache cache = handler.getCache(key.getCacheType());
         if (cache != null) {
@@ -231,6 +219,7 @@ public class DesktopAssetManager implements AssetManager {
         }
     }
     
+    @Override
     public <T> boolean deleteFromCache(AssetKey<T> key) {
         AssetCache cache = handler.getCache(key.getCacheType());
         if (cache != null) {
@@ -240,6 +229,7 @@ public class DesktopAssetManager implements AssetManager {
         }
     }
     
+    @Override
     public void clearCache(){
         handler.clearCache();
         if (logger.isLoggable(Level.FINER)){
@@ -248,13 +238,110 @@ public class DesktopAssetManager implements AssetManager {
     }
 
     /**
-     * <font color="red">Thread-safe.</font>
-     *
-     * @param <T>
-     * @param key
-     * @return the loaded asset
+     * Loads an asset that has already been located.
+     * @param <T> The asset type
+     * @param key The asset key
+     * @param info The AssetInfo from the locator
+     * @param proc AssetProcessor to use, or null to disable processing
+     * @param cache The cache to store the asset in, or null to disable caching
+     * @return The loaded asset
+     * 
+     * @throws AssetLoadException If failed to load asset due to exception or
+     * other error.
+     */
+    protected <T> T loadLocatedAsset(AssetKey<T> key, AssetInfo info, AssetProcessor proc, AssetCache cache) {
+        AssetLoader loader = handler.aquireLoader(key);
+        Object obj;
+        try {
+            handler.establishParentKey(key);
+            obj = loader.load(info);
+        } catch (IOException ex) {
+            throw new AssetLoadException("An exception has occured while loading asset: " + key, ex);
+        } finally {
+            handler.releaseParentKey(key);
+        }
+        if (obj == null) {
+            throw new AssetLoadException("Error occured while loading asset \""
+                    + key + "\" using " + loader.getClass().getSimpleName());
+        } else {
+            if (logger.isLoggable(Level.FINER)) {
+                logger.log(Level.FINER, "Loaded {0} with {1}",
+                        new Object[]{key, loader.getClass().getSimpleName()});
+            }
+
+            if (proc != null) {
+                // do processing on asset before caching
+                obj = proc.postProcess(key, obj);
+            }
+
+            if (cache != null) {
+                // At this point, obj should be of type T
+                cache.addToCache(key, (T) obj);
+            }
+
+            for (AssetEventListener listener : eventListeners) {
+                listener.assetLoaded(key);
+            }
+
+            return (T) obj;
+        }
+    }
+    
+    /**
+     * Clones the asset using the given processor and registers the clone
+     * with the cache.
+     * 
+     * @param <T> The asset type
+     * @param key The asset key
+     * @param obj The asset to clone / register, must implement 
+     * {@link CloneableSmartAsset}.
+     * @param proc The processor which will generate the clone, cannot be null
+     * @param cache The cache to register the clone with, cannot be null.
+     * @return The cloned asset, cannot be the same as the given asset since
+     * it is a clone.
+     * 
+     * @throws IllegalStateException If asset does not implement 
+     * {@link CloneableSmartAsset}, if the cache is null, or if the 
+     * processor did not clone the asset.
      */
-      public <T> T loadAsset(AssetKey<T> key){
+    protected <T> T registerAndCloneSmartAsset(AssetKey<T> key, T obj, AssetProcessor proc, AssetCache cache) {
+        // object obj is the original asset
+        // create an instance for user
+        T clone = (T) obj;
+        if (proc == null) {
+            throw new IllegalStateException("Asset implements "
+                    + "CloneableSmartAsset but doesn't "
+                    + "have processor to handle cloning");
+        } else {
+            clone = (T) proc.createClone(obj);
+            if (cache != null && clone != obj) {
+                cache.registerAssetClone(key, clone);
+            } else {
+                throw new IllegalStateException("Asset implements "
+                        + "CloneableSmartAsset but doesn't have cache or "
+                        + "was not cloned");
+            }
+        }
+        return clone;
+    }
+    
+    @Override
+    public <T> T loadAssetFromStream(AssetKey<T> key, InputStream inputStream) {
+        if (key == null) {
+            throw new IllegalArgumentException("key cannot be null");
+        }
+        
+        for (AssetEventListener listener : eventListeners){
+            listener.assetRequested(key);
+        }
+        
+        AssetProcessor proc = handler.getProcessor(key.getProcessorType());
+        StreamAssetInfo info = new StreamAssetInfo(this, key, inputStream);
+        return loadLocatedAsset(key, info, proc, null);
+    }
+    
+    @Override
+    public <T> T loadAsset(AssetKey<T> key){
         if (key == null)
             throw new IllegalArgumentException("key cannot be null");
         
@@ -268,7 +355,6 @@ public class DesktopAssetManager implements AssetManager {
         Object obj = cache != null ? cache.getFromCache(key) : null;
         if (obj == null){
             // Asset not in cache, load it from file system.
-            AssetLoader loader = handler.aquireLoader(key);
             AssetInfo info = handler.tryLocate(key);
             if (info == null){
                 if (handler.getParentKey() != null){
@@ -282,59 +368,16 @@ public class DesktopAssetManager implements AssetManager {
                 }
                 throw new AssetNotFoundException(key.toString());
             }
-
-            try {
-                handler.establishParentKey(key);
-                obj = loader.load(info);
-            } catch (IOException ex) {
-                throw new AssetLoadException("An exception has occured while loading asset: " + key, ex);
-            } finally {
-                handler.releaseParentKey(key);
-            }
-            if (obj == null){
-                throw new AssetLoadException("Error occured while loading asset \"" + key + "\" using " + loader.getClass().getSimpleName());
-            }else{
-                if (logger.isLoggable(Level.FINER)){
-                    logger.log(Level.FINER, "Loaded {0} with {1}",
-                            new Object[]{key, loader.getClass().getSimpleName()});
-                }
-                
-                if (proc != null){
-                    // do processing on asset before caching
-                    obj = proc.postProcess(key, obj);
-                }
-                
-                if (cache != null){
-                    // At this point, obj should be of type T
-                    cache.addToCache(key, (T) obj);
-                }
-                
-                for (AssetEventListener listener : eventListeners){
-                    listener.assetLoaded(key);
-                }
-            }
+            
+            obj = loadLocatedAsset(key, info, proc, cache);
         }
 
-        // object obj is the original asset
-        // create an instance for user
         T clone = (T) obj;
-        if (clone instanceof CloneableSmartAsset){
-            if (proc == null){
-                throw new IllegalStateException("Asset implements "
-                        + "CloneableSmartAsset but doesn't "
-                        + "have processor to handle cloning");
-            }else{
-                clone = (T) proc.createClone(obj);
-                if (cache != null && clone != obj){
-                    cache.registerAssetClone(key, clone);
-                } else{
-                    throw new IllegalStateException("Asset implements "
-                        + "CloneableSmartAsset but doesn't have cache or "
-                        + "was not cloned");
-                }
-            }
+        
+        if (obj instanceof CloneableSmartAsset) {
+            clone = registerAndCloneSmartAsset(key, clone, proc, cache);
         }
-       
+        
         return clone;
     }
 

+ 4 - 2
jme3-core/src/main/java/com/jme3/asset/ImplHandler.java

@@ -204,8 +204,10 @@ public class ImplHandler {
     
     public void clearCache(){
         // The iterator of the values collection is thread safe
-        for (AssetCache cache : classToCacheMap.values()){
-            cache.clearCache();
+        synchronized (classToCacheMap) {
+            for (AssetCache cache : classToCacheMap.values()){
+                cache.clearCache();
+            }
         }
     }
     

+ 26 - 5
jme3-core/src/tools/java/jme3tools/converters/Converter.java → jme3-core/src/main/java/com/jme3/asset/StreamAssetInfo.java

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2012 jMonkeyEngine
+ * Copyright (c) 2009-2015 jMonkeyEngine
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,11 +29,32 @@
  * 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 jme3tools.converters;
+import java.io.InputStream;
 
-import java.util.Map;
+/**
+ * An {@link AssetInfo} wrapper for {@link InputStream InputStreams}.
+ * 
+ * @author Kirill Vainer
+ */
+public class StreamAssetInfo extends AssetInfo {
 
-public interface Converter<T> {
-    public T convert(T input, Map<String, String> params);
+    private boolean alreadyOpened;
+    private final InputStream inputStream;
+    
+    public StreamAssetInfo(AssetManager assetManager, AssetKey<?> assetKey, InputStream inputStream) {
+        super(assetManager, assetKey);
+        this.inputStream = inputStream;
+    }
+    
+    @Override
+    public InputStream openStream() {
+        if (alreadyOpened) {
+            throw new IllegalStateException("Stream already opened");
+        }
+        alreadyOpened = true;
+        return inputStream;
+    }
+    
 }

+ 0 - 5
jme3-core/src/main/java/com/jme3/asset/cache/WeakRefAssetCache.java

@@ -77,7 +77,6 @@ public class WeakRefAssetCache implements AssetCache {
             // 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) {
@@ -92,10 +91,6 @@ public class WeakRefAssetCache implements AssetCache {
         // 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) {

+ 1 - 1
jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java

@@ -42,7 +42,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
- * <codeWeakRefCloneAssetCache</code> caches cloneable assets in a weak-key
+ * <code>WeakRefCloneAssetCache</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 

+ 30 - 0
jme3-core/src/main/java/com/jme3/asset/cache/package.html

@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+
+<head>
+<title></title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+</head>
+<body>
+
+<code>com.jme3.asset.cache</code> contains the {@link com.jme3.asset.cache.AssetCache}
+interface as well as its implementations.<br>
+
+<p>
+    
+<h3>AssetCaches</h3>
+The asset cache implementations are used by {@link com.jme3.asset.AssetManager}
+to cache loaded assets for faster access if they are requested again.
+<p>
+Assets in jME3 are cached in such a way that if there are no instances of
+that asset anymore in memory, then jME3 is likely to reclaim them. 
+Some asset types must be cloned prior to being used, for example, 3D models 
+cannot be stored in the cache as-is, because the user is likely to modify them
+after loading them. To handle this, a copy of the asset is stored in the 
+cache instead. The asset cache that implements these rules is the 
+{@link com.jme3.asset.cache.WeakRefCloneAssetCache} and it is used
+for caching most asset types.
+
+</body>
+</html>
+

+ 6 - 4
jme3-core/src/main/java/com/jme3/renderer/RenderManager.java

@@ -863,10 +863,12 @@ public class RenderManager {
     private void setViewPort(Camera cam) {
         // this will make sure to update viewport only if needed
         if (cam != prevCam || cam.isViewportChanged()) {
-            viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
-            viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
-            viewWidth = ((int)(cam.getViewPortRight() * cam.getWidth())) - ((int)(cam.getViewPortLeft() * cam.getWidth()));
-            viewHeight = ((int)(cam.getViewPortTop() * cam.getHeight())) - ((int)(cam.getViewPortBottom() * cam.getHeight()));
+            viewX      = (int) (cam.getViewPortLeft() * cam.getWidth());
+            viewY      = (int) (cam.getViewPortBottom() * cam.getHeight());
+            int viewX2 = (int) (cam.getViewPortRight() * cam.getWidth());
+            int viewY2 = (int) (cam.getViewPortTop() * cam.getHeight());
+            viewWidth  = viewX2 - viewX;
+            viewHeight = viewY2 - viewY;
             uniformBindingManager.setViewPort(viewX, viewY, viewWidth, viewHeight);
             renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
             renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);

+ 10 - 0
jme3-core/src/main/java/com/jme3/system/JmeSystem.java

@@ -35,6 +35,7 @@ import com.jme3.asset.AssetManager;
 import com.jme3.audio.AudioRenderer;
 import com.jme3.input.SoftTextDialogInput;
 import com.jme3.texture.Image;
+import com.jme3.texture.image.DefaultImageRaster;
 import com.jme3.texture.image.ImageRaster;
 import java.io.File;
 import java.io.IOException;
@@ -166,6 +167,15 @@ public class JmeSystem {
         return systemDelegate.newAudioRenderer(settings);
     }
 
+    public static String getPlatformAssetConfigPath() {
+        checkDelegate();
+        return systemDelegate.getPlatformAssetConfigPath();
+    }
+    
+    /**
+     * @deprecated Directly create an image raster via {@link DefaultImageRaster}.
+     */
+    @Deprecated
     public static ImageRaster createImageRaster(Image image, int slice) {
         checkDelegate();
         return systemDelegate.createImageRaster(image, slice);

+ 18 - 6
jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java

@@ -32,9 +32,11 @@
 package com.jme3.system;
 
 import com.jme3.asset.AssetManager;
+import com.jme3.asset.DesktopAssetManager;
 import com.jme3.audio.AudioRenderer;
 import com.jme3.input.SoftTextDialogInput;
 import com.jme3.texture.Image;
+import com.jme3.texture.image.DefaultImageRaster;
 import com.jme3.texture.image.ImageRaster;
 import java.io.File;
 import java.io.IOException;
@@ -117,15 +119,25 @@ public abstract class JmeSystemDelegate {
     public void setSoftTextDialogInput(SoftTextDialogInput input) {
         softTextDialogInput = input;
     }
+    
     public SoftTextDialogInput getSoftTextDialogInput() {
         return softTextDialogInput;
     }
 
-    public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
-
-    public abstract AssetManager newAssetManager(URL configFile);
+    public final AssetManager newAssetManager(URL configFile) {
+        return new DesktopAssetManager(configFile);
+    }
 
-    public abstract AssetManager newAssetManager();
+    public final AssetManager newAssetManager() {
+        return new DesktopAssetManager(null);
+    }
+    
+    @Deprecated
+    public final ImageRaster createImageRaster(Image image, int slice) {
+        return new DefaultImageRaster(image, slice);
+    }
+    
+    public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
 
     public abstract void showErrorDialog(String message);
 
@@ -181,13 +193,13 @@ public abstract class JmeSystemDelegate {
         return sb.toString();
     }
     
+    public abstract String getPlatformAssetConfigPath();
+    
     public abstract JmeContext newContext(AppSettings settings, JmeContext.Type contextType);
 
     public abstract AudioRenderer newAudioRenderer(AppSettings settings);
 
     public abstract void initialize(AppSettings settings);
 
-    public abstract ImageRaster createImageRaster(Image image, int slice);
-
     public abstract void showSoftKeyboard(boolean show);
 }

+ 3 - 2
jme3-core/src/main/resources/com/jme3/asset/Desktop.cfg

@@ -1,7 +1,8 @@
-LOCATOR / com.jme3.asset.plugins.ClasspathLocator
+INCLUDE com/jme3/asset/General.cfg
 
+# Desktop-specific loaders
 LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg
-LOADER com.jme3.audio.plugins.WAVLoader : wav
+LOADER com.jme3.audio.plugins.OGGLoader : oggLOADER com.jme3.audio.plugins.WAVLoader : wav
 LOADER com.jme3.audio.plugins.OGGLoader : ogg
 LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
 LOADER com.jme3.material.plugins.J3MLoader : j3m

+ 26 - 0
jme3-core/src/main/resources/com/jme3/asset/General.cfg

@@ -0,0 +1,26 @@
+# Generic locators that should be supported on all platforms.
+LOCATOR / com.jme3.asset.plugins.ClasspathLocator
+
+# Generic loaders that should be supported on all platforms.
+LOADER com.jme3.audio.plugins.WAVLoader : wav
+LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
+LOADER com.jme3.material.plugins.J3MLoader : j3m
+LOADER com.jme3.material.plugins.J3MLoader : j3md
+LOADER com.jme3.material.plugins.ShaderNodeDefinitionLoader : j3sn
+LOADER com.jme3.font.plugins.BitmapFontLoader : fnt
+LOADER com.jme3.texture.plugins.DDSLoader : dds
+LOADER com.jme3.texture.plugins.PFMLoader : pfm
+LOADER com.jme3.texture.plugins.HDRLoader : hdr
+LOADER com.jme3.texture.plugins.TGALoader : tga
+LOADER com.jme3.export.binary.BinaryImporter : j3o
+LOADER com.jme3.export.binary.BinaryImporter : j3f
+LOADER com.jme3.scene.plugins.OBJLoader : obj
+LOADER com.jme3.scene.plugins.MTLLoader : mtl
+LOADER com.jme3.scene.plugins.ogre.MeshLoader : meshxml, mesh.xml
+LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml
+LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
+LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
+LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
+LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib
+LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx
+LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba

+ 10 - 0
jme3-core/src/plugins/java/com/jme3/asset/plugins/ClasspathLocator.java

@@ -41,6 +41,16 @@ import java.util.logging.Logger;
 
 /**
  * The <code>ClasspathLocator</code> looks up an asset in the classpath.
+ * 
+ * This locator is used by default in all jME3 projects (unless 
+ * {@link AssetManager#unregisterLocator(java.lang.String, java.lang.Class) unregistered}
+ * ).
+ * Unlike Java's default resource loading mechanism, the <code>ClasspathLocator</code>
+ * enforces case-sensitivity on platforms which do not have it such as Windows.
+ * Therefore, it is critical to provide a path matching the case of the file on
+ * the filesystem. This also ensures that the file can be loaded if it was
+ * later included in a <code>.JAR</code> file instead of a folder.
+ * 
  * @author Kirill Vainer
  */
 public class ClasspathLocator implements AssetLocator {

+ 1 - 0
jme3-core/src/plugins/java/com/jme3/asset/plugins/FileLocator.java

@@ -37,6 +37,7 @@ import java.io.*;
 /**
  * <code>FileLocator</code> allows you to specify a folder where to
  * look for assets. 
+ * 
  * @author Kirill Vainer
  */
 public class FileLocator implements AssetLocator {

+ 17 - 0
jme3-core/src/plugins/java/com/jme3/asset/plugins/HttpZipLocator.java

@@ -52,6 +52,23 @@ import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 import java.util.zip.ZipEntry;
 
+/**
+ * <code>HttpZipLocator</code> is similar to {@link ZipLocator}, except
+ * it allows loading assets from a <code>.ZIP</code> file on the web instead of
+ * on the local filesystem.
+ * <p>
+ * The root path must be a valid HTTP(S) {@link URL} pointing to ZIP or
+ * ZIP-like file (such as a JAR). For example,<br>
+ * <code>https://www.example.com/my/sub/path/assets.zip</code>.
+ * <p>
+ * The locator is designed in such a way that it does not require downloading
+ * the entire <code>.ZIP</code> file from the web in order to load
+ * assets from it. Instead, the ZIP header is extracted first, and then
+ * is used to lookup assets from within the ZIP file and download them
+ * as requested by the user. 
+ * 
+ * @author Kirill Vainer
+ */
 public class HttpZipLocator implements AssetLocator {
 
     private static final Logger logger = Logger.getLogger(HttpZipLocator.class.getName());

+ 4 - 0
jme3-core/src/plugins/java/com/jme3/asset/plugins/UrlLocator.java

@@ -46,6 +46,10 @@ import java.util.logging.Logger;
  * <code>UrlLocator</code> is a locator that combines a root URL
  * and the given path in the AssetKey to construct a new URL
  * that allows locating the asset.
+ * <p>
+ * The root path must be a valid {@link URL}, for example, <br>
+ * <code>https://www.example.com/assets/</code>
+ * 
  * @author Kirill Vainer
  */
 public class UrlLocator implements AssetLocator {

+ 7 - 1
jme3-core/src/plugins/java/com/jme3/asset/plugins/ZipLocator.java

@@ -40,7 +40,13 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 /**
- * <code>ZipLocator</code> is a locator that looks up resources in a .ZIP file.
+ * <code>ZipLocator</code> is a locator that looks up resources in a 
+ * <code>.ZIP</code> file.
+ * 
+ * The root path must be a valid ZIP or ZIP-like {@link File file}, 
+ * for example, <br>
+ * <code>C:\My App\data.zip</code>
+ * 
  * @author Kirill Vainer
  */
 public class ZipLocator implements AssetLocator {

+ 0 - 80
jme3-core/src/tools/java/jme3tools/converters/FolderConverter.java

@@ -1,80 +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 jme3tools.converters;
-
-import com.jme3.asset.AssetManager;
-import com.jme3.system.JmeSystem;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.jar.JarEntry;
-import java.util.jar.JarOutputStream;
-
-public class FolderConverter {
-
-    private static AssetManager assetManager;
-    private static File sourceRoot;
-    private static JarOutputStream jarOut;
-    private static long time;
-
-    private static void process(File file) throws IOException{
-        String name = file.getName().replaceAll("[\\/\\.]", "_");
-        JarEntry entry = new JarEntry(name);
-        entry.setTime(time);
-
-        jarOut.putNextEntry(entry);
-    }
-
-    public static void main(String[] args) throws IOException{
-        if (args.length == 0){
-            System.out.println("Usage: java -jar FolderConverter <input folder>");
-            System.out.println();
-            System.out.println("  Converts files from input to output");
-            System.exit(1);
-        }
-
-        sourceRoot = new File(args[0]);
-        
-        File jarFile = new File(sourceRoot.getParent(), sourceRoot.getName()+".jar");
-        FileOutputStream out = new FileOutputStream(jarFile);
-        jarOut = new JarOutputStream(out);
-
-        assetManager = JmeSystem.newAssetManager();
-        assetManager.registerLocator(sourceRoot.toString(), 
-                                     "com.jme3.asset.plugins.FileSystemLocator");
-        for (File f : sourceRoot.listFiles()){
-             process(f);
-        }
-    }
-
-}

+ 0 - 351
jme3-core/src/tools/java/jme3tools/converters/model/FloatToFixed.java

@@ -1,351 +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 jme3tools.converters.model;
-
-import com.jme3.bounding.BoundingBox;
-import com.jme3.math.Transform;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Mesh;
-import com.jme3.scene.VertexBuffer;
-import com.jme3.scene.VertexBuffer.Format;
-import com.jme3.scene.VertexBuffer.Type;
-import com.jme3.scene.VertexBuffer.Usage;
-import com.jme3.scene.mesh.IndexBuffer;
-import com.jme3.util.BufferUtils;
-import java.nio.*;
-
-@Deprecated
-public class FloatToFixed {
-
-    private static final float shortSize = Short.MAX_VALUE - Short.MIN_VALUE;
-    private static final float shortOff  = (Short.MAX_VALUE + Short.MIN_VALUE) * 0.5f;
-
-    private static final float byteSize = Byte.MAX_VALUE - Byte.MIN_VALUE;
-    private static final float byteOff  = (Byte.MAX_VALUE + Byte.MIN_VALUE) * 0.5f;
-
-    @Deprecated
-    public static void convertToFixed(Geometry geom, Format posFmt, Format nmFmt, Format tcFmt){
-        geom.updateModelBound();
-        BoundingBox bbox = (BoundingBox) geom.getModelBound();
-        Mesh mesh = geom.getMesh();
-
-        VertexBuffer positions = mesh.getBuffer(Type.Position);
-        VertexBuffer normals   = mesh.getBuffer(Type.Normal);
-        VertexBuffer texcoords = mesh.getBuffer(Type.TexCoord);
-        VertexBuffer indices   = mesh.getBuffer(Type.Index);
-
-        // positions
-        FloatBuffer fb = (FloatBuffer) positions.getData();
-        if (posFmt != Format.Float){
-            Buffer newBuf = VertexBuffer.createBuffer(posFmt, positions.getNumComponents(),
-                                                      mesh.getVertexCount());
-            Transform t = convertPositions(fb, bbox, newBuf);
-            t.combineWithParent(geom.getLocalTransform());
-            geom.setLocalTransform(t);
-
-            VertexBuffer newPosVb = new VertexBuffer(Type.Position);
-            newPosVb.setupData(positions.getUsage(),
-                               positions.getNumComponents(),
-                               posFmt,
-                               newBuf);
-            mesh.clearBuffer(Type.Position);
-            mesh.setBuffer(newPosVb);
-        }
-
-        // normals, automatically convert to signed byte
-        fb = (FloatBuffer) normals.getData();
-
-        ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
-        convertNormals(fb, bb);
-
-        normals = new VertexBuffer(Type.Normal);
-        normals.setupData(Usage.Static, 3, Format.Byte, bb);
-        normals.setNormalized(true);
-        mesh.clearBuffer(Type.Normal);
-        mesh.setBuffer(normals);
-
-        // texcoords
-        fb = (FloatBuffer) texcoords.getData();
-        if (tcFmt != Format.Float){
-            Buffer newBuf = VertexBuffer.createBuffer(tcFmt,
-                                                      texcoords.getNumComponents(),
-                                                      mesh.getVertexCount());
-            convertTexCoords2D(fb, newBuf);
-
-            VertexBuffer newTcVb = new VertexBuffer(Type.TexCoord);
-            newTcVb.setupData(texcoords.getUsage(),
-                              texcoords.getNumComponents(),
-                              tcFmt,
-                              newBuf);
-            mesh.clearBuffer(Type.TexCoord);
-            mesh.setBuffer(newTcVb);
-        }
-    }
-
-    public static void compressIndexBuffer(Mesh mesh){
-        int vertCount = mesh.getVertexCount();
-        VertexBuffer vb = mesh.getBuffer(Type.Index);
-        Format targetFmt;
-        if (vb.getFormat() == Format.UnsignedInt && vertCount <= 0xffff){
-            if (vertCount <= 256)
-                targetFmt = Format.UnsignedByte;
-            else
-                targetFmt = Format.UnsignedShort;
-        }else if (vb.getFormat() == Format.UnsignedShort && vertCount <= 0xff){
-            targetFmt = Format.UnsignedByte;
-        }else{
-            return;
-        }
-
-        IndexBuffer src = mesh.getIndexBuffer();
-        Buffer newBuf = VertexBuffer.createBuffer(targetFmt, vb.getNumComponents(), src.size());
-
-        VertexBuffer newVb = new VertexBuffer(Type.Index);
-        newVb.setupData(vb.getUsage(), vb.getNumComponents(), targetFmt, newBuf);
-        mesh.clearBuffer(Type.Index);
-        mesh.setBuffer(newVb);
-
-        IndexBuffer dst = mesh.getIndexBuffer();
-        for (int i = 0; i < src.size(); i++){
-            dst.put(i, src.get(i));
-        }
-    }
-
-    private static void convertToFixed(FloatBuffer input, IntBuffer output){
-        if (output.capacity() < input.capacity())
-            throw new RuntimeException("Output must be at least as large as input!");
-
-        input.clear();
-        output.clear();
-        for (int i = 0; i < input.capacity(); i++){
-            output.put( (int) (input.get() * (float)(1<<16)) );
-        }
-        output.flip();
-    }
-
-    private static void convertToFloat(IntBuffer input, FloatBuffer output){
-        if (output.capacity() < input.capacity())
-            throw new RuntimeException("Output must be at least as large as input!");
-
-        input.clear();
-        output.clear();
-        for (int i = 0; i < input.capacity(); i++){
-            output.put( ((float)input.get() / (float)(1<<16)) );
-        }
-        output.flip();
-    }
-
-    private static void convertToUByte(FloatBuffer input, ByteBuffer output){
-        if (output.capacity() < input.capacity())
-            throw new RuntimeException("Output must be at least as large as input!");
-
-        input.clear();
-        output.clear();
-        for (int i = 0; i < input.capacity(); i++){
-            output.put( (byte) (input.get() * 255f) );
-        }
-        output.flip();
-    }
-
-
-    public static VertexBuffer convertToUByte(VertexBuffer vb){
-        FloatBuffer fb = (FloatBuffer) vb.getData();
-        ByteBuffer bb = BufferUtils.createByteBuffer(fb.capacity());
-        convertToUByte(fb, bb);
-
-        VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
-        newVb.setupData(vb.getUsage(),
-                        vb.getNumComponents(),
-                        Format.UnsignedByte,
-                        bb);
-        newVb.setNormalized(true);
-        return newVb;
-    }
-
-    public static VertexBuffer convertToFixed(VertexBuffer vb){
-        if (vb.getFormat() == Format.Int)
-            return vb;
-
-        FloatBuffer fb = (FloatBuffer) vb.getData();
-        IntBuffer ib = BufferUtils.createIntBuffer(fb.capacity());
-        convertToFixed(fb, ib);
-
-        VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
-        newVb.setupData(vb.getUsage(),
-                        vb.getNumComponents(),
-                        Format.Int,
-                        ib);
-        return newVb;
-    }
-
-    public static VertexBuffer convertToFloat(VertexBuffer vb){
-        if (vb.getFormat() == Format.Float)
-            return vb;
-
-        IntBuffer ib = (IntBuffer) vb.getData();
-        FloatBuffer fb = BufferUtils.createFloatBuffer(ib.capacity());
-        convertToFloat(ib, fb);
-
-        VertexBuffer newVb = new VertexBuffer(vb.getBufferType());
-        newVb.setupData(vb.getUsage(),
-                        vb.getNumComponents(),
-                        Format.Float,
-                        fb);
-        return newVb;
-    }
-
-    private static void convertNormals(FloatBuffer input, ByteBuffer output){
-        if (output.capacity() < input.capacity())
-            throw new RuntimeException("Output must be at least as large as input!");
-
-        input.clear();
-        output.clear();
-        Vector3f temp = new Vector3f();
-        int vertexCount = input.capacity() / 3;
-        for (int i = 0; i < vertexCount; i++){
-            BufferUtils.populateFromBuffer(temp, input, i);
-
-            // offset and scale vector into -128 ... 127
-            temp.multLocal(127).addLocal(0.5f, 0.5f, 0.5f);
-
-            // quantize
-            byte v1 = (byte) temp.getX();
-            byte v2 = (byte) temp.getY();
-            byte v3 = (byte) temp.getZ();
-
-            // store
-            output.put(v1).put(v2).put(v3);
-        }
-    }
-
-    private static void convertTexCoords2D(FloatBuffer input, Buffer output){
-        if (output.capacity() < input.capacity())
-            throw new RuntimeException("Output must be at least as large as input!");
-
-        input.clear();
-        output.clear();
-        Vector2f temp = new Vector2f();
-        int vertexCount = input.capacity() / 2;
-
-        ShortBuffer sb = null;
-        IntBuffer ib = null;
-
-        if (output instanceof ShortBuffer)
-            sb = (ShortBuffer) output;
-        else if (output instanceof IntBuffer)
-            ib = (IntBuffer) output;
-        else
-            throw new UnsupportedOperationException();
-
-        for (int i = 0; i < vertexCount; i++){
-            BufferUtils.populateFromBuffer(temp, input, i);
-
-            if (sb != null){
-                sb.put( (short) (temp.getX()*Short.MAX_VALUE) );
-                sb.put( (short) (temp.getY()*Short.MAX_VALUE) );
-            }else{
-                int v1 = (int) (temp.getX() * ((float)(1 << 16)));
-                int v2 = (int) (temp.getY() * ((float)(1 << 16)));
-                ib.put(v1).put(v2);
-            }
-        }
-    }
-
-    private static Transform convertPositions(FloatBuffer input, BoundingBox bbox, Buffer output){
-        if (output.capacity() < input.capacity())
-            throw new RuntimeException("Output must be at least as large as input!");
-
-        Vector3f offset = bbox.getCenter().negate();
-        Vector3f size = new Vector3f(bbox.getXExtent(), bbox.getYExtent(), bbox.getZExtent());
-        size.multLocal(2);
-
-        ShortBuffer sb = null;
-        ByteBuffer bb = null;
-        float dataTypeSize;
-        float dataTypeOffset;
-        if (output instanceof ShortBuffer){
-            sb = (ShortBuffer) output;
-            dataTypeOffset = shortOff;
-            dataTypeSize = shortSize;
-        }else{
-            bb = (ByteBuffer) output;
-            dataTypeOffset = byteOff;
-            dataTypeSize = byteSize;
-        }
-        Vector3f scale = new Vector3f();
-        scale.set(dataTypeSize, dataTypeSize, dataTypeSize).divideLocal(size);
-
-        Vector3f invScale = new Vector3f();
-        invScale.set(size).divideLocal(dataTypeSize);
-
-        offset.multLocal(scale);
-        offset.addLocal(dataTypeOffset, dataTypeOffset, dataTypeOffset);
-
-        // offset = (-modelOffset * shortSize)/modelSize + shortOff
-        // scale = shortSize / modelSize
-
-        input.clear();
-        output.clear();
-        Vector3f temp = new Vector3f();
-        int vertexCount = input.capacity() / 3;
-        for (int i = 0; i < vertexCount; i++){
-            BufferUtils.populateFromBuffer(temp, input, i);
-
-            // offset and scale vector into -32768 ... 32767
-            // or into -128 ... 127 if using bytes
-            temp.multLocal(scale);
-            temp.addLocal(offset);
-
-            // quantize and store
-            if (sb != null){
-                short v1 = (short) temp.getX();
-                short v2 = (short) temp.getY();
-                short v3 = (short) temp.getZ();
-                sb.put(v1).put(v2).put(v3);
-            }else{
-                byte v1 = (byte) temp.getX();
-                byte v2 = (byte) temp.getY();
-                byte v3 = (byte) temp.getZ();
-                bb.put(v1).put(v2).put(v3);
-            }
-        }
-
-        Transform transform = new Transform();
-        transform.setTranslation(offset.negate().multLocal(invScale));
-        transform.setScale(invScale);
-        return transform;
-    }
-
-}

+ 3 - 14
jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java

@@ -75,10 +75,10 @@ import javax.swing.SwingUtilities;
 public class JmeDesktopSystem extends JmeSystemDelegate {
 
     @Override
-    public AssetManager newAssetManager(URL configFile) {
-        return new DesktopAssetManager(configFile);
+    public String getPlatformAssetConfigPath() {
+        return "com/jme3/asset/Desktop.cfg";
     }
-
+    
     private static BufferedImage verticalFlip(BufferedImage original) {
         AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
         tx.translate(0, -original.getHeight());
@@ -119,17 +119,6 @@ public class JmeDesktopSystem extends JmeSystemDelegate {
         }
     }
 
-    @Override
-    public ImageRaster createImageRaster(Image image, int slice) {
-        assert image.getEfficentData() == null;
-        return new DefaultImageRaster(image, slice);
-    }
-
-    @Override
-    public AssetManager newAssetManager() {
-        return new DesktopAssetManager(null);
-    }
-
     @Override
     public void showErrorDialog(String message) {
         final String msg = message;

+ 4 - 0
jme3-ios/src/main/java/com/jme3/asset/IOS.cfg

@@ -0,0 +1,4 @@
+INCLUDE com/jme3/asset/General.cfg
+
+# IOS specific loaders
+LOADER com.jme3.system.ios.IosImageLoader : jpg, bmp, gif, png, jpeg

+ 0 - 109
jme3-ios/src/main/java/com/jme3/system/ios/IosAssetManager.java

@@ -1,109 +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.system.ios;
-
-import com.jme3.asset.AssetLoader;
-import com.jme3.asset.DesktopAssetManager;
-import com.jme3.asset.TextureKey;
-import com.jme3.asset.plugins.ClasspathLocator;
-import com.jme3.audio.plugins.WAVLoader;
-import com.jme3.texture.Texture;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- *
- * @author normenhansen
- */
-public class IosAssetManager extends DesktopAssetManager {
-
-    private static final Logger logger = Logger.getLogger(IosAssetManager.class.getName());
-
-    public IosAssetManager() {
-        this(null);
-    }
-
-    @Deprecated
-    public IosAssetManager(boolean loadDefaults) {
-        //this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Android.cfg"));
-        this(null);
-    }
-    
-    private void registerLoaderSafe(String loaderClass, String ... extensions) {
-        try {
-            Class<? extends AssetLoader> loader = (Class<? extends AssetLoader>) Class.forName(loaderClass);
-            registerLoader(loader, extensions);
-        } catch (Exception e){
-            logger.log(Level.WARNING, "Failed to load AssetLoader", e);
-        }
-    }
-
-    /**
-     * AndroidAssetManager constructor
-     * If URL == null then a default list of locators and loaders for android is set
-     * @param configFile
-     */
-    public IosAssetManager(URL configFile) {
-        System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
-        
-        // Set Default iOS config
-        registerLocator("", ClasspathLocator.class);
-        
-        registerLoader(IosImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
-        //registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
-        //registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav");
-        registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
-        registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
-        registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
-        registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o");
-        registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
-        registerLoader(WAVLoader.class, "wav");
-        
-        // Less common loaders (especially on iOS)
-        registerLoaderSafe("com.jme3.audio.plugins.OGGLoader", "ogg");
-        registerLoaderSafe("com.jme3.texture.plugins.DDSLoader", "dds");
-        registerLoaderSafe("com.jme3.texture.plugins.PFMLoader", "pfm");
-        registerLoaderSafe("com.jme3.texture.plugins.HDRLoader", "hdr");
-        registerLoaderSafe("com.jme3.texture.plugins.TGALoader", "tga");
-        registerLoaderSafe("com.jme3.scene.plugins.OBJLoader", "obj");
-        registerLoaderSafe("com.jme3.scene.plugins.MTLLoader", "mtl");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.MeshLoader", "mesh.xml");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.SkeletonLoader", "skeleton.xml");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.MaterialLoader", "material");
-        registerLoaderSafe("com.jme3.scene.plugins.ogre.SceneLoader", "scene");
-        
-
-        logger.fine("IosAssetManager created.");
-    }
-}

+ 5 - 19
jme3-ios/src/main/java/com/jme3/system/ios/JmeIosSystem.java

@@ -31,17 +31,13 @@
  */
 package com.jme3.system.ios;
 
-import com.jme3.asset.AssetManager;
 import com.jme3.audio.AudioRenderer;
 import com.jme3.system.AppSettings;
 import com.jme3.system.JmeContext;
 import com.jme3.system.JmeSystemDelegate;
 import com.jme3.system.NullContext;
-import com.jme3.texture.Image;
-import com.jme3.texture.image.ImageRaster;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.net.URL;
 import java.nio.ByteBuffer;
 import java.util.logging.Logger;
 
@@ -52,18 +48,13 @@ import java.util.logging.Logger;
 public class JmeIosSystem extends JmeSystemDelegate {
 
     @Override
-    public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
-    public AssetManager newAssetManager(URL configFile) {
-        return new IosAssetManager(configFile);
+    public String getPlatformAssetConfigPath() {
+        return "com/jme3/asset/IOS.cfg";
     }
-
+    
     @Override
-    public AssetManager newAssetManager() {
-        return new IosAssetManager();
+    public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
     }
 
     @Override
@@ -106,11 +97,6 @@ public class JmeIosSystem extends JmeSystemDelegate {
 //                throw new UnsupportedOperationException("Not supported yet.");
     }
 
-    @Override
-    public ImageRaster createImageRaster(Image image, int slice) {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
     @Override
     public void showSoftKeyboard(boolean show) {
         throw new UnsupportedOperationException("Not supported yet.");

+ 224 - 0
jme3-plugins/src/fbx/java/com/jme3/scene/plugins/fbx/file/FBXDump.java

@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2009-2015 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.scene.plugins.fbx.file;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Array;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.Map;
+import static org.omg.IOP.IORHelper.id;
+
+/**
+ * Quick n' dirty dumper of FBX binary files.
+ * 
+ * Outputs a format similar to an ASCII FBX file.
+ * 
+ * @author Kirill Vainer
+ */
+public final class FBXDump {
+    
+    private static final DecimalFormat DECIMAL_FORMAT 
+            = new DecimalFormat("0.0000000000");
+    
+    private FBXDump() { }
+    
+    /**
+     * Creates a map between object UIDs and the objects themselves.
+     * 
+     * @param file The file to create the mappings for.
+     * @return The UID to object map.
+     */
+    private static Map<Long, FBXElement> createUidToObjectMap(FBXFile file) {
+        Map<Long, FBXElement> uidToObjectMap = new HashMap<Long, FBXElement>();
+        for (FBXElement rootElement : file.rootElements) {
+            if (rootElement.id.equals("Objects")) {
+                for (FBXElement fbxObj : rootElement.children) {
+                    if (fbxObj.propertiesTypes[0] != 'L') {
+                        continue; // error
+                    }
+                    Long uid = (Long) fbxObj.properties.get(0);
+                    uidToObjectMap.put(uid, fbxObj);
+                }
+            }
+        }
+        return uidToObjectMap;
+    }
+    
+    /**
+     * Dump FBX to standard output.
+     * 
+     * @param file the file to dump.
+     */
+    public static void dumpFBX(FBXFile file) {
+        dumpFBX(file, System.out);
+    }
+    
+    /**
+     * Dump FBX to the given output stream.
+     * 
+     * @param file the file to dump.
+     * @param out the output stream where to output.
+     */
+    public static void dumpFBX(FBXFile file, OutputStream out) {
+        Map<Long, FBXElement> uidToObjectMap = createUidToObjectMap(file);
+        PrintStream ps = new PrintStream(out);
+        for (FBXElement rootElement : file.rootElements) {
+            dumpFBXElement(rootElement, ps, 0, uidToObjectMap);
+        }
+    }
+    
+    private static String indent(int amount) {
+        return "                        ".substring(0, amount);
+    }
+    
+    /**
+     * Convert FBX string - this replaces all instances of
+     * <code>\x00\x01</code> to "::".
+     * 
+     * @param string The string to convert
+     * @return 
+     */
+    private static String convertFBXString(String string) {
+        return string.replaceAll("\u0000\u0001", "::");
+    }
+
+    protected static void dumpFBXProperty(String id, char propertyType, 
+                                          Object property, PrintStream ps, 
+                                          Map<Long, FBXElement> uidToObjectMap) {
+        switch (propertyType) {
+            case 'S':
+                // String
+                String str = (String) property;
+                ps.print("\"" + convertFBXString(str) + "\"");
+                break;
+            case 'R':
+                // RAW data.
+                byte[] bytes = (byte[]) property;
+                ps.print("[");
+                for (int j = 0; j < bytes.length; j++) {
+                    ps.print(String.format("%02X", bytes[j] & 0xff));
+                    if (j != bytes.length - 1) {
+                        ps.print(" ");
+                    }
+                }
+                ps.print("]");
+                break;
+            case 'D':
+            case 'F':
+                // Double, Float.
+                if (property instanceof Double) {
+                    ps.print(DECIMAL_FORMAT.format((Double)property));
+                } else if (property instanceof Float) {
+                    ps.print(DECIMAL_FORMAT.format((Float)property));
+                } else {
+                    ps.print(property);
+                }
+                break;
+            case 'I':
+            case 'Y':
+                // Integer, Signed Short.
+                ps.print(property);
+                break;
+            case 'C':
+                // Boolean
+                ps.print((Boolean)property ? "1" : "0");
+                break;
+            case 'L':
+                // Long
+                // If this is a connection, decode UID into object name.
+                if (id.equals("C")) {
+                    Long uid = (Long) property;
+                    FBXElement element = uidToObjectMap.get(uid);
+                    if (element != null) {
+                        String name = (String) element.properties.get(1);
+                        ps.print("\"" + convertFBXString(name) + "\"");
+                    } else {
+                        ps.print(property);
+                    }
+                } else {
+                    ps.print(property);
+                }
+                break;
+            case 'd':
+            case 'i':
+            case 'l':
+            case 'f':
+                // Arrays of things..
+                int length = Array.getLength(property);
+                for (int j = 0; j < length; j++) {
+                    Object arrayEntry = Array.get(property, j);
+                    dumpFBXProperty(id, Character.toUpperCase(propertyType), arrayEntry, ps, uidToObjectMap);
+                    if (j != length - 1) {
+                        ps.print(",");
+                    }
+                }
+                break;
+            default: 
+                throw new UnsupportedOperationException("" + propertyType);
+        }
+    }
+    
+    protected static void dumpFBXElement(FBXElement el, PrintStream ps, 
+                                         int indent, Map<Long, FBXElement> uidToObjectMap) {
+        // 4 spaces per tab should be OK.
+        String indentStr = indent(indent * 4);
+        String textId = el.id;
+        
+        // Properties are called 'P' and connections are called 'C'.
+        if (el.id.equals("P")) {
+            textId = "Property";
+        } else if (el.id.equals("C")) {
+            textId = "Connect";
+        }
+        
+        ps.print(indentStr + textId + ": ");
+        for (int i = 0; i < el.properties.size(); i++) {
+            Object property = el.properties.get(i);
+            char propertyType = el.propertiesTypes[i];
+            dumpFBXProperty(el.id, propertyType, property, ps, uidToObjectMap);
+            if (i != el.properties.size() - 1) {
+                ps.print(", ");
+            }
+        }
+        if (el.children.isEmpty()) {
+            ps.println();
+        } else {
+            ps.println(" {");
+            for (FBXElement childElement : el.children) {
+                dumpFBXElement(childElement, ps, indent + 1, uidToObjectMap);
+            }
+            ps.println(indentStr + "}");
+        }
+    }
+}

+ 7 - 4
jme3-plugins/src/xml/java/com/jme3/export/xml/XMLImporter.java

@@ -71,12 +71,15 @@ public class XMLImporter implements JmeImporter {
         this.assetManager = assetManager;
     }
 
-    public Object load(AssetInfo info) throws IOException{
+    public Object load(AssetInfo info) throws IOException {
         assetManager = info.getManager();
         InputStream in = info.openStream();
-        Savable obj = load(in);
-        in.close();
-        return obj;
+        try {
+            return load(in);
+        } finally {
+            if (in != null)
+                in.close();
+        }
     }
     
     public Savable load(File f) throws IOException {