diff --git a/Source/Android/res/layout/slider_layout.xml b/Source/Android/res/layout/slider_layout.xml
new file mode 100644
index 0000000000..1448bf44ad
--- /dev/null
+++ b/Source/Android/res/layout/slider_layout.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/Android/res/values/arrays.xml b/Source/Android/res/values/arrays.xml
index 8e9ba5ede3..0c0a60d8d8 100644
--- a/Source/Android/res/values/arrays.xml
+++ b/Source/Android/res/values/arrays.xml
@@ -155,5 +155,18 @@
- 3
- 4
-
+
+
+
+ - Off
+ - Side-by-Side
+ - Top-and-Bottom
+ - Anaglyph
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+
diff --git a/Source/Android/res/values/strings.xml b/Source/Android/res/values/strings.xml
index 6c68328e8b..80e1b3f909 100644
--- a/Source/Android/res/values/strings.xml
+++ b/Source/Android/res/values/strings.xml
@@ -174,6 +174,16 @@
Force texture filtering even if the emulated game explicitly disabled it. Improves texture quality slightly but causes glitches in some games.
Disable Fog
Makes distant objects more visible by removing fog, thus increasing the overall detail. Disabling fog will break some games which rely on proper fog emulation.
+ Stereoscopy
+ Stereoscopy allows you to get a better feeling of depth if you have the necessary hardware.\nHeavily decreases emulation speed and sometimes causes issues
+ Stereoscopy Mode
+ Select the stereoscopic 3D mode.
+ Depthn
+ Control the distance between the virtual cameras.\nA higher value creates a stronger feeling of depth while a lower value is more comfortable.
+ Convergence
+ Control the distance of the convergence plane, this is the distance at which objects will appear to be in front of the screen.\nA higher value creates stronger out-of-screen effects while a lower value is more comfortable.
+ Swap Eyes
+ Swap the left and right eye, mostly useful if you want to view side-by-side cross-eyed.
Hacks
Embedded Frame Buffer
diff --git a/Source/Android/res/xml/video_prefs.xml b/Source/Android/res/xml/video_prefs.xml
index b52dc7dcf6..9ace18dd4e 100644
--- a/Source/Android/res/xml/video_prefs.xml
+++ b/Source/Android/res/xml/video_prefs.xml
@@ -57,6 +57,38 @@
android:summary="@string/disable_fog_descrip"
android:title="@string/disable_fog"/>
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/UserPreferences.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/UserPreferences.java
index d2ae56b40f..710ebca7ee 100644
--- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/UserPreferences.java
+++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/UserPreferences.java
@@ -57,6 +57,10 @@ public final class UserPreferences
editor.putBoolean("disableFog", getConfig("gfx_opengl.ini", "Settings", "DisableFog", "False").equals("True"));
editor.putBoolean("skipEFBAccess", getConfig("gfx_opengl.ini", "Hacks", "EFBAccessEnable", "False").equals("True"));
editor.putBoolean("ignoreFormatChanges", getConfig("gfx_opengl.ini", "Hacks", "EFBEmulateFormatChanges", "False").equals("False"));
+ editor.putString("stereoscopyMode", getConfig("gfx_opengl.ini", "Enhancements", "StereoMode", "0"));
+ editor.putBoolean("stereoSwapEyes", getConfig("gfx_opengl.ini", "Enhancements", "StereoSwapEyes", "False").equals("True"));
+ editor.putString("stereoDepth", getConfig("gfx_opengl.ini", "Enhancements", "StereoDepth", "20"));
+ editor.putString("stereoConvergence", getConfig("gfx_opengl.ini", "Enhancements", "StereoConvergence", "20"));
String efbCopyOn = getConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
String efbToTexture = getConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "True");
@@ -182,6 +186,17 @@ public final class UserPreferences
// Whether or not fog is disabled.
boolean fogIsDisabled = prefs.getBoolean("disableFog", false);
+ // Stereoscopy setting
+ String stereoscopyMode = prefs.getString("stereoscopyMode", "0");
+
+ // Stereoscopy swap eyes
+ boolean stereoscopyEyeSwap = prefs.getBoolean("stereoSwapEyes", false);
+
+ // Stereoscopy separation
+ String stereoscopySeparation = prefs.getString("stereoDepth", "20");
+
+ // Stereoscopy convergence
+ String stereoscopyConvergence = prefs.getString("stereoConvergence", "20");
// CPU related Settings
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUCore", currentEmuCore);
@@ -251,5 +266,9 @@ public final class UserPreferences
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "EnablePixelLighting", usingPerPixelLighting ? "True" : "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "ForceFiltering", isForcingTextureFiltering ? "True" : "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "DisableFog", fogIsDisabled ? "True" : "False");
+ NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoMode", stereoscopyMode);
+ NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoSwapEyes", stereoscopyEyeSwap ? "True" : "False");
+ NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoDepth", stereoscopySeparation);
+ NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "StereoConvergence", stereoscopyConvergence);
}
}
diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java b/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java
index e5444e8c3b..214612f895 100644
--- a/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java
+++ b/Source/Android/src/org/dolphinemu/dolphinemu/settings/video/VideoSettingsFragment.java
@@ -121,6 +121,15 @@ public final class VideoSettingsFragment extends PreferenceFragment
mainScreen.getPreference(0).setEnabled(true);
mainScreen.getPreference(1).setEnabled(true);
mainScreen.getPreference(3).setEnabled(true);
+
+ // Check if we support stereo
+ // If we support desktop GL then we must support at least OpenGL 3.2
+ // If we only support OpenGLES then we need both OpenGLES 3.1 and AEP
+ if ((eglHelper.supportsOpenGL() && eglHelper.GetVersion() >= 320) ||
+ (eglHelper.supportsGLES3() && eglHelper.GetVersion() >= 310 && eglHelper.SupportsExtension("GL_ANDROID_extension_pack_es31a")))
+ mainScreen.findPreference("StereoscopyScreen").setEnabled(true);
+ else
+ mainScreen.findPreference("StereoscopyScreen").setEnabled(false);
}
// Also set a listener, so that if someone changes the video backend, it will disable
diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java b/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java
index c908a7631f..4eef5f6a3d 100644
--- a/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java
+++ b/Source/Android/src/org/dolphinemu/dolphinemu/utils/EGLHelper.java
@@ -354,6 +354,29 @@ public final class EGLHelper
return GLES30.glGetStringi(glEnum, index);
}
+ public boolean SupportsExtension(String extension)
+ {
+ int[] num_ext = new int[1];
+ GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0);
+
+ for (int i = 0; i < num_ext[0]; ++i)
+ {
+ String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i);
+ if (ext.equals(extension))
+ return true;
+ }
+ return false;
+ }
+
+ public int GetVersion()
+ {
+ int[] major = new int[1];
+ int[] minor = new int[1];
+ GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0);
+ GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, minor, 0);
+ return major[0] * 100 + minor[0] * 10;
+ }
+
/**
* Simplified call to {@link GL10#glGetIntegerv(int, int[], int)
*
diff --git a/Source/Android/src/org/dolphinemu/dolphinemu/utils/SliderPreference.java b/Source/Android/src/org/dolphinemu/dolphinemu/utils/SliderPreference.java
new file mode 100644
index 0000000000..b5b394ed83
--- /dev/null
+++ b/Source/Android/src/org/dolphinemu/dolphinemu/utils/SliderPreference.java
@@ -0,0 +1,97 @@
+package org.dolphinemu.dolphinemu.utils;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.preference.DialogPreference;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import org.dolphinemu.dolphinemu.R;
+
+public class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener, View.OnClickListener
+{
+ private static final String androidns = "http://schemas.android.com/apk/res/android";
+
+ private Context m_context;
+
+ // SeekBar
+ private int m_max, m_value;
+ private SeekBar m_seekbar;
+
+ // TextView
+ private TextView m_textview;
+
+ public SliderPreference(Context context, AttributeSet attrs)
+ {
+ super(context,attrs);
+ m_context = context;
+
+ // Seekbar values
+ m_value = attrs.getAttributeIntValue(androidns, "defaultValue", 0);
+ m_max = attrs.getAttributeIntValue(androidns, "max", 100);
+ }
+
+ @Override
+ protected View onCreateDialogView()
+ {
+ LayoutInflater inflater = LayoutInflater.from(m_context);
+ LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.slider_layout, null, false);
+
+ m_seekbar = (SeekBar)layout.getChildAt(0);
+ m_textview = (TextView)layout.getChildAt(1);
+
+ if (shouldPersist())
+ m_value = Integer.valueOf(getPersistedString(Integer.toString(m_value)));
+
+ m_seekbar.setMax(m_max);
+ m_seekbar.setProgress(m_value);
+ setProgressText(m_value);
+ m_seekbar.setOnSeekBarChangeListener(this);
+
+ return layout;
+ }
+
+ // SeekBar overrides
+ @Override
+ public void onProgressChanged(SeekBar seek, int value, boolean fromTouch)
+ {
+ m_value = value;
+ setProgressText(value);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seek) {}
+ @Override
+ public void onStopTrackingTouch(SeekBar seek) {}
+
+ void setProgressText(int value)
+ {
+ m_textview.setText(String.valueOf(value));
+ }
+
+ @Override
+ public void showDialog(Bundle state) {
+
+ super.showDialog(state);
+
+ Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE);
+ positiveButton.setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (shouldPersist())
+ {
+ persistString(Integer.toString(m_seekbar.getProgress()));
+ callChangeListener(m_seekbar.getProgress());
+ }
+ ((AlertDialog) getDialog()).dismiss();
+ }
+}