From a64db6fc7b14035d238357ea7605467058bd44cb Mon Sep 17 00:00:00 2001 From: "Sha..rd" Date: Sat, 11 Feb 2012 06:42:19 +0000 Subject: [PATCH] * 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 --- .../com/jme3/asset/AndroidAssetManager.java | 26 +----- .../jme3/asset/plugins/AndroidLocator.java | 92 +++++++++++-------- .../renderer/android/OGLESShaderRenderer.java | 5 +- .../jme3/renderer/android/TextureUtil.java | 11 ++- .../texture/plugins/AndroidImageLoader.java | 70 ++------------ 5 files changed, 75 insertions(+), 129 deletions(-) diff --git a/engine/src/android/com/jme3/asset/AndroidAssetManager.java b/engine/src/android/com/jme3/asset/AndroidAssetManager.java index 92bc02ad0..59e9ca5df 100644 --- a/engine/src/android/com/jme3/asset/AndroidAssetManager.java +++ b/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 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(); - classLoaders.add(loader); - } - - public void removeClassLoader(ClassLoader loader){ - if(classLoaders != null) - classLoaders.remove(loader); - } - - public List 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()) { diff --git a/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java b/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java index c7a8c3d4e..01b1cab9e 100644 --- a/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java +++ b/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; } - } diff --git a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java index ad039a23c..275dc0e4f 100644 --- a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java +++ b/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 bmps = (List) img.getEfficentData(); + List bmps = (List) 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 diff --git a/engine/src/android/com/jme3/renderer/android/TextureUtil.java b/engine/src/android/com/jme3/renderer/android/TextureUtil.java index 672fbc25f..53b96b400 100644 --- a/engine/src/android/com/jme3/renderer/android/TextureUtil.java +++ b/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){ diff --git a/engine/src/android/com/jme3/texture/plugins/AndroidImageLoader.java b/engine/src/android/com/jme3/texture/plugins/AndroidImageLoader.java index 25852a885..17f850e7a 100644 --- a/engine/src/android/com/jme3/texture/plugins/AndroidImageLoader.java +++ b/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; } }