diff options
Diffstat (limited to 'platform/android/java/src')
14 files changed, 1276 insertions, 635 deletions
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java index 374d40463a..751e885118 100644 --- a/platform/android/java/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/src/org/godotengine/godot/Godot.java @@ -30,8 +30,6 @@  package org.godotengine.godot; -//import android.R; -  import android.Manifest;  import android.app.Activity;  import android.app.ActivityManager; @@ -64,6 +62,7 @@ import android.util.Log;  import android.view.Display;  import android.view.KeyEvent;  import android.view.MotionEvent; +import android.view.Surface;  import android.view.View;  import android.view.ViewGroup;  import android.view.ViewGroup.LayoutParams; @@ -73,7 +72,6 @@ import android.view.WindowManager;  import android.widget.Button;  import android.widget.FrameLayout;  import android.widget.ProgressBar; -import android.widget.RelativeLayout;  import android.widget.TextView;  import com.google.android.vending.expansion.downloader.DownloadProgressInfo;  import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller; @@ -94,6 +92,7 @@ import java.util.Locale;  import javax.microedition.khronos.opengles.GL10;  import org.godotengine.godot.input.GodotEditText;  import org.godotengine.godot.payments.PaymentsManager; +import org.godotengine.godot.xr.XRMode;  public class Godot extends Activity implements SensorEventListener, IDownloaderClient { @@ -120,6 +119,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC  	private boolean use_immersive = false;  	private boolean use_debug_opengl = false;  	private boolean mStatePaused; +	private boolean activityResumed;  	private int mState;  	static private Intent mCurrentIntent; @@ -282,7 +282,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC  		// ...add to FrameLayout  		layout.addView(edittext); -		mView = new GodotView(getApplication(), io, use_gl3, use_32_bits, use_debug_opengl, this); +		mView = new GodotView(this, XRMode.PANCAKE, use_gl3, use_32_bits, use_debug_opengl);  		layout.addView(mView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));  		edittext.setView(mView);  		io.setEdit(edittext); @@ -402,6 +402,20 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC  		}  	} +	/** +	 * Used by the native code (java_godot_wrapper.h) to check whether the activity is resumed or paused. +	 */ +	private boolean isActivityResumed() { +		return activityResumed; +	} + +	/** +	 * Used by the native code (java_godot_wrapper.h) to access the Android surface. +	 */ +	private Surface getSurface() { +		return mView.getHolder().getSurface(); +	} +  	String expansion_pack_path;  	private void initializeGodot() { @@ -612,6 +626,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC  	@Override  	protected void onPause() {  		super.onPause(); +		activityResumed = false; +  		if (!godot_initialized) {  			if (null != mDownloaderClientStub) {  				mDownloaderClientStub.disconnect(this); @@ -687,6 +703,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC  			singletons[i].onMainResume();  		} + +		activityResumed = true;  	}  	public void UiChangeListener() { @@ -1059,4 +1077,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC  		mProgressFraction.setText(Helpers.getDownloadProgressString(progress.mOverallProgress,  				progress.mOverallTotal));  	} +	public void initInputDevices() { +		mView.initInputDevices(); +	}  } diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java index 31ca9a8500..81c98bcc79 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java @@ -68,8 +68,8 @@ public class GodotLib {  	public static native void singleton(String p_name, Object p_object);  	public static native void method(String p_sname, String p_name, String p_ret, String[] p_params);  	public static native String getGlobal(String p_key); -	public static native void callobject(int p_ID, String p_method, Object[] p_params); -	public static native void calldeferred(int p_ID, String p_method, Object[] p_params); +	public static native void callobject(int p_id, String p_method, Object[] p_params); +	public static native void calldeferred(int p_id, String p_method, Object[] p_params);  	public static native void requestPermissionResult(String p_permission, boolean p_result);  	public static native void setVirtualKeyboardHeight(int p_height); diff --git a/platform/android/java/src/org/godotengine/godot/GodotRenderer.java b/platform/android/java/src/org/godotengine/godot/GodotRenderer.java new file mode 100644 index 0000000000..8e3775c2a9 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/GodotRenderer.java @@ -0,0 +1,61 @@ +/*************************************************************************/ +/*  GodotRenderer.java                                                   */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot; + +import android.opengl.GLSurfaceView; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; +import org.godotengine.godot.utils.GLUtils; + +/** + * Godot's renderer implementation. + */ +class GodotRenderer implements GLSurfaceView.Renderer { + +	public void onDrawFrame(GL10 gl) { +		GodotLib.step(); +		for (int i = 0; i < Godot.singleton_count; i++) { +			Godot.singletons[i].onGLDrawFrame(gl); +		} +	} + +	public void onSurfaceChanged(GL10 gl, int width, int height) { + +		GodotLib.resize(width, height); +		for (int i = 0; i < Godot.singleton_count; i++) { +			Godot.singletons[i].onGLSurfaceChanged(gl, width, height); +		} +	} + +	public void onSurfaceCreated(GL10 gl, EGLConfig config) { +		GodotLib.newcontext(GLUtils.use_32); +	} +} diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java index d7cd5b4360..1c189a1579 100644 --- a/platform/android/java/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/src/org/godotengine/godot/GodotView.java @@ -30,28 +30,20 @@  package org.godotengine.godot;  import android.annotation.SuppressLint; -import android.content.Context; -import android.content.ContextWrapper;  import android.graphics.PixelFormat; -import android.hardware.input.InputManager;  import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import android.util.Log; -import android.view.InputDevice;  import android.view.KeyEvent;  import android.view.MotionEvent; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.opengles.GL10; -import org.godotengine.godot.input.InputManagerCompat; -import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener; +import org.godotengine.godot.input.GodotInputHandler; +import org.godotengine.godot.utils.GLUtils; +import org.godotengine.godot.xr.XRMode; +import org.godotengine.godot.xr.ovr.OvrConfigChooser; +import org.godotengine.godot.xr.ovr.OvrContextFactory; +import org.godotengine.godot.xr.ovr.OvrWindowSurfaceFactory; +import org.godotengine.godot.xr.pancake.PancakeConfigChooser; +import org.godotengine.godot.xr.pancake.PancakeContextFactory; +import org.godotengine.godot.xr.pancake.PancakeFallbackConfigChooser; +  /**   * A simple GLSurfaceView sub-class that demonstrate how to perform   * OpenGL ES 2.0 rendering into a GL Surface. Note the following important @@ -70,45 +62,26 @@ import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener;   *   that matches it exactly (with regards to red/green/blue/alpha channels   *   bit depths). Failure to do so would result in an EGL_BAD_MATCH error.   */ -public class GodotView extends GLSurfaceView implements InputDeviceListener { - -	private static String TAG = "GodotView"; -	private static final boolean DEBUG = false; -	private Context ctx; - -	private GodotIO io; -	private static boolean use_gl3 = false; -	private static boolean use_32 = false; -	private static boolean use_debug_opengl = false; +public class GodotView extends GLSurfaceView { -	private Godot activity; +	private static String TAG = GodotView.class.getSimpleName(); -	private InputManagerCompat mInputManager; -	public GodotView(Context context, GodotIO p_io, boolean p_use_gl3, boolean p_use_32_bits, boolean p_use_debug_opengl, Godot p_activity) { -		super(context); -		ctx = context; -		io = p_io; -		use_gl3 = p_use_gl3; -		use_32 = p_use_32_bits; -		use_debug_opengl = p_use_debug_opengl; +	private final Godot activity; +	private final GodotInputHandler inputHandler; -		activity = p_activity; - -		setPreserveEGLContextOnPause(true); +	public GodotView(Godot activity, XRMode xrMode, boolean p_use_gl3, boolean p_use_32_bits, boolean p_use_debug_opengl) { +		super(activity); +		GLUtils.use_gl3 = p_use_gl3; +		GLUtils.use_32 = p_use_32_bits; +		GLUtils.use_debug_opengl = p_use_debug_opengl; -		mInputManager = InputManagerCompat.Factory.getInputManager(this.getContext()); -		mInputManager.registerInputDeviceListener(this, null); -		init(false, 16, 0); +		this.activity = activity; +		this.inputHandler = new GodotInputHandler(this); +		init(xrMode, false, 16, 0);  	} -	public GodotView(Context context) { -		super(context); -		ctx = context; -	} - -	public GodotView(Context context, boolean translucent, int depth, int stencil) { -		super(context); -		init(translucent, depth, stencil); +	public void initInputDevices() { +		this.inputHandler.initInputDevices();  	}  	@SuppressLint("ClickableViewAccessibility") @@ -118,609 +91,80 @@ public class GodotView extends GLSurfaceView implements InputDeviceListener {  		return activity.gotTouchEvent(event);  	} -	public int get_godot_button(int keyCode) { - -		int button; -		switch (keyCode) { -			case KeyEvent.KEYCODE_BUTTON_A: // Android A is SNES B -				button = 0; -				break; -			case KeyEvent.KEYCODE_BUTTON_B: -				button = 1; -				break; -			case KeyEvent.KEYCODE_BUTTON_X: // Android X is SNES Y -				button = 2; -				break; -			case KeyEvent.KEYCODE_BUTTON_Y: -				button = 3; -				break; -			case KeyEvent.KEYCODE_BUTTON_L1: -				button = 9; -				break; -			case KeyEvent.KEYCODE_BUTTON_L2: -				button = 15; -				break; -			case KeyEvent.KEYCODE_BUTTON_R1: -				button = 10; -				break; -			case KeyEvent.KEYCODE_BUTTON_R2: -				button = 16; -				break; -			case KeyEvent.KEYCODE_BUTTON_SELECT: -				button = 4; -				break; -			case KeyEvent.KEYCODE_BUTTON_START: -				button = 6; -				break; -			case KeyEvent.KEYCODE_BUTTON_THUMBL: -				button = 7; -				break; -			case KeyEvent.KEYCODE_BUTTON_THUMBR: -				button = 8; -				break; -			case KeyEvent.KEYCODE_DPAD_UP: -				button = 11; -				break; -			case KeyEvent.KEYCODE_DPAD_DOWN: -				button = 12; -				break; -			case KeyEvent.KEYCODE_DPAD_LEFT: -				button = 13; -				break; -			case KeyEvent.KEYCODE_DPAD_RIGHT: -				button = 14; -				break; -			case KeyEvent.KEYCODE_BUTTON_C: -				button = 17; -				break; -			case KeyEvent.KEYCODE_BUTTON_Z: -				button = 18; -				break; - -			default: -				button = keyCode - KeyEvent.KEYCODE_BUTTON_1 + 20; -				break; -		} -		return button; -	}; - -	private static class joystick { -		public int device_id; -		public String name; -		public ArrayList<InputDevice.MotionRange> axes; -		public ArrayList<InputDevice.MotionRange> hats; -	} - -	private static class RangeComparator implements Comparator<InputDevice.MotionRange> { -		@Override -		public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) { -			return arg0.getAxis() - arg1.getAxis(); -		} -	} - -	ArrayList<joystick> joy_devices = new ArrayList<joystick>(); - -	private int find_joy_device(int device_id) { -		for (int i = 0; i < joy_devices.size(); i++) { -			if (joy_devices.get(i).device_id == device_id) { -				return i; -			} -		} - -		return -1; -	} - -	@Override -	public void onInputDeviceAdded(int deviceId) { -		int id = find_joy_device(deviceId); - -		// Check if the device has not been already added -		if (id < 0) { -			InputDevice device = mInputManager.getInputDevice(deviceId); - -			id = joy_devices.size(); - -			joystick joy = new joystick(); -			joy.device_id = deviceId; -			joy.name = device.getName(); -			joy.axes = new ArrayList<InputDevice.MotionRange>(); -			joy.hats = new ArrayList<InputDevice.MotionRange>(); - -			List<InputDevice.MotionRange> ranges = device.getMotionRanges(); -			Collections.sort(ranges, new RangeComparator()); - -			for (InputDevice.MotionRange range : ranges) { -				if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) { -					joy.hats.add(range); -				} else { -					joy.axes.add(range); -				} -			} - -			joy_devices.add(joy); - -			final int device_id = id; -			final String name = joy.name; -			queueEvent(new Runnable() { -				@Override -				public void run() { -					GodotLib.joyconnectionchanged(device_id, true, name); -				} -			}); -		} -	} - -	@Override -	public void onInputDeviceRemoved(int deviceId) { -		final int device_id = find_joy_device(deviceId); - -		// Check if the evice has not been already removed -		if (device_id > -1) { -			joy_devices.remove(device_id); - -			queueEvent(new Runnable() { -				@Override -				public void run() { -					GodotLib.joyconnectionchanged(device_id, false, ""); -				} -			}); -		} -	} - -	@Override -	public void onInputDeviceChanged(int deviceId) { -	}  	@Override  	public boolean onKeyUp(final int keyCode, KeyEvent event) { - -		if (keyCode == KeyEvent.KEYCODE_BACK) { -			return true; -		} - -		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { -			return super.onKeyUp(keyCode, event); -		}; - -		int source = event.getSource(); -		if ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { - -			final int button = get_godot_button(keyCode); -			final int device_id = find_joy_device(event.getDeviceId()); - -			// Check if the device exists -			if (device_id > -1) { -				queueEvent(new Runnable() { -					@Override -					public void run() { -						GodotLib.joybutton(device_id, button, false); -					} -				}); -				return true; -			} -		} else { -			final int chr = event.getUnicodeChar(0); -			queueEvent(new Runnable() { -				@Override -				public void run() { -					GodotLib.key(keyCode, chr, false); -				} -			}); -		}; - -		return super.onKeyUp(keyCode, event); -	}; +		return inputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); +	}  	@Override  	public boolean onKeyDown(final int keyCode, KeyEvent event) { - -		if (keyCode == KeyEvent.KEYCODE_BACK) { -			activity.onBackPressed(); -			// press 'back' button should not terminate program -			//normal handle 'back' event in game logic -			return true; -		} - -		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { -			return super.onKeyDown(keyCode, event); -		}; - -		int source = event.getSource(); -		//Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD))); - -		if ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { - -			if (event.getRepeatCount() > 0) // ignore key echo -				return true; - -			final int button = get_godot_button(keyCode); -			final int device_id = find_joy_device(event.getDeviceId()); - -			// Check if the device exists -			if (device_id > -1) { -				queueEvent(new Runnable() { -					@Override -					public void run() { -						GodotLib.joybutton(device_id, button, true); -					} -				}); -				return true; -			} -		} else { -			final int chr = event.getUnicodeChar(0); -			queueEvent(new Runnable() { -				@Override -				public void run() { -					GodotLib.key(keyCode, chr, true); -				} -			}); -		}; - -		return super.onKeyDown(keyCode, event); +		return inputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);  	}  	@Override  	public boolean onGenericMotionEvent(MotionEvent event) { - -		if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { - -			final int device_id = find_joy_device(event.getDeviceId()); - -			// Check if the device exists -			if (device_id > -1) { -				joystick joy = joy_devices.get(device_id); - -				for (int i = 0; i < joy.axes.size(); i++) { -					InputDevice.MotionRange range = joy.axes.get(i); -					final float value = (event.getAxisValue(range.getAxis()) - range.getMin()) / range.getRange() * 2.0f - 1.0f; -					final int idx = i; -					queueEvent(new Runnable() { -						@Override -						public void run() { -							GodotLib.joyaxis(device_id, idx, value); -						} -					}); -				} - -				for (int i = 0; i < joy.hats.size(); i += 2) { -					final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis())); -					final int hatY = Math.round(event.getAxisValue(joy.hats.get(i + 1).getAxis())); -					queueEvent(new Runnable() { -						@Override -						public void run() { -							GodotLib.joyhat(device_id, hatX, hatY); -						} -					}); -				} -				return true; -			} -		}; - -		return super.onGenericMotionEvent(event); -	}; - -	private void init(boolean translucent, int depth, int stencil) { - -		this.setFocusableInTouchMode(true); -		/* By default, GLSurfaceView() creates a RGB_565 opaque surface. -		 * If we want a translucent one, we should change the surface's -		 * format here, using PixelFormat.TRANSLUCENT for GL Surfaces -		 * is interpreted as any 32-bit surface with alpha by SurfaceFlinger. -		 */ -		if (translucent) { -			this.getHolder().setFormat(PixelFormat.TRANSLUCENT); -		} - -		/* Setup the context factory for 2.0 rendering. -		 * See ContextFactory class definition below -		 */ -		setEGLContextFactory(new ContextFactory()); - -		/* We need to choose an EGLConfig that matches the format of -		 * our surface exactly. This is going to be done in our -		 * custom config chooser. See ConfigChooser class definition -		 * below. -		 */ - -		if (use_32) { -			setEGLConfigChooser(translucent ? -										new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(8, 8, 8, 8, 16, stencil)) : -										new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(5, 6, 5, 0, 16, stencil))); - -		} else { -			setEGLConfigChooser(translucent ? -										new ConfigChooser(8, 8, 8, 8, 16, stencil) : -										new ConfigChooser(5, 6, 5, 0, 16, stencil)); -		} - -		/* Set the renderer responsible for frame rendering */ -		setRenderer(new Renderer()); -	} - -	private static final int _EGL_CONTEXT_FLAGS_KHR = 0x30FC; -	private static final int _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR = 0x00000001; - -	private static class ContextFactory implements GLSurfaceView.EGLContextFactory { -		private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; -		public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { -			String driver_name = GodotLib.getGlobal("rendering/quality/driver/driver_name"); -			if (use_gl3 && !driver_name.equals("GLES3")) { -				use_gl3 = false; -			} -			if (use_gl3) -				Log.w(TAG, "creating OpenGL ES 3.0 context :"); -			else -				Log.w(TAG, "creating OpenGL ES 2.0 context :"); - -			checkEglError("Before eglCreateContext", egl); -			EGLContext context; -			if (use_debug_opengl) { -				int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; -				int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; -				context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl3 ? attrib_list3 : attrib_list2); -			} else { -				int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; -				int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; -				context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl3 ? attrib_list3 : attrib_list2); -			} -			checkEglError("After eglCreateContext", egl); -			return context; -		} - -		public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { -			egl.eglDestroyContext(display, context); -		} -	} - -	private static void checkEglError(String prompt, EGL10 egl) { -		int error; -		while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { -			Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); -		} -	} -	/* Fallback if 32bit View is not supported*/ -	private static class FallbackConfigChooser extends ConfigChooser { -		private ConfigChooser fallback; - -		public FallbackConfigChooser(int r, int g, int b, int a, int depth, int stencil, ConfigChooser fallback) { -			super(r, g, b, a, depth, stencil); -			this.fallback = fallback; -		} - -		@Override -		public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { -			EGLConfig ec = super.chooseConfig(egl, display, configs); -			if (ec == null) { -				Log.w(TAG, "Trying ConfigChooser fallback"); -				ec = fallback.chooseConfig(egl, display, configs); -				use_32 = false; -			} -			return ec; -		} +		return inputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);  	} -	private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { - -		public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { -			mRedSize = r; -			mGreenSize = g; -			mBlueSize = b; -			mAlphaSize = a; -			mDepthSize = depth; -			mStencilSize = stencil; -		} - -		/* This EGL config specification is used to specify 2.0 rendering. -		 * We use a minimum size of 4 bits for red/green/blue, but will -		 * perform actual matching in chooseConfig() below. -		 */ -		private static int EGL_OPENGL_ES2_BIT = 4; -		private static int[] s_configAttribs2 = { -			EGL10.EGL_RED_SIZE, 4, -			EGL10.EGL_GREEN_SIZE, 4, -			EGL10.EGL_BLUE_SIZE, 4, -			//  EGL10.EGL_DEPTH_SIZE,     16, -			// EGL10.EGL_STENCIL_SIZE,   EGL10.EGL_DONT_CARE, -			EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, -			EGL10.EGL_NONE -		}; -		private static int[] s_configAttribs3 = { -			EGL10.EGL_RED_SIZE, 4, -			EGL10.EGL_GREEN_SIZE, 4, -			EGL10.EGL_BLUE_SIZE, 4, -			// EGL10.EGL_DEPTH_SIZE,     16, -			//  EGL10.EGL_STENCIL_SIZE,   EGL10.EGL_DONT_CARE, -			EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //apparently there is no EGL_OPENGL_ES3_BIT -			EGL10.EGL_NONE -		}; - -		public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { - -			/* Get the number of minimally matching EGL configurations -			 */ -			int[] num_config = new int[1]; -			egl.eglChooseConfig(display, use_gl3 ? s_configAttribs3 : s_configAttribs2, null, 0, num_config); - -			int numConfigs = num_config[0]; - -			if (numConfigs <= 0) { -				throw new IllegalArgumentException("No configs match configSpec"); -			} - -			/* Allocate then read the array of minimally matching EGL configs -			 */ -			EGLConfig[] configs = new EGLConfig[numConfigs]; -			egl.eglChooseConfig(display, use_gl3 ? s_configAttribs3 : s_configAttribs2, configs, numConfigs, num_config); +	private void init(XRMode xrMode, boolean translucent, int depth, int stencil) { -			if (DEBUG) { -				printConfigs(egl, display, configs); -			} -			/* Now return the "best" one -			 */ -			return chooseConfig(egl, display, configs); -		} +		setPreserveEGLContextOnPause(true); +		setFocusableInTouchMode(true); +		switch (xrMode) { -		public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, -				EGLConfig[] configs) { -			for (EGLConfig config : configs) { -				int d = findConfigAttrib(egl, display, config, -						EGL10.EGL_DEPTH_SIZE, 0); -				int s = findConfigAttrib(egl, display, config, -						EGL10.EGL_STENCIL_SIZE, 0); +			case OVR: +				// Replace the default egl config chooser. +				setEGLConfigChooser(new OvrConfigChooser()); -				// We need at least mDepthSize and mStencilSize bits -				if (d < mDepthSize || s < mStencilSize) -					continue; +				// Replace the default context factory. +				setEGLContextFactory(new OvrContextFactory()); -				// We want an *exact* match for red/green/blue/alpha -				int r = findConfigAttrib(egl, display, config, -						EGL10.EGL_RED_SIZE, 0); -				int g = findConfigAttrib(egl, display, config, -						EGL10.EGL_GREEN_SIZE, 0); -				int b = findConfigAttrib(egl, display, config, -						EGL10.EGL_BLUE_SIZE, 0); -				int a = findConfigAttrib(egl, display, config, -						EGL10.EGL_ALPHA_SIZE, 0); +				// Replace the default window surface factory. +				setEGLWindowSurfaceFactory(new OvrWindowSurfaceFactory()); +				break; -				if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) -					return config; -			} -			return null; -		} +			case PANCAKE: +			default: +				/* By default, GLSurfaceView() creates a RGB_565 opaque surface. +				 * If we want a translucent one, we should change the surface's +				 * format here, using PixelFormat.TRANSLUCENT for GL Surfaces +				 * is interpreted as any 32-bit surface with alpha by SurfaceFlinger. +				 */ +				if (translucent) { +					this.getHolder().setFormat(PixelFormat.TRANSLUCENT); +				} -		private int findConfigAttrib(EGL10 egl, EGLDisplay display, -				EGLConfig config, int attribute, int defaultValue) { +				/* Setup the context factory for 2.0 rendering. +				 * See ContextFactory class definition below +				 */ +				setEGLContextFactory(new PancakeContextFactory()); -			if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { -				return mValue[0]; -			} -			return defaultValue; -		} +				/* We need to choose an EGLConfig that matches the format of +				 * our surface exactly. This is going to be done in our +				 * custom config chooser. See ConfigChooser class definition +				 * below. +				 */ -		private void printConfigs(EGL10 egl, EGLDisplay display, -				EGLConfig[] configs) { -			int numConfigs = configs.length; -			Log.w(TAG, String.format("%d configurations", numConfigs)); -			for (int i = 0; i < numConfigs; i++) { -				Log.w(TAG, String.format("Configuration %d:\n", i)); -				printConfig(egl, display, configs[i]); -			} -		} +				if (GLUtils.use_32) { +					setEGLConfigChooser(translucent ? +												new PancakeFallbackConfigChooser(8, 8, 8, 8, 24, stencil, +														new PancakeConfigChooser(8, 8, 8, 8, 16, stencil)) : +												new PancakeFallbackConfigChooser(8, 8, 8, 8, 24, stencil, +														new PancakeConfigChooser(5, 6, 5, 0, 16, stencil))); -		private void printConfig(EGL10 egl, EGLDisplay display, -				EGLConfig config) { -			int[] attributes = { -				EGL10.EGL_BUFFER_SIZE, -				EGL10.EGL_ALPHA_SIZE, -				EGL10.EGL_BLUE_SIZE, -				EGL10.EGL_GREEN_SIZE, -				EGL10.EGL_RED_SIZE, -				EGL10.EGL_DEPTH_SIZE, -				EGL10.EGL_STENCIL_SIZE, -				EGL10.EGL_CONFIG_CAVEAT, -				EGL10.EGL_CONFIG_ID, -				EGL10.EGL_LEVEL, -				EGL10.EGL_MAX_PBUFFER_HEIGHT, -				EGL10.EGL_MAX_PBUFFER_PIXELS, -				EGL10.EGL_MAX_PBUFFER_WIDTH, -				EGL10.EGL_NATIVE_RENDERABLE, -				EGL10.EGL_NATIVE_VISUAL_ID, -				EGL10.EGL_NATIVE_VISUAL_TYPE, -				0x3030, // EGL10.EGL_PRESERVED_RESOURCES, -				EGL10.EGL_SAMPLES, -				EGL10.EGL_SAMPLE_BUFFERS, -				EGL10.EGL_SURFACE_TYPE, -				EGL10.EGL_TRANSPARENT_TYPE, -				EGL10.EGL_TRANSPARENT_RED_VALUE, -				EGL10.EGL_TRANSPARENT_GREEN_VALUE, -				EGL10.EGL_TRANSPARENT_BLUE_VALUE, -				0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, -				0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, -				0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, -				0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, -				EGL10.EGL_LUMINANCE_SIZE, -				EGL10.EGL_ALPHA_MASK_SIZE, -				EGL10.EGL_COLOR_BUFFER_TYPE, -				EGL10.EGL_RENDERABLE_TYPE, -				0x3042 // EGL10.EGL_CONFORMANT -			}; -			String[] names = { -				"EGL_BUFFER_SIZE", -				"EGL_ALPHA_SIZE", -				"EGL_BLUE_SIZE", -				"EGL_GREEN_SIZE", -				"EGL_RED_SIZE", -				"EGL_DEPTH_SIZE", -				"EGL_STENCIL_SIZE", -				"EGL_CONFIG_CAVEAT", -				"EGL_CONFIG_ID", -				"EGL_LEVEL", -				"EGL_MAX_PBUFFER_HEIGHT", -				"EGL_MAX_PBUFFER_PIXELS", -				"EGL_MAX_PBUFFER_WIDTH", -				"EGL_NATIVE_RENDERABLE", -				"EGL_NATIVE_VISUAL_ID", -				"EGL_NATIVE_VISUAL_TYPE", -				"EGL_PRESERVED_RESOURCES", -				"EGL_SAMPLES", -				"EGL_SAMPLE_BUFFERS", -				"EGL_SURFACE_TYPE", -				"EGL_TRANSPARENT_TYPE", -				"EGL_TRANSPARENT_RED_VALUE", -				"EGL_TRANSPARENT_GREEN_VALUE", -				"EGL_TRANSPARENT_BLUE_VALUE", -				"EGL_BIND_TO_TEXTURE_RGB", -				"EGL_BIND_TO_TEXTURE_RGBA", -				"EGL_MIN_SWAP_INTERVAL", -				"EGL_MAX_SWAP_INTERVAL", -				"EGL_LUMINANCE_SIZE", -				"EGL_ALPHA_MASK_SIZE", -				"EGL_COLOR_BUFFER_TYPE", -				"EGL_RENDERABLE_TYPE", -				"EGL_CONFORMANT" -			}; -			int[] value = new int[1]; -			for (int i = 0; i < attributes.length; i++) { -				int attribute = attributes[i]; -				String name = names[i]; -				if (egl.eglGetConfigAttrib(display, config, attribute, value)) { -					Log.w(TAG, String.format("  %s: %d\n", name, value[0]));  				} else { -					// Log.w(TAG, String.format("  %s: failed\n", name)); -					while (egl.eglGetError() != EGL10.EGL_SUCCESS) -						; +					setEGLConfigChooser(translucent ? +												new PancakeConfigChooser(8, 8, 8, 8, 16, stencil) : +												new PancakeConfigChooser(5, 6, 5, 0, 16, stencil));  				} -			} +				break;  		} -		// Subclasses can adjust these values: -		protected int mRedSize; -		protected int mGreenSize; -		protected int mBlueSize; -		protected int mAlphaSize; -		protected int mDepthSize; -		protected int mStencilSize; -		private int[] mValue = new int[1]; +		/* Set the renderer responsible for frame rendering */ +		setRenderer(new GodotRenderer());  	} -	private static class Renderer implements GLSurfaceView.Renderer { - -		public void onDrawFrame(GL10 gl) { -			GodotLib.step(); -			for (int i = 0; i < Godot.singleton_count; i++) { -				Godot.singletons[i].onGLDrawFrame(gl); -			} -		} - -		public void onSurfaceChanged(GL10 gl, int width, int height) { - -			GodotLib.resize(width, height); -			for (int i = 0; i < Godot.singleton_count; i++) { -				Godot.singletons[i].onGLSurfaceChanged(gl, width, height); -			} -		} - -		public void onSurfaceCreated(GL10 gl, EGLConfig config) { -			GodotLib.newcontext(use_32); -		} +	public void onBackPressed() { +		activity.onBackPressed();  	}  } diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/src/org/godotengine/godot/input/GodotInputHandler.java new file mode 100644 index 0000000000..d01f958123 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/input/GodotInputHandler.java @@ -0,0 +1,352 @@ +/*************************************************************************/ +/*  GodotInputHandler.java                                               */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.input; + +import static org.godotengine.godot.utils.GLUtils.DEBUG; + +import android.util.Log; +import android.view.InputDevice; +import android.view.InputDevice.MotionRange; +import android.view.KeyEvent; +import android.view.MotionEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import org.godotengine.godot.GodotLib; +import org.godotengine.godot.GodotView; +import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener; + +/** + * Handles input related events for the {@link GodotView} view. + */ +public class GodotInputHandler implements InputDeviceListener { + +	private final ArrayList<Joystick> joysticksDevices = new ArrayList<Joystick>(); + +	private final GodotView godotView; +	private final InputManagerCompat inputManager; + +	public GodotInputHandler(GodotView godotView) { +		this.godotView = godotView; +		this.inputManager = InputManagerCompat.Factory.getInputManager(godotView.getContext()); +		this.inputManager.registerInputDeviceListener(this, null); +	} + +	private void queueEvent(Runnable task) { +		godotView.queueEvent(task); +	} + +	public boolean onKeyUp(final int keyCode, KeyEvent event) { +		if (keyCode == KeyEvent.KEYCODE_BACK) { +			return true; +		} + +		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { +			return false; +		}; + +		int source = event.getSource(); +		if ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { + +			final int button = getGodotButton(keyCode); +			final int device_id = findJoystickDevice(event.getDeviceId()); + +			// Check if the device exists +			if (device_id > -1) { +				queueEvent(new Runnable() { +					@Override +					public void run() { +						GodotLib.joybutton(device_id, button, false); +					} +				}); +				return true; +			} +		} else { +			final int chr = event.getUnicodeChar(0); +			queueEvent(new Runnable() { +				@Override +				public void run() { +					GodotLib.key(keyCode, chr, false); +				} +			}); +		}; + +		return false; +	} + +	public boolean onKeyDown(final int keyCode, KeyEvent event) { +		if (keyCode == KeyEvent.KEYCODE_BACK) { +			godotView.onBackPressed(); +			// press 'back' button should not terminate program +			//normal handle 'back' event in game logic +			return true; +		} + +		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { +			return false; +		}; + +		int source = event.getSource(); +		//Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD))); + +		if ((source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { + +			if (event.getRepeatCount() > 0) // ignore key echo +				return true; + +			final int button = getGodotButton(keyCode); +			final int device_id = findJoystickDevice(event.getDeviceId()); + +			// Check if the device exists +			if (device_id > -1) { +				queueEvent(new Runnable() { +					@Override +					public void run() { +						GodotLib.joybutton(device_id, button, true); +					} +				}); +				return true; +			} +		} else { +			final int chr = event.getUnicodeChar(0); +			queueEvent(new Runnable() { +				@Override +				public void run() { +					GodotLib.key(keyCode, chr, true); +				} +			}); +		}; + +		return false; +	} + +	public boolean onGenericMotionEvent(MotionEvent event) { +		if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { + +			final int device_id = findJoystickDevice(event.getDeviceId()); + +			// Check if the device exists +			if (device_id > -1) { +				Joystick joy = joysticksDevices.get(device_id); + +				for (int i = 0; i < joy.axes.size(); i++) { +					InputDevice.MotionRange range = joy.axes.get(i); +					final float value = (event.getAxisValue(range.getAxis()) - range.getMin()) / range.getRange() * 2.0f - 1.0f; +					final int idx = i; +					queueEvent(new Runnable() { +						@Override +						public void run() { +							GodotLib.joyaxis(device_id, idx, value); +						} +					}); +				} + +				for (int i = 0; i < joy.hats.size(); i += 2) { +					final int hatX = Math.round(event.getAxisValue(joy.hats.get(i).getAxis())); +					final int hatY = Math.round(event.getAxisValue(joy.hats.get(i + 1).getAxis())); +					queueEvent(new Runnable() { +						@Override +						public void run() { +							GodotLib.joyhat(device_id, hatX, hatY); +						} +					}); +				} +				return true; +			} +		}; + +		return false; +	} + +	public void initInputDevices() { +		/* initially add input devices*/ +		int[] deviceIds = inputManager.getInputDeviceIds(); +		for (int deviceId : deviceIds) { +			InputDevice device = inputManager.getInputDevice(deviceId); +			if (DEBUG) { +				Log.v("GodotView", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName())); +			} +			onInputDeviceAdded(deviceId); +		} +	} + +	@Override +	public void onInputDeviceAdded(int deviceId) { +		int id = findJoystickDevice(deviceId); + +		// Check if the device has not been already added +		if (id < 0) { +			InputDevice device = inputManager.getInputDevice(deviceId); +			//device can be null if deviceId is not found +			if (device != null) { +				int sources = device.getSources(); +				if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || +						((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { +					id = joysticksDevices.size(); + +					Joystick joy = new Joystick(); +					joy.device_id = deviceId; +					joy.name = device.getName(); +					joy.axes = new ArrayList<InputDevice.MotionRange>(); +					joy.hats = new ArrayList<InputDevice.MotionRange>(); + +					List<InputDevice.MotionRange> ranges = device.getMotionRanges(); +					Collections.sort(ranges, new RangeComparator()); + +					for (InputDevice.MotionRange range : ranges) { +						if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) { +							joy.hats.add(range); +						} else { +							joy.axes.add(range); +						} +					} + +					joysticksDevices.add(joy); + +					final int device_id = id; +					final String name = joy.name; +					queueEvent(new Runnable() { +						@Override +						public void run() { +							GodotLib.joyconnectionchanged(device_id, true, name); +						} +					}); +				} +			} +		} +	} + +	@Override +	public void onInputDeviceRemoved(int deviceId) { +		final int device_id = findJoystickDevice(deviceId); + +		// Check if the evice has not been already removed +		if (device_id > -1) { +			joysticksDevices.remove(device_id); + +			queueEvent(new Runnable() { +				@Override +				public void run() { +					GodotLib.joyconnectionchanged(device_id, false, ""); +				} +			}); +		} +	} + +	@Override +	public void onInputDeviceChanged(int deviceId) { +		onInputDeviceRemoved(deviceId); +		onInputDeviceAdded(deviceId); +	} + +	private static class RangeComparator implements Comparator<MotionRange> { +		@Override +		public int compare(MotionRange arg0, MotionRange arg1) { +			return arg0.getAxis() - arg1.getAxis(); +		} +	} + +	public static int getGodotButton(int keyCode) { +		int button; +		switch (keyCode) { +			case KeyEvent.KEYCODE_BUTTON_A: // Android A is SNES B +				button = 0; +				break; +			case KeyEvent.KEYCODE_BUTTON_B: +				button = 1; +				break; +			case KeyEvent.KEYCODE_BUTTON_X: // Android X is SNES Y +				button = 2; +				break; +			case KeyEvent.KEYCODE_BUTTON_Y: +				button = 3; +				break; +			case KeyEvent.KEYCODE_BUTTON_L1: +				button = 9; +				break; +			case KeyEvent.KEYCODE_BUTTON_L2: +				button = 15; +				break; +			case KeyEvent.KEYCODE_BUTTON_R1: +				button = 10; +				break; +			case KeyEvent.KEYCODE_BUTTON_R2: +				button = 16; +				break; +			case KeyEvent.KEYCODE_BUTTON_SELECT: +				button = 4; +				break; +			case KeyEvent.KEYCODE_BUTTON_START: +				button = 6; +				break; +			case KeyEvent.KEYCODE_BUTTON_THUMBL: +				button = 7; +				break; +			case KeyEvent.KEYCODE_BUTTON_THUMBR: +				button = 8; +				break; +			case KeyEvent.KEYCODE_DPAD_UP: +				button = 11; +				break; +			case KeyEvent.KEYCODE_DPAD_DOWN: +				button = 12; +				break; +			case KeyEvent.KEYCODE_DPAD_LEFT: +				button = 13; +				break; +			case KeyEvent.KEYCODE_DPAD_RIGHT: +				button = 14; +				break; +			case KeyEvent.KEYCODE_BUTTON_C: +				button = 17; +				break; +			case KeyEvent.KEYCODE_BUTTON_Z: +				button = 18; +				break; + +			default: +				button = keyCode - KeyEvent.KEYCODE_BUTTON_1 + 20; +				break; +		} +		return button; +	} + +	private int findJoystickDevice(int device_id) { +		for (int i = 0; i < joysticksDevices.size(); i++) { +			if (joysticksDevices.get(i).device_id == device_id) { +				return i; +			} +		} + +		return -1; +	} +} diff --git a/platform/android/java/src/org/godotengine/godot/input/Joystick.java b/platform/android/java/src/org/godotengine/godot/input/Joystick.java new file mode 100644 index 0000000000..ff95bfb0c5 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/input/Joystick.java @@ -0,0 +1,44 @@ +/*************************************************************************/ +/*  Joystick.java                                                        */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.input; + +import android.view.InputDevice.MotionRange; +import java.util.ArrayList; + +/** + * POJO class to represent a Joystick input device. + */ +class Joystick { +	int device_id; +	String name; +	ArrayList<MotionRange> axes; +	ArrayList<MotionRange> hats; +} diff --git a/platform/android/java/src/org/godotengine/godot/utils/GLUtils.java b/platform/android/java/src/org/godotengine/godot/utils/GLUtils.java new file mode 100644 index 0000000000..6c95494f8b --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/utils/GLUtils.java @@ -0,0 +1,157 @@ +/*************************************************************************/ +/*  GLUtils.java                                                         */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.utils; + +import android.util.Log; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; + +/** + * Contains GL utilities methods. + */ +public class GLUtils { + +	private static final String TAG = GLUtils.class.getSimpleName(); + +	public static final boolean DEBUG = false; + +	public static boolean use_gl3 = false; +	public static boolean use_32 = false; +	public static boolean use_debug_opengl = false; + +	private static final String[] ATTRIBUTES_NAMES = new String[] { +		"EGL_BUFFER_SIZE", +		"EGL_ALPHA_SIZE", +		"EGL_BLUE_SIZE", +		"EGL_GREEN_SIZE", +		"EGL_RED_SIZE", +		"EGL_DEPTH_SIZE", +		"EGL_STENCIL_SIZE", +		"EGL_CONFIG_CAVEAT", +		"EGL_CONFIG_ID", +		"EGL_LEVEL", +		"EGL_MAX_PBUFFER_HEIGHT", +		"EGL_MAX_PBUFFER_PIXELS", +		"EGL_MAX_PBUFFER_WIDTH", +		"EGL_NATIVE_RENDERABLE", +		"EGL_NATIVE_VISUAL_ID", +		"EGL_NATIVE_VISUAL_TYPE", +		"EGL_PRESERVED_RESOURCES", +		"EGL_SAMPLES", +		"EGL_SAMPLE_BUFFERS", +		"EGL_SURFACE_TYPE", +		"EGL_TRANSPARENT_TYPE", +		"EGL_TRANSPARENT_RED_VALUE", +		"EGL_TRANSPARENT_GREEN_VALUE", +		"EGL_TRANSPARENT_BLUE_VALUE", +		"EGL_BIND_TO_TEXTURE_RGB", +		"EGL_BIND_TO_TEXTURE_RGBA", +		"EGL_MIN_SWAP_INTERVAL", +		"EGL_MAX_SWAP_INTERVAL", +		"EGL_LUMINANCE_SIZE", +		"EGL_ALPHA_MASK_SIZE", +		"EGL_COLOR_BUFFER_TYPE", +		"EGL_RENDERABLE_TYPE", +		"EGL_CONFORMANT" +	}; + +	private static final int[] ATTRIBUTES = new int[] { +		EGL10.EGL_BUFFER_SIZE, +		EGL10.EGL_ALPHA_SIZE, +		EGL10.EGL_BLUE_SIZE, +		EGL10.EGL_GREEN_SIZE, +		EGL10.EGL_RED_SIZE, +		EGL10.EGL_DEPTH_SIZE, +		EGL10.EGL_STENCIL_SIZE, +		EGL10.EGL_CONFIG_CAVEAT, +		EGL10.EGL_CONFIG_ID, +		EGL10.EGL_LEVEL, +		EGL10.EGL_MAX_PBUFFER_HEIGHT, +		EGL10.EGL_MAX_PBUFFER_PIXELS, +		EGL10.EGL_MAX_PBUFFER_WIDTH, +		EGL10.EGL_NATIVE_RENDERABLE, +		EGL10.EGL_NATIVE_VISUAL_ID, +		EGL10.EGL_NATIVE_VISUAL_TYPE, +		0x3030, // EGL10.EGL_PRESERVED_RESOURCES, +		EGL10.EGL_SAMPLES, +		EGL10.EGL_SAMPLE_BUFFERS, +		EGL10.EGL_SURFACE_TYPE, +		EGL10.EGL_TRANSPARENT_TYPE, +		EGL10.EGL_TRANSPARENT_RED_VALUE, +		EGL10.EGL_TRANSPARENT_GREEN_VALUE, +		EGL10.EGL_TRANSPARENT_BLUE_VALUE, +		0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, +		0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, +		0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, +		0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, +		EGL10.EGL_LUMINANCE_SIZE, +		EGL10.EGL_ALPHA_MASK_SIZE, +		EGL10.EGL_COLOR_BUFFER_TYPE, +		EGL10.EGL_RENDERABLE_TYPE, +		0x3042 // EGL10.EGL_CONFORMANT +	}; + +	private GLUtils() {} + +	public static void checkEglError(String tag, String prompt, EGL10 egl) { +		int error; +		while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { +			Log.e(tag, String.format("%s: EGL error: 0x%x", prompt, error)); +		} +	} + +	public static void printConfigs(EGL10 egl, EGLDisplay display, +			EGLConfig[] configs) { +		int numConfigs = configs.length; +		Log.v(TAG, String.format("%d configurations", numConfigs)); +		for (int i = 0; i < numConfigs; i++) { +			Log.v(TAG, String.format("Configuration %d:\n", i)); +			printConfig(egl, display, configs[i]); +		} +	} + +	private static void printConfig(EGL10 egl, EGLDisplay display, +			EGLConfig config) { +		int[] value = new int[1]; +		for (int i = 0; i < ATTRIBUTES.length; i++) { +			int attribute = ATTRIBUTES[i]; +			String name = ATTRIBUTES_NAMES[i]; +			if (egl.eglGetConfigAttrib(display, config, attribute, value)) { +				Log.i(TAG, String.format("  %s: %d\n", name, value[0])); +			} else { +				// Log.w(TAG, String.format("  %s: failed\n", name)); +				while (egl.eglGetError() != EGL10.EGL_SUCCESS) +					; +			} +		} +	} +} diff --git a/platform/android/java/src/org/godotengine/godot/xr/XRMode.java b/platform/android/java/src/org/godotengine/godot/xr/XRMode.java new file mode 100644 index 0000000000..cbc8a1e902 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/xr/XRMode.java @@ -0,0 +1,39 @@ +/*************************************************************************/ +/*  XRMode.java                                                          */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.xr; + +/** + * Godot available XR modes. + */ +public enum XRMode { +	PANCAKE, // Regular/flatscreen +	OVR, // Oculus mobile VR SDK +} diff --git a/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrConfigChooser.java b/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrConfigChooser.java new file mode 100644 index 0000000000..ff836a31ca --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrConfigChooser.java @@ -0,0 +1,112 @@ +/*************************************************************************/ +/*  OvrConfigChooser.java                                                */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.xr.ovr; + +import android.opengl.EGLExt; +import android.opengl.GLSurfaceView; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; + +/** + * EGL config chooser for the Oculus Mobile VR SDK. + */ +public class OvrConfigChooser implements GLSurfaceView.EGLConfigChooser { + +	private static final int[] CONFIG_ATTRIBS = { +		EGL10.EGL_RED_SIZE, 8, +		EGL10.EGL_GREEN_SIZE, 8, +		EGL10.EGL_BLUE_SIZE, 8, +		EGL10.EGL_ALPHA_SIZE, 8, // Need alpha for the multi-pass timewarp compositor +		EGL10.EGL_DEPTH_SIZE, 0, +		EGL10.EGL_STENCIL_SIZE, 0, +		EGL10.EGL_SAMPLES, 0, +		EGL10.EGL_NONE +	}; + +	@Override +	public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { +		// Do NOT use eglChooseConfig, because the Android EGL code pushes in +		// multisample flags in eglChooseConfig if the user has selected the "force 4x +		// MSAA" option in settings, and that is completely wasted for our warp +		// target. +		int[] numConfig = new int[1]; +		if (!egl.eglGetConfigs(display, null, 0, numConfig)) { +			throw new IllegalArgumentException("eglGetConfigs failed."); +		} + +		int configsCount = numConfig[0]; +		if (configsCount <= 0) { +			throw new IllegalArgumentException("No configs match configSpec"); +		} + +		EGLConfig[] configs = new EGLConfig[configsCount]; +		if (!egl.eglGetConfigs(display, configs, configsCount, numConfig)) { +			throw new IllegalArgumentException("eglGetConfigs #2 failed."); +		} + +		int[] value = new int[1]; +		for (EGLConfig config : configs) { +			egl.eglGetConfigAttrib(display, config, EGL10.EGL_RENDERABLE_TYPE, value); +			if ((value[0] & EGLExt.EGL_OPENGL_ES3_BIT_KHR) != EGLExt.EGL_OPENGL_ES3_BIT_KHR) { +				continue; +			} + +			// The pbuffer config also needs to be compatible with normal window rendering +			// so it can share textures with the window context. +			egl.eglGetConfigAttrib(display, config, EGL10.EGL_SURFACE_TYPE, value); +			if ((value[0] & (EGL10.EGL_WINDOW_BIT | EGL10.EGL_PBUFFER_BIT)) != (EGL10.EGL_WINDOW_BIT | EGL10.EGL_PBUFFER_BIT)) { +				continue; +			} + +			// Check each attribute in CONFIG_ATTRIBS (which are the attributes we care about) +			// and ensure the value in config matches. +			int attribIndex = 0; +			while (CONFIG_ATTRIBS[attribIndex] != EGL10.EGL_NONE) { +				egl.eglGetConfigAttrib(display, config, CONFIG_ATTRIBS[attribIndex], value); +				if (value[0] != CONFIG_ATTRIBS[attribIndex + 1]) { +					// Attribute key's value does not match the configs value. +					// Start checking next config. +					break; +				} + +				// Step by two because CONFIG_ATTRIBS is in key/value pairs. +				attribIndex += 2; +			} + +			if (CONFIG_ATTRIBS[attribIndex] == EGL10.EGL_NONE) { +				// All relevant attributes match, set the config and stop checking the rest. +				return config; +			} +		} +		return null; +	} +} diff --git a/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrContextFactory.java b/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrContextFactory.java new file mode 100644 index 0000000000..5f6da8c672 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrContextFactory.java @@ -0,0 +1,58 @@ +/*************************************************************************/ +/*  OvrContextFactory.java                                               */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.xr.ovr; + +import android.opengl.EGL14; +import android.opengl.GLSurfaceView; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; + +/** + * EGL Context factory for the Oculus mobile VR SDK. + */ +public class OvrContextFactory implements GLSurfaceView.EGLContextFactory { + +	private static final int[] CONTEXT_ATTRIBS = { +		EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE +	}; + +	@Override +	public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { +		return egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, CONTEXT_ATTRIBS); +	} + +	@Override +	public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { +		egl.eglDestroyContext(display, context); +	} +} diff --git a/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrWindowSurfaceFactory.java b/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrWindowSurfaceFactory.java new file mode 100644 index 0000000000..f1e38c35d8 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/xr/ovr/OvrWindowSurfaceFactory.java @@ -0,0 +1,60 @@ +/*************************************************************************/ +/*  OvrWindowSurfaceFactory.java                                         */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.xr.ovr; + +import android.opengl.GLSurfaceView; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + +/** + * EGL window surface factory for the Oculus mobile VR SDK. + */ +public class OvrWindowSurfaceFactory implements GLSurfaceView.EGLWindowSurfaceFactory { + +	private final static int[] SURFACE_ATTRIBS = { +		EGL10.EGL_WIDTH, 16, +		EGL10.EGL_HEIGHT, 16, +		EGL10.EGL_NONE +	}; + +	@Override +	public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, +			Object nativeWindow) { +		return egl.eglCreatePbufferSurface(display, config, SURFACE_ATTRIBS); +	} + +	@Override +	public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) { +		egl.eglDestroySurface(display, surface); +	} +} diff --git a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeConfigChooser.java b/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeConfigChooser.java new file mode 100644 index 0000000000..ac19a09e76 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeConfigChooser.java @@ -0,0 +1,151 @@ +/*************************************************************************/ +/*  PancakeConfigChooser.java                                            */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.xr.pancake; + +import android.opengl.GLSurfaceView; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; +import org.godotengine.godot.utils.GLUtils; + +/** + * Used to select the egl config for pancake games. + */ +public class PancakeConfigChooser implements GLSurfaceView.EGLConfigChooser { + +	private static final String TAG = PancakeConfigChooser.class.getSimpleName(); + +	private int[] mValue = new int[1]; + +	/* This EGL config specification is used to specify 2.0 rendering. +	 * We use a minimum size of 4 bits for red/green/blue, but will +	 * perform actual matching in chooseConfig() below. +	 */ +	private static int EGL_OPENGL_ES2_BIT = 4; +	private static int[] s_configAttribs2 = { +		EGL10.EGL_RED_SIZE, 4, +		EGL10.EGL_GREEN_SIZE, 4, +		EGL10.EGL_BLUE_SIZE, 4, +		//  EGL10.EGL_DEPTH_SIZE,     16, +		// EGL10.EGL_STENCIL_SIZE,   EGL10.EGL_DONT_CARE, +		EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, +		EGL10.EGL_NONE +	}; +	private static int[] s_configAttribs3 = { +		EGL10.EGL_RED_SIZE, 4, +		EGL10.EGL_GREEN_SIZE, 4, +		EGL10.EGL_BLUE_SIZE, 4, +		// EGL10.EGL_DEPTH_SIZE,     16, +		//  EGL10.EGL_STENCIL_SIZE,   EGL10.EGL_DONT_CARE, +		EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //apparently there is no EGL_OPENGL_ES3_BIT +		EGL10.EGL_NONE +	}; + +	public PancakeConfigChooser(int r, int g, int b, int a, int depth, int stencil) { +		mRedSize = r; +		mGreenSize = g; +		mBlueSize = b; +		mAlphaSize = a; +		mDepthSize = depth; +		mStencilSize = stencil; +	} + +	public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + +		/* Get the number of minimally matching EGL configurations +		 */ +		int[] num_config = new int[1]; +		egl.eglChooseConfig(display, GLUtils.use_gl3 ? s_configAttribs3 : s_configAttribs2, null, 0, num_config); + +		int numConfigs = num_config[0]; + +		if (numConfigs <= 0) { +			throw new IllegalArgumentException("No configs match configSpec"); +		} + +		/* Allocate then read the array of minimally matching EGL configs +		 */ +		EGLConfig[] configs = new EGLConfig[numConfigs]; +		egl.eglChooseConfig(display, GLUtils.use_gl3 ? s_configAttribs3 : s_configAttribs2, configs, numConfigs, num_config); + +		if (GLUtils.DEBUG) { +			GLUtils.printConfigs(egl, display, configs); +		} +		/* Now return the "best" one +		 */ +		return chooseConfig(egl, display, configs); +	} + +	public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, +			EGLConfig[] configs) { +		for (EGLConfig config : configs) { +			int d = findConfigAttrib(egl, display, config, +					EGL10.EGL_DEPTH_SIZE, 0); +			int s = findConfigAttrib(egl, display, config, +					EGL10.EGL_STENCIL_SIZE, 0); + +			// We need at least mDepthSize and mStencilSize bits +			if (d < mDepthSize || s < mStencilSize) +				continue; + +			// We want an *exact* match for red/green/blue/alpha +			int r = findConfigAttrib(egl, display, config, +					EGL10.EGL_RED_SIZE, 0); +			int g = findConfigAttrib(egl, display, config, +					EGL10.EGL_GREEN_SIZE, 0); +			int b = findConfigAttrib(egl, display, config, +					EGL10.EGL_BLUE_SIZE, 0); +			int a = findConfigAttrib(egl, display, config, +					EGL10.EGL_ALPHA_SIZE, 0); + +			if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) +				return config; +		} +		return null; +	} + +	private int findConfigAttrib(EGL10 egl, EGLDisplay display, +			EGLConfig config, int attribute, int defaultValue) { + +		if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { +			return mValue[0]; +		} +		return defaultValue; +	} + +	// Subclasses can adjust these values: +	protected int mRedSize; +	protected int mGreenSize; +	protected int mBlueSize; +	protected int mAlphaSize; +	protected int mDepthSize; +	protected int mStencilSize; +} diff --git a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeContextFactory.java b/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeContextFactory.java new file mode 100644 index 0000000000..aca6ffdba6 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeContextFactory.java @@ -0,0 +1,81 @@ +/*************************************************************************/ +/*  PancakeContextFactory.java                                           */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.xr.pancake; + +import android.opengl.GLSurfaceView; +import android.util.Log; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import org.godotengine.godot.GodotLib; +import org.godotengine.godot.utils.GLUtils; + +/** + * Factory used to setup the opengl context for pancake games. + */ +public class PancakeContextFactory implements GLSurfaceView.EGLContextFactory { +	private static final String TAG = PancakeContextFactory.class.getSimpleName(); + +	private static final int _EGL_CONTEXT_FLAGS_KHR = 0x30FC; +	private static final int _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR = 0x00000001; + +	private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + +	public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { +		String driver_name = GodotLib.getGlobal("rendering/quality/driver/driver_name"); +		if (GLUtils.use_gl3 && !driver_name.equals("GLES3")) { +			GLUtils.use_gl3 = false; +		} +		if (GLUtils.use_gl3) +			Log.w(TAG, "creating OpenGL ES 3.0 context :"); +		else +			Log.w(TAG, "creating OpenGL ES 2.0 context :"); + +		GLUtils.checkEglError(TAG, "Before eglCreateContext", egl); +		EGLContext context; +		if (GLUtils.use_debug_opengl) { +			int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; +			int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE }; +			context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, GLUtils.use_gl3 ? attrib_list3 : attrib_list2); +		} else { +			int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; +			int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE }; +			context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, GLUtils.use_gl3 ? attrib_list3 : attrib_list2); +		} +		GLUtils.checkEglError(TAG, "After eglCreateContext", egl); +		return context; +	} + +	public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { +		egl.eglDestroyContext(display, context); +	} +} diff --git a/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeFallbackConfigChooser.java b/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeFallbackConfigChooser.java new file mode 100644 index 0000000000..e19f218916 --- /dev/null +++ b/platform/android/java/src/org/godotengine/godot/xr/pancake/PancakeFallbackConfigChooser.java @@ -0,0 +1,61 @@ +/*************************************************************************/ +/*  PancakeFallbackConfigChooser.java                                    */ +/*************************************************************************/ +/*                       This file is part of:                           */ +/*                           GODOT ENGINE                                */ +/*                      https://godotengine.org                          */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ +/*                                                                       */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the       */ +/* "Software"), to deal in the Software without restriction, including   */ +/* without limitation the rights to use, copy, modify, merge, publish,   */ +/* distribute, sublicense, and/or sell copies of the Software, and to    */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions:                                             */ +/*                                                                       */ +/* The above copyright notice and this permission notice shall be        */ +/* included in all copies or substantial portions of the Software.       */ +/*                                                                       */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ +/*************************************************************************/ + +package org.godotengine.godot.xr.pancake; + +import android.util.Log; +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLDisplay; +import org.godotengine.godot.utils.GLUtils; + +/* Fallback if 32bit View is not supported*/ +public class PancakeFallbackConfigChooser extends PancakeConfigChooser { + +	private static final String TAG = PancakeFallbackConfigChooser.class.getSimpleName(); + +	private PancakeConfigChooser fallback; + +	public PancakeFallbackConfigChooser(int r, int g, int b, int a, int depth, int stencil, PancakeConfigChooser fallback) { +		super(r, g, b, a, depth, stencil); +		this.fallback = fallback; +	} + +	@Override +	public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) { +		EGLConfig ec = super.chooseConfig(egl, display, configs); +		if (ec == null) { +			Log.w(TAG, "Trying ConfigChooser fallback"); +			ec = fallback.chooseConfig(egl, display, configs); +			GLUtils.use_32 = false; +		} +		return ec; +	} +}  |