From 9f36081a8f84cbef302a210a4c779250133ec5ba Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 25 Oct 2013 16:52:46 -0400 Subject: [Android] Implement a very basic version of the input overlay configuration screen. Still a bit of a mess, but this will get cleaned up during finalizations. --- .../org/dolphinemu/dolphinemu/AboutFragment.java | 2 +- .../dolphinemu/emulation/EmulationActivity.java | 4 +- .../dolphinemu/emulation/overlay/InputOverlay.java | 64 +++++ .../emulation/overlay/InputOverlayItem.java | 107 ++++++++ .../dolphinemu/settings/CPUSettingsFragment.java | 51 ---- .../dolphinemu/settings/InputConfigFragment.java | 237 ----------------- .../dolphinemu/settings/PrefsActivity.java | 3 + .../dolphinemu/settings/VideoSettingsFragment.java | 290 --------------------- .../settings/cpu/CPUSettingsFragment.java | 51 ++++ .../settings/input/InputConfigFragment.java | 246 +++++++++++++++++ .../settings/input/InputOverlayConfigActivity.java | 27 ++ .../settings/input/InputOverlayConfigButton.java | 52 ++++ .../settings/video/VideoSettingsFragment.java | 290 +++++++++++++++++++++ 13 files changed, 843 insertions(+), 581 deletions(-) create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlay.java create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlayItem.java delete mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/CPUSettingsFragment.java delete mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/InputConfigFragment.java delete mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/VideoSettingsFragment.java create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/cpu/CPUSettingsFragment.java create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputConfigFragment.java create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigActivity.java create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigButton.java create mode 100644 Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java (limited to 'Source/Android/src') diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java index 8b29e607d7..3695bfa40b 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/AboutFragment.java @@ -20,7 +20,7 @@ import android.widget.TextView; import java.util.ArrayList; import java.util.List; -import org.dolphinemu.dolphinemu.settings.VideoSettingsFragment; +import org.dolphinemu.dolphinemu.settings.video.VideoSettingsFragment; /** * Represents the about screen. diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java index 912fc021c5..8b8f4e0551 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/EmulationActivity.java @@ -21,8 +21,8 @@ import android.view.WindowManager.LayoutParams; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.settings.InputConfigFragment; -import org.dolphinemu.dolphinemu.settings.VideoSettingsFragment; +import org.dolphinemu.dolphinemu.settings.input.InputConfigFragment; +import org.dolphinemu.dolphinemu.settings.video.VideoSettingsFragment; import java.util.List; diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlay.java b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlay.java new file mode 100644 index 0000000000..c2272fdc5f --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlay.java @@ -0,0 +1,64 @@ +package org.dolphinemu.dolphinemu.emulation.overlay; + +import java.util.HashSet; +import java.util.Set; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.SurfaceView; +import android.view.View; +import android.view.View.OnTouchListener; + +/** + * Draws the interactive input overlay on top of the + * {@link NativeGLSurfaceView} that is rendering emulation. + */ +public final class InputOverlay extends SurfaceView implements OnTouchListener +{ + private final Set overlayItems = new HashSet(); + + /** + * Constructor + * + * @param context The current {@link Context}. + * @param attrs {@link AttributeSet} for parsing XML attributes. + */ + public InputOverlay(Context context, AttributeSet attrs) + { + super(context, attrs); + + // Force draw + setWillNotDraw(false); + + // Request focus for the overlay so it has priority on presses. + requestFocus(); + } + + @Override + public boolean onTouch(View v, MotionEvent event) + { + switch (event.getAction()) + { + case MotionEvent.ACTION_DOWN: + { + // TODO: Handle down presses. + return true; + } + } + + return false; + } + + @Override + public void onDraw(Canvas canvas) + { + super.onDraw(canvas); + + for (InputOverlayItem item : overlayItems) + { + item.draw(canvas); + } + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlayItem.java b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlayItem.java new file mode 100644 index 0000000000..a45578b263 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/emulation/overlay/InputOverlayItem.java @@ -0,0 +1,107 @@ +package org.dolphinemu.dolphinemu.emulation.overlay; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; + +/** + * Represents a drawable image for the {@link InputOverlay} + */ +public final class InputOverlayItem +{ + // The image as a BitmapDrawable + private BitmapDrawable drawable; + + // Width and height of the underlying image. + private int width; + private int height; + + // X and Y coordinates to display this item at. + private int x; + private int y; + + // Image scale factor. + private float scaleFactor = 1.0f; + + // Rectangle that we draw this item to. + private Rect drawRect; + + /** + * Constructor. + * + * @param res Reference to the app resources for fetching display metrics. + * @param resId Resource ID of the {@link BitmapDrawable} to encapsulate. + */ + public InputOverlayItem(Resources res, int resId) + { + // Idiot-proof the constructor. + if (res == null) + throw new IllegalArgumentException("res cannot be null"); + + // Everything is valid, decode the filename as a bitmap. + drawable = (BitmapDrawable) res.getDrawable(resId); + Bitmap image = drawable.getBitmap(); + + // Set width/height + width = image.getWidth(); + height = image.getHeight(); + + // Initialize rectangle to zero width, height, x, and y. + drawRect = new Rect(); + } + + /** + * Constructor + * + * @param res Reference to the app resources for fetching display metrics. + * @param resId Resource ID of the {@link BitmapDrawable} to encapsulate. + * @param x X coordinate on the screen to place the control. + * @param y Y coordinate on the screen to place the control. + */ + public InputOverlayItem(Resources res, int resId, int x, int y) + { + this(res, resId); + + setPosition(x, y); + } + + /** + * Sets the position of this item on the screen. + * + * @param x New x-coordinate for this image. + * @param y New y-coordinate for this image. + */ + public void setPosition(int x, int y) + { + this.x = x; + this.y = y; + + drawRect.set(x, y, x + (int)(width * scaleFactor), y + (int)(height * scaleFactor)); + drawable.setBounds(drawRect); + } + + /** + * Sets a new scaling factor for the current image. + * + * @param scaleFactor The new scaling factor. Note that 1.0 is normal size. + */ + public void setScaleFactor(float scaleFactor) + { + this.scaleFactor = scaleFactor; + + // Adjust for the new scale factor. + setPosition(x, y); + } + + /** + * Draws this item to a given canvas. + * + * @param canvas The canvas to draw this item to. + */ + public void draw(Canvas canvas) + { + drawable.draw(canvas); + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/CPUSettingsFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/CPUSettingsFragment.java deleted file mode 100644 index 47f0cb7d35..0000000000 --- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/CPUSettingsFragment.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright 2013 Dolphin Emulator Project - * Licensed under GPLv2 - * Refer to the license.txt file included. - */ - -package org.dolphinemu.dolphinemu.settings; - -import org.dolphinemu.dolphinemu.R; - -import android.os.Build; -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.PreferenceFragment; - -/** - * Responsible for the loading of the CPU preferences. - */ -public final class CPUSettingsFragment extends PreferenceFragment -{ - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.cpu_prefs); - - final ListPreference cpuCores = (ListPreference) findPreference("cpuCorePref"); - - // - // Set valid emulation cores depending on the CPU architecture - // that the Android device is running on. - // - if (Build.CPU_ABI.contains("x86")) - { - cpuCores.setEntries(R.array.emuCoreEntriesX86); - cpuCores.setEntryValues(R.array.emuCoreValuesX86); - } - else if (Build.CPU_ABI.contains("arm")) - { - cpuCores.setEntries(R.array.emuCoreEntriesARM); - cpuCores.setEntryValues(R.array.emuCoreValuesARM); - } - else - { - cpuCores.setEntries(R.array.emuCoreEntriesOther); - cpuCores.setEntryValues(R.array.emuCoreValuesOther); - } - } -} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/InputConfigFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/InputConfigFragment.java deleted file mode 100644 index a23f1b4a3f..0000000000 --- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/InputConfigFragment.java +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright 2013 Dolphin Emulator Project - * Licensed under GPLv2 - * Refer to the license.txt file included. - */ - -package org.dolphinemu.dolphinemu.settings; - -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Build; -import android.os.Bundle; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; -import android.util.Log; -import android.view.*; - -import java.util.ArrayList; -import java.util.List; - -import org.dolphinemu.dolphinemu.NativeLibrary; -import org.dolphinemu.dolphinemu.R; - -/** - * The {@link Fragment} responsible for implementing the functionality - * within the input control mapping config. - */ -public final class InputConfigFragment extends PreferenceFragment -{ - /** - * Gets the descriptor for the given {@link InputDevice}. - * - * @param input The {@link InputDevice} to get the descriptor of. - * - * @return the descriptor for the given {@link InputDevice}. - */ - public static String getInputDesc(InputDevice input) - { - if (input == null) - return "null"; // Happens when the InputDevice is from an unknown source - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - { - return input.getDescriptor(); - } - else - { - List motions = input.getMotionRanges(); - String fakeid = ""; - - for (InputDevice.MotionRange range : motions) - fakeid += range.getAxis(); - - return fakeid; - } - } - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - // Expand the preferences from the XML. - addPreferencesFromResource(R.xml.input_prefs); - - // Set the summary messages of the preferences to whatever binding - // is currently set within the Dolphin config. - final String[] keys = - { - "InputA", "InputB", "InputX", "InputY", "InputZ", "InputStart", - "DPadUp", "DPadDown", "DPadLeft", "DPadRight", - "MainUp", "MainDown", "MainLeft", "MainRight", - "CStickUp", "CStickDown", "CStickLeft", "CStickRight", - "InputL", "InputR", - }; - - Preference pref; - for (String key : keys) - { - String binding = NativeLibrary.GetConfig("Dolphin.ini", "Android", key, "None"); - pref = findPreference(key); - pref.setSummary(binding); - } - } - - @Override - public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference pref) - { - // If the user is on the preference screen to set Gamecube input bindings. - if (screen.getTitle().equals(getString(R.string.gamecube_bindings))) - { - // Begin the creation of the input alert. - final MotionAlertDialog dialog = new MotionAlertDialog(getActivity(), pref); - - // Set the cancel button. - dialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.cancel), new AlertDialog.OnClickListener() - { - @Override - public void onClick(DialogInterface dialog, int which) - { - // Do nothing. Just makes the cancel button show up. - } - }); - - // Set the title and description message. - dialog.setTitle(R.string.input_binding); - dialog.setMessage(String.format(getString(R.string.input_binding_descrip), pref.getTitle())); - - // Don't allow the dialog to close when a user taps - // outside of it. They must press cancel or provide an input. - dialog.setCanceledOnTouchOutside(false); - - // Everything is set, show the dialog. - dialog.show(); - } - - return true; - } - - /** - * {@link AlertDialog} derivative that listens for - * motion events from controllers and joysticks. - */ - private static final class MotionAlertDialog extends AlertDialog - { - // The selected input preference - private final Preference inputPref; - - private boolean firstEvent = true; - private final ArrayList m_values = new ArrayList(); - - /** - * Constructor - * - * @param ctx The current {@link Context}. - * @param inputPref The Preference to show this dialog for. - */ - public MotionAlertDialog(Context ctx, Preference inputPref) - { - super(ctx); - - this.inputPref = inputPref; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) - { - Log.d("InputConfigFragment", "Received key event: " + event.getAction()); - switch (event.getAction()) - { - case KeyEvent.ACTION_DOWN: - case KeyEvent.ACTION_UP: - InputDevice input = event.getDevice(); - String bindStr = "Device '" + getInputDesc(input) + "'-Button " + event.getKeyCode(); - NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr); - inputPref.setSummary(bindStr); - dismiss(); - return true; - - default: - break; - } - - return false; - } - - - // Method that will be called within dispatchGenericMotionEvent - // that handles joystick/controller movements. - private boolean onMotionEvent(MotionEvent event) - { - if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) - return false; - - Log.d("InputConfigFragment", "Received motion event: " + event.getAction()); - - InputDevice input = event.getDevice(); - List motions = input.getMotionRanges(); - if (firstEvent) - { - m_values.clear(); - - for (InputDevice.MotionRange range : motions) - { - m_values.add(event.getAxisValue(range.getAxis())); - } - - firstEvent = false; - } - else - { - for (int a = 0; a < motions.size(); ++a) - { - InputDevice.MotionRange range = motions.get(a); - - if (m_values.get(a) > (event.getAxisValue(range.getAxis()) + 0.5f)) - { - String bindStr = "Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "-"; - NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr); - inputPref.setSummary(bindStr); - dismiss(); - } - else if (m_values.get(a) < (event.getAxisValue(range.getAxis()) - 0.5f)) - { - String bindStr = "Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "+"; - NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr); - inputPref.setSummary(bindStr); - dismiss(); - } - } - } - - return true; - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) - { - if (onKeyDown(event.getKeyCode(), event)) - return true; - - return super.dispatchKeyEvent(event); - } - - @Override - public boolean dispatchGenericMotionEvent(MotionEvent event) - { - if (onMotionEvent(event)) - return true; - - return super.dispatchGenericMotionEvent(event); - } - } -} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java index 51153866e1..5368475319 100644 --- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/PrefsActivity.java @@ -7,6 +7,9 @@ package org.dolphinemu.dolphinemu.settings; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.settings.cpu.CPUSettingsFragment; +import org.dolphinemu.dolphinemu.settings.input.InputConfigFragment; +import org.dolphinemu.dolphinemu.settings.video.VideoSettingsFragment; import android.app.ActionBar; import android.app.ActionBar.Tab; diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/VideoSettingsFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/VideoSettingsFragment.java deleted file mode 100644 index fffea888a7..0000000000 --- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/VideoSettingsFragment.java +++ /dev/null @@ -1,290 +0,0 @@ -/** - * Copyright 2013 Dolphin Emulator Project - * Licensed under GPLv2 - * Refer to the license.txt file included. - */ - -package org.dolphinemu.dolphinemu.settings; - -import android.app.Activity; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.os.Bundle; -import android.preference.ListPreference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceManager; -import android.preference.PreferenceScreen; -import org.dolphinemu.dolphinemu.R; - -import javax.microedition.khronos.egl.*; -import javax.microedition.khronos.opengles.GL10; - -/** - * Responsible for handling the loading of the video preferences. - */ -public final class VideoSettingsFragment extends PreferenceFragment -{ - public static String m_GLVersion; - public static String m_GLVendor; - public static String m_GLRenderer; - public static String m_GLExtensions; - private Activity m_activity; - - /** - * Class which provides a means to retrieve various - * info about the OpenGL ES support/features within a device. - */ - public static final class VersionCheck - { - private EGL10 mEGL; - private EGLDisplay mEGLDisplay; - private EGLConfig[] mEGLConfigs; - private EGLConfig mEGLConfig; - private EGLContext mEGLContext; - private EGLSurface mEGLSurface; - private GL10 mGL; - - String mThreadOwner; - - public VersionCheck() - { - int[] version = new int[2]; - int[] attribList = new int[] { - EGL10.EGL_WIDTH, 1, - EGL10.EGL_HEIGHT, 1, - EGL10.EGL_RENDERABLE_TYPE, 4, - EGL10.EGL_NONE - }; - int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - int[] ctx_attribs = new int[] { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL10.EGL_NONE - }; - - // No error checking performed, minimum required code to elucidate logic - mEGL = (EGL10) EGLContext.getEGL(); - mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - mEGL.eglInitialize(mEGLDisplay, version); - mEGLConfig = chooseConfig(); // Choosing a config is a little more complicated - mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT, ctx_attribs); - mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, attribList); - mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext); - mGL = (GL10) mEGLContext.getGL(); - - // Record thread owner of OpenGL context - mThreadOwner = Thread.currentThread().getName(); - } - - /** - * Gets the OpenGL ES version string. - * - * @return the OpenGL ES version string. - */ - public String getVersion() - { - return mGL.glGetString(GL10.GL_VERSION); - } - - /** - * Gets the OpenGL ES vendor string. - * - * @return the OpenGL ES vendor string. - */ - public String getVendor() - { - return mGL.glGetString(GL10.GL_VENDOR); - } - - /** - * Gets the name of the OpenGL ES renderer. - * - * @return the name of the OpenGL ES renderer. - */ - public String getRenderer() - { - return mGL.glGetString(GL10.GL_RENDERER); - } - - /** - * Gets the extension that the device supports - * - * @return String containing the extensions - */ - public String getExtensions() - { - return mGL.glGetString(GL10.GL_EXTENSIONS); - } - - private EGLConfig chooseConfig() - { - int[] attribList = new int[] { - EGL10.EGL_DEPTH_SIZE, 0, - EGL10.EGL_STENCIL_SIZE, 0, - EGL10.EGL_RED_SIZE, 8, - EGL10.EGL_GREEN_SIZE, 8, - EGL10.EGL_BLUE_SIZE, 8, - EGL10.EGL_ALPHA_SIZE, 8, - EGL10.EGL_NONE - }; - - // No error checking performed, minimum required code to elucidate logic - // Expand on this logic to be more selective in choosing a configuration - int[] numConfig = new int[1]; - mEGL.eglChooseConfig(mEGLDisplay, attribList, null, 0, numConfig); - int configSize = numConfig[0]; - mEGLConfigs = new EGLConfig[configSize]; - mEGL.eglChooseConfig(mEGLDisplay, attribList, mEGLConfigs, configSize, numConfig); - - return mEGLConfigs[0]; // Best match is probably the first configuration - } - } - - /** - * Checks if this device supports OpenGL ES 3. - * - * @return true if this device supports OpenGL ES 3; false otherwise. - */ - public static boolean SupportsGLES3() - { - VersionCheck mbuffer = new VersionCheck(); - m_GLVersion = mbuffer.getVersion(); - m_GLVendor = mbuffer.getVendor(); - m_GLRenderer = mbuffer.getRenderer(); - m_GLExtensions = mbuffer.getExtensions(); - - boolean mSupportsGLES3 = false; - - // Check for OpenGL ES 3 support (General case). - if (m_GLVersion != null && m_GLVersion.contains("OpenGL ES 3.0")) - mSupportsGLES3 = true; - - // Checking for OpenGL ES 3 support for certain Qualcomm devices. - if (!mSupportsGLES3 && m_GLVendor != null && m_GLVendor.equals("Qualcomm")) - { - if (m_GLRenderer.contains("Adreno (TM) 3")) - { - int mVStart = m_GLVersion.indexOf("V@") + 2; - int mVEnd = 0; - float mVersion; - - for (int a = mVStart; a < m_GLVersion.length(); ++a) - { - if (m_GLVersion.charAt(a) == ' ') - { - mVEnd = a; - break; - } - } - - mVersion = Float.parseFloat(m_GLVersion.substring(mVStart, mVEnd)); - - if (mVersion >= 14.0f) - mSupportsGLES3 = true; - } - } - if (!mSupportsGLES3 && - m_GLVendor != null && m_GLVendor.equals("NVIDIA Corporation") && - m_GLRenderer != null && m_GLRenderer.equals("NVIDIA Tegra") && - m_GLExtensions != null && m_GLExtensions.contains("GL_OES_depth24")) - { - // Is a Tegra 4 since it supports 24bit depth - mSupportsGLES3 = true; - } - if (!mSupportsGLES3 && - m_GLVendor == null && - m_GLRenderer == null && - m_GLExtensions == null) - { - // Couldn't get information. Give them the benefit of the doubt - mSupportsGLES3 = true; - } - return mSupportsGLES3; - } - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.video_prefs); - - // - // Setting valid video backends. - // - final ListPreference videoBackends = (ListPreference) findPreference("gpuPref"); - final boolean deviceSupportsGLES3 = SupportsGLES3(); - - if (deviceSupportsGLES3) - { - videoBackends.setEntries(R.array.videoBackendEntriesGLES3); - videoBackends.setEntryValues(R.array.videoBackendValuesGLES3); - } - else - { - videoBackends.setEntries(R.array.videoBackendEntriesNoGLES3); - videoBackends.setEntryValues(R.array.videoBackendValuesNoGLES3); - } - - // - // Disable all options if Software Rendering is used. - // - // Note that the numeric value in 'getPreference()' - // denotes the placement on the UI. So if more elements are - // added to the video settings, these may need to change. - // - final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(m_activity); - final PreferenceScreen mainScreen = getPreferenceScreen(); - - if (videoBackends.getValue().equals("Software Renderer")) - { - mainScreen.getPreference(0).setEnabled(false); - mainScreen.getPreference(1).setEnabled(false); - mainScreen.getPreference(3).setEnabled(false); - //mainScreen.getPreference(4).setEnabled(true); - } - else if (videoBackends.getValue().equals("OGL")) - { - mainScreen.getPreference(0).setEnabled(true); - mainScreen.getPreference(1).setEnabled(true); - mainScreen.getPreference(3).setEnabled(true); - //mainScreen.getPreference(4).setEnabled(false); - } - - // Also set a listener, so that if someone changes the video backend, it will disable - // the video settings, upon the user choosing "Software Rendering". - sPrefs.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener() - { - @Override - public void onSharedPreferenceChanged(SharedPreferences preference, String key) - { - if (key.equals("gpuPref")) - { - if (preference.getString(key, "Software Renderer").equals("Software Renderer")) - { - mainScreen.getPreference(0).setEnabled(false); - mainScreen.getPreference(1).setEnabled(false); - mainScreen.getPreference(3).setEnabled(false); - //mainScreen.getPreference(4).setEnabled(true); - } - else if (preference.getString(key, "Software Renderer").equals("OGL")) - { - mainScreen.getPreference(0).setEnabled(true); - mainScreen.getPreference(1).setEnabled(true); - mainScreen.getPreference(3).setEnabled(true); - //mainScreen.getPreference(4).setEnabled(false); - } - } - } - }); - } - - @Override - public void onAttach(Activity activity) - { - super.onAttach(activity); - - // Cache the activity instance. - m_activity = activity; - } -} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/cpu/CPUSettingsFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/cpu/CPUSettingsFragment.java new file mode 100644 index 0000000000..77caec2b83 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/cpu/CPUSettingsFragment.java @@ -0,0 +1,51 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.settings.cpu; + +import org.dolphinemu.dolphinemu.R; + +import android.os.Build; +import android.os.Bundle; +import android.preference.ListPreference; +import android.preference.PreferenceFragment; + +/** + * Responsible for the loading of the CPU preferences. + */ +public final class CPUSettingsFragment extends PreferenceFragment +{ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.cpu_prefs); + + final ListPreference cpuCores = (ListPreference) findPreference("cpuCorePref"); + + // + // Set valid emulation cores depending on the CPU architecture + // that the Android device is running on. + // + if (Build.CPU_ABI.contains("x86")) + { + cpuCores.setEntries(R.array.emuCoreEntriesX86); + cpuCores.setEntryValues(R.array.emuCoreValuesX86); + } + else if (Build.CPU_ABI.contains("arm")) + { + cpuCores.setEntries(R.array.emuCoreEntriesARM); + cpuCores.setEntryValues(R.array.emuCoreValuesARM); + } + else + { + cpuCores.setEntries(R.array.emuCoreEntriesOther); + cpuCores.setEntryValues(R.array.emuCoreValuesOther); + } + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputConfigFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputConfigFragment.java new file mode 100644 index 0000000000..2ada44ccff --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputConfigFragment.java @@ -0,0 +1,246 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.settings.input; + +import android.app.AlertDialog; +import android.app.Fragment; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; +import android.util.Log; +import android.view.*; + +import java.util.ArrayList; +import java.util.List; + +import org.dolphinemu.dolphinemu.NativeLibrary; +import org.dolphinemu.dolphinemu.R; + +/** + * The {@link Fragment} responsible for implementing the functionality + * within the input control mapping config. + */ +public final class InputConfigFragment extends PreferenceFragment +{ + /** + * Gets the descriptor for the given {@link InputDevice}. + * + * @param input The {@link InputDevice} to get the descriptor of. + * + * @return the descriptor for the given {@link InputDevice}. + */ + public static String getInputDesc(InputDevice input) + { + if (input == null) + return "null"; // Happens when the InputDevice is from an unknown source + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) + { + return input.getDescriptor(); + } + else + { + List motions = input.getMotionRanges(); + String fakeid = ""; + + for (InputDevice.MotionRange range : motions) + fakeid += range.getAxis(); + + return fakeid; + } + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + // Expand the preferences from the XML. + addPreferencesFromResource(R.xml.input_prefs); + + // Set the summary messages of the preferences to whatever binding + // is currently set within the Dolphin config. + final String[] keys = + { + "InputA", "InputB", "InputX", "InputY", "InputZ", "InputStart", + "DPadUp", "DPadDown", "DPadLeft", "DPadRight", + "MainUp", "MainDown", "MainLeft", "MainRight", + "CStickUp", "CStickDown", "CStickLeft", "CStickRight", + "InputL", "InputR", + }; + + Preference pref; + for (String key : keys) + { + String binding = NativeLibrary.GetConfig("Dolphin.ini", "Android", key, "None"); + pref = findPreference(key); + pref.setSummary(binding); + } + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference pref) + { + // If the user is on the preference screen to set Gamecube input bindings. + if (screen.getTitle().equals(getString(R.string.gamecube_bindings))) + { + // Begin the creation of the input alert. + final MotionAlertDialog dialog = new MotionAlertDialog(getActivity(), pref); + + // Set the cancel button. + dialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.cancel), new AlertDialog.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + // Do nothing. Just makes the cancel button show up. + } + }); + + // Set the title and description message. + dialog.setTitle(R.string.input_binding); + dialog.setMessage(String.format(getString(R.string.input_binding_descrip), pref.getTitle())); + + // Don't allow the dialog to close when a user taps + // outside of it. They must press cancel or provide an input. + dialog.setCanceledOnTouchOutside(false); + + // Everything is set, show the dialog. + dialog.show(); + return true; + } + + if (pref.getKey().equals("inputOverlayConfigPref")) + { + Intent inputOverlayConfig = new Intent(getActivity(), InputOverlayConfigActivity.class); + startActivity(inputOverlayConfig); + return true; + } + + return false; + } + + /** + * {@link AlertDialog} derivative that listens for + * motion events from controllers and joysticks. + */ + private static final class MotionAlertDialog extends AlertDialog + { + // The selected input preference + private final Preference inputPref; + + private boolean firstEvent = true; + private final ArrayList m_values = new ArrayList(); + + /** + * Constructor + * + * @param ctx The current {@link Context}. + * @param inputPref The Preference to show this dialog for. + */ + public MotionAlertDialog(Context ctx, Preference inputPref) + { + super(ctx); + + this.inputPref = inputPref; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + Log.d("InputConfigFragment", "Received key event: " + event.getAction()); + switch (event.getAction()) + { + case KeyEvent.ACTION_DOWN: + case KeyEvent.ACTION_UP: + InputDevice input = event.getDevice(); + String bindStr = "Device '" + getInputDesc(input) + "'-Button " + event.getKeyCode(); + NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr); + inputPref.setSummary(bindStr); + dismiss(); + return true; + + default: + break; + } + + return false; + } + + + // Method that will be called within dispatchGenericMotionEvent + // that handles joystick/controller movements. + private boolean onMotionEvent(MotionEvent event) + { + if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) + return false; + + Log.d("InputConfigFragment", "Received motion event: " + event.getAction()); + + InputDevice input = event.getDevice(); + List motions = input.getMotionRanges(); + if (firstEvent) + { + m_values.clear(); + + for (InputDevice.MotionRange range : motions) + { + m_values.add(event.getAxisValue(range.getAxis())); + } + + firstEvent = false; + } + else + { + for (int a = 0; a < motions.size(); ++a) + { + InputDevice.MotionRange range = motions.get(a); + + if (m_values.get(a) > (event.getAxisValue(range.getAxis()) + 0.5f)) + { + String bindStr = "Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "-"; + NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr); + inputPref.setSummary(bindStr); + dismiss(); + } + else if (m_values.get(a) < (event.getAxisValue(range.getAxis()) - 0.5f)) + { + String bindStr = "Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "+"; + NativeLibrary.SetConfig("Dolphin.ini", "Android", inputPref.getKey(), bindStr); + inputPref.setSummary(bindStr); + dismiss(); + } + } + } + + return true; + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) + { + if (onKeyDown(event.getKeyCode(), event)) + return true; + + return super.dispatchKeyEvent(event); + } + + @Override + public boolean dispatchGenericMotionEvent(MotionEvent event) + { + if (onMotionEvent(event)) + return true; + + return super.dispatchGenericMotionEvent(event); + } + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigActivity.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigActivity.java new file mode 100644 index 0000000000..3084c181d1 --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigActivity.java @@ -0,0 +1,27 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.settings.input; + +import org.dolphinemu.dolphinemu.R; + +import android.app.Activity; +import android.os.Bundle; + +/** + * {@link Activity} used for configuring the input overlay. + */ +public final class InputOverlayConfigActivity extends Activity +{ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + // Set the initial layout. + setContentView(R.layout.input_overlay_config_layout); + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigButton.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigButton.java new file mode 100644 index 0000000000..cca596e85c --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/input/InputOverlayConfigButton.java @@ -0,0 +1,52 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.settings.input; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.widget.Button; + +/** + * A movable {@link Button} for use within the + * input overlay configuration screen. + */ +public final class InputOverlayConfigButton extends Button implements OnTouchListener +{ + /** + * Constructor + * + * @param context The current {@link Context}. + * @param attribs {@link AttributeSet} for parsing XML attributes. + */ + public InputOverlayConfigButton(Context context, AttributeSet attribs) + { + super(context, attribs); + + // Set the button as its own OnTouchListener. + setOnTouchListener(this); + } + + @Override + public boolean onTouch(View v, MotionEvent event) + { + switch(event.getAction()) + { + // Only change the X/Y coordinates when we move the button. + case MotionEvent.ACTION_MOVE: + { + setX(getX() + event.getX()); + setY(getY() + event.getY()); + return true; + } + } + + return false; + } +} diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java new file mode 100644 index 0000000000..47f9ef475f --- /dev/null +++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java @@ -0,0 +1,290 @@ +/** + * Copyright 2013 Dolphin Emulator Project + * Licensed under GPLv2 + * Refer to the license.txt file included. + */ + +package org.dolphinemu.dolphinemu.settings.video; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.os.Bundle; +import android.preference.ListPreference; +import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; +import android.preference.PreferenceScreen; +import org.dolphinemu.dolphinemu.R; + +import javax.microedition.khronos.egl.*; +import javax.microedition.khronos.opengles.GL10; + +/** + * Responsible for handling the loading of the video preferences. + */ +public final class VideoSettingsFragment extends PreferenceFragment +{ + public static String m_GLVersion; + public static String m_GLVendor; + public static String m_GLRenderer; + public static String m_GLExtensions; + private Activity m_activity; + + /** + * Class which provides a means to retrieve various + * info about the OpenGL ES support/features within a device. + */ + public static final class VersionCheck + { + private EGL10 mEGL; + private EGLDisplay mEGLDisplay; + private EGLConfig[] mEGLConfigs; + private EGLConfig mEGLConfig; + private EGLContext mEGLContext; + private EGLSurface mEGLSurface; + private GL10 mGL; + + String mThreadOwner; + + public VersionCheck() + { + int[] version = new int[2]; + int[] attribList = new int[] { + EGL10.EGL_WIDTH, 1, + EGL10.EGL_HEIGHT, 1, + EGL10.EGL_RENDERABLE_TYPE, 4, + EGL10.EGL_NONE + }; + int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + int[] ctx_attribs = new int[] { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL10.EGL_NONE + }; + + // No error checking performed, minimum required code to elucidate logic + mEGL = (EGL10) EGLContext.getEGL(); + mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + mEGL.eglInitialize(mEGLDisplay, version); + mEGLConfig = chooseConfig(); // Choosing a config is a little more complicated + mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT, ctx_attribs); + mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, attribList); + mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext); + mGL = (GL10) mEGLContext.getGL(); + + // Record thread owner of OpenGL context + mThreadOwner = Thread.currentThread().getName(); + } + + /** + * Gets the OpenGL ES version string. + * + * @return the OpenGL ES version string. + */ + public String getVersion() + { + return mGL.glGetString(GL10.GL_VERSION); + } + + /** + * Gets the OpenGL ES vendor string. + * + * @return the OpenGL ES vendor string. + */ + public String getVendor() + { + return mGL.glGetString(GL10.GL_VENDOR); + } + + /** + * Gets the name of the OpenGL ES renderer. + * + * @return the name of the OpenGL ES renderer. + */ + public String getRenderer() + { + return mGL.glGetString(GL10.GL_RENDERER); + } + + /** + * Gets the extension that the device supports + * + * @return String containing the extensions + */ + public String getExtensions() + { + return mGL.glGetString(GL10.GL_EXTENSIONS); + } + + private EGLConfig chooseConfig() + { + int[] attribList = new int[] { + EGL10.EGL_DEPTH_SIZE, 0, + EGL10.EGL_STENCIL_SIZE, 0, + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_NONE + }; + + // No error checking performed, minimum required code to elucidate logic + // Expand on this logic to be more selective in choosing a configuration + int[] numConfig = new int[1]; + mEGL.eglChooseConfig(mEGLDisplay, attribList, null, 0, numConfig); + int configSize = numConfig[0]; + mEGLConfigs = new EGLConfig[configSize]; + mEGL.eglChooseConfig(mEGLDisplay, attribList, mEGLConfigs, configSize, numConfig); + + return mEGLConfigs[0]; // Best match is probably the first configuration + } + } + + /** + * Checks if this device supports OpenGL ES 3. + * + * @return true if this device supports OpenGL ES 3; false otherwise. + */ + public static boolean SupportsGLES3() + { + VersionCheck mbuffer = new VersionCheck(); + m_GLVersion = mbuffer.getVersion(); + m_GLVendor = mbuffer.getVendor(); + m_GLRenderer = mbuffer.getRenderer(); + m_GLExtensions = mbuffer.getExtensions(); + + boolean mSupportsGLES3 = false; + + // Check for OpenGL ES 3 support (General case). + if (m_GLVersion != null && m_GLVersion.contains("OpenGL ES 3.0")) + mSupportsGLES3 = true; + + // Checking for OpenGL ES 3 support for certain Qualcomm devices. + if (!mSupportsGLES3 && m_GLVendor != null && m_GLVendor.equals("Qualcomm")) + { + if (m_GLRenderer.contains("Adreno (TM) 3")) + { + int mVStart = m_GLVersion.indexOf("V@") + 2; + int mVEnd = 0; + float mVersion; + + for (int a = mVStart; a < m_GLVersion.length(); ++a) + { + if (m_GLVersion.charAt(a) == ' ') + { + mVEnd = a; + break; + } + } + + mVersion = Float.parseFloat(m_GLVersion.substring(mVStart, mVEnd)); + + if (mVersion >= 14.0f) + mSupportsGLES3 = true; + } + } + if (!mSupportsGLES3 && + m_GLVendor != null && m_GLVendor.equals("NVIDIA Corporation") && + m_GLRenderer != null && m_GLRenderer.equals("NVIDIA Tegra") && + m_GLExtensions != null && m_GLExtensions.contains("GL_OES_depth24")) + { + // Is a Tegra 4 since it supports 24bit depth + mSupportsGLES3 = true; + } + if (!mSupportsGLES3 && + m_GLVendor == null && + m_GLRenderer == null && + m_GLExtensions == null) + { + // Couldn't get information. Give them the benefit of the doubt + mSupportsGLES3 = true; + } + return mSupportsGLES3; + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.video_prefs); + + // + // Setting valid video backends. + // + final ListPreference videoBackends = (ListPreference) findPreference("gpuPref"); + final boolean deviceSupportsGLES3 = SupportsGLES3(); + + if (deviceSupportsGLES3) + { + videoBackends.setEntries(R.array.videoBackendEntriesGLES3); + videoBackends.setEntryValues(R.array.videoBackendValuesGLES3); + } + else + { + videoBackends.setEntries(R.array.videoBackendEntriesNoGLES3); + videoBackends.setEntryValues(R.array.videoBackendValuesNoGLES3); + } + + // + // Disable all options if Software Rendering is used. + // + // Note that the numeric value in 'getPreference()' + // denotes the placement on the UI. So if more elements are + // added to the video settings, these may need to change. + // + final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(m_activity); + final PreferenceScreen mainScreen = getPreferenceScreen(); + + if (videoBackends.getValue().equals("Software Renderer")) + { + mainScreen.getPreference(0).setEnabled(false); + mainScreen.getPreference(1).setEnabled(false); + mainScreen.getPreference(3).setEnabled(false); + //mainScreen.getPreference(4).setEnabled(true); + } + else if (videoBackends.getValue().equals("OGL")) + { + mainScreen.getPreference(0).setEnabled(true); + mainScreen.getPreference(1).setEnabled(true); + mainScreen.getPreference(3).setEnabled(true); + //mainScreen.getPreference(4).setEnabled(false); + } + + // Also set a listener, so that if someone changes the video backend, it will disable + // the video settings, upon the user choosing "Software Rendering". + sPrefs.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener() + { + @Override + public void onSharedPreferenceChanged(SharedPreferences preference, String key) + { + if (key.equals("gpuPref")) + { + if (preference.getString(key, "Software Renderer").equals("Software Renderer")) + { + mainScreen.getPreference(0).setEnabled(false); + mainScreen.getPreference(1).setEnabled(false); + mainScreen.getPreference(3).setEnabled(false); + //mainScreen.getPreference(4).setEnabled(true); + } + else if (preference.getString(key, "Software Renderer").equals("OGL")) + { + mainScreen.getPreference(0).setEnabled(true); + mainScreen.getPreference(1).setEnabled(true); + mainScreen.getPreference(3).setEnabled(true); + //mainScreen.getPreference(4).setEnabled(false); + } + } + } + }); + } + + @Override + public void onAttach(Activity activity) + { + super.onAttach(activity); + + // Cache the activity instance. + m_activity = activity; + } +} -- cgit v1.2.3