* 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
This commit is contained in:
parent
3fa629053a
commit
a64db6fc7b
@ -37,8 +37,6 @@ import com.jme3.audio.plugins.AndroidAudioLoader;
|
|||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
import com.jme3.texture.plugins.AndroidImageLoader;
|
import com.jme3.texture.plugins.AndroidImageLoader;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,7 +47,6 @@ import java.util.logging.Logger;
|
|||||||
public class AndroidAssetManager extends DesktopAssetManager {
|
public class AndroidAssetManager extends DesktopAssetManager {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AndroidAssetManager.class.getName());
|
private static final Logger logger = Logger.getLogger(AndroidAssetManager.class.getName());
|
||||||
private List<ClassLoader> classLoaders;
|
|
||||||
|
|
||||||
public AndroidAssetManager() {
|
public AndroidAssetManager() {
|
||||||
this(null);
|
this(null);
|
||||||
@ -67,10 +64,8 @@ public class AndroidAssetManager extends DesktopAssetManager {
|
|||||||
* @param configFile
|
* @param configFile
|
||||||
*/
|
*/
|
||||||
public AndroidAssetManager(URL configFile) {
|
public AndroidAssetManager(URL configFile) {
|
||||||
|
|
||||||
System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
|
System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
|
||||||
|
|
||||||
|
|
||||||
// Set Default Android config
|
// Set Default Android config
|
||||||
this.registerLocator("", AndroidLocator.class);
|
this.registerLocator("", AndroidLocator.class);
|
||||||
this.registerLocator("", ClasspathLocator.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.scene.plugins.ogre.SceneLoader.class, "scene");
|
||||||
this.registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
|
this.registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
|
||||||
|
|
||||||
|
|
||||||
logger.info("AndroidAssetManager created.");
|
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.
|
* Loads a texture.
|
||||||
*
|
*
|
||||||
@ -120,7 +99,10 @@ public class AndroidAssetManager extends DesktopAssetManager {
|
|||||||
public Texture loadTexture(TextureKey key) {
|
public Texture loadTexture(TextureKey key) {
|
||||||
Texture tex = (Texture) loadAsset(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.setMagFilter(Texture.MagFilter.Nearest);
|
||||||
tex.setAnisotropicFilter(0);
|
tex.setAnisotropicFilter(0);
|
||||||
if (tex.getMinFilter().usesMipMapLevels()) {
|
if (tex.getMinFilter().usesMipMapLevels()) {
|
||||||
|
@ -1,74 +1,90 @@
|
|||||||
package com.jme3.asset.plugins;
|
package com.jme3.asset.plugins;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
import com.jme3.asset.*;
|
||||||
import com.jme3.asset.AssetInfo;
|
|
||||||
import com.jme3.asset.AssetKey;
|
|
||||||
import com.jme3.asset.AssetLocator;
|
|
||||||
import com.jme3.system.android.JmeAndroidSystem;
|
import com.jme3.system.android.JmeAndroidSystem;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class AndroidLocator implements AssetLocator {
|
public class AndroidLocator implements AssetLocator {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AndroidLocator.class.getName());
|
private static final Logger logger = Logger.getLogger(AndroidLocator.class.getName());
|
||||||
private Resources resources;
|
|
||||||
private android.content.res.AssetManager androidManager;
|
private android.content.res.AssetManager androidManager;
|
||||||
private String rootPath = "";
|
private String rootPath = "";
|
||||||
|
|
||||||
private class AndroidAssetInfo extends AssetInfo {
|
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)
|
public AndroidAssetInfo(com.jme3.asset.AssetManager assetManager, AssetKey<?> key, String assetPath, InputStream in) {
|
||||||
{
|
super(assetManager, key);
|
||||||
super(manager, key);
|
this.assetPath = assetPath;
|
||||||
this.in = in;
|
this.in = in;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream openStream() {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AndroidAssetInfo create(AssetManager assetManager, AssetKey key, String assetPath) throws IOException {
|
||||||
public AndroidLocator()
|
try {
|
||||||
{
|
InputStream in = androidManager.open(assetPath);
|
||||||
resources = JmeAndroidSystem.getResources();
|
if (in == null){
|
||||||
androidManager = resources.getAssets();
|
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;
|
this.rootPath = rootPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
public AssetInfo locate(com.jme3.asset.AssetManager manager, AssetKey key)
|
public AssetInfo locate(com.jme3.asset.AssetManager manager, AssetKey key) {
|
||||||
{
|
String assetPath = rootPath + key.getName();
|
||||||
InputStream in = null;
|
|
||||||
String sAssetPath = rootPath + key.getName();
|
|
||||||
// Fix path issues
|
// Fix path issues
|
||||||
if (sAssetPath.startsWith("/"))
|
if (assetPath.startsWith("/")) {
|
||||||
{
|
|
||||||
// Remove leading /
|
// Remove leading /
|
||||||
sAssetPath = sAssetPath.substring(1);
|
assetPath = assetPath.substring(1);
|
||||||
}
|
}
|
||||||
sAssetPath = sAssetPath.replace("//", "/");
|
assetPath = assetPath.replace("//", "/");
|
||||||
try {
|
try {
|
||||||
in = androidManager.open(sAssetPath);
|
return create(manager, key, assetPath);
|
||||||
if (in == null)
|
}catch (IOException ex){
|
||||||
return null;
|
// This is different handling than URL locator
|
||||||
|
// since classpath locating would return null at the getResource()
|
||||||
return new AndroidAssetInfo(manager, key, in);
|
// call, otherwise there's a more critical error...
|
||||||
|
throw new AssetLoadException("Failed to open asset " + assetPath, ex);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
//logger.log(Level.WARNING, "Failed to locate {0} ", sAssetPath);
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import android.opengl.GLES10;
|
|||||||
import android.opengl.GLES11;
|
import android.opengl.GLES11;
|
||||||
import android.opengl.GLES20;
|
import android.opengl.GLES20;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import com.jme3.asset.AndroidImageInfo;
|
||||||
import com.jme3.light.LightList;
|
import com.jme3.light.LightList;
|
||||||
import com.jme3.material.RenderState;
|
import com.jme3.material.RenderState;
|
||||||
import com.jme3.math.*;
|
import com.jme3.math.*;
|
||||||
@ -1915,7 +1916,7 @@ public class OGLESShaderRenderer implements Renderer {
|
|||||||
if (target == GLES20.GL_TEXTURE_CUBE_MAP) {
|
if (target == GLES20.GL_TEXTURE_CUBE_MAP) {
|
||||||
// Upload a cube map / sky box
|
// Upload a cube map / sky box
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<Bitmap> bmps = (List<Bitmap>) img.getEfficentData();
|
List<AndroidImageInfo> bmps = (List<AndroidImageInfo>) img.getEfficentData();
|
||||||
if (bmps != null) {
|
if (bmps != null) {
|
||||||
// Native android bitmap
|
// Native android bitmap
|
||||||
if (bmps.size() != 6) {
|
if (bmps.size() != 6) {
|
||||||
@ -1923,7 +1924,7 @@ public class OGLESShaderRenderer implements Renderer {
|
|||||||
+ "Cubemap textures must contain 6 data units.");
|
+ "Cubemap textures must contain 6 data units.");
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 6; i++) {
|
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 {
|
} else {
|
||||||
// Standard jme3 image data
|
// Standard jme3 image data
|
||||||
|
@ -3,6 +3,7 @@ package com.jme3.renderer.android;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.opengl.GLES20;
|
import android.opengl.GLES20;
|
||||||
import android.opengl.GLUtils;
|
import android.opengl.GLUtils;
|
||||||
|
import com.jme3.asset.AndroidImageInfo;
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.texture.Image;
|
import com.jme3.texture.Image;
|
||||||
import com.jme3.texture.Image.Format;
|
import com.jme3.texture.Image.Format;
|
||||||
@ -118,12 +119,16 @@ public class TextureUtil {
|
|||||||
boolean generateMips,
|
boolean generateMips,
|
||||||
boolean powerOf2){
|
boolean powerOf2){
|
||||||
|
|
||||||
if (img.getEfficentData() instanceof Bitmap){
|
if (img.getEfficentData() instanceof AndroidImageInfo){
|
||||||
Bitmap bitmap = (Bitmap) img.getEfficentData();
|
// If image was loaded from asset manager, use fast path
|
||||||
uploadTextureBitmap(target, bitmap, generateMips, powerOf2);
|
AndroidImageInfo imageInfo = (AndroidImageInfo) img.getEfficentData();
|
||||||
|
uploadTextureBitmap(target, imageInfo.getBitmap(), generateMips, powerOf2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise upload image directly.
|
||||||
|
// Prefer to only use power of 2 textures here to avoid errors.
|
||||||
|
|
||||||
Image.Format fmt = img.getFormat();
|
Image.Format fmt = img.getFormat();
|
||||||
ByteBuffer data;
|
ByteBuffer data;
|
||||||
if (index >= 0 || img.getData() != null && img.getData().size() > 0){
|
if (index >= 0 || img.getData() != null && img.getData().size() > 0){
|
||||||
|
@ -1,78 +1,20 @@
|
|||||||
package com.jme3.texture.plugins;
|
package com.jme3.texture.plugins;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import com.jme3.asset.AndroidImageInfo;
|
||||||
import android.graphics.Matrix;
|
|
||||||
import com.jme3.asset.AssetInfo;
|
import com.jme3.asset.AssetInfo;
|
||||||
import com.jme3.asset.AssetLoader;
|
import com.jme3.asset.AssetLoader;
|
||||||
import com.jme3.asset.TextureKey;
|
|
||||||
import com.jme3.texture.Image;
|
import com.jme3.texture.Image;
|
||||||
import com.jme3.texture.Image.Format;
|
|
||||||
import com.jme3.util.BufferUtils;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class AndroidImageLoader implements AssetLoader {
|
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 {
|
public Object load(AssetInfo info) throws IOException {
|
||||||
InputStream in = null;
|
AndroidImageInfo imageInfo = new AndroidImageInfo(info);
|
||||||
Bitmap bitmap = null;
|
Bitmap bitmap = imageInfo.getBitmap();
|
||||||
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();
|
Image image = new Image(imageInfo.getFormat(), bitmap.getWidth(), bitmap.getHeight(), null);
|
||||||
int height = bitmap.getHeight();
|
image.setEfficentData(imageInfo);
|
||||||
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);
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user