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;
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.plugins.AndroidImageLoader;
import java.io.File;
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.net.URL;
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 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(){
this(false);
}
public AndroidAssetManager(boolean loadDefaults){
if (loadDefaults){
// AssetConfig cfg = new AssetConfig(this);
// InputStream stream = AssetManager.class.getResourceAsStream("Desktop.cfg");
// try{
// cfg.loadText(stream);
// }catch (IOException ex){
// logger.log(Level.SEVERE, "Failed to load asset config", ex);
// }finally{
// if (stream != null)
// try{
// stream.close();
// }catch (IOException ex){
// }
// }
this(null);
}
@Deprecated
public AndroidAssetManager(boolean loadDefaults){
//this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Android.cfg"));
this(null);
}
/**
* AndroidAssetManager constructor
* If URL == null then a default list of locators and loaders for android is set
* @param configFile
*/
public AndroidAssetManager(URL configFile)
{
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.");
}
public void registerLoader(String loaderClass, String ... extensions){
}
public void registerLocator(String rootPath, String locatorClass, String ... extensions){
}
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);
}
/**
* Loads a texture.
*
* @return
*/
@Override
public Texture loadTexture(TextureKey key){
return (Texture) loadAsset(key);
}
public Texture loadTexture(String name){
return loadTexture(new TextureKey(name, false));
}
public Shader loadShader(ShaderKey key){
logger.info("loadShader(" + key + ")");
String vertName = key.getVertName();
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.");
Texture tex = (Texture) loadAsset(key);
// Needed for Android
tex.setMagFilter(Texture.MagFilter.Nearest);
tex.setAnisotropicFilter(0);
if (tex.getMinFilter().usesMipMapLevels()){
tex.setMinFilter(Texture.MinFilter.NearestNearestMipMap);
}else{
tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
}
return tex;
}
}

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

