src/android patchset: changes AndroidAssetManager, AndroidInput, OGLESContext, JmeSystem, TextureLoader
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7502 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
0ec3bb6dba
commit
a8e9d803dc
287
engine/src/android/com/jme3/app/android/AndroidApplication.java
Normal file
287
engine/src/android/com/jme3/app/android/AndroidApplication.java
Normal file
@ -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);
|
||||
this(null);
|
||||
}
|
||||
|
||||
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){
|
||||
// }
|
||||
// }
|
||||
@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);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 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 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',
|
||||
',',
|
||||
'.',
|
||||
private final static int MAX_EVENTS = 1024;
|
||||
|
||||
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 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();
|
||||
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 (motionEvent.getAction()){
|
||||
|
||||
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)
|
||||
{
|
||||
return createView(new AndroidInput(activity));
|
||||
}
|
||||
|
||||
|
||||
public GLSurfaceView createView(AndroidInput view)
|
||||
{
|
||||
this.view = view;
|
||||
|
||||
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.");
|
||||
|
||||
/*
|
||||
* 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(); // ???
|
||||
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
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl)
|
||||
{
|
||||
|
||||
if (frameRate > 0){
|
||||
// Display.sync(frameRate);
|
||||
// synchronzie to framerate
|
||||
}
|
||||
|
||||
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!");
|
||||
if (!created.get())
|
||||
throw new IllegalStateException("onDrawFrame without create");
|
||||
|
||||
if (needClose.get())
|
||||
{
|
||||
deinitInThread();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (renderable.get())
|
||||
{
|
||||
milliStart = System.currentTimeMillis();
|
||||
|
||||
|
||||
public void create(){
|
||||
create(false);
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
}
|
||||
|
||||
public boolean isRenderable() {
|
||||
// TODO isRenderable
|
||||
return true;
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: get these methods to follow the spec
|
||||
* @param waitFor
|
||||
*/
|
||||
public void destroy(boolean waitFor) {
|
||||
needClose.set(true);
|
||||
@Override
|
||||
public boolean isRenderable()
|
||||
{
|
||||
return renderable.get();
|
||||
}
|
||||
|
||||
public void destroy(){
|
||||
|
||||
@Override
|
||||
public void create(boolean waitFor)
|
||||
{
|
||||
if (waitFor)
|
||||
waitFor(true);
|
||||
}
|
||||
|
||||
public void create()
|
||||
{
|
||||
create(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restart()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(boolean waitFor)
|
||||
{
|
||||
needClose.set(true);
|
||||
if (waitFor)
|
||||
waitFor(false);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
359
engine/src/android/com/jme3/util/FastInteger.java
Normal file
359
engine/src/android/com/jme3/util/FastInteger.java
Normal file
@ -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…
x
Reference in New Issue
Block a user