Add Cardboard VR

Based on hrydgard/ppsspp/pull/12449
This commit is contained in:
SutandoTsukai181 2020-06-10 13:44:21 +03:00 committed by xperia64
parent bc3a4855e4
commit fb079a27bd
13 changed files with 221 additions and 14 deletions

View File

@ -358,6 +358,11 @@ public final class SettingsFragmentPresenter {
Setting render3dMode = rendererSection.getSetting(SettingsFile.KEY_RENDER_3D);
Setting factor3d = rendererSection.getSetting(SettingsFile.KEY_FACTOR_3D);
SettingSection layoutSection = mSettings.getSection(Settings.SECTION_LAYOUT);
Setting cardboardScreenSize = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE);
Setting cardboardXShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT);
Setting cardboardYShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT);
sl.add(new HeaderSetting(null, null, R.string.renderer, 0));
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor));
sl.add(new CheckBoxSetting(SettingsFile.KEY_FILTER_MODE, Settings.SECTION_RENDERER, R.string.linear_filtering, R.string.linear_filtering_description, true, filterMode));
@ -367,6 +372,11 @@ public final class SettingsFragmentPresenter {
sl.add(new HeaderSetting(null, null, R.string.stereoscopy, 0));
sl.add(new SingleChoiceSetting(SettingsFile.KEY_RENDER_3D, Settings.SECTION_RENDERER, R.string.render3d, 0, R.array.render3dModes, R.array.render3dValues, 0, render3dMode));
sl.add(new SliderSetting(SettingsFile.KEY_FACTOR_3D, Settings.SECTION_RENDERER, R.string.factor3d, R.string.factor3d_description, 0, 100, "%", 0, factor3d));
sl.add(new HeaderSetting(null, null, R.string.cardboard_vr, 0));
sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE, Settings.SECTION_LAYOUT, R.string.cardboard_screen_size, R.string.cardboard_screen_size_description, 30, 100, "%", 85, cardboardScreenSize));
sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_x_shift, R.string.cardboard_x_shift_description, -100, 100, "%", 0, cardboardXShift));
sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_y_shift, R.string.cardboard_y_shift_description, -100, 100, "%", 0, cardboardYShift));
}
private void addAudioSettings(ArrayList<SettingsItem> sl) {

View File

@ -59,6 +59,9 @@ public final class SettingsFile {
public static final String KEY_LAYOUT_OPTION = "layout_option";
public static final String KEY_SWAP_SCREEN = "swap_screen";
public static final String KEY_CARDBOARD_SCREEN_SIZE = "cardboard_screen_size";
public static final String KEY_CARDBOARD_X_SHIFT = "cardboard_x_shift";
public static final String KEY_CARDBOARD_Y_SHIFT = "cardboard_y_shift";
public static final String KEY_AUDIO_OUTPUT_ENGINE = "output_engine";
public static final String KEY_ENABLE_AUDIO_STRETCHING = "enable_audio_stretching";

View File

@ -138,7 +138,7 @@ void Config::ReadValues() {
else if (Settings::values.render_3d == Settings::StereoRenderOption::Interlaced)
default_shader = "horizontal (builtin)";
Settings::values.pp_shader_name =
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
sdl2_config->GetString("Renderer", "pp_shader_name", default_shader);
Settings::values.filter_mode = sdl2_config->GetBoolean("Renderer", "filter_mode", true);
Settings::values.bg_red = static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0));
@ -166,6 +166,12 @@ void Config::ReadValues() {
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_right", 360));
Settings::values.custom_bottom_bottom =
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_bottom_bottom", 480));
Settings::values.cardboard_screen_size =
static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_screen_size", 85));
Settings::values.cardboard_x_shift =
static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_x_shift", 0));
Settings::values.cardboard_y_shift =
static_cast<int>(sdl2_config->GetInteger("Layout", "cardboard_y_shift", 0));
// Audio
Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false);

View File

@ -140,7 +140,7 @@ bg_blue =
bg_green =
# Whether and how Stereoscopic 3D should be rendered
# 0 (default): Off, 1: Side by Side, 2: Anaglyph, 3: Interlaced
# 0 (default): Off, 1: Side by Side, 2: Anaglyph, 3: Interlaced, 4: Reverse Interlaced, 5: Cardboard VR
render_3d =
# Change 3D Intensity
@ -182,6 +182,14 @@ custom_bottom_bottom =
# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent
swap_screen =
# Screen placement settings when using Cardboard VR (render3d = 4)
# 30 - 100: Screen size as a percentage of the viewport. 85 (default)
cardboard_screen_size =
# -100 - 100: Screen X-Coordinate shift as a percentage of empty space. 0 (default)
cardboard_x_shift =
# -100 - 100: Screen Y-Coordinate shift as a percentage of empty space. 0 (default)
cardboard_y_shift =
[Audio]
# Whether or not to enable DSP LLE
# 0 (default): No, 1: Yes

View File

@ -33,9 +33,9 @@ JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxis
JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val);
JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchEvent(JNIEnv* env,
jclass clazz, jfloat x,
jfloat y,
jboolean pressed);
jclass clazz,
jfloat x, jfloat y,
jboolean pressed);
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved(JNIEnv* env,
jclass clazz, jfloat x,
@ -142,7 +142,9 @@ JNIEXPORT jboolean Java_org_citra_citra_1emu_NativeLibrary_LoadAmiibo(JNIEnv* en
JNIEXPORT void Java_org_citra_citra_1emu_NativeLibrary_RemoveAmiibo(JNIEnv* env, jclass clazz);
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_InstallCIAS(JNIEnv* env, jclass clazz, jobjectArray path);
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_InstallCIAS(JNIEnv* env,
jclass clazz,
jobjectArray path);
#ifdef __cplusplus
}

View File

@ -159,6 +159,8 @@
<item>Side by Side</item>
<item>Anaglyph</item>
<item>Interlaced</item>
<item>Reverse Interlaced</item>
<item>Cardboard VR</item>
</string-array>
<integer-array name="render3dValues">
@ -166,5 +168,7 @@
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
</integer-array>
</resources>

View File

@ -93,6 +93,13 @@
<string name="render3d">Stereoscopic 3D Mode</string>
<string name="factor3d">Depth</string>
<string name="factor3d_description">Specifies the value of the 3D slider. This should be set to higher than 0% when Stereoscopic 3D is enabled.</string>
<string name="cardboard_vr">Cardboard VR</string>
<string name="cardboard_screen_size">Cardboard Screen size</string>
<string name="cardboard_screen_size_description">Scales the screen to a percentage of its original size.</string>
<string name="cardboard_x_shift">Horizontal shift</string>
<string name="cardboard_x_shift_description">Specifies the percentage of empty space to shift the screens horizontally. Positive values move the two eyes closer to the middle, while negative values move them away.</string>
<string name="cardboard_y_shift">Vertical shift</string>
<string name="cardboard_y_shift_description">Specifies the percentage of empty space to shift the screens vertically. Positive values move the two eyes towards the bottom, while negative values move them towards the top.</string>
<!-- Premium strings -->
<string name="premium_text">Premium</string>

View File

@ -73,6 +73,14 @@ static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigne
framebuffer_x < layout.bottom_screen.right / 2) ||
(framebuffer_x >= (layout.bottom_screen.left / 2) + (layout.width / 2) &&
framebuffer_x < (layout.bottom_screen.right / 2) + (layout.width / 2))));
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
return (framebuffer_y >= layout.bottom_screen.top &&
framebuffer_y < layout.bottom_screen.bottom &&
((framebuffer_x >= layout.bottom_screen.left &&
framebuffer_x < layout.bottom_screen.right) ||
(framebuffer_x >= layout.cardboard.bottom_screen_right_eye + (layout.width / 2) &&
framebuffer_x < layout.cardboard.bottom_screen_right_eye +
layout.bottom_screen.GetWidth() + (layout.width / 2))));
} else {
return (framebuffer_y >= layout.bottom_screen.top &&
framebuffer_y < layout.bottom_screen.bottom &&
@ -82,9 +90,14 @@ static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigne
}
std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) const {
if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
if (new_x >= framebuffer_layout.width / 2)
if (new_x >= framebuffer_layout.width / 2) {
if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide)
new_x -= framebuffer_layout.width / 2;
else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR)
new_x -=
(framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2);
}
if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
new_x = std::max(new_x, framebuffer_layout.bottom_screen.left / 2);
new_x = std::min(new_x, framebuffer_layout.bottom_screen.right / 2 - 1);
} else {
@ -102,9 +115,13 @@ bool EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
return false;
if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide &&
framebuffer_x >= framebuffer_layout.width / 2)
framebuffer_x -= framebuffer_layout.width / 2;
if (framebuffer_x >= framebuffer_layout.width / 2) {
if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide)
framebuffer_x -= framebuffer_layout.width / 2;
else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR)
framebuffer_x -=
(framebuffer_layout.width / 2) - (framebuffer_layout.cardboard.user_x_shift * 2);
}
std::lock_guard guard(touch_state->mutex);
if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
touch_state->touch_x =
@ -192,6 +209,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height,
}
UpdateMinimumWindowSize(min_size);
}
if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
layout = Layout::GetCardboardSettings(layout);
}
NotifyFramebufferLayoutChanged(layout);
}

