src/android patchset: changes AndroidAssetManager, AndroidInput, OGLESContext, JmeSystem, TextureLoader

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7502 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
kim..ng 14 years ago
parent 0ec3bb6dba
commit a8e9d803dc
  1. 287
      engine/src/android/com/jme3/app/android/AndroidApplication.java
  2. 347
      engine/src/android/com/jme3/asset/AndroidAssetManager.java
  3. 43
      engine/src/android/com/jme3/asset/plugins/AndroidLocator.java
  4. 534
      engine/src/android/com/jme3/input/android/AndroidInput.java
  5. 19
      engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java
  6. 70
      engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
  7. 80
      engine/src/android/com/jme3/renderer/android/TextureUtil.java
  8. 34
      engine/src/android/com/jme3/system/JmeSystem.java
  9. 20
      engine/src/android/com/jme3/system/android/AndroidTimer.java
  10. 315
      engine/src/android/com/jme3/system/android/OGLESContext.java
  11. 58
      engine/src/android/com/jme3/texture/plugins/AndroidImageLoader.java
  12. 359
      engine/src/android/com/jme3/util/FastInteger.java

@ -0,0 +1,287 @@
/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.app.android;
import java.nio.CharBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import com.jme3.app.Application;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.android.AndroidInput;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
import com.jme3.util.FastInteger;
/**
* <code>AndroidApplication</code> extends the {@link com.jme3.app.Application}
* class to provide default functionality like a first-person camera,
* and an accessible root node that is updated and rendered regularly.
* It will display the current frames-per-second value on-screen.
*
*
*/
public abstract class AndroidApplication extends Application implements DialogInterface.OnClickListener
{
protected Node rootNode = new Node("Root Node");
protected Node guiNode = new Node("Gui Node");
protected float secondCounter = 0.0f;
protected BitmapText fpsText;
protected CharBuffer textBuf = CharBuffer.allocate(50);
protected char[] fpsBuf = new char[16];
protected BitmapFont guiFont;
protected Activity activity;
protected AndroidInput input;
protected final AtomicBoolean loadingFinished;
public AndroidApplication()
{
this(null, null);
}
public AndroidApplication(Activity activity, AndroidInput input)
{
super();
this.activity = activity;
this.input = input;
loadingFinished = new AtomicBoolean(false);
}
@Override
public void start()
{
// Set the correct xml parser driver for android
System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");
if (settings == null)
{
settings = new AppSettings(true);
}
// Use vertex arrays for rendering
settings.putBoolean("USE_VA", true);
// Verbose logging off
settings.putBoolean("VERBOSE_LOGGING", false);
//re-setting settings they can have been merged from the registry.
setSettings(settings);
super.start();
}
/**
* Retrieves guiNode
* @return guiNode Node object
*
*/
public Node getGuiNode() {
return guiNode;
}
/**
* Retrieves rootNode
* @return rootNode Node object
*
*/
public Node getRootNode() {
return rootNode;
}
/**
* Attaches FPS statistics to guiNode and displays it on the screen.
*
*/
public void loadFPSText() {
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
fpsText = new BitmapText(guiFont, false);
fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0);
fpsText.setText("Frames per second");
guiNode.attachChild(fpsText);
}
@Override
public void initialize()
{
// Create a default Android assetmanager before Application can create one in super.initialize();
assetManager = JmeSystem.newAssetManager(null);
super.initialize();
guiNode.setQueueBucket(Bucket.Gui);
guiNode.setCullHint(CullHint.Never);
loadFPSText();
viewPort.attachScene(rootNode);
guiViewPort.attachScene(guiNode);
// call user code
init();
// Start thread for async load
Thread t = new Thread(new Runnable()
{
@Override
public void run ()
{
try
{
// call user code
asyncload();
}
catch (Exception e)
{
handleError("AsyncLoad failed", e);
}
loadingFinished.set(true);
}
});
t.setDaemon(true);
t.start();
}
@Override
public void update() {
super.update(); // makes sure to execute AppTasks
if (speed == 0 || paused) {
return;
}
float tpf = timer.getTimePerFrame() * speed;
secondCounter += timer.getTimePerFrame();
int fps = (int) timer.getFrameRate();
if (secondCounter >= 5.0f) {
textBuf.clear();
textBuf.put("Frames per second: ");
FastInteger.toCharArray(fps, fpsBuf);
textBuf.put(fpsBuf);
textBuf.flip();
fpsText.setText(textBuf);
secondCounter = 0.0f;
}
// update states
stateManager.update(tpf);
// simple update and root node
update(tpf);
rootNode.updateLogicalState(tpf);
guiNode.updateLogicalState(tpf);
rootNode.updateGeometricState();
guiNode.updateGeometricState();
// render states
stateManager.render(renderManager);
renderManager.render(tpf);
render(renderManager);
stateManager.postRender();
}
public abstract void init();
public void update(float tpf) {
}
public void render(RenderManager rm) {
}
/**
* Gets called by a different thread to allow
* async loading of assets.
*
* This means that update and rendering can already
* happen while some assets are still loading.
*/
public void asyncload()
{
}
/**
* Called when an error has occured. This is typically
* invoked when an uncought exception is thrown in the render thread.
* @param errorMsg The error message, if any, or null.
* @param t Throwable object, or null.
*/
@Override
public void handleError(final String errorMsg, final Throwable t)
{
String s = "";
if (t != null && t.getStackTrace() != null)
{
for (StackTraceElement ste: t.getStackTrace())
{
s += ste.getClassName() + "." + ste.getMethodName() + "(" + + ste.getLineNumber() + ") ";
}
}
final String sTrace = s;
activity.runOnUiThread(new Runnable() {
@Override
public void run()
{
AlertDialog dialog = new AlertDialog.Builder(activity)
// .setIcon(R.drawable.alert_dialog_icon)
.setTitle(t != null ? t.toString() : "Failed")
.setPositiveButton("Kill", AndroidApplication.this)
.setMessage((errorMsg != null ? errorMsg + ": " : "") + sTrace)
.create();
dialog.show();
}
});
}
/**
* Called by the android alert dialog, terminate the activity and OpenGL rendering
* @param dialog
* @param whichButton
*/
public void onClick(DialogInterface dialog, int whichButton)
{
this.stop();
activity.finish();
}
}

