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. 321
      engine/src/android/com/jme3/asset/AndroidAssetManager.java
  3. 39
      engine/src/android/com/jme3/asset/plugins/AndroidLocator.java
  4. 472
      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. 78
      engine/src/android/com/jme3/renderer/android/TextureUtil.java
  8. 30
      engine/src/android/com/jme3/system/JmeSystem.java
  9. 20
      engine/src/android/com/jme3/system/android/AndroidTimer.java
  10. 237
      engine/src/android/com/jme3/system/android/OGLESContext.java
  11. 54
      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,147 +1,110 @@
/*
* 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);
} }
@Deprecated
public AndroidAssetManager(boolean loadDefaults){ public AndroidAssetManager(boolean loadDefaults){
if (loadDefaults){ //this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Android.cfg"));
// AssetConfig cfg = new AssetConfig(this); this(null);
// 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){
// }
// }
}
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; /**
* 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");
} }
private void tryPutToHD(AssetKey key, Object data){ logger.info("AndroidAssetManager created.");
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 + ")"); * Loads a texture.
Object asset; *
// Object asset = tryLoadFromHD(key); * @return
// if (asset != null) */
// return asset; @Override
public Texture loadTexture(TextureKey key){
if (key.shouldCache()){ Texture tex = (Texture) loadAsset(key);
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(); // Needed for Android
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.setMagFilter(Texture.MagFilter.Nearest);
tex.setAnisotropicFilter(0); tex.setAnisotropicFilter(0);
if (tex.getMinFilter().usesMipMapLevels()){ if (tex.getMinFilter().usesMipMapLevels()){
@ -149,121 +112,7 @@ public final class AndroidAssetManager implements AssetManager {
}else{ }else{
tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps); tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
} }
asset = tex; return 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){
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.");
}
} }

@ -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;
String sAssetPath = rootPath + key.getName();
// Fix path issues
if (sAssetPath.startsWith("/"))
{
// Remove leading /
sAssetPath = sAssetPath.substring(1);
}
sAssetPath = sAssetPath.replace("//", "/");
try { try {
in = androidManager.open(key.getName()); 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)
try {
in.close();
} catch (IOException ex1) {
} }
catch (IOException ex)
{
logger.log(Level.WARNING, "Failed to locate {0} ", sAssetPath);
} }
return null; return null;
} }

