Browse Source

* Andrid - AndroidLocator now follows spec when regards to multiple call support with AssetInfo.openStream()
* Android - fix exception with recycled bitmaps that occurs when jME3 application is restored/maximized after pause

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9144 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Sha..rd 13 years ago
parent
commit
a64db6fc7b

+ 4 - 22
engine/src/android/com/jme3/asset/AndroidAssetManager.java

@@ -37,8 +37,6 @@ import com.jme3.audio.plugins.AndroidAudioLoader;
 import com.jme3.texture.Texture;
 import com.jme3.texture.plugins.AndroidImageLoader;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.logging.Logger;
 
 /**
@@ -49,7 +47,6 @@ import java.util.logging.Logger;
 public class AndroidAssetManager extends DesktopAssetManager {
 
     private static final Logger logger = Logger.getLogger(AndroidAssetManager.class.getName());
-    private List<ClassLoader> classLoaders;
 
     public AndroidAssetManager() {
         this(null);
@@ -67,10 +64,8 @@ public class AndroidAssetManager extends DesktopAssetManager {
      * @param configFile
      */
     public AndroidAssetManager(URL configFile) {
-
         System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
 
-
         // Set Default Android config        	       
         this.registerLocator("", AndroidLocator.class);
         this.registerLocator("", ClasspathLocator.class);
@@ -92,25 +87,9 @@ public class AndroidAssetManager extends DesktopAssetManager {
         this.registerLoader(com.jme3.scene.plugins.ogre.SceneLoader.class, "scene");
         this.registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
 
-
         logger.info("AndroidAssetManager created.");
     }
 
-    public void addClassLoader(ClassLoader loader){
-        if(classLoaders == null)
-            classLoaders = new ArrayList<ClassLoader>();
-        classLoaders.add(loader);
-    }
-    
-    public void removeClassLoader(ClassLoader loader){
-        if(classLoaders != null)
-            classLoaders.remove(loader);
-    }
-
-    public List<ClassLoader> getClassLoaders(){
-        return classLoaders;
-    }
-    
     /**
      * Loads a texture. 
      *
@@ -120,7 +99,10 @@ public class AndroidAssetManager extends DesktopAssetManager {
     public Texture loadTexture(TextureKey key) {
         Texture tex = (Texture) loadAsset(key);
 
-        // Needed for Android
+        // XXX: This will improve performance on some really
+        // low end GPUs (e.g. ones with OpenGL ES 1 support only)
+        // but otherwise won't help on the higher ones. 
+        // Strongly consider removing this.
         tex.setMagFilter(Texture.MagFilter.Nearest);
         tex.setAnisotropicFilter(0);
         if (tex.getMinFilter().usesMipMapLevels()) {

+ 54 - 38
engine/src/android/com/jme3/asset/plugins/AndroidLocator.java

@@ -1,74 +1,90 @@
 package com.jme3.asset.plugins;
 
-import android.content.res.Resources;
-import com.jme3.asset.AssetInfo;
-import com.jme3.asset.AssetKey;
-import com.jme3.asset.AssetLocator;
+import com.jme3.asset.*;
 import com.jme3.system.android.JmeAndroidSystem;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 public class AndroidLocator implements AssetLocator {
 
     private static final Logger logger = Logger.getLogger(AndroidLocator.class.getName());
-    private Resources resources;
+    
     private android.content.res.AssetManager androidManager;
     private String rootPath = "";
 
     private class AndroidAssetInfo extends AssetInfo {
 
-        private final InputStream in;
+        private InputStream in;
+        private final String assetPath;
 
-        public AndroidAssetInfo(com.jme3.asset.AssetManager manager, AssetKey<?> key, InputStream in)
-        {
-            super(manager, key);
+        public AndroidAssetInfo(com.jme3.asset.AssetManager assetManager, AssetKey<?> key, String assetPath, InputStream in) {
+            super(assetManager, key);
+            this.assetPath = assetPath;
             this.in = in;
         }
-
+        
         @Override
         public InputStream openStream() {
-            return in;
+            if (in != null){
+                // Reuse the already existing stream (only once)
+                InputStream in2 = in;
+                in = null;
+                return in2;
+            }else{
+                // Create a new stream for subsequent invocations.
+                try {
+                    return androidManager.open(assetPath);
+                } catch (IOException ex) {
+                    throw new AssetLoadException("Failed to open asset " + assetPath, ex);
+                }
+            }
         }
     }
 
-
-    public AndroidLocator()
-    {
-        resources = JmeAndroidSystem.getResources();
-        androidManager = resources.getAssets();
+    private AndroidAssetInfo create(AssetManager assetManager, AssetKey key, String assetPath) throws IOException {
+        try {
+            InputStream in = androidManager.open(assetPath);
+            if (in == null){
+                return null;
+            }else{
+                return new AndroidAssetInfo(assetManager, key, assetPath, in);
+            }
+        } catch (IOException ex) {
+            // XXX: Prefer to show warning here?
+            // Should only surpress exceptions for "file missing" type errors.
+            return null;
+        }
     }
     
-    public void setRootPath(String rootPath) 
-    {
+    public AndroidLocator() {
+        androidManager = JmeAndroidSystem.getResources().getAssets();
+    }
+
+    public void setRootPath(String rootPath) {
         this.rootPath = rootPath;
     }
 
     @SuppressWarnings("rawtypes")
     @Override
-    public AssetInfo locate(com.jme3.asset.AssetManager manager, AssetKey key) 
-    {
-        InputStream in = null;
-        String sAssetPath = rootPath + key.getName();
+    public AssetInfo locate(com.jme3.asset.AssetManager manager, AssetKey key) {
+        String assetPath = rootPath + key.getName();
         // Fix path issues
-        if (sAssetPath.startsWith("/"))
-        {
+        if (assetPath.startsWith("/")) {
             // Remove leading /
-            sAssetPath = sAssetPath.substring(1);
+            assetPath = assetPath.substring(1);
         }
-        sAssetPath = sAssetPath.replace("//", "/");
-        try {      
-            in = androidManager.open(sAssetPath);
-            if (in == null)
-                return null;
-
-            return new AndroidAssetInfo(manager, key, in);
-        } 
-        catch (IOException ex) 
-        {
-            //logger.log(Level.WARNING, "Failed to locate {0} ", sAssetPath);
+        assetPath = assetPath.replace("//", "/");
+        try {
+            return create(manager, key, assetPath);
+        }catch (IOException ex){
+            // This is different handling than URL locator
+            // since classpath locating would return null at the getResource() 
+            // call, otherwise there's a more critical error...
+            throw new AssetLoadException("Failed to open asset " + assetPath, ex);
         }
-        return null;
     }
-
 }

+ 3 - 2
engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java

@@ -36,6 +36,7 @@ import android.opengl.GLES10;
 import android.opengl.GLES11;
 import android.opengl.GLES20;
 import android.os.Build;
+import com.jme3.asset.AndroidImageInfo;
 import com.jme3.light.LightList;
 import com.jme3.material.RenderState;
 import com.jme3.math.*;
@@ -1915,7 +1916,7 @@ public class OGLESShaderRenderer implements Renderer {
         if (target == GLES20.GL_TEXTURE_CUBE_MAP) {
             // Upload a cube map / sky box
             @SuppressWarnings("unchecked")
-            List<Bitmap> bmps = (List<Bitmap>) img.getEfficentData();
+            List<AndroidImageInfo> bmps = (List<AndroidImageInfo>) img.getEfficentData();
             if (bmps != null) {
                 // Native android bitmap                                       
                 if (bmps.size() != 6) {
@@ -1923,7 +1924,7 @@ public class OGLESShaderRenderer implements Renderer {
                             + "Cubemap textures must contain 6 data units.");
                 }
                 for (int i = 0; i < 6; i++) {
-                    TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i), false, powerOf2);
+                    TextureUtil.uploadTextureBitmap(GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, bmps.get(i).getBitmap(), false, powerOf2);
                 }
             } else {
                 // Standard jme3 image data

+ 8 - 3
engine/src/android/com/jme3/renderer/android/TextureUtil.java

@@ -3,6 +3,7 @@ package com.jme3.renderer.android;
 import android.graphics.Bitmap;
 import android.opengl.GLES20;
 import android.opengl.GLUtils;
+import com.jme3.asset.AndroidImageInfo;
 import com.jme3.math.FastMath;
 import com.jme3.texture.Image;
 import com.jme3.texture.Image.Format;
@@ -118,12 +119,16 @@ public class TextureUtil {
                                      boolean generateMips,
                                      boolean powerOf2){
 
-        if (img.getEfficentData() instanceof Bitmap){
-            Bitmap bitmap = (Bitmap) img.getEfficentData();
-            uploadTextureBitmap(target, bitmap, generateMips, powerOf2);
+        if (img.getEfficentData() instanceof AndroidImageInfo){
+            // If image was loaded from asset manager, use fast path
+            AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData();
+            uploadTextureBitmap(target, imageInfo.getBitmap(), generateMips, powerOf2);
             return;
         }
 
+        // Otherwise upload image directly. 
+        // Prefer to only use power of 2 textures here to avoid errors.
+        
         Image.Format fmt = img.getFormat();
         ByteBuffer data;
         if (index >= 0 || img.getData() != null && img.getData().size() > 0){

+ 6 - 64
engine/src/android/com/jme3/texture/plugins/AndroidImageLoader.java

@@ -1,78 +1,20 @@
 package com.jme3.texture.plugins;
 
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Matrix;
+import com.jme3.asset.AndroidImageInfo;
 import com.jme3.asset.AssetInfo;
 import com.jme3.asset.AssetLoader;
-import com.jme3.asset.TextureKey;
 import com.jme3.texture.Image;
-import com.jme3.texture.Image.Format;
-import com.jme3.util.BufferUtils;
 import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
 
 public class AndroidImageLoader implements AssetLoader {
 
-    public Object load2(AssetInfo info) throws IOException {
-        ByteBuffer bb = BufferUtils.createByteBuffer(1 * 1 * 2);
-        bb.put((byte) 0xff).put((byte) 0xff);
-        bb.clear();
-        return new Image(Format.RGB5A1, 1, 1, bb);
-    }
-
     public Object load(AssetInfo info) throws IOException {
-        InputStream in = null;
-        Bitmap bitmap = null;
-        try {
-            in = info.openStream();
-            bitmap = BitmapFactory.decodeStream(in);
-            if (bitmap == null) {
-                throw new IOException("Failed to load image: " + info.getKey().getName());
-            }
-        } finally {
-            if (in != null) {
-                in.close();
-            }
-        }
-
-        int width = bitmap.getWidth();
-        int height = bitmap.getHeight();
-        Format fmt;
-
-        switch (bitmap.getConfig()) {
-            case ALPHA_8:
-                fmt = Format.Alpha8;
-                break;
-            case ARGB_4444:
-                fmt = Format.ARGB4444;
-                break;
-            case ARGB_8888:
-                fmt = Format.RGBA8;
-                break;
-            case RGB_565:
-                fmt = Format.RGB565;
-                break;
-            default:
-                return null;
-        }
-
-        if (((TextureKey) info.getKey()).isFlipY()) {
-            Bitmap newBitmap = null;
-            Matrix flipMat = new Matrix();
-            flipMat.preScale(1.0f, -1.0f);
-            newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), flipMat, false);
-            bitmap.recycle();
-            bitmap = newBitmap;
-
-            if (bitmap == null) {
-                throw new IOException("Failed to flip image: " + info.getKey().getName());
-            }
-        }
-
-        Image image = new Image(fmt, width, height, null);
-        image.setEfficentData(bitmap);
+        AndroidImageInfo imageInfo = new AndroidImageInfo(info);
+        Bitmap bitmap = imageInfo.getBitmap();
+        
+        Image image = new Image(imageInfo.getFormat(), bitmap.getWidth(), bitmap.getHeight(), null);
+        image.setEfficentData(imageInfo);
         return image;
     }
 }