@ -1,269 +1,118 @@
/*
* Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.asset; package com.jme3.asset;
import com.jme3.asset.plugins.AndroidLocator;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioKey;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.export.binary.BinaryImporter;
import com.jme3.font.BitmapFont;
import com.jme3.font.plugins.BitmapFontLoader;
import com.jme3.material.Material;
import com.jme3.material.plugins.J3MLoader;
import com.jme3.scene.Spatial;
import com.jme3.shader.Shader;
import com.jme3.shader.ShaderKey;
import com.jme3.shader.plugins.GLSLLoader;
import com.jme3.texture.Image;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import com.jme3.texture.plugins.AndroidImageLoader; import com.jme3.texture.plugins.AndroidImageLoader;
import java.io.File; import java.net.URL;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.asset.plugins.AndroidLocator;
import com.jme3.asset.plugins.ClasspathLocator;
/** /**
* AssetManager for Android * <code>AndroidAssetManager</code> is an implementation of DesktopAssetManager for Android
* *
* @author Kirill Vainer * @author larynx
*/ */
public final class AndroidAssetManager implements AssetManager { 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 final AndroidLocator locator = new AndroidLocator();
private final AndroidImageLoader imageLoader = new AndroidImageLoader();
private final BinaryImporter modelLoader = new BinaryImporter();
private final BitmapFontLoader fontLoader = new BitmapFontLoader();
private final J3MLoader j3mLoader = new J3MLoader();
private final J3MLoader j3mdLoader = new J3MLoader();
private final GLSLLoader glslLoader = new GLSLLoader();
private final BinaryExporter exporter = new BinaryExporter();
private final HashMap<AssetKey, Object> cache = new HashMap<AssetKey, Object>();
public AndroidAssetManager(){ public AndroidAssetManager(){
this(false); this(null);
} }
public AndroidAssetManager(boolean loadDefaults){ @Deprecated
if (loadDefaults){ public AndroidAssetManager(boolean loadDefaults){
// AssetConfig cfg = new AssetConfig(this); //this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Android.cfg"));
// InputStream stream = AssetManager.class.getResourceAsStream("Desktop.cfg"); this(null);
// try{ }
// cfg.loadText(stream);
// }catch (IOException ex){ /**
// logger.log(Level.SEVERE, "Failed to load asset config", ex); * AndroidAssetManager constructor
// }finally{ * If URL == null then a default list of locators and loaders for android is set
// if (stream != null) * @param configFile
// try{ */
// stream.close(); public AndroidAssetManager(URL configFile)
// }catch (IOException ex){ {
// } super(configFile);
// } System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");
if (configFile == null)
{
// Set Default
this.registerLocator("", AndroidLocator.class);
this.registerLocator("", ClasspathLocator.class);
this.registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
this.registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
this.registerLoader(com.jme3.texture.plugins.DDSLoader.class, "dds");
this.registerLoader(com.jme3.texture.plugins.PFMLoader.class, "pfm");
this.registerLoader(com.jme3.texture.plugins.HDRLoader.class, "hdr");
this.registerLoader(com.jme3.texture.plugins.TGALoader.class, "tga");
this.registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o");
this.registerLoader(com.jme3.scene.plugins.OBJLoader.class, "obj");
this.registerLoader(com.jme3.scene.plugins.MTLLoader.class, "mtl");
this.registerLoader(com.jme3.scene.plugins.ogre.MeshLoader.class, "meshxml", "mesh.xml");
this.registerLoader(com.jme3.scene.plugins.ogre.SkeletonLoader.class, "skeletonxml", "skeleton.xml");
this.registerLoader(com.jme3.scene.plugins.ogre.MaterialLoader.class, "material");
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."); logger.info("AndroidAssetManager created.");
} }
public void registerLoader(String loaderClass, String ... extensions){ /**
} * Loads a texture.
*
public void registerLocator(String rootPath, String locatorClass, String ... extensions){ * @return
} */
@Override
private Object tryLoadFromHD(AssetKey key){
if (!key.getExtension().equals("fnt"))
return null;
File f = new File("/sdcard/" + key.getName() + ".opt");
if (!f.exists())
return null;
try {
InputStream stream = new FileInputStream(f);
BitmapFont font = (BitmapFont) modelLoader.load(stream, null, null);
stream.close();
return font;
} catch (IOException ex){
}
return null;
}
private void tryPutToHD(AssetKey key, Object data){
if (!key.getExtension().equals("fnt"))
return;
File f = new File("/sdcard/" + key.getName() + ".opt");
try {
BitmapFont font = (BitmapFont) data;
OutputStream stream = new FileOutputStream(f);
exporter.save(font, stream);
stream.close();
} catch (IOException ex){
}
}
public Object loadAsset(AssetKey key){
logger.info("loadAsset(" + key + ")");
Object asset;
// Object asset = tryLoadFromHD(key);
// if (asset != null)
// return asset;
if (key.shouldCache()){
asset = cache.get(key);
if (asset != null)
return key.createClonedInstance(asset);
}
// find resource
AssetInfo info = locator.locate(this, key);
if (info == null){
logger.log(Level.WARNING, "Cannot locate resource: "+key.getName());
return null;
}
String ex = key.getExtension();
logger.log(Level.INFO, "Loading asset: "+key.getName());
try{
if (ex.equals("png") || ex.equals("jpg")
|| ex.equals("jpeg") || ex.equals("j3i")){
Image image;
if (ex.equals("j3i")){
image = (Image) modelLoader.load(info);
}else{
image = (Image) imageLoader.load(info);
}
TextureKey tkey = (TextureKey) key;
asset = image;
Texture tex = (Texture) tkey.postProcess(asset);
tex.setMagFilter(Texture.MagFilter.Nearest);
tex.setAnisotropicFilter(0);
if (tex.getMinFilter().usesMipMapLevels()){
tex.setMinFilter(Texture.MinFilter.NearestNearestMipMap);
}else{
tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
}
asset = tex;
}else if (ex.equals("j3o")){
asset = modelLoader.load(info);
}else if (ex.equals("fnt")){
asset = fontLoader.load(info);
}else if (ex.equals("j3md")){
asset = j3mdLoader.load(info);
}else if (ex.equals("j3m")){
asset = j3mLoader.load(info);
}else{
logger.info("loading asset as glsl shader ...");
asset = glslLoader.load(info);
// logger.log(Level.WARNING, "No loader registered for type: "+ex);
// return null;
}
if (key.shouldCache())
cache.put(key, asset);
// tryPutToHD(key, asset);
return key.createClonedInstance(asset);
} catch (Exception e){
logger.log(Level.WARNING, "Failed to load resource: "+key.getName(), e);
}
return null;
}
public AssetInfo locateAsset(AssetKey<?> key){
AssetInfo info = locator.locate(this, key);
if (info == null){
logger.log(Level.WARNING, "Cannot locate resource: "+key.getName());
return null;
}
return info;
}
public Object loadAsset(String name) {
return loadAsset(new AssetKey(name));
}
public Spatial loadModel(String name) {
return (Spatial) loadAsset(name);
}
public Material loadMaterial(String name) {
return (Material) loadAsset(name);
}
public BitmapFont loadFont(String name){
return (BitmapFont) loadAsset(name);
}
public Texture loadTexture(TextureKey key){ public Texture loadTexture(TextureKey key){
return (Texture) loadAsset(key); Texture tex = (Texture) loadAsset(key);
}
// Needed for Android
public Texture loadTexture(String name){ tex.setMagFilter(Texture.MagFilter.Nearest);
return loadTexture(new TextureKey(name, false)); tex.setAnisotropicFilter(0);
} if (tex.getMinFilter().usesMipMapLevels()){
tex.setMinFilter(Texture.MinFilter.NearestNearestMipMap);
public Shader loadShader(ShaderKey key){ }else{
logger.info("loadShader(" + key + ")"); tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
}
String vertName = key.getVertName(); return tex;
String fragName = key.getFragName();
String vertSource = (String) loadAsset(new AssetKey(vertName));
String fragSource = (String) loadAsset(new AssetKey(fragName));
Shader s = new Shader(key.getLanguage());
s.addSource(Shader.ShaderType.Vertex, vertName, vertSource, key.getDefines().getCompiled());
s.addSource(Shader.ShaderType.Fragment, fragName, fragSource, key.getDefines().getCompiled());
logger.info("returing shader: [" + s + "]");
return s;
}
public void registerLocator(String rootPath, String locatorClassName) {
throw new UnsupportedOperationException("Not supported yet.");
}
public AudioData loadAudio(AudioKey key) {
throw new UnsupportedOperationException("Not supported yet.");
}
public AudioData loadAudio(String name) {
throw new UnsupportedOperationException("Not supported yet.");
}
public Spatial loadModel(ModelKey key) {
throw new UnsupportedOperationException("Not supported yet.");
}
/* new */
private AssetEventListener eventListener = null;
public void setAssetEventListener(AssetEventListener listener){
eventListener = listener;
}
public void registerLocator(String rootPath, Class<? extends AssetLocator> locatorClass){
logger.warning("not implemented.");
}
public void registerLoader(Class<? extends AssetLoader> loader, String ... extensions){
logger.warning("not implemented.");
} }
} }

@ -1,6 +1,5 @@
package com.jme3.asset.plugins; package com.jme3.asset.plugins;
import android.content.res.AssetManager;
import android.content.res.Resources; import android.content.res.Resources;
import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetKey; import com.jme3.asset.AssetKey;
@ -8,20 +7,22 @@ import com.jme3.asset.AssetLocator;
import com.jme3.system.JmeSystem; import com.jme3.system.JmeSystem;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
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 Resources resources;
private AssetManager androidManager; private android.content.res.AssetManager androidManager;
private String rootPath = "";
private class AndroidAssetInfo extends AssetInfo { private class AndroidAssetInfo extends AssetInfo {
private final InputStream in; private final InputStream in;
public AndroidAssetInfo(com.jme3.asset.AssetManager manager, AssetKey key, public AndroidAssetInfo(com.jme3.asset.AssetManager manager, AssetKey<?> key, InputStream in)
InputStream in){ {
super(manager, key); super(manager, key);
this.in = in; this.in = in;
} }
@ -33,28 +34,40 @@ public class AndroidLocator implements AssetLocator {
} }
public AndroidLocator(){ public AndroidLocator()
{
resources = JmeSystem.getResources(); resources = JmeSystem.getResources();
androidManager = resources.getAssets(); androidManager = resources.getAssets();
} }
public void setRootPath(String rootPath) { public void setRootPath(String rootPath)
{
this.rootPath = rootPath;
} }
public AssetInfo locate(com.jme3.asset.AssetManager manager, AssetKey key) { @SuppressWarnings("rawtypes")
@Override
public AssetInfo locate(com.jme3.asset.AssetManager manager, AssetKey key)
{
InputStream in = null; InputStream in = null;
try { String sAssetPath = rootPath + key.getName();
in = androidManager.open(key.getName()); // Fix path issues
if (sAssetPath.startsWith("/"))
{
// Remove leading /
sAssetPath = sAssetPath.substring(1);
}
sAssetPath = sAssetPath.replace("//", "/");
try {
in = androidManager.open(sAssetPath);
if (in == null) if (in == null)
return null; return null;
return new AndroidAssetInfo(manager, key, in); return new AndroidAssetInfo(manager, key, in);
} catch (IOException ex) { }
if (in != null) catch (IOException ex)
try { {
in.close(); logger.log(Level.WARNING, "Failed to locate {0} ", sAssetPath);
} catch (IOException ex1) {
}
} }
return null; return null;
} }

@ -2,124 +2,45 @@ package com.jme3.input.android;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.logging.Logger;
import android.content.Context; import android.content.Context;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import com.jme3.input.android.TouchEvent;
import com.jme3.input.KeyInput; import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput; import com.jme3.input.MouseInput;
import com.jme3.input.RawInputListener; import com.jme3.input.RawInputListener;
import com.jme3.input.event.KeyInputEvent; import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent; import com.jme3.input.event.MouseMotionEvent;
import com.jme3.math.Vector2f;
public class AndroidInput extends GLSurfaceView implements KeyInput, MouseInput {
public class AndroidInput extends GLSurfaceView implements KeyInput, MouseInput,
GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener
{
private final static Logger logger = Logger.getLogger(AndroidInput.class.getName());
private RawInputListener listener; private RawInputListener listenerRaw = null;
private int lastX = -1, lastY = -1; private AndroidTouchInputListener listenerTouch = null;
private ScaleGestureDetector scaledetector;
private static final char[] ANDROID_TO_JME_CHR = { private GestureDetector detector;
0x0,// unknown private Vector2f lastPos = new Vector2f();
0x0,// soft left private boolean dragging = false;
0x0,// soft right
0x0,// home private List<Object> currentEvents = new ArrayList<Object>();
0x0,// back
0x0,// call
0x0,// endcall
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'*',
'#',
0x0,//dpad_up
0x0,//dpad_down
0x0,//dpad_left
0x0,//dpad_right
0x0,//dpad_center
0x0,//volume up
0x0,//volume down
0x0,//power
0x0,//camera
0x0,//clear
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
',',
'.',
0x0,//left alt
0x0,//right alt
0x0,//left ctrl
0x0,//right ctrl
// 0x0,//fn
// 0x0,//cap
'\t',
' ',
0x0,//sym(bol)
0x0,//explorer
0x0,//envelope
'\n',//newline
0x0,//delete
'`',
'-',
'=',
'[',
']',
'\\',//backslash
';',
'\'',//apostrophe
'/',//slash
'@',//at
0x0,//num
0x0,//headset hook
0x0,//focus
0x0,
0x0,//menu
0x0,//notification
0x0,//search
0x0,//media play/pause
0x0,//media stop
0x0,//media next
0x0,//media previous
0x0,//media rewind
0x0,//media fastforward
0x0,//mute
};
private final static int MAX_EVENTS = 1024;
private boolean FIRE_MOUSE_EVENTS = true;
private static final int[] ANDROID_TO_JME = { private static final int[] ANDROID_TO_JME = {
0x0, // unknown 0x0, // unknown
0x0, // key code soft left 0x0, // key code soft left
@ -223,170 +144,170 @@ public class AndroidInput extends GLSurfaceView implements KeyInput, MouseInput
0x0,//mute 0x0,//mute
}; };
// private int[] keyMap = { public AndroidInput(Context ctx, AttributeSet attribs)
// 0x0, {
// KeyEvent.KEYCODE_BACK, // ESC key
//
// KeyEvent.KEYCODE_1,
// KeyEvent.KEYCODE_2,
// KeyEvent.KEYCODE_3,
// KeyEvent.KEYCODE_4,
// KeyEvent.KEYCODE_5,
// KeyEvent.KEYCODE_6,
// KeyEvent.KEYCODE_7,
// KeyEvent.KEYCODE_8,
// KeyEvent.KEYCODE_9,
// KeyEvent.KEYCODE_0,
// KeyEvent.KEYCODE_MINUS,
// KeyEvent.KEYCODE_EQUALS,
// KeyEvent.KEYCODE_BACK,
// KeyEvent.KEYCODE_TAB,
// KeyEvent.KEYCODE_Q,
// KeyEvent.KEYCODE_W,
// KeyEvent.KEYCODE_E,
// KeyEvent.KEYCODE_R,
// KeyEvent.KEYCODE_T,
// KeyEvent.KEYCODE_Y,
// KeyEvent.KEYCODE_U,
// KeyEvent.KEYCODE_I,
// KeyEvent.KEYCODE_O,
// KeyEvent.KEYCODE_P,
// KeyEvent.KEYCODE_LEFT_BRACKET,
// KeyEvent.KEYCODE_RIGHT_BRACKET,
// KeyEvent.KEYCODE_ENTER,
// KeyEvent.KEYCODE_SOFT_LEFT, // Left Ctrl
// KeyEvent.KEYCODE_A,
// KeyEvent.KEYCODE_S,
// KeyEvent.KEYCODE_D,
// KeyEvent.KEYCODE_F,
// KeyEvent.KEYCODE_G,
// KeyEvent.KEYCODE_H,
// KeyEvent.KEYCODE_J,
// KeyEvent.KEYCODE_K,
// KeyEvent.KEYCODE_L,
// KeyEvent.KEYCODE_SEMICOLON,
// KeyEvent.KEYCODE_APOSTROPHE,
// KeyEvent.KEYCODE_GRAVE,
// KeyEvent.KEYCODE_SHIFT_LEFT,
// KeyEvent.KEYCODE_BACKSLASH,
// KeyEvent.KEYCODE_Z,
// KeyEvent.KEYCODE_X,
// KeyEvent.KEYCODE_C,
// KeyEvent.KEYCODE_V,
// KeyEvent.KEYCODE_B,
// KeyEvent.KEYCODE_N,
// KeyEvent.KEYCODE_M,
//
// KeyEvent.KEYCODE_COMMA,
// KeyEvent.KEYCODE_PERIOD,
// KeyEvent.KEYCODE_SLASH,
// KeyEvent.KEYCODE_SHIFT_RIGHT,
// KeyEvent.KEYCODE_STAR,
//
// KeyEvent.KEYCODE_ALT_LEFT,
// KeyEvent.KEYCODE_SPACE,
//
// 0x0, // no caps lock
//
// 0x0, // F1
// 0x0, // F2
// 0x0, // F3
// 0x0, // F4
// 0x0, // F5
// 0x0, // F6
// 0x0, // F7
// 0x0, // F8
// 0x0, // F9
// 0x0, // F10
//
// KeyEvent.KEYCODE_NUM,
// 0x0, // scroll lock
//
// 0x0, // numpad7
// 0x0, // numpad8
// 0x0, // numpad9
//
// KeyEvent.
// }
public AndroidInput(Context ctx, AttributeSet attribs){
super(ctx, attribs); super(ctx, attribs);
detector=new GestureDetector(this);
scaledetector=new ScaleGestureDetector(ctx, this);
} }
public AndroidInput(Context ctx){ public AndroidInput(Context ctx)
{
super(ctx); super(ctx);
detector=new GestureDetector(this);
scaledetector=new ScaleGestureDetector(ctx, this);
} }
/**
* onTouchEvent gets called from android thread on touchpad events
*/
@Override @Override
public boolean onTouchEvent(MotionEvent motionEvent){ public boolean onTouchEvent(MotionEvent event)
int newX = getWidth() - (int) motionEvent.getX(); {
int newY = (int) motionEvent.getY(); boolean bWasHandled = false;
MouseButtonEvent btn;
TouchEvent touch;
switch (motionEvent.getAction()){
// Send the raw event
processEvent(event);
// Try to detect gestures
this.detector.onTouchEvent(event);
this.scaledetector.onTouchEvent(event);
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
MouseButtonEvent btn = new MouseButtonEvent(0, true, newX, newY);
btn.setTime(motionEvent.getEventTime()); // Store current pos
processEvent(btn); lastPos.set(event.getX(),event.getY());
// listener.onMouseButtonEvent(btn);
lastX = -1; if (FIRE_MOUSE_EVENTS)
lastY = -1; {
return true; // Handle mouse events
btn = new MouseButtonEvent(0, true, (int)lastPos.getX(), (int)lastPos.getY());
btn.setTime(event.getEventTime());
processEvent(btn);
}
// Handle gesture events
touch = new TouchEvent(TouchEvent.Type.GRABBED, TouchEvent.Operation.NOP,event.getX(),event.getY(),0,0,null);
processEvent(touch);
bWasHandled = true;
break;
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
MouseButtonEvent btn2 = new MouseButtonEvent(0, false, newX, newY);
btn2.setTime(motionEvent.getEventTime()); if (FIRE_MOUSE_EVENTS)
processEvent(btn2); {
// listener.onMouseButtonEvent(btn2); // Handle mouse events
lastX = -1; btn = new MouseButtonEvent(0, false, (int)event.getX(), (int)event.getY());
lastY = -1; btn.setTime(event.getEventTime());
return true; processEvent(btn);
}
// Handle gesture events
if(dragging)
{
touch = new TouchEvent(TouchEvent.Type.DRAGGED, TouchEvent.Operation.STOPPED,event.getX(),event.getY(),event.getX()-lastPos.getX(),event.getY()-lastPos.getY(),null);
processEvent(touch);
}
touch = new TouchEvent(TouchEvent.Type.RELEASED, TouchEvent.Operation.NOP,event.getX(),event.getY(),0,0,null);
processEvent(touch);
dragging=false;
bWasHandled = true;
break;
case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_MOVE:
// int newX = getWidth() - (int) motionEvent.getX(); if(!scaledetector.isInProgress())
// int newY = (int) motionEvent.getY(); {
int dx; if(!dragging)
int dy; touch = new TouchEvent(TouchEvent.Type.DRAGGED, TouchEvent.Operation.STARTED,event.getX(),event.getY(),event.getX()-lastPos.getX(),event.getY()-lastPos.getY(),null);
if (lastX != -1){ else
dx = newX - lastX; touch = new TouchEvent(TouchEvent.Type.DRAGGED, TouchEvent.Operation.RUNNING,event.getX(),event.getY(),event.getX()-lastPos.getX(),event.getY()-lastPos.getY(),null);
dy = newY - lastY;
}else{ processEvent(touch);
dx = 0; dragging=true;
dy = 0;
} }
lastX = newX; if (FIRE_MOUSE_EVENTS)
lastY = newY; {
MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0); int newX = getWidth() - (int) event.getX();
mot.setTime(motionEvent.getEventTime()); int newY = (int) event.getY();
processEvent(mot); int dx;
//listener.onMouseMotionEvent(mot); int dy;
try{ if (lastPos.getX() != -1){
Thread.sleep(15); dx = newX - (int)lastPos.getX();
} catch (InterruptedException ex) { dy = newY - (int)lastPos.getY();
}else{
dx = 0;
dy = 0;
}
MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0);
mot.setTime(event.getEventTime());
processEvent(mot);
} }
return true; bWasHandled = true;
break;
// TODO: implement motion events
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_OUTSIDE:
break;
case MotionEvent.ACTION_CANCEL:
break;
} }
return false; return bWasHandled;
} }
@Override @Override
public boolean onKeyDown (int keyCode, KeyEvent event) { public boolean onKeyDown (int keyCode, KeyEvent event) {
// Send the raw event
processEvent(event);
int jmeCode = ANDROID_TO_JME[keyCode]; int jmeCode = ANDROID_TO_JME[keyCode];
String str = event.getCharacters(); if (jmeCode != 0)
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0; {
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, true, false); String str = event.getCharacters();
processEvent(evt); char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
// listener.onKeyEvent(evt); KeyInputEvent evt = new KeyInputEvent(jmeCode, c, true, false);
return false; logger.info("onKeyDown " + evt);
processEvent(evt);
}
// Handle all keys ourself, except the back button (4)
if (keyCode == 4)
return false;
else
return true;
} }
@Override @Override
public boolean onKeyUp (int keyCode, KeyEvent event) { public boolean onKeyUp (int keyCode, KeyEvent event) {
// Send the raw event
processEvent(event);
int jmeCode = ANDROID_TO_JME[keyCode]; int jmeCode = ANDROID_TO_JME[keyCode];
String str = event.getCharacters(); if (jmeCode != 0)
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0; {
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, false, false); String str = event.getCharacters();
processEvent(evt); char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
//listener.onKeyEvent(evt); KeyInputEvent evt = new KeyInputEvent(jmeCode, c, false, false);
return false; logger.info("onKeyUp " + evt);
processEvent(evt);
}
// Handle all keys ourself, except the back button (4)
if (keyCode == 4)
return false;
else
return true;
} }
public void setCursorVisible(boolean visible){ public void setCursorVisible(boolean visible){
@ -410,39 +331,130 @@ public class AndroidInput extends GLSurfaceView implements KeyInput, MouseInput
return true; return true;
} }
// XXX: android does not have an Event interface?
private List<Object> currentEvents = new ArrayList<Object>();
private final static int MAX_EVENTS = 1024;
private void processEvent(Object event) { private void processEvent(Object event)
{
synchronized (currentEvents) { synchronized (currentEvents) {
if (currentEvents.size() < MAX_EVENTS) if (currentEvents.size() < MAX_EVENTS)
currentEvents.add(event); currentEvents.add(event);
} }
} }
Object event;
private void generateEvents() { private void generateEvents() {
synchronized (currentEvents) { if (listenerRaw != null)
for (Object event: currentEvents) { {
if (event instanceof MouseButtonEvent) { synchronized (currentEvents) {
listener.onMouseButtonEvent((MouseButtonEvent) event); //for (Object event: currentEvents) {
} else if (event instanceof MouseMotionEvent) { for (int i = 0; i < currentEvents.size(); i++) {
listener.onMouseMotionEvent((MouseMotionEvent) event); event = currentEvents.get(i);
} else if (event instanceof KeyInputEvent) { if (event instanceof MouseButtonEvent) {
listener.onKeyEvent((KeyInputEvent) event); listenerRaw.onMouseButtonEvent((MouseButtonEvent) event);
} } else if (event instanceof MouseMotionEvent) {
} listenerRaw.onMouseMotionEvent((MouseMotionEvent) event);
currentEvents.clear(); } else if (event instanceof KeyInputEvent) {
} listenerRaw.onKeyEvent((KeyInputEvent) event);
} else if (event instanceof TouchEvent) {
if (listenerTouch != null)
listenerTouch.onTouchEvent((TouchEvent) event);
} else if (event instanceof MotionEvent) {
if (listenerTouch != null)
listenerTouch.onMotionEvent((MotionEvent) event);
} else if (event instanceof KeyEvent) {
if (listenerTouch != null)
listenerTouch.onAndroidKeyEvent((KeyEvent) event);
}
}
currentEvents.clear();
}
}
} }
public void setInputListener(RawInputListener listener) { public void setInputListener(RawInputListener listener) {
this.listener = listener; this.listenerRaw = listener;
}
public void setInputListener(AndroidTouchInputListener listener) {
this.listenerRaw = listener;
this.listenerTouch = listener;
} }
public long getInputTimeNanos() { public long getInputTimeNanos() {
return System.nanoTime(); return System.nanoTime();
} }
// --------------- Gesture detected callback events ----------------------------------
public boolean onDown(MotionEvent event)
{
return false;
}
public void onLongPress(MotionEvent event)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.LONGPRESSED, TouchEvent.Operation.NOP,event.getX(),event.getY(),0,0,null);
processEvent(touch);
}
public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.FLING, TouchEvent.Operation.NOP,event.getX(),event.getY(),0,0,null);
processEvent(touch);
return true;
}
public boolean onSingleTapConfirmed(MotionEvent event)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.TAP, TouchEvent.Operation.NOP,event.getX(),event.getY(),0,0,null);
processEvent(touch);
return true;
}
public boolean onDoubleTap(MotionEvent event)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.DOUBLETAP, TouchEvent.Operation.NOP,event.getX(),event.getY(),0,0,null);
processEvent(touch);
return true;
}
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.SCALE, TouchEvent.Operation.STARTED,scaleGestureDetector.getFocusX(),scaleGestureDetector.getFocusY(),0,0,new float[]{scaleGestureDetector.getCurrentSpan(),scaleGestureDetector.getScaleFactor()});
processEvent(touch);
return true;
}
public boolean onScale(ScaleGestureDetector scaleGestureDetector)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.SCALE, TouchEvent.Operation.RUNNING,scaleGestureDetector.getFocusX(),scaleGestureDetector.getFocusY(),0,0,new float[]{scaleGestureDetector.getCurrentSpan(),scaleGestureDetector.getScaleFactor()});
processEvent(touch);
return false;
}
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.SCALE, TouchEvent.Operation.STOPPED,scaleGestureDetector.getFocusX(),scaleGestureDetector.getFocusY(),0,0,new float[]{scaleGestureDetector.getCurrentSpan(),scaleGestureDetector.getScaleFactor()});
processEvent(touch);
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return false;
}
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
public boolean onSingleTapUp(MotionEvent event)
{
TouchEvent touch = new TouchEvent(TouchEvent.Type.TAP, TouchEvent.Operation.NOP,event.getX(),event.getY(),0,0,null);
processEvent(touch);
return true;
}
} }

