mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-26 21:10:42 +00:00
ui: Make aspect ratio config independent, add autodetect
This commit is contained in:
parent
129c48dd6e
commit
0ee7502c23
@ -138,8 +138,12 @@ display:
|
|||||||
default: true
|
default: true
|
||||||
fit:
|
fit:
|
||||||
type: enum
|
type: enum
|
||||||
values: [center, scale, scale_16_9, scale_4_3, stretch]
|
values: [center, scale, stretch]
|
||||||
default: scale
|
default: scale
|
||||||
|
aspect_ratio:
|
||||||
|
type: enum
|
||||||
|
values: [native, auto, 4x3, 16x9]
|
||||||
|
default: auto
|
||||||
scale:
|
scale:
|
||||||
type: integer
|
type: integer
|
||||||
default: 1
|
default: 1
|
||||||
|
2
dtc
2
dtc
@ -1 +1 @@
|
|||||||
Subproject commit 85e5d839847af54efab170f2b1331b2a6421e647
|
Subproject commit b6910bec11614980a21e46fbccc35934b671bd81
|
@ -30,6 +30,7 @@
|
|||||||
#include "hw/xbox/xbox_pci.h"
|
#include "hw/xbox/xbox_pci.h"
|
||||||
#include "hw/xbox/acpi_xbox.h"
|
#include "hw/xbox/acpi_xbox.h"
|
||||||
#include "migration/vmstate.h"
|
#include "migration/vmstate.h"
|
||||||
|
#include "ui/xemu-widescreen.h"
|
||||||
|
|
||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -44,6 +45,8 @@
|
|||||||
#define XBOX_PM_GPIO_BASE 0xC0
|
#define XBOX_PM_GPIO_BASE 0xC0
|
||||||
#define XBOX_PM_GPIO_LEN 26
|
#define XBOX_PM_GPIO_LEN 26
|
||||||
|
|
||||||
|
#define XBOX_PM_GPIO_ASPECT_RATIO 0x16
|
||||||
|
|
||||||
static int field_pin;
|
static int field_pin;
|
||||||
|
|
||||||
static uint64_t xbox_pm_gpio_read(void *opaque, hwaddr addr, unsigned width)
|
static uint64_t xbox_pm_gpio_read(void *opaque, hwaddr addr, unsigned width)
|
||||||
@ -66,6 +69,12 @@ static void xbox_pm_gpio_write(void *opaque, hwaddr addr, uint64_t val,
|
|||||||
unsigned width)
|
unsigned width)
|
||||||
{
|
{
|
||||||
XBOX_DPRINTF("pm gpio write [0x%llx] = 0x%llx\n", addr, val);
|
XBOX_DPRINTF("pm gpio write [0x%llx] = 0x%llx\n", addr, val);
|
||||||
|
|
||||||
|
if (addr == XBOX_PM_GPIO_ASPECT_RATIO) {
|
||||||
|
xemu_set_widescreen(val == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Add GPIO to VM state
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps xbox_pm_gpio_ops = {
|
static const MemoryRegionOps xbox_pm_gpio_ops = {
|
||||||
|
2
meson
2
meson
@ -1 +1 @@
|
|||||||
Subproject commit 776acd2a805c9b42b4f0375150977df42130317f
|
Subproject commit 3a9b285a55b91b53b2acda987192274352ecb5be
|
@ -28,6 +28,7 @@ xemu_ss.add(files(
|
|||||||
'xemu-data.c',
|
'xemu-data.c',
|
||||||
'xemu-snapshots.c',
|
'xemu-snapshots.c',
|
||||||
'xemu-thumbnail.cc',
|
'xemu-thumbnail.cc',
|
||||||
|
'xemu-widescreen.c',
|
||||||
))
|
))
|
||||||
|
|
||||||
subdir('xui')
|
subdir('xui')
|
||||||
|
37
ui/xemu-widescreen.c
Normal file
37
ui/xemu-widescreen.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* xemu wide screen handler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Matt Borgerson
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xemu-widescreen.h"
|
||||||
|
|
||||||
|
static bool g_widescreen = false;
|
||||||
|
|
||||||
|
void xemu_set_widescreen(bool widescreen)
|
||||||
|
{
|
||||||
|
g_widescreen = widescreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xemu_get_widescreen(void)
|
||||||
|
{
|
||||||
|
return g_widescreen;
|
||||||
|
}
|
40
ui/xemu-widescreen.h
Normal file
40
ui/xemu-widescreen.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* xemu wide screen handler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Matt Borgerson
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef XEMU_WIDESCREEN
|
||||||
|
#define XEMU_WIDESCREEN
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void xemu_set_widescreen(bool widescreen);
|
||||||
|
bool xemu_get_widescreen(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -28,6 +28,7 @@
|
|||||||
#include "ui/shader/xemu-logo-frag.h"
|
#include "ui/shader/xemu-logo-frag.h"
|
||||||
#include "data/xemu_64x64.png.h"
|
#include "data/xemu_64x64.png.h"
|
||||||
#include "notifications.hh"
|
#include "notifications.hh"
|
||||||
|
#include "ui/xemu-widescreen.h"
|
||||||
|
|
||||||
Fbo *controller_fbo,
|
Fbo *controller_fbo,
|
||||||
*logo_fbo;
|
*logo_fbo;
|
||||||
@ -706,6 +707,21 @@ void RenderFramebuffer(GLint tex, int width, int height, bool flip, float scale[
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GetDisplayAspectRatio(int width, int height)
|
||||||
|
{
|
||||||
|
switch (g_config.display.ui.aspect_ratio) {
|
||||||
|
case CONFIG_DISPLAY_UI_ASPECT_RATIO_NATIVE:
|
||||||
|
return (float)width/(float)height;
|
||||||
|
case CONFIG_DISPLAY_UI_ASPECT_RATIO_16X9:
|
||||||
|
return 16.0f/9.0f;
|
||||||
|
case CONFIG_DISPLAY_UI_ASPECT_RATIO_4X3:
|
||||||
|
return 4.0f/3.0f;
|
||||||
|
case CONFIG_DISPLAY_UI_ASPECT_RATIO_AUTO:
|
||||||
|
default:
|
||||||
|
return xemu_get_widescreen() ? 16.0f/9.0f : 4.0f/3.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RenderFramebuffer(GLint tex, int width, int height, bool flip)
|
void RenderFramebuffer(GLint tex, int width, int height, bool flip)
|
||||||
{
|
{
|
||||||
int tw, th;
|
int tw, th;
|
||||||
@ -723,20 +739,11 @@ void RenderFramebuffer(GLint tex, int width, int height, bool flip)
|
|||||||
scale[1] = 1.0;
|
scale[1] = 1.0;
|
||||||
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_CENTER) {
|
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_CENTER) {
|
||||||
// Centered
|
// Centered
|
||||||
scale[0] = (float)tw/(float)width;
|
float t_ratio = GetDisplayAspectRatio(tw, th);
|
||||||
|
scale[0] = t_ratio*(float)th/(float)width;
|
||||||
scale[1] = (float)th/(float)height;
|
scale[1] = (float)th/(float)height;
|
||||||
} else {
|
} else {
|
||||||
float t_ratio;
|
float t_ratio = GetDisplayAspectRatio(tw, th);
|
||||||
if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_16_9) {
|
|
||||||
// Scale to fit window using a fixed 16:9 aspect ratio
|
|
||||||
t_ratio = 16.0f/9.0f;
|
|
||||||
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_4_3) {
|
|
||||||
t_ratio = 4.0f/3.0f;
|
|
||||||
} else {
|
|
||||||
// Scale to fit, preserving framebuffer aspect ratio
|
|
||||||
t_ratio = (float)tw/(float)th;
|
|
||||||
}
|
|
||||||
|
|
||||||
float w_ratio = (float)width/(float)height;
|
float w_ratio = (float)width/(float)height;
|
||||||
if (w_ratio >= t_ratio) {
|
if (w_ratio >= t_ratio) {
|
||||||
scale[0] = t_ratio/w_ratio;
|
scale[0] = t_ratio/w_ratio;
|
||||||
@ -759,11 +766,7 @@ bool RenderFramebufferToPng(GLuint tex, bool flip, std::vector<uint8_t> &png, in
|
|||||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
|
||||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
|
||||||
|
|
||||||
if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_16_9) {
|
width = height * GetDisplayAspectRatio(width, height);
|
||||||
width = height * (16.0f / 9.0f);
|
|
||||||
} else if (g_config.display.ui.fit == CONFIG_DISPLAY_UI_FIT_SCALE_4_3) {
|
|
||||||
width = height * (4.0f / 3.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!max_width) max_width = width;
|
if (!max_width) max_width = width;
|
||||||
if (!max_height) max_height = height;
|
if (!max_height) max_height = height;
|
||||||
|
@ -340,10 +340,14 @@ void MainMenuDisplayView::Draw()
|
|||||||
ChevronCombo("Display mode", &g_config.display.ui.fit,
|
ChevronCombo("Display mode", &g_config.display.ui.fit,
|
||||||
"Center\0"
|
"Center\0"
|
||||||
"Scale\0"
|
"Scale\0"
|
||||||
"Scale (Widescreen 16:9)\0"
|
|
||||||
"Scale (4:3)\0"
|
|
||||||
"Stretch\0",
|
"Stretch\0",
|
||||||
"Select how the framebuffer should fit or scale into the window");
|
"Select how the framebuffer should fit or scale into the window");
|
||||||
|
ChevronCombo("Aspect ratio", &g_config.display.ui.aspect_ratio,
|
||||||
|
"Native\0"
|
||||||
|
"Auto (Default)\0"
|
||||||
|
"4:3\0"
|
||||||
|
"16:9\0",
|
||||||
|
"Select the displayed aspect ratio");
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenuAudioView::Draw()
|
void MainMenuAudioView::Draw()
|
||||||
|
@ -191,11 +191,12 @@ void ShowMainMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Combo("Display Mode", &g_config.display.ui.fit,
|
ImGui::Combo("Display Mode", &g_config.display.ui.fit,
|
||||||
"Center\0Scale\0Scale (Widescreen 16:9)\0Scale "
|
"Center\0Scale\0Stretch\0");
|
||||||
"(4:3)\0Stretch\0");
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
HelpMarker("Controls how the rendered content should be scaled "
|
HelpMarker("Controls how the rendered content should be scaled "
|
||||||
"into the window");
|
"into the window");
|
||||||
|
ImGui::Combo("Aspect Ratio", &g_config.display.ui.aspect_ratio,
|
||||||
|
"Native\0Auto\0""4:3\0""16:9\0");
|
||||||
if (ImGui::MenuItem("Fullscreen", SHORTCUT_MENU_TEXT(Alt + F),
|
if (ImGui::MenuItem("Fullscreen", SHORTCUT_MENU_TEXT(Alt + F),
|
||||||
xemu_is_fullscreen(), true)) {
|
xemu_is_fullscreen(), true)) {
|
||||||
xemu_toggle_fullscreen();
|
xemu_toggle_fullscreen();
|
||||||
|
@ -258,7 +258,7 @@ public:
|
|||||||
bool DrawItems(PopupMenuItemDelegate &nav) override
|
bool DrawItems(PopupMenuItemDelegate &nav) override
|
||||||
{
|
{
|
||||||
const char *values[] = {
|
const char *values[] = {
|
||||||
"Center", "Scale", "Scale (Widescreen 16:9)", "Scale (4:3)", "Stretch"
|
"Center", "Scale", "Stretch"
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < CONFIG_DISPLAY_UI_FIT__COUNT; i++) {
|
for (int i = 0; i < CONFIG_DISPLAY_UI_FIT__COUNT; i++) {
|
||||||
@ -272,11 +272,34 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AspectRatioPopupMenu : public virtual PopupMenu {
|
||||||
|
public:
|
||||||
|
bool DrawItems(PopupMenuItemDelegate &nav) override
|
||||||
|
{
|
||||||
|
const char *values[] = {
|
||||||
|
"Native",
|
||||||
|
"Auto (Default)",
|
||||||
|
"4:3",
|
||||||
|
"16:9"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < CONFIG_DISPLAY_UI_ASPECT_RATIO__COUNT; i++) {
|
||||||
|
bool selected = g_config.display.ui.aspect_ratio == i;
|
||||||
|
if (m_focus && selected) ImGui::SetKeyboardFocusHere();
|
||||||
|
if (PopupMenuCheck(values[i], "", selected))
|
||||||
|
g_config.display.ui.aspect_ratio = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
extern MainMenuScene g_main_menu;
|
extern MainMenuScene g_main_menu;
|
||||||
|
|
||||||
class SettingsPopupMenu : public virtual PopupMenu {
|
class SettingsPopupMenu : public virtual PopupMenu {
|
||||||
protected:
|
protected:
|
||||||
DisplayModePopupMenu display_mode;
|
DisplayModePopupMenu display_mode;
|
||||||
|
AspectRatioPopupMenu aspect_ratio;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool DrawItems(PopupMenuItemDelegate &nav) override
|
bool DrawItems(PopupMenuItemDelegate &nav) override
|
||||||
@ -295,6 +318,10 @@ public:
|
|||||||
nav.PushFocus();
|
nav.PushFocus();
|
||||||
nav.PushMenu(display_mode);
|
nav.PushMenu(display_mode);
|
||||||
}
|
}
|
||||||
|
if (PopupMenuSubmenuButton("Aspect Ratio", ICON_FA_EXPAND)) {
|
||||||
|
nav.PushFocus();
|
||||||
|
nav.PushMenu(aspect_ratio);
|
||||||
|
}
|
||||||
if (PopupMenuButton("Snapshots...", ICON_FA_CLOCK_ROTATE_LEFT)) {
|
if (PopupMenuButton("Snapshots...", ICON_FA_CLOCK_ROTATE_LEFT)) {
|
||||||
nav.ClearMenuStack();
|
nav.ClearMenuStack();
|
||||||
g_scene_mgr.PushScene(g_main_menu);
|
g_scene_mgr.PushScene(g_main_menu);
|
||||||
|
Loading…
Reference in New Issue
Block a user