@ -2,123 +2,44 @@ 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 {
private RawInputListener listener; public class AndroidInput extends GLSurfaceView implements KeyInput, MouseInput,
private int lastX = -1, lastY = -1; GestureDetector.OnGestureListener, ScaleGestureDetector.OnScaleGestureListener
{
private final static Logger logger = Logger.getLogger(AndroidInput.class.getName());
private static final char[] ANDROID_TO_JME_CHR = { private RawInputListener listenerRaw = null;
0x0,// unknown private AndroidTouchInputListener listenerTouch = null;
0x0,// soft left private ScaleGestureDetector scaledetector;
0x0,// soft right private GestureDetector detector;
0x0,// home private Vector2f lastPos = new Vector2f();
0x0,// back private boolean dragging = false;
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 private List<Object> currentEvents = new ArrayList<Object>();
// 0x0,//cap
private final static int MAX_EVENTS = 1024;
private boolean FIRE_MOUSE_EVENTS = true;
'\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 static final int[] ANDROID_TO_JME = { private static final int[] ANDROID_TO_JME = {
0x0, // unknown 0x0, // unknown
@ -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;
// Send the raw event
processEvent(event);
// Try to detect gestures
this.detector.onTouchEvent(event);
this.scaledetector.onTouchEvent(event);
switch (motionEvent.getAction()){ 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
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); processEvent(btn);
// listener.onMouseButtonEvent(btn); }
lastX = -1;
lastY = -1; // Handle gesture events
return true; 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(); {
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;
}
if (FIRE_MOUSE_EVENTS)
{
int newX = getWidth() - (int) event.getX();
int newY = (int) event.getY();
int dx; int dx;
int dy; int dy;
if (lastX != -1){ if (lastPos.getX() != -1){
dx = newX - lastX; dx = newX - (int)lastPos.getX();
dy = newY - lastY; dy = newY - (int)lastPos.getY();
}else{ }else{
dx = 0; dx = 0;
dy = 0; dy = 0;
} }
lastX = newX;
lastY = newY;
MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0); MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0);
mot.setTime(motionEvent.getEventTime()); mot.setTime(event.getEventTime());
processEvent(mot); processEvent(mot);
//listener.onMouseMotionEvent(mot);
try{
Thread.sleep(15);
} catch (InterruptedException ex) {
} }
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];
if (jmeCode != 0)
{
String str = event.getCharacters(); String str = event.getCharacters();
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0; char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, true, false); KeyInputEvent evt = new KeyInputEvent(jmeCode, c, true, false);
logger.info("onKeyDown " + evt);
processEvent(evt); processEvent(evt);
// listener.onKeyEvent(evt); }
// Handle all keys ourself, except the back button (4)
if (keyCode == 4)
return false; 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];
if (jmeCode != 0)
{
String str = event.getCharacters(); String str = event.getCharacters();
char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0; char c = str != null && str.length() > 0 ? str.charAt(0) : 0x0;
KeyInputEvent evt = new KeyInputEvent(jmeCode, c, false, false); KeyInputEvent evt = new KeyInputEvent(jmeCode, c, false, false);
logger.info("onKeyUp " + evt);
processEvent(evt); processEvent(evt);
//listener.onKeyEvent(evt); }
// Handle all keys ourself, except the back button (4)
if (keyCode == 4)
return false; 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() {
if (listenerRaw != null)
{
synchronized (currentEvents) { synchronized (currentEvents) {
for (Object event: currentEvents) { //for (Object event: currentEvents) {
for (int i = 0; i < currentEvents.size(); i++) {
event = currentEvents.get(i);
if (event instanceof MouseButtonEvent) { if (event instanceof MouseButtonEvent) {
listener.onMouseButtonEvent((MouseButtonEvent) event); listenerRaw.onMouseButtonEvent((MouseButtonEvent) event);
} else if (event instanceof MouseMotionEvent) { } else if (event instanceof MouseMotionEvent) {
listener.onMouseMotionEvent((MouseMotionEvent) event); listenerRaw.onMouseMotionEvent((MouseMotionEvent) event);
} else if (event instanceof KeyInputEvent) { } else if (event instanceof KeyInputEvent) {
listener.onKeyEvent((KeyInputEvent) event); 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(); 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() {
public OGLESShaderRenderer(GL10 gl) {
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(){
// TODO invalidateState
} }
@Override
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,7 +85,6 @@ 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,
@ -95,7 +95,7 @@ public class TextureUtil {
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
}
}; };
} }
@ -86,15 +102,15 @@ 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,47 +50,59 @@ 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;
public OGLESContext(){ 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 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));
}
public GLSurfaceView createView(AndroidInput view)
{
this.view = view;
/* /*
* Requesting client version from GLSurfaceView which is extended by * Requesting client version from GLSurfaceView which is extended by
* AndroidInput. * AndroidInput.
* This is required to get OpenGL ES 2.0 * This is required to get OpenGL ES 2.0
*/ */
logger.info("setEGLContextClientVersion(2)");
view.setEGLContextClientVersion(2); view.setEGLContextClientVersion(2);
logger.info("setEGLContextClientVersion(2) ... done.");
//RGB565, Depth16 //RGB565, Depth16
view.setEGLConfigChooser(5, 6, 5, 0, 16, 0); view.setEGLConfigChooser(5, 6, 5, 0, 16, 0);
@ -105,11 +116,10 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
} }
protected void applySettings(AppSettings setting){
}
protected void initInThread(GL10 gl){ protected void initInThread()
logger.info("Display created."); {
logger.info("OGLESContext create");
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() {
@ -118,174 +128,219 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
} }
}); });
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 needClose.set(false);
// forcefully remove all gui nodes
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()
listener.destroy(); {
if (renderer != null) { if (renderer != null)
renderer.cleanup(); renderer.cleanup();
// do android specific cleaning here
listener.destroy();
// do android specific cleaning here
logger.info("Display destroyed."); logger.info("Display destroyed.");
renderable.set(false);
created.set(false); created.set(false);
renderer = null; renderer = null;
timer = null; timer = null;
} }
}
protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings) { protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings)
{
logger.warning("setSettings.USE_VA: [" + settings.getBoolean("USE_VA") + "]"); logger.warning("setSettings.USE_VA: [" + settings.getBoolean("USE_VA") + "]");
logger.warning("setSettings.VERBOSE_LOGGING: [" + settings.getBoolean("VERBOSE_LOGGING") + "]"); logger.warning("setSettings.VERBOSE_LOGGING: [" + settings.getBoolean("VERBOSE_LOGGING") + "]");
renderer.setUseVA(settings.getBoolean("USE_VA")); renderer.setUseVA(settings.getBoolean("USE_VA"));
renderer.setVerboseLogging(settings.getBoolean("VERBOSE_LOGGING")); renderer.setVerboseLogging(settings.getBoolean("VERBOSE_LOGGING"));
} }
protected void applySettings(AppSettings setting)
{
if (renderer != null)
applySettingsToRenderer(renderer, settings);
}
@Override @Override
public void setSettings(AppSettings settings) { public void setSettings(AppSettings settings)
{
this.settings.copyFrom(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 (renderable.get())
// if (!wasActive){ {
// listener.gainFocus(); milliStart = System.currentTimeMillis();
// wasActive = true;
// }else{
// listener.loseFocus();
// wasActive = false;
// }
// }
if (!created.get())
throw new IllegalStateException();
listener.update();
// swap buffers listener.update();
if (frameRate > 0){
// Display.sync(frameRate);
// synchronzie to framerate
}
if (autoFlush) if (autoFlush)
{
renderer.onFrame(); renderer.onFrame();
} }
/** milliDelta = System.currentTimeMillis() - milliStart;
* TODO: get these methods to follow the spec
* @param waitFor // Enforce a FPS cap
*/ if (milliDelta < minFrameDuration)
public void create(boolean waitFor) { {
if (created.get()){ //logger.log(Level.INFO, "Time per frame {0}", milliDelta);
logger.warning("create() called when display is already created!"); try {
return; Thread.sleep(minFrameDuration - milliDelta);
} catch (InterruptedException e) {
} }
} }
public void create(){
create(false);
} }
public void restart() {
}
@Override
public boolean isRenderable()
{
return renderable.get();
} }
public boolean isRenderable() { @Override
// TODO isRenderable public void create(boolean waitFor)
return true; {
if (waitFor)
waitFor(true);
} }
/** public void create()
* TODO: get these methods to follow the spec {
* @param waitFor create(false);
*/ }
public void destroy(boolean waitFor) {
@Override
public void restart()
{
}
@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,56 +42,38 @@ 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);

@ -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