@ -0,0 +1,19 @@
package com.jme3.input.android;
import com.jme3.input.RawInputListener;
import android.view.KeyEvent;
import android.view.MotionEvent;
/**
* AndroidTouchInputListener is an inputlistener interface which defines callbacks/events for android touch screens
* For use with class AndroidInput
* @author larynx
*
*/
public interface AndroidTouchInputListener extends RawInputListener
{
public void onTouchEvent(TouchEvent evt);
public void onMotionEvent(MotionEvent evt);
public void onAndroidKeyEvent(KeyEvent evt);
}

@ -76,53 +76,10 @@ import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/*
//import org.lwjgl.opengl.ARBGeometryShader4;
//import org.lwjgl.opengl.ARBHalfFloatVertex;
//import org.lwjgl.opengl.ARBVertexArrayObject;
//import org.lwjgl.opengl.ARBHalfFloatVertex;
//import org.lwjgl.opengl.ARBVertexArrayObject;
import org.lwjgl.opengl.ARBDrawBuffers;
//import org.lwjgl.opengl.ARBDrawInstanced;
import org.lwjgl.opengl.ARBDrawInstanced;
import org.lwjgl.opengl.ARBMultisample;
import org.lwjgl.opengl.ContextCapabilities;
import org.lwjgl.opengl.EXTTextureArray;
import org.lwjgl.opengl.EXTTextureFilterAnisotropic;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.opengl.NVHalfFloat;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.EXTFramebufferObject.*;
import static org.lwjgl.opengl.EXTFramebufferMultisample.*;
import static org.lwjgl.opengl.EXTFramebufferBlit.*;
import org.lwjgl.opengl.ARBShaderObjects.*;
import org.lwjgl.opengl.ARBVertexArrayObject;
//import static org.lwjgl.opengl.ARBDrawInstanced.*;
*/
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES10; import android.opengl.GLES10;
import android.opengl.GLES11; import android.opengl.GLES11;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.os.SystemClock;
import android.util.Log;
@ -168,14 +125,14 @@ public class OGLESShaderRenderer implements Renderer {
private int clipX, clipY, clipW, clipH; private int clipX, clipY, clipW, clipH;
private final GL10 gl; //private final GL10 gl;
private boolean powerOf2 = false; private boolean powerOf2 = false;
private boolean verboseLogging = false; private boolean verboseLogging = false;
private boolean useVBO = true; private boolean useVBO = false;
public OGLESShaderRenderer(GL10 gl) { public OGLESShaderRenderer() {
this.gl = gl;
} }
public void setUseVA(boolean value) { public void setUseVA(boolean value) {
@ -1869,7 +1826,7 @@ public class OGLESShaderRenderer implements Renderer {
return; return;
} }
for (int i = 0; i < 6; i++){ for (int i = 0; i < 6; i++){
TextureUtil.uploadTexture(gl, img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc, true, powerOf2); TextureUtil.uploadTexture(img, GLES20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, 0, tdc, true, powerOf2);
} }
}/*else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT){ }/*else if (target == EXTTextureArray.GL_TEXTURE_2D_ARRAY_EXT){
List<ByteBuffer> data = img.getData(); List<ByteBuffer> data = img.getData();
@ -1881,7 +1838,7 @@ public class OGLESShaderRenderer implements Renderer {
TextureUtil.uploadTexture(img, target, i, 0, tdc); TextureUtil.uploadTexture(img, target, i, 0, tdc);
} }
}*/else{ }*/else{
TextureUtil.uploadTexture(gl, img, target, 0, 0, tdc, true, powerOf2); TextureUtil.uploadTexture(img, target, 0, 0, tdc, true, powerOf2);
if (verboseLogging) if (verboseLogging)
logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)"); logger.info("GLES20.glTexParameteri(" + target + "GLES11.GL_GENERATE_MIMAP, GLES20.GL_TRUE)");
@ -2843,11 +2800,18 @@ public class OGLESShaderRenderer implements Renderer {
public void setAlphaToCoverage(boolean value) public void setAlphaToCoverage(boolean value)
{ {
// TODO Auto-generated method stub if (value) {
GLES20.glEnable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE);
} else {
GLES20.glDisable(GLES20.GL_SAMPLE_ALPHA_TO_COVERAGE);
}
} }
public void invalidateState(){ @Override
// TODO invalidateState public void invalidateState()
{
context.reset();
boundShader = null;
lastFb = null;
} }
} }