View File

@ -452,9 +452,92 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
break;
}
}
if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
layout = Layout::GetCardboardSettings(layout);
}
return layout;
}
FramebufferLayout GetCardboardSettings(FramebufferLayout layout) {
FramebufferLayout newLayout = layout;
float top_screen_left = 0;
float top_screen_top = 0;
float bottom_screen_left = 0;
float bottom_screen_top = 0;
float cardboardScreenScale = Settings::values.cardboard_screen_size / 100.0f;
float top_screen_width = layout.top_screen.GetWidth() / 2.0f * cardboardScreenScale;
float top_screen_height = layout.top_screen.GetHeight() / 2.0f * cardboardScreenScale;
float bottom_screen_width = layout.bottom_screen.GetWidth() / 2.0f * cardboardScreenScale;
float bottom_screen_height = layout.bottom_screen.GetHeight() / 2.0f * cardboardScreenScale;
bool is_swapped = Settings::values.swap_screen;
bool is_portrait = layout.height > layout.width;
float cardboardScreenWidth;
float cardboardScreenHeight;
switch (Settings::values.layout_option) {
case Settings::LayoutOption::MobileLandscape:
case Settings::LayoutOption::SideScreen:
// If orientation is portrait, only use MobilePortrait
if (!is_portrait) {
cardboardScreenWidth = top_screen_width + bottom_screen_width;
cardboardScreenHeight = is_swapped ? bottom_screen_height : top_screen_height;
if (is_swapped)
top_screen_left += bottom_screen_width;
else
bottom_screen_left += top_screen_width;
break;
} else {
[[fallthrough]];
}
case Settings::LayoutOption::SingleScreen:
default:
if (!is_portrait) {
// Default values when using LayoutOption::SingleScreen
cardboardScreenWidth = is_swapped ? bottom_screen_width : top_screen_width;
cardboardScreenHeight = is_swapped ? bottom_screen_height : top_screen_height;
break;
} else {
[[fallthrough]];
}
case Settings::LayoutOption::MobilePortrait:
cardboardScreenWidth = top_screen_width;
cardboardScreenHeight = top_screen_height + bottom_screen_height;
bottom_screen_left += (top_screen_width - bottom_screen_width) / 2.0f;
if (is_swapped)
top_screen_top += bottom_screen_height;
else
bottom_screen_top += top_screen_height;
break;
}
float cardboardMaxXShift = (layout.width / 2.0f - cardboardScreenWidth) / 2.0f;
float cardboardUserXShift = (Settings::values.cardboard_x_shift / 100.0f) * cardboardMaxXShift;
float cardboardMaxYShift = ((float)layout.height - cardboardScreenHeight) / 2.0f;
float cardboardUserYShift = (Settings::values.cardboard_y_shift / 100.0f) * cardboardMaxYShift;
// Center the screens and apply user Y shift
newLayout.top_screen.left = top_screen_left + cardboardMaxXShift;
newLayout.top_screen.top = top_screen_top + cardboardMaxYShift + cardboardUserYShift;
newLayout.bottom_screen.left = bottom_screen_left + cardboardMaxXShift;
newLayout.bottom_screen.top = bottom_screen_top + cardboardMaxYShift + cardboardUserYShift;
// Set the X coordinates for the right eye and apply user X shift
newLayout.cardboard.top_screen_right_eye = newLayout.top_screen.left - cardboardUserXShift;
newLayout.top_screen.left += cardboardUserXShift;
newLayout.cardboard.bottom_screen_right_eye =
newLayout.bottom_screen.left - cardboardUserXShift;
newLayout.bottom_screen.left += cardboardUserXShift;
newLayout.cardboard.user_x_shift = cardboardUserXShift;
// Update right/bottom instead of passing new variables for width/height
newLayout.top_screen.right = newLayout.top_screen.left + top_screen_width;
newLayout.top_screen.bottom = newLayout.top_screen.top + top_screen_height;
newLayout.bottom_screen.right = newLayout.bottom_screen.left + bottom_screen_width;
newLayout.bottom_screen.bottom = newLayout.bottom_screen.top + bottom_screen_height;
return newLayout;
}
std::pair<unsigned, unsigned> GetMinimumSizeFromLayout(Settings::LayoutOption layout,
bool upright_screen) {
unsigned min_width, min_height;

View File

@ -9,6 +9,13 @@
namespace Layout {
/// Describes the horizontal coordinates for the right eye screen when using Cardboard VR
struct CardboardSettings {
float top_screen_right_eye;
float bottom_screen_right_eye;
float user_x_shift;
};
/// Describes the layout of the window framebuffer (size and top/bottom screen positions)
struct FramebufferLayout {
u32 width;
@ -19,6 +26,8 @@ struct FramebufferLayout {
Common::Rectangle<u32> bottom_screen;
bool is_rotated = true;
CardboardSettings cardboard;
/**
* Returns the ration of pixel size of the top screen, compared to the native size of the 3DS
* screen.
@ -104,6 +113,13 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height);
*/
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale);
/**
* Convenience method for transforming a frame layout when using Cardboard VR
* @param layout frame layout to transform
* @return layout transformed with the user cardboard settings
*/
FramebufferLayout GetCardboardSettings(FramebufferLayout layout);
std::pair<unsigned, unsigned> GetMinimumSizeFromLayout(Settings::LayoutOption layout,
bool upright_screen);

View File

@ -40,7 +40,14 @@ enum class MicInputType {
Static,
};
enum class StereoRenderOption { Off, SideBySide, Anaglyph, Interlaced, ReverseInterlaced };
enum class StereoRenderOption {
Off,
SideBySide,
Anaglyph,
Interlaced,
ReverseInterlaced,
CardboardVR
};
enum class GpuTimingMode {
Skip,
@ -209,6 +216,10 @@ struct Values {
StereoRenderOption render_3d;
std::atomic<u8> factor_3d;
int cardboard_screen_size;
int cardboard_x_shift;
int cardboard_y_shift;
bool filter_mode;
std::string pp_shader_name;

View File

@ -355,6 +355,5 @@ public:
std::unique_ptr<TextureDownloaderES> texture_downloader_es;
};
void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width,
u32 height);
void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width, u32 height);
} // namespace OpenGL

View File

@ -971,6 +971,16 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
((float)top_screen.left / 2) + ((float)layout.width / 2),
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreenRotated(screen_infos[0], layout.top_screen.left,
layout.top_screen.top, layout.top_screen.GetWidth(),
layout.top_screen.GetHeight());
glUniform1i(uniform_layer, 1);
DrawSingleScreenRotated(screen_infos[1],
layout.cardboard.top_screen_right_eye +
((float)layout.width / 2),
layout.top_screen.top, layout.top_screen.GetWidth(),
layout.top_screen.GetHeight());
} else if (stereo_single_screen) {
DrawSingleScreenStereoRotated(
screen_infos[0], screen_infos[1], (float)top_screen.left, (float)top_screen.top,
@ -988,6 +998,14 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
((float)top_screen.left / 2) + ((float)layout.width / 2),
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
(float)top_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreen(screen_infos[0], layout.top_screen.left, layout.top_screen.top,
layout.top_screen.GetWidth(), layout.top_screen.GetHeight());
glUniform1i(uniform_layer, 1);
DrawSingleScreen(screen_infos[1],
layout.cardboard.top_screen_right_eye + ((float)layout.width / 2),
layout.top_screen.top, layout.top_screen.GetWidth(),
layout.top_screen.GetHeight());
} else if (stereo_single_screen) {
DrawSingleScreenStereo(screen_infos[0], screen_infos[1], (float)top_screen.left,
(float)top_screen.top, (float)top_screen.GetWidth(),
@ -1011,6 +1029,16 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
screen_infos[2], ((float)bottom_screen.left / 2) + ((float)layout.width / 2),
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreenRotated(screen_infos[2], layout.bottom_screen.left,
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight());
glUniform1i(uniform_layer, 1);
DrawSingleScreenRotated(screen_infos[2],
layout.cardboard.bottom_screen_right_eye +
((float)layout.width / 2),
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight());
} else if (stereo_single_screen) {
DrawSingleScreenStereoRotated(screen_infos[2], screen_infos[2],
(float)bottom_screen.left, (float)bottom_screen.top,
@ -1031,6 +1059,16 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
((float)bottom_screen.left / 2) + ((float)layout.width / 2),
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
(float)bottom_screen.GetHeight());
} else if (Settings::values.render_3d == Settings::StereoRenderOption::CardboardVR) {
DrawSingleScreen(screen_infos[2], layout.bottom_screen.left,
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight());
glUniform1i(uniform_layer, 1);
DrawSingleScreen(screen_infos[2],
layout.cardboard.bottom_screen_right_eye +
((float)layout.width / 2),
layout.bottom_screen.top, layout.bottom_screen.GetWidth(),
layout.bottom_screen.GetHeight());
} else if (stereo_single_screen) {
DrawSingleScreenStereo(screen_infos[2], screen_infos[2], (float)bottom_screen.left,
(float)bottom_screen.top, (float)bottom_screen.GetWidth(),