@ -2,124 +2,45 @@ package com.jme3.input.android;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Logger;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import com.jme3.input.android.TouchEvent;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.RawInputListener;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.event.MouseButtonEvent;
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 int lastX = -1, lastY = -1;
private static final char[] ANDROID_TO_JME_CHR = {
0x0,// unknown
0x0,// soft left
0x0,// soft right
0x0,// home
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 RawInputListener listenerRaw = null;
private AndroidTouchInputListener listenerTouch = null;
private ScaleGestureDetector scaledetector;
private GestureDetector detector;
private Vector2f lastPos = new Vector2f();
private boolean dragging = false;
private List<Object> currentEvents = new ArrayList<Object>();
private final static int MAX_EVENTS = 1024;
private boolean FIRE_MOUSE_EVENTS = true;
private static final int[] ANDROID_TO_JME = {
0x0, // unknown
0x0, // key code soft left
@ -223,170 +144,170 @@ public class AndroidInput extends GLSurfaceView implements KeyInput, MouseInput
0x0,//mute
};
// private int[] keyMap = {
// 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){
public AndroidInput(Context ctx, AttributeSet attribs)
{
super(ctx, attribs);
detector=new GestureDetector(this);
scaledetector=new ScaleGestureDetector(ctx, this);
}
public AndroidInput(Context ctx){
public AndroidInput(Context ctx)
{
super(ctx);
detector=new GestureDetector(this);
scaledetector=new ScaleGestureDetector(ctx, this);
}
/**
* onTouchEvent gets called from android thread on touchpad events
*/
@Override
public boolean onTouchEvent(MotionEvent motionEvent){
int newX = getWidth() - (int) motionEvent.getX();
int newY = (int) motionEvent.getY();
switch (motionEvent.getAction()){
public boolean onTouchEvent(MotionEvent event)
{
boolean bWasHandled = false;
MouseButtonEvent btn;
TouchEvent touch;
// 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:
MouseButtonEvent btn = new MouseButtonEvent(0, true, newX, newY);
btn.setTime(motionEvent.getEventTime());
processEvent(btn);
// listener.onMouseButtonEvent(btn);
lastX = -1;
lastY = -1;
return true;
// Store current pos
lastPos.set(event.getX(),event.getY());
if (FIRE_MOUSE_EVENTS)
{
// 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:
MouseButtonEvent btn2 = new MouseButtonEvent(0, false, newX, newY);
btn2.setTime(motionEvent.getEventTime());
processEvent(btn2);
// listener.onMouseButtonEvent(btn2);
lastX = -1;
lastY = -1;
return true;
if (FIRE_MOUSE_EVENTS)
{
// Handle mouse events
btn = new MouseButtonEvent(0, false, (int)event.getX(), (int)event.getY());
btn.setTime(event.getEventTime());
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:
// int newX = getWidth() - (int) motionEvent.getX();
// int newY = (int) motionEvent.getY();
int dx;
int dy;
if (lastX != -1){
dx = newX - lastX;
dy = newY - lastY;
}else{
dx = 0;
dy = 0;
if(!scaledetector.isInProgress())
{
if(!dragging)
touch = new TouchEvent(TouchEvent.Type.DRAGGED, TouchEvent.Operation.STARTED,event.getX(),event.getY(),event.getX()-lastPos.getX(),event.getY()-lastPos.getY(),null);
else
touch = new TouchEvent(TouchEvent.Type.DRAGGED, TouchEvent.Operation.RUNNING,event.getX(),event.getY(),event.getX()-lastPos.getX(),event.getY()-lastPos.getY(),null);
processEvent(touch);
dragging=true;
}
lastX = newX;
lastY = newY;
MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0);
mot.setTime(motionEvent.getEventTime());
processEvent(mot);
//listener.onMouseMotionEvent(mot);
try{
Thread.sleep(15);
} catch (InterruptedException ex) {
if (FIRE_MOUSE_EVENTS)
{
int newX = getWidth() - (int) event.getX();
int newY = (int) event.getY();
int dx;
int dy;
if (lastPos.getX() != -1){
dx = newX - (int)lastPos.getX();
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
public boolean onKeyDown (int keyCode, KeyEvent event) {
// Send the raw event
processEvent(event);
int jmeCode = ANDROID_TO_JME[keyCode];
String str = event.getCharacters();
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, true, false);
processEvent(evt);
// listener.onKeyEvent(evt);
return false;
if (jmeCode != 0)
{
String str = event.getCharacters();
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, true, 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
public boolean onKeyUp (int keyCode, KeyEvent event) {
// Send the raw event
processEvent(event);
int jmeCode = ANDROID_TO_JME[keyCode];
String str = event.getCharacters();
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, false, false);
processEvent(evt);
//listener.onKeyEvent(evt);
return false;
if (jmeCode != 0)
{
String str = event.getCharacters();
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, false, 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){
@ -410,39 +331,130 @@ public class AndroidInput extends GLSurfaceView implements KeyInput, MouseInput
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) {
if (currentEvents.size() < MAX_EVENTS)
currentEvents.add(event);
}
}
Object event;
private void generateEvents() {
synchronized (currentEvents) {
for (Object event: currentEvents) {
if (event instanceof MouseButtonEvent) {
listener.onMouseButtonEvent((MouseButtonEvent) event);
} else if (event instanceof MouseMotionEvent) {
listener.onMouseMotionEvent((MouseMotionEvent) event);
} else if (event instanceof KeyInputEvent) {
listener.onKeyEvent((KeyInputEvent) event);
}
}
currentEvents.clear();
}
if (listenerRaw != null)
{
synchronized (currentEvents) {
//for (Object event: currentEvents) {
for (int i = 0; i < currentEvents.size(); i++) {
event = currentEvents.get(i);
if (event instanceof MouseButtonEvent) {
listenerRaw.onMouseButtonEvent((MouseButtonEvent) event);
} else if (event instanceof MouseMotionEvent) {
listenerRaw.onMouseMotionEvent((MouseMotionEvent) event);
} 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) {
this.listener = listener;
this.listenerRaw = listener;
}
public void setInputListener(AndroidTouchInputListener listener) {
this.listenerRaw = listener;
this.listenerTouch = listener;
}
public long getInputTimeNanos() {
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.logging.Level;
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 android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES10;
import android.opengl.GLES11;
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 final GL10 gl;
//private final GL10 gl;
private boolean powerOf2 = false;
private boolean verboseLogging = false;
private boolean useVBO = true;
private boolean useVBO = false;
public OGLESShaderRenderer(GL10 gl) {
this.gl = gl;
public OGLESShaderRenderer() {
}
public void setUseVA(boolean value) {
@ -1869,7 +1826,7 @@ public class OGLESShaderRenderer implements Renderer {
return;
}
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){
List<ByteBuffer> data = img.getData();
@ -1881,7 +1838,7 @@ public class OGLESShaderRenderer implements Renderer {
TextureUtil.uploadTexture(img, target, i, 0, tdc);
}
}*/else{
TextureUtil.uploadTexture(gl, img, target, 0, 0, tdc, true, powerOf2);
TextureUtil.uploadTexture(img, target, 0, 0, tdc, true, powerOf2);
if (verboseLogging)
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)
{
// 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(){
// TODO invalidateState
@Override
public void invalidateState()
{
context.reset();
boundShader = null;
lastFb = null;
}
}

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

@ -6,8 +6,8 @@ import com.jme3.asset.AndroidAssetManager;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.AudioParam;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.Environment;
import com.jme3.audio.Listener;
import com.jme3.audio.ListenerParam;
@ -28,6 +28,7 @@ public class JmeSystem {
private static final Logger logger = Logger.getLogger(JmeSystem.class.getName());
private static boolean initialized = false;
private static boolean lowPermissions = false;
private static Resources res;
public static void initialize(AppSettings settings){
@ -51,7 +52,15 @@ public class JmeSystem {
}
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) {
@ -71,8 +80,15 @@ public class JmeSystem {
public void initialize() {}
public void update(float tpf) {}
public void cleanup() {}
public void updateListenerParam(Listener listener, ListenerParam parameter) {}
public void updateSourceParam(AudioNode node, AudioParam parameter) {}
public void updateListenerParam(Listener listener,
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(){
logger.info("newAssetManager()");
return new AndroidAssetManager(true);
logger.info("newAssetManager()");
return new AndroidAssetManager(null);
}
public static AssetManager newAssetManager(URL url){
logger.info("newAssetManager(" + url + ")");
return new AndroidAssetManager(true);
logger.info("newAssetManager(" + url + ")");
return new AndroidAssetManager(url);
}
public static boolean showSettingsDialog(AppSettings settings) {
public static boolean showSettingsDialog(AppSettings settings, boolean loadSettings) {
return true;
}

@ -35,15 +35,14 @@ package com.jme3.system.android;
import com.jme3.system.Timer;
/**
* <code>NanoTimer</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
* <code>AndroidTimer</code> is a System.nanoTime implementation of <code>Timer</code>.
*/
public class AndroidTimer extends Timer {
private static final long TIMER_RESOLUTION = 1000L;
private static final float INVERSE_TIMER_RESOLUTION = 1f/1000L;
//private static final long TIMER_RESOLUTION = 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 previousTime;
@ -51,7 +50,8 @@ public class AndroidTimer extends Timer {
private float fps;
public AndroidTimer() {
startTime = System.currentTimeMillis();
//startTime = System.currentTimeMillis();
startTime = System.nanoTime();
}
/**
@ -66,7 +66,8 @@ public class AndroidTimer extends Timer {
}
public long getTime() {
return System.currentTimeMillis() - startTime;
//return System.currentTimeMillis() - startTime;
return System.nanoTime() - startTime;
}
public long getResolution() {
@ -88,7 +89,8 @@ public class AndroidTimer extends Timer {
}
public void reset() {
startTime = System.currentTimeMillis();
//startTime = System.currentTimeMillis();
startTime = System.nanoTime();
previousTime = getTime();
}
}

@ -39,7 +39,6 @@ import com.jme3.input.JoyInput;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.android.AndroidInput;
//import com.jme3.renderer.android.OGLESRenderer;
import com.jme3.renderer.android.OGLESShaderRenderer;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext;
@ -51,48 +50,60 @@ import javax.microedition.khronos.egl.EGLConfig;
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());
protected AtomicBoolean created = new AtomicBoolean(false);
protected AppSettings settings = new AppSettings(true);
protected final AtomicBoolean created = new AtomicBoolean(false);
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+) */
protected OGLESShaderRenderer renderer;
protected Timer timer;
protected SystemListener listener;
protected AtomicBoolean needClose = new AtomicBoolean(false);
protected boolean wasActive = false;
protected int frameRate = 0;
protected boolean autoFlush = true;
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;
}
public GLSurfaceView createView(Activity activity){
view = new AndroidInput(activity);
/*
* Requesting client version from GLSurfaceView which is extended by
* AndroidInput.
* This is required to get OpenGL ES 2.0
*/
logger.info("setEGLContextClientVersion(2)");
view.setEGLContextClientVersion(2);
logger.info("setEGLContextClientVersion(2) ... done.");
public GLSurfaceView createView(Activity activity)
{
return createView(new AndroidInput(activity));
}
public GLSurfaceView createView(AndroidInput view)
{
this.view = view;
/*
* Requesting client version from GLSurfaceView which is extended by
* AndroidInput.
* This is required to get OpenGL ES 2.0
*/
view.setEGLContextClientVersion(2);
//RGB565, Depth16
view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
view.setFocusableInTouchMode(true);
@ -104,12 +115,11 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
return view;
}
protected void applySettings(AppSettings setting){
}
protected void initInThread(GL10 gl){
logger.info("Display created.");
protected void initInThread()
{
logger.info("OGLESContext create");
logger.fine("Running on thread: "+Thread.currentThread().getName());
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);
}
});
created.set(true);
timer = new AndroidTimer();
renderer = new OGLESShaderRenderer(gl);
applySettingsToRenderer(renderer, settings);
renderer = new OGLESShaderRenderer();
renderer.setUseVA(true);
renderer.setVerboseLogging(false);
renderer.initialize();
listener.initialize();
// OGLESShaderRenderer does not support guiView yet
// forcefully remove all gui nodes
if (listener instanceof com.jme3.app.SimpleApplication) {
((com.jme3.app.SimpleApplication) listener).getGuiNode().detachAllChildren();
}
listener.initialize();
created.set(true);
needClose.set(false);
}
/**
* De-initialize in the OpenGL thread.
*/
protected void deinitInThread(){
protected void deinitInThread()
{
if (renderer != null)
renderer.cleanup();
listener.destroy();
if (renderer != null) {
renderer.cleanup();
// do android specific cleaning here
logger.info("Display destroyed.");
// do android specific cleaning here
logger.info("Display destroyed.");
renderable.set(false);
created.set(false);
renderer = 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);
}
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"));
}
@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 setSettings(AppSettings settings)
{
this.settings.copyFrom(settings);
}
@Override
public void setSystemListener(SystemListener listener){
this.listener = listener;
}
@Override
public AppSettings getSettings() {
return settings;
}
@Override
public com.jme3.renderer.Renderer getRenderer() {
return renderer;
}
@Override
public MouseInput getMouseInput() {
return view;
}
@Override
public KeyInput getKeyInput() {
return view;
}
@Override
public JoyInput getJoyInput() {
return null;
}
public Timer getTimer() {
@Override
public Timer getTimer()
{
return timer;
}
public void setTitle(String title) {
@Override
public void setTitle(String title)
{
}
public boolean isCreated(){
@Override
public boolean isCreated()
{
return created.get();
}
public void setAutoFlushFrames(boolean enabled){
@Override
public void setAutoFlushFrames(boolean enabled)
{
this.autoFlush = enabled;
}
// renderer:initialize
public void onSurfaceCreated(GL10 gl, EGLConfig cfg) {
logger.info("Using Android");
initInThread(gl);
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig cfg)
{
logger.info("GL Surface created");
initInThread();
renderable.set(true);
}
// 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);
listener.reshape(width, height);
}
// SystemListener:update
public void onDrawFrame(GL10 gl) {
if (needClose.get()){
deinitInThread(); // ???
@Override
public void onDrawFrame(GL10 gl)
{
if (!created.get())
throw new IllegalStateException("onDrawFrame without create");
if (needClose.get())
{
deinitInThread();
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){
// Display.sync(frameRate);
// synchronzie to framerate
}
if (renderable.get())
{
milliStart = System.currentTimeMillis();
if (autoFlush)
renderer.onFrame();
}
/**
* TODO: get these methods to follow the spec
* @param waitFor
*/
public void create(boolean waitFor) {
if (created.get()){
logger.warning("create() called when display is already created!");
return;
listener.update();
if (autoFlush)
{
renderer.onFrame();
}
milliDelta = System.currentTimeMillis() - milliStart;
// 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(){
create(false);
@Override
public boolean isRenderable()
{
return renderable.get();
}
public void restart() {
@Override
public void create(boolean waitFor)
{
if (waitFor)
waitFor(true);
}
public boolean isRenderable() {
// TODO isRenderable
return true;
public void create()
{
create(false);
}
/**
* TODO: get these methods to follow the spec
* @param waitFor
*/
public void destroy(boolean waitFor) {
@Override
public void restart()
{
}
@Override
public void destroy(boolean waitFor)
{
needClose.set(true);
if (waitFor)
waitFor(false);
}
public void destroy(){
public void destroy()
{
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.BitmapFactory;
import android.graphics.Matrix;
import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetLoader;
import com.jme3.asset.TextureKey;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.util.BufferUtils;
@ -11,16 +14,19 @@ 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 {
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;
Bitmap bitmap = null;
try {
@ -36,59 +42,41 @@ public class AndroidImageLoader implements AssetLoader {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int bytesPerPixel = -1;
Format fmt;
switch (bitmap.getConfig()){
case ALPHA_8:
bytesPerPixel = 1;
fmt = Format.Alpha8;
break;
case ARGB_4444:
bytesPerPixel = 2;
fmt = Format.ARGB4444;
break;
case ARGB_8888:
bytesPerPixel = 4;
fmt = Format.RGBA8;
break;
case RGB_565:
bytesPerPixel = 2;
case RGB_565:
fmt = Format.RGB565;
break;
default:
return null;
}
// if (width > 128 || height > 128){
// if (width > height){
// float aspect = (float) height / width;
// width = 128;
// height = (int) (128 * aspect);
//
// }else{
// float aspect = (float) width / height;
// width = (int) (128 * aspect);
// height = 128;
// }
// bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
// }
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 ( ((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 load image2: "+info.getKey().getName());
// }
// }
if (bitmap == null){
throw new IOException("Failed to flip image: "+info.getKey().getName());
}
}
Image image = new Image(fmt, width, height, null);
image.setEfficentData(bitmap);
image.setEfficentData(bitmap);
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