@ -1,6 +1,7 @@
package com.jme3.renderer.android; package com.jme3.renderer.android;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.opengl.GLES20;
import android.opengl.GLUtils; import android.opengl.GLUtils;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.texture.Image; import com.jme3.texture.Image;
@ -36,7 +37,7 @@ public class TextureUtil {
} }
} }
private static void buildMipmap(GL10 gl, Bitmap bitmap) { private static void buildMipmap(Bitmap bitmap) {
int level = 0; int level = 0;
int height = bitmap.getHeight(); int height = bitmap.getHeight();
int width = bitmap.getWidth(); int width = bitmap.getWidth();
@ -61,7 +62,7 @@ public class TextureUtil {
} }
} }
private static void uploadTextureBitmap(GL10 gl, Bitmap bitmap, boolean generateMips, boolean powerOf2){ private static void uploadTextureBitmap(Bitmap bitmap, boolean generateMips, boolean powerOf2){
if (!powerOf2){ if (!powerOf2){
int width = bitmap.getWidth(); int width = bitmap.getWidth();
int height = bitmap.getHeight(); int height = bitmap.getHeight();
@ -76,7 +77,7 @@ public class TextureUtil {
} }
if (generateMips){ if (generateMips){
buildMipmap(gl, bitmap); buildMipmap(bitmap);
}else{ }else{
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle(); bitmap.recycle();
@ -84,18 +85,17 @@ public class TextureUtil {
} }
public static void uploadTexture( public static void uploadTexture(
GL10 gl,
Image img, Image img,
int target, int target,
int index, int index,
int border, int border,
boolean tdc, boolean tdc,
boolean generateMips, boolean generateMips,
boolean powerOf2){ boolean powerOf2){
if (img.getEfficentData() instanceof Bitmap){ if (img.getEfficentData() instanceof Bitmap){
Bitmap bitmap = (Bitmap) img.getEfficentData(); Bitmap bitmap = (Bitmap) img.getEfficentData();
uploadTextureBitmap(gl, bitmap, generateMips, powerOf2); uploadTextureBitmap(bitmap, generateMips, powerOf2);
// img.setEfficentData(null); // img.setEfficentData(null);
return; return;
} }
@ -118,71 +118,71 @@ public class TextureUtil {
switch (fmt){ switch (fmt){
case Alpha16: case Alpha16:
format = gl.GL_ALPHA; format = GL10.GL_ALPHA;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case Alpha8: case Alpha8:
format = gl.GL_ALPHA; format = GL10.GL_ALPHA;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case Luminance8: case Luminance8:
format = gl.GL_LUMINANCE; format = GL10.GL_LUMINANCE;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case Luminance8Alpha8: case Luminance8Alpha8:
format = gl.GL_LUMINANCE_ALPHA; format = GL10.GL_LUMINANCE_ALPHA;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case Luminance16Alpha16: case Luminance16Alpha16:
format = gl.GL_LUMINANCE_ALPHA; format = GL10.GL_LUMINANCE_ALPHA;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case Luminance16: case Luminance16:
format = gl.GL_LUMINANCE; format = GL10.GL_LUMINANCE;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case RGB565: case RGB565:
format = gl.GL_RGB; format = GL10.GL_RGB;
dataType = gl.GL_UNSIGNED_SHORT_5_6_5; dataType = GL10.GL_UNSIGNED_SHORT_5_6_5;
break; break;
case ARGB4444: case ARGB4444:
format = gl.GL_RGBA; format = GL10.GL_RGBA;
dataType = gl.GL_UNSIGNED_SHORT_4_4_4_4; dataType = GL10.GL_UNSIGNED_SHORT_4_4_4_4;
break; break;
case RGB10: case RGB10:
format = gl.GL_RGB; format = GL10.GL_RGB;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case RGB16: case RGB16:
format = gl.GL_RGB; format = GL10.GL_RGB;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case RGB5A1: case RGB5A1:
format = gl.GL_RGBA; format = GL10.GL_RGBA;
dataType = gl.GL_UNSIGNED_SHORT_5_5_5_1; dataType = GL10.GL_UNSIGNED_SHORT_5_5_5_1;
break; break;
case RGB8: case RGB8:
format = gl.GL_RGB; format = GL10.GL_RGB;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case BGR8: case BGR8:
format = gl.GL_RGB; format = GL10.GL_RGB;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case RGBA16: case RGBA16:
format = gl.GL_RGBA; format = GL10.GL_RGBA;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
case RGBA8: case RGBA8:
format = gl.GL_RGBA; format = GL10.GL_RGBA;
dataType = gl.GL_UNSIGNED_BYTE; dataType = GL10.GL_UNSIGNED_BYTE;
break; break;
default: default:
throw new UnsupportedOperationException("Unrecognized format: "+fmt); throw new UnsupportedOperationException("Unrecognized format: "+fmt);
} }
if (data != null) if (data != null)
gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1); GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
int[] mipSizes = img.getMipMapSizes(); int[] mipSizes = img.getMipMapSizes();
int pos = 0; int pos = 0;
@ -197,7 +197,7 @@ public class TextureUtil {
// of more than paletted compressions is added.. // of more than paletted compressions is added..
if (compress){ if (compress){
data.clear(); data.clear();
gl.glCompressedTexImage2D(gl.GL_TEXTURE_2D, GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D,
1 - mipSizes.length, 1 - mipSizes.length,
format, format,
width, width,
@ -219,7 +219,7 @@ public class TextureUtil {
} }
if (compress && data != null){ if (compress && data != null){
gl.glCompressedTexImage2D(gl.GL_TEXTURE_2D, GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D,
i, i,
format, format,
mipWidth, mipWidth,
@ -228,7 +228,7 @@ public class TextureUtil {
data.remaining(), data.remaining(),
data); data);
}else{ }else{
gl.glTexImage2D(gl.GL_TEXTURE_2D, GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D,
i, i,
format, format,
mipWidth, mipWidth,

@ -6,8 +6,8 @@ import com.jme3.asset.AndroidAssetManager;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioNode; import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioData; import com.jme3.audio.AudioData;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.AudioParam; import com.jme3.audio.AudioParam;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.Environment; import com.jme3.audio.Environment;
import com.jme3.audio.Listener; import com.jme3.audio.Listener;
import com.jme3.audio.ListenerParam; import com.jme3.audio.ListenerParam;
@ -28,6 +28,7 @@ public class JmeSystem {
private static final Logger logger = Logger.getLogger(JmeSystem.class.getName()); private static final Logger logger = Logger.getLogger(JmeSystem.class.getName());
private static boolean initialized = false; private static boolean initialized = false;
private static boolean lowPermissions = false;
private static Resources res; private static Resources res;
public static void initialize(AppSettings settings){ public static void initialize(AppSettings settings){
@ -51,7 +52,15 @@ public class JmeSystem {
} }
public static String getFullName(){ public static String getFullName(){
return "jMonkey Engine 3 ALPHA 0.50"; return "jMonkey Engine 3 ALPHA 0.50 Android";
}
public static void setLowPermissions(boolean lowPerm){
lowPermissions = lowPerm;
}
public static boolean isLowPermissions() {
return lowPermissions;
} }
public static JmeContext newContext(AppSettings settings, Type contextType) { public static JmeContext newContext(AppSettings settings, Type contextType) {
@ -71,8 +80,15 @@ public class JmeSystem {
public void initialize() {} public void initialize() {}
public void update(float tpf) {} public void update(float tpf) {}
public void cleanup() {} public void cleanup() {}
public void updateListenerParam(Listener listener, ListenerParam parameter) {} public void updateListenerParam(Listener listener,
public void updateSourceParam(AudioNode node, AudioParam parameter) {} ListenerParam param) {
// TODO Auto-generated method stub
}
public void updateSourceParam(AudioNode src, AudioParam param) {
// TODO Auto-generated method stub
}
}; };
} }
@ -85,16 +101,16 @@ public class JmeSystem {
} }
public static AssetManager newAssetManager(){ public static AssetManager newAssetManager(){
logger.info("newAssetManager()"); logger.info("newAssetManager()");
return new AndroidAssetManager(true); return new AndroidAssetManager(null);
} }
public static AssetManager newAssetManager(URL url){ public static AssetManager newAssetManager(URL url){
logger.info("newAssetManager(" + url + ")"); logger.info("newAssetManager(" + url + ")");
return new AndroidAssetManager(true); return new AndroidAssetManager(url);
} }
public static boolean showSettingsDialog(AppSettings settings) { public static boolean showSettingsDialog(AppSettings settings, boolean loadSettings) {
return true; return true;
} }

@ -35,15 +35,14 @@ package com.jme3.system.android;
import com.jme3.system.Timer; import com.jme3.system.Timer;
/** /**
* <code>NanoTimer</code> is a System.nanoTime implementation of <code>Timer</code>. * <code>AndroidTimer</code> is a System.nanoTime implementation of <code>Timer</code>.
* This is primarily useful for headless applications running on a server.
*
* @author Matthew D. Hicks
*/ */
public class AndroidTimer extends Timer { public class AndroidTimer extends Timer {
private static final long TIMER_RESOLUTION = 1000L; //private static final long TIMER_RESOLUTION = 1000L;
private static final float INVERSE_TIMER_RESOLUTION = 1f/1000L; //private static final float INVERSE_TIMER_RESOLUTION = 1f/1000L;
private static final long TIMER_RESOLUTION = 1000000000L;
private static final float INVERSE_TIMER_RESOLUTION = 1f/1000000000L;
private long startTime; private long startTime;
private long previousTime; private long previousTime;
@ -51,7 +50,8 @@ public class AndroidTimer extends Timer {
private float fps; private float fps;
public AndroidTimer() { public AndroidTimer() {
startTime = System.currentTimeMillis(); //startTime = System.currentTimeMillis();
startTime = System.nanoTime();
} }
/** /**
@ -66,7 +66,8 @@ public class AndroidTimer extends Timer {
} }
public long getTime() { public long getTime() {
return System.currentTimeMillis() - startTime; //return System.currentTimeMillis() - startTime;
return System.nanoTime() - startTime;
} }
public long getResolution() { public long getResolution() {
@ -88,7 +89,8 @@ public class AndroidTimer extends Timer {
} }
public void reset() { public void reset() {
startTime = System.currentTimeMillis(); //startTime = System.currentTimeMillis();
startTime = System.nanoTime();
previousTime = getTime(); previousTime = getTime();
} }
} }

@ -39,7 +39,6 @@ import com.jme3.input.JoyInput;
import com.jme3.input.KeyInput; import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput; import com.jme3.input.MouseInput;
import com.jme3.input.android.AndroidInput; import com.jme3.input.android.AndroidInput;
//import com.jme3.renderer.android.OGLESRenderer;
import com.jme3.renderer.android.OGLESShaderRenderer; import com.jme3.renderer.android.OGLESShaderRenderer;
import com.jme3.system.AppSettings; import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext; import com.jme3.system.JmeContext;
@ -51,48 +50,60 @@ import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL10;
public class OGLESContext implements JmeContext, GLSurfaceView.Renderer { public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
{
private static final Logger logger = Logger.getLogger(OGLESContext.class.getName()); private static final Logger logger = Logger.getLogger(OGLESContext.class.getName());
protected AtomicBoolean created = new AtomicBoolean(false); protected final AtomicBoolean created = new AtomicBoolean(false);
protected AppSettings settings = new AppSettings(true); protected final AtomicBoolean renderable = new AtomicBoolean(false);
protected final AtomicBoolean needClose = new AtomicBoolean(false);
protected final Object createdLock = new Object();
protected final AppSettings settings = new AppSettings(true);
/* < OpenGL ES 2.0 * */
//protected OGLESRenderer renderer;
/* >= OpenGL ES 2.0 (Android 2.2+) */ /* >= OpenGL ES 2.0 (Android 2.2+) */
protected OGLESShaderRenderer renderer; protected OGLESShaderRenderer renderer;
protected Timer timer; protected Timer timer;
protected SystemListener listener; protected SystemListener listener;
protected AtomicBoolean needClose = new AtomicBoolean(false);
protected boolean wasActive = false; protected boolean wasActive = false;
protected int frameRate = 0;
protected boolean autoFlush = true; protected boolean autoFlush = true;
protected AndroidInput view; protected AndroidInput view;
private long milliStart;
private long milliDelta;
protected int frameRate = 33;
//protected int minFrameDuration = 1000 / frameRate; // Set a max FPS of 33
protected int minFrameDuration = 0; // No FPS cap
public OGLESContext(){ public OGLESContext() { }
}
public Type getType() { @Override
public Type getType()
{
return Type.Display; return Type.Display;
} }
public GLSurfaceView createView(Activity activity){ public GLSurfaceView createView(Activity activity)
view = new AndroidInput(activity); {
return createView(new AndroidInput(activity));
/* }
* Requesting client version from GLSurfaceView which is extended by
* AndroidInput.
* This is required to get OpenGL ES 2.0 public GLSurfaceView createView(AndroidInput view)
*/ {
this.view = view;
logger.info("setEGLContextClientVersion(2)");
view.setEGLContextClientVersion(2); /*
logger.info("setEGLContextClientVersion(2) ... done."); * Requesting client version from GLSurfaceView which is extended by
* AndroidInput.
* This is required to get OpenGL ES 2.0
*/
view.setEGLContextClientVersion(2);
//RGB565, Depth16 //RGB565, Depth16
view.setEGLConfigChooser(5, 6, 5, 0, 16, 0); view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
view.setFocusableInTouchMode(true); view.setFocusableInTouchMode(true);
@ -104,12 +115,11 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
return view; return view;
} }
protected void applySettings(AppSettings setting){ protected void initInThread()
} {
logger.info("OGLESContext create");
protected void initInThread(GL10 gl){
logger.info("Display created.");
logger.fine("Running on thread: "+Thread.currentThread().getName()); logger.fine("Running on thread: "+Thread.currentThread().getName());
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@ -117,175 +127,220 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown); listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
} }
}); });
created.set(true);
timer = new AndroidTimer(); timer = new AndroidTimer();
renderer = new OGLESShaderRenderer(gl); renderer = new OGLESShaderRenderer();
applySettingsToRenderer(renderer, settings);
renderer.setUseVA(true);
renderer.setVerboseLogging(false);
renderer.initialize(); renderer.initialize();
listener.initialize(); listener.initialize();
created.set(true);
// OGLESShaderRenderer does not support guiView yet
// forcefully remove all gui nodes needClose.set(false);
if (listener instanceof com.jme3.app.SimpleApplication) {
((com.jme3.app.SimpleApplication) listener).getGuiNode().detachAllChildren();
}
} }
/** /**
* De-initialize in the OpenGL thread. * De-initialize in the OpenGL thread.
*/ */
protected void deinitInThread(){ protected void deinitInThread()
{
if (renderer != null)
renderer.cleanup();
listener.destroy(); listener.destroy();
if (renderer != null) {
renderer.cleanup(); // do android specific cleaning here
// do android specific cleaning here logger.info("Display destroyed.");
renderable.set(false);
logger.info("Display destroyed.");
created.set(false); created.set(false);
renderer = null; renderer = null;
timer = null; timer = null;
} }
protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings)
{
logger.warning("setSettings.USE_VA: [" + settings.getBoolean("USE_VA") + "]");
logger.warning("setSettings.VERBOSE_LOGGING: [" + settings.getBoolean("VERBOSE_LOGGING") + "]");
renderer.setUseVA(settings.getBoolean("USE_VA"));
renderer.setVerboseLogging(settings.getBoolean("VERBOSE_LOGGING"));
}
protected void applySettings(AppSettings setting)
{
if (renderer != null)
applySettingsToRenderer(renderer, settings);
} }
@Override
protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings) { public void setSettings(AppSettings settings)
logger.warning("setSettings.USE_VA: [" + settings.getBoolean("USE_VA") + "]"); {
logger.warning("setSettings.VERBOSE_LOGGING: [" + settings.getBoolean("VERBOSE_LOGGING") + "]"); this.settings.copyFrom(settings);
renderer.setUseVA(settings.getBoolean("USE_VA"));
renderer.setVerboseLogging(settings.getBoolean("VERBOSE_LOGGING"));
}
@Override
public void setSettings(AppSettings settings) {
this.settings.copyFrom(settings);
// XXX This code should be somewhere else
if (renderer != null)
applySettingsToRenderer(renderer, this.settings);
} }
@Override
public void setSystemListener(SystemListener listener){ public void setSystemListener(SystemListener listener){
this.listener = listener; this.listener = listener;
} }
@Override
public AppSettings getSettings() { public AppSettings getSettings() {
return settings; return settings;
} }
@Override
public com.jme3.renderer.Renderer getRenderer() { public com.jme3.renderer.Renderer getRenderer() {
return renderer; return renderer;
} }
@Override
public MouseInput getMouseInput() { public MouseInput getMouseInput() {
return view; return view;
} }
@Override
public KeyInput getKeyInput() { public KeyInput getKeyInput() {
return view; return view;
} }
@Override
public JoyInput getJoyInput() { public JoyInput getJoyInput() {
return null; return null;
} }
public Timer getTimer() { @Override
public Timer getTimer()
{
return timer; return timer;
} }
public void setTitle(String title) { @Override
public void setTitle(String title)
{
} }
public boolean isCreated(){ @Override
public boolean isCreated()
{
return created.get(); return created.get();
} }
@Override
public void setAutoFlushFrames(boolean enabled){ public void setAutoFlushFrames(boolean enabled)
{
this.autoFlush = enabled; this.autoFlush = enabled;
} }
// renderer:initialize // renderer:initialize
public void onSurfaceCreated(GL10 gl, EGLConfig cfg) { @Override
logger.info("Using Android"); public void onSurfaceCreated(GL10 gl, EGLConfig cfg)
initInThread(gl); {
logger.info("GL Surface created");
initInThread();
renderable.set(true);
} }
// SystemListener:reshape // SystemListener:reshape
public void onSurfaceChanged(GL10 gl, int width, int height) { @Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
settings.setResolution(width, height); settings.setResolution(width, height);
listener.reshape(width, height); listener.reshape(width, height);
} }
// SystemListener:update // SystemListener:update
public void onDrawFrame(GL10 gl) { @Override
if (needClose.get()){ public void onDrawFrame(GL10 gl)
deinitInThread(); // ??? {
if (!created.get())
throw new IllegalStateException("onDrawFrame without create");
if (needClose.get())
{
deinitInThread();
return; return;
} }
// if (wasActive != Display.isActive()){
// if (!wasActive){
// listener.gainFocus();
// wasActive = true;
// }else{
// listener.loseFocus();
// wasActive = false;
// }
// }
if (!created.get())
throw new IllegalStateException();
listener.update();
// swap buffers
if (frameRate > 0){ if (renderable.get())
// Display.sync(frameRate); {
// synchronzie to framerate milliStart = System.currentTimeMillis();
}
if (autoFlush)
renderer.onFrame(); listener.update();
}
/** if (autoFlush)
* TODO: get these methods to follow the spec {
* @param waitFor renderer.onFrame();
*/ }
public void create(boolean waitFor) {
if (created.get()){ milliDelta = System.currentTimeMillis() - milliStart;
logger.warning("create() called when display is already created!");
return; // Enforce a FPS cap
if (milliDelta < minFrameDuration)
{
//logger.log(Level.INFO, "Time per frame {0}", milliDelta);
try {
Thread.sleep(minFrameDuration - milliDelta);
} catch (InterruptedException e) {
}
}
} }
} }
public void create(){ @Override
create(false); public boolean isRenderable()
{
return renderable.get();
} }
public void restart() { @Override
public void create(boolean waitFor)
{
if (waitFor)
waitFor(true);
} }
public boolean isRenderable() { public void create()
// TODO isRenderable {
return true; create(false);
} }
/** @Override
* TODO: get these methods to follow the spec public void restart()
* @param waitFor {
*/
public void destroy(boolean waitFor) { }
@Override
public void destroy(boolean waitFor)
{
needClose.set(true); needClose.set(true);
if (waitFor)
waitFor(false);
} }
public void destroy(){ public void destroy()
{
destroy(false); destroy(false);
} }
protected void waitFor(boolean createdVal)
{
synchronized (createdLock){
while (created.get() != createdVal){
try {
createdLock.wait();
} catch (InterruptedException ex) {
}
}
}
}
} }

@ -2,8 +2,11 @@ package com.jme3.texture.plugins;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
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.texture.Image.Format;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
@ -11,16 +14,19 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public class AndroidImageLoader implements AssetLoader { public class AndroidImageLoader implements AssetLoader
{
public Object load2(AssetInfo info) throws IOException { public Object load2(AssetInfo info) throws IOException
{
ByteBuffer bb = BufferUtils.createByteBuffer(1 * 1 * 2); ByteBuffer bb = BufferUtils.createByteBuffer(1 * 1 * 2);
bb.put( (byte) 0xff ).put( (byte) 0xff ); bb.put( (byte) 0xff ).put( (byte) 0xff );
bb.clear(); bb.clear();
return new Image(Format.RGB5A1, 1, 1, bb); 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; InputStream in = null;
Bitmap bitmap = null; Bitmap bitmap = null;
try { try {
@ -36,59 +42,41 @@ public class AndroidImageLoader implements AssetLoader {
int width = bitmap.getWidth(); int width = bitmap.getWidth();
int height = bitmap.getHeight(); int height = bitmap.getHeight();
int bytesPerPixel = -1;
Format fmt; Format fmt;
switch (bitmap.getConfig()){ switch (bitmap.getConfig()){
case ALPHA_8: case ALPHA_8:
bytesPerPixel = 1;
fmt = Format.Alpha8; fmt = Format.Alpha8;
break; break;
case ARGB_4444: case ARGB_4444:
bytesPerPixel = 2;
fmt = Format.ARGB4444; fmt = Format.ARGB4444;
break; break;
case ARGB_8888: case ARGB_8888:
bytesPerPixel = 4;
fmt = Format.RGBA8; fmt = Format.RGBA8;
break; break;
case RGB_565: case RGB_565:
bytesPerPixel = 2;
fmt = Format.RGB565; fmt = Format.RGB565;
break; break;
default: default:
return null; return null;
} }
// if (width > 128 || height > 128){ if ( ((TextureKey)info.getKey()).isFlipY() )
// if (width > height){ {
// float aspect = (float) height / width; Bitmap newBitmap = null;
// width = 128; Matrix flipMat = new Matrix();
// height = (int) (128 * aspect); flipMat.preScale(1.0f, -1.0f);
// newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), flipMat, false);
// }else{ bitmap.recycle();
// float aspect = (float) width / height; bitmap = newBitmap;
// width = (int) (128 * aspect);
// height = 128;
// }
// bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
// }
// if ( ((TextureKey)info.getKey()).isFlipY() ){ if (bitmap == null){
// Bitmap newBitmap = null; throw new IOException("Failed to flip image: "+info.getKey().getName());
// 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 load image2: "+info.getKey().getName());
// }
// }
Image image = new Image(fmt, width, height, null); Image image = new Image(fmt, width, height, null);
image.setEfficentData(bitmap); image.setEfficentData(bitmap);
return image; return image;
} }

@ -0,0 +1,359 @@
package com.jme3.util;
/**
* The wrapper for the primitive type {@code int}.
* <p>
* As with the specification, this implementation relies on code laid out in <a
* href="http://www.hackersdelight.org/">Henry S. Warren, Jr.'s Hacker's
* Delight, (Addison Wesley, 2002)</a> as well as <a
* href="http://aggregate.org/MAGIC/">The Aggregate's Magic Algorithms</a>.
*
* @see java.lang.Number
* @since 1.1
*/
public final class FastInteger {
/**
* Constant for the maximum {@code int} value, 2<sup>31</sup>-1.
*/
public static final int MAX_VALUE = 0x7FFFFFFF;
/**
* Constant for the minimum {@code int} value, -2<sup>31</sup>.
*/
public static final int MIN_VALUE = 0x80000000;
/**
* Constant for the number of bits needed to represent an {@code int} in
* two's complement form.
*
* @since 1.5
*/
public static final int SIZE = 32;
/*
* Progressively smaller decimal order of magnitude that can be represented
* by an instance of Integer. Used to help compute the String
* representation.
*/
private static final int[] decimalScale = new int[] { 1000000000, 100000000,
10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
/**
* Converts the specified integer into its decimal string representation.
* The returned string is a concatenation of a minus sign if the number is
* negative and characters from '0' to '9'.
*
* @param value
* the integer to convert.
* @return the decimal string representation of {@code value}.
*/
public static boolean toCharArray(int value, char[] output) {
if (value == 0)
{
output[0] = '0';
output[1] = 0;
return true;
}
// Faster algorithm for smaller Integers
if (value < 1000 && value > -1000) {
int positive_value = value < 0 ? -value : value;
int first_digit = 0;
if (value < 0) {
output[0] = '-';
first_digit++;
}
int last_digit = first_digit;
int quot = positive_value;
do {
int res = quot / 10;
int digit_value = quot - ((res << 3) + (res << 1));
digit_value += '0';
output[last_digit++] = (char) digit_value;
quot = res;
} while (quot != 0);
int count = last_digit--;
do {
char tmp = output[last_digit];
output[last_digit--] = output[first_digit];
output[first_digit++] = tmp;
} while (first_digit < last_digit);
output[count] = 0;
return true;
}
if (value == MIN_VALUE) {
System.arraycopy("-2147483648".toCharArray(), 0, output, 0, 12);
output[12] = 0;
return true;
}
int positive_value = value < 0 ? -value : value;
byte first_digit = 0;
if (value < 0) {
output[0] = '-';
first_digit++;
}
byte last_digit = first_digit;
byte count;
int number;
boolean start = false;
for (int i = 0; i < 9; i++) {
count = 0;
if (positive_value < (number = decimalScale[i])) {
if (start) {
output[last_digit++] = '0';
}
continue;
}
if (i > 0) {
number = (decimalScale[i] << 3);
if (positive_value >= number) {
positive_value -= number;
count += 8;
}
number = (decimalScale[i] << 2);
if (positive_value >= number) {
positive_value -= number;
count += 4;
}
}
number = (decimalScale[i] << 1);
if (positive_value >= number) {
positive_value -= number;
count += 2;
}
if (positive_value >= decimalScale[i]) {
positive_value -= decimalScale[i];
count++;
}
if (count > 0 && !start) {
start = true;
}
if (start) {
output[last_digit++] = (char) (count + '0');
}
}
output[last_digit++] = (char) (positive_value + '0');
output[last_digit] = 0;
count = last_digit--;
return true;
}
/**
* Determines the highest (leftmost) bit of the specified integer that is 1
* and returns the bit mask value for that bit. This is also referred to as
* the Most Significant 1 Bit. Returns zero if the specified integer is
* zero.
*
* @param i
* the integer to examine.
* @return the bit mask indicating the highest 1 bit in {@code i}.
* @since 1.5
*/
public static int highestOneBit(int i) {
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return (i & ~(i >>> 1));
}
/**
* Determines the lowest (rightmost) bit of the specified integer that is 1
* and returns the bit mask value for that bit. This is also referred
* to as the Least Significant 1 Bit. Returns zero if the specified integer
* is zero.
*
* @param i
* the integer to examine.
* @return the bit mask indicating the lowest 1 bit in {@code i}.
* @since 1.5
*/
public static int lowestOneBit(int i) {
return (i & (-i));
}
/**
* Determines the number of leading zeros in the specified integer prior to
* the {@link #highestOneBit(int) highest one bit}.
*
* @param i
* the integer to examine.
* @return the number of leading zeros in {@code i}.
* @since 1.5
*/
public static int numberOfLeadingZeros(int i) {
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
return bitCount(~i);
}
/**
* Determines the number of trailing zeros in the specified integer after
* the {@link #lowestOneBit(int) lowest one bit}.
*
* @param i
* the integer to examine.
* @return the number of trailing zeros in {@code i}.
* @since 1.5
*/
public static int numberOfTrailingZeros(int i) {
return bitCount((i & -i) - 1);
}
/**
* Counts the number of 1 bits in the specified integer; this is also
* referred to as population count.
*
* @param i
* the integer to examine.
* @return the number of 1 bits in {@code i}.
* @since 1.5
*/
public static int bitCount(int i) {
i -= ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (((i >> 4) + i) & 0x0F0F0F0F);
i += (i >> 8);
i += (i >> 16);
return (i & 0x0000003F);
}
/**
* Rotates the bits of the specified integer to the left by the specified
* number of bits.
*
* @param i
* the integer value to rotate left.
* @param distance
* the number of bits to rotate.
* @return the rotated value.
* @since 1.5
*/
public static int rotateLeft(int i, int distance) {
if (distance == 0) {
return i;
}
/*
* According to JLS3, 15.19, the right operand of a shift is always
* implicitly masked with 0x1F, which the negation of 'distance' is
* taking advantage of.
*/
return ((i << distance) | (i >>> (-distance)));
}
/**
* Rotates the bits of the specified integer to the right by the specified
* number of bits.
*
* @param i
* the integer value to rotate right.
* @param distance
* the number of bits to rotate.
* @return the rotated value.
* @since 1.5
*/
public static int rotateRight(int i, int distance) {
if (distance == 0) {
return i;
}
/*
* According to JLS3, 15.19, the right operand of a shift is always
* implicitly masked with 0x1F, which the negation of 'distance' is
* taking advantage of.
*/
return ((i >>> distance) | (i << (-distance)));
}
/**
* Reverses the order of the bytes of the specified integer.
*
* @param i
* the integer value for which to reverse the byte order.
* @return the reversed value.
* @since 1.5
*/
public static int reverseBytes(int i) {
int b3 = i >>> 24;
int b2 = (i >>> 8) & 0xFF00;
int b1 = (i & 0xFF00) << 8;
int b0 = i << 24;
return (b0 | b1 | b2 | b3);
}
/**
* Reverses the order of the bits of the specified integer.
*
* @param i
* the integer value for which to reverse the bit order.
* @return the reversed value.
* @since 1.5
*/
public static int reverse(int i) {
// From Hacker's Delight, 7-1, Figure 7-1
i = (i & 0x55555555) << 1 | (i >> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >> 2) & 0x33333333;
i = (i & 0x0F0F0F0F) << 4 | (i >> 4) & 0x0F0F0F0F;
return reverseBytes(i);
}
/**
* Returns the value of the {@code signum} function for the specified
* integer.
*
* @param i
* the integer value to check.
* @return -1 if {@code i} is negative, 1 if {@code i} is positive, 0 if
* {@code i} is zero.
* @since 1.5
*/
public static int signum(int i) {
return (i == 0 ? 0 : (i < 0 ? -1 : 1));
}
/**
* Returns a {@code Integer} instance for the specified integer value.
* <p>
* If it is not necessary to get a new {@code Integer} instance, it is
* recommended to use this method instead of the constructor, since it
* maintains a cache of instances which may result in better performance.
*
* @param i
* the integer value to store in the instance.
* @return a {@code Integer} instance containing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i < -128 || i > 127) {
return new Integer(i);
}
return valueOfCache.CACHE [i+128];
}
static class valueOfCache {
/**
* <p>
* A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing.
*/
static final Integer[] CACHE = new Integer[256];
static {
for(int i=-128; i<=127; i++) {
CACHE[i+128] = new Integer(i);
}
}
}
}
Loading…
Cancel
Save