GameSettings: Add custom aspect ratios
This commit is contained in:
parent
17a4712a3e
commit
864e7f0c91
1
NEWS.md
1
NEWS.md
|
@ -1,3 +1,4 @@
|
||||||
|
- 2021/04/29: Custom aspect ratio support added.
|
||||||
- 2021/03/20: Memory card editor added to Android app.
|
- 2021/03/20: Memory card editor added to Android app.
|
||||||
- 2021/03/17: Add support for loading **homebrew** PBP images. PSN images are not loadable due to potential legal issues surrounding the encryption.
|
- 2021/03/17: Add support for loading **homebrew** PBP images. PSN images are not loadable due to potential legal issues surrounding the encryption.
|
||||||
- 2021/03/14: Multiple controllers, multitap, and external controller vibration added to Android app. You will need to rebind your controllers.
|
- 2021/03/14: Multiple controllers, multitap, and external controller vibration added to Android app. You will need to rebind your controllers.
|
||||||
|
|
|
@ -18,6 +18,7 @@ A "BIOS" ROM image is required to to start the emulator and to play games. You c
|
||||||
## Latest News
|
## Latest News
|
||||||
Older entries are available at https://github.com/stenzek/duckstation/blob/master/NEWS.md
|
Older entries are available at https://github.com/stenzek/duckstation/blob/master/NEWS.md
|
||||||
|
|
||||||
|
- 2021/04/29: Custom aspect ratio support added.
|
||||||
- 2021/03/20: Memory card editor added to Android app.
|
- 2021/03/20: Memory card editor added to Android app.
|
||||||
- 2021/03/17: Add support for loading **homebrew** PBP images. PSN images are not loadable due to potential legal issues surrounding the encryption.
|
- 2021/03/17: Add support for loading **homebrew** PBP images. PSN images are not loadable due to potential legal issues surrounding the encryption.
|
||||||
- 2021/03/14: Multiple controllers, multitap, and external controller vibration added to Android app. You will need to rebind your controllers.
|
- 2021/03/14: Multiple controllers, multitap, and external controller vibration added to Android app. You will need to rebind your controllers.
|
||||||
|
|
|
@ -368,11 +368,25 @@ void GamePropertiesDialog::populateGameSettings()
|
||||||
QSignalBlocker sb(m_ui.userCropMode);
|
QSignalBlocker sb(m_ui.userCropMode);
|
||||||
m_ui.userCropMode->setCurrentIndex(static_cast<int>(gs.display_crop_mode.value()) + 1);
|
m_ui.userCropMode->setCurrentIndex(static_cast<int>(gs.display_crop_mode.value()) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gs.display_aspect_ratio.has_value())
|
if (gs.display_aspect_ratio.has_value())
|
||||||
{
|
{
|
||||||
QSignalBlocker sb(m_ui.userAspectRatio);
|
QSignalBlocker sb(m_ui.userAspectRatio);
|
||||||
m_ui.userAspectRatio->setCurrentIndex(static_cast<int>(gs.display_aspect_ratio.value()) + 1);
|
m_ui.userAspectRatio->setCurrentIndex(static_cast<int>(gs.display_aspect_ratio.value()) + 1);
|
||||||
}
|
}
|
||||||
|
if (gs.display_aspect_ratio_custom_numerator.has_value())
|
||||||
|
{
|
||||||
|
QSignalBlocker sb(m_ui.userCustomAspectRatioNumerator);
|
||||||
|
m_ui.userCustomAspectRatioNumerator->setValue(static_cast<int>(gs.display_aspect_ratio_custom_numerator.value()));
|
||||||
|
}
|
||||||
|
if (gs.display_aspect_ratio_custom_denominator.has_value())
|
||||||
|
{
|
||||||
|
QSignalBlocker sb(m_ui.userCustomAspectRatioDenominator);
|
||||||
|
m_ui.userCustomAspectRatioDenominator->setValue(
|
||||||
|
static_cast<int>(gs.display_aspect_ratio_custom_denominator.value()));
|
||||||
|
}
|
||||||
|
onUserAspectRatioChanged();
|
||||||
|
|
||||||
if (gs.gpu_downsample_mode.has_value())
|
if (gs.gpu_downsample_mode.has_value())
|
||||||
{
|
{
|
||||||
QSignalBlocker sb(m_ui.userDownsampleMode);
|
QSignalBlocker sb(m_ui.userDownsampleMode);
|
||||||
|
@ -566,6 +580,21 @@ void GamePropertiesDialog::connectUi()
|
||||||
else
|
else
|
||||||
m_game_settings.display_aspect_ratio = static_cast<DisplayAspectRatio>(index - 1);
|
m_game_settings.display_aspect_ratio = static_cast<DisplayAspectRatio>(index - 1);
|
||||||
saveGameSettings();
|
saveGameSettings();
|
||||||
|
onUserAspectRatioChanged();
|
||||||
|
});
|
||||||
|
connect(m_ui.userCustomAspectRatioNumerator, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value) {
|
||||||
|
if (value <= 0)
|
||||||
|
m_game_settings.display_aspect_ratio_custom_numerator.reset();
|
||||||
|
else
|
||||||
|
m_game_settings.display_aspect_ratio_custom_numerator = static_cast<u16>(value);
|
||||||
|
saveGameSettings();
|
||||||
|
});
|
||||||
|
connect(m_ui.userCustomAspectRatioDenominator, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value) {
|
||||||
|
if (value <= 0)
|
||||||
|
m_game_settings.display_aspect_ratio_custom_denominator.reset();
|
||||||
|
else
|
||||||
|
m_game_settings.display_aspect_ratio_custom_denominator = static_cast<u16>(value);
|
||||||
|
saveGameSettings();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_ui.userCropMode, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
connect(m_ui.userCropMode, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
|
||||||
|
@ -795,6 +824,16 @@ void GamePropertiesDialog::updateCPUClockSpeedLabel()
|
||||||
m_ui.userCPUClockSpeedLabel->setText(tr("%1% (%2MHz)").arg(percent).arg(frequency / 1000000.0, 0, 'f', 2));
|
m_ui.userCPUClockSpeedLabel->setText(tr("%1% (%2MHz)").arg(percent).arg(frequency / 1000000.0, 0, 'f', 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GamePropertiesDialog::onUserAspectRatioChanged()
|
||||||
|
{
|
||||||
|
const int index = m_ui.userAspectRatio->currentIndex();
|
||||||
|
const bool is_custom = (index > 0 && static_cast<DisplayAspectRatio>(index - 1) == DisplayAspectRatio::Custom);
|
||||||
|
|
||||||
|
m_ui.userCustomAspectRatioNumerator->setVisible(is_custom);
|
||||||
|
m_ui.userCustomAspectRatioDenominator->setVisible(is_custom);
|
||||||
|
m_ui.userCustomAspectRatioSeparator->setVisible(is_custom);
|
||||||
|
}
|
||||||
|
|
||||||
void GamePropertiesDialog::fillEntryFromUi(GameListCompatibilityEntry* entry)
|
void GamePropertiesDialog::fillEntryFromUi(GameListCompatibilityEntry* entry)
|
||||||
{
|
{
|
||||||
entry->code = m_game_code;
|
entry->code = m_game_code;
|
||||||
|
|
|
@ -50,6 +50,7 @@ private:
|
||||||
void fillEntryFromUi(GameListCompatibilityEntry* entry);
|
void fillEntryFromUi(GameListCompatibilityEntry* entry);
|
||||||
void computeTrackHashes();
|
void computeTrackHashes();
|
||||||
void onResize();
|
void onResize();
|
||||||
|
void onUserAspectRatioChanged();
|
||||||
|
|
||||||
Ui::GamePropertiesDialog m_ui;
|
Ui::GamePropertiesDialog m_ui;
|
||||||
std::array<QCheckBox*, static_cast<u32>(GameSettings::Trait::Count)> m_trait_checkboxes{};
|
std::array<QCheckBox*, static_cast<u32>(GameSettings::Trait::Count)> m_trait_checkboxes{};
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>793</width>
|
<width>793</width>
|
||||||
<height>619</height>
|
<height>651</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -269,8 +269,39 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_8" stretch="1,0,0,0">
|
||||||
|
<item>
|
||||||
<widget class="QComboBox" name="userAspectRatio"/>
|
<widget class="QComboBox" name="userAspectRatio"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="userCustomAspectRatioNumerator">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>9999</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="userCustomAspectRatioSeparator">
|
||||||
|
<property name="text">
|
||||||
|
<string>:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="userCustomAspectRatioDenominator">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>9999</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_17">
|
<widget class="QLabel" name="label_17">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
|
@ -129,7 +129,7 @@ private:
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
|
GAME_LIST_CACHE_SIGNATURE = 0x45434C47,
|
||||||
GAME_LIST_CACHE_VERSION = 27
|
GAME_LIST_CACHE_VERSION = 28
|
||||||
};
|
};
|
||||||
|
|
||||||
using CacheMap = std::unordered_map<std::string, GameListEntry>;
|
using CacheMap = std::unordered_map<std::string, GameListEntry>;
|
||||||
|
|
|
@ -122,6 +122,8 @@ bool Entry::LoadFromStream(ByteStream* stream)
|
||||||
!ReadOptionalFromStream(stream, &display_linear_upscaling) ||
|
!ReadOptionalFromStream(stream, &display_linear_upscaling) ||
|
||||||
!ReadOptionalFromStream(stream, &display_integer_upscaling) ||
|
!ReadOptionalFromStream(stream, &display_integer_upscaling) ||
|
||||||
!ReadOptionalFromStream(stream, &display_force_4_3_for_24bit) ||
|
!ReadOptionalFromStream(stream, &display_force_4_3_for_24bit) ||
|
||||||
|
!ReadOptionalFromStream(stream, &display_aspect_ratio_custom_numerator) ||
|
||||||
|
!ReadOptionalFromStream(stream, &display_aspect_ratio_custom_denominator) ||
|
||||||
!ReadOptionalFromStream(stream, &gpu_resolution_scale) || !ReadOptionalFromStream(stream, &gpu_multisamples) ||
|
!ReadOptionalFromStream(stream, &gpu_resolution_scale) || !ReadOptionalFromStream(stream, &gpu_multisamples) ||
|
||||||
!ReadOptionalFromStream(stream, &gpu_per_sample_shading) || !ReadOptionalFromStream(stream, &gpu_true_color) ||
|
!ReadOptionalFromStream(stream, &gpu_per_sample_shading) || !ReadOptionalFromStream(stream, &gpu_true_color) ||
|
||||||
!ReadOptionalFromStream(stream, &gpu_scaled_dithering) ||
|
!ReadOptionalFromStream(stream, &gpu_scaled_dithering) ||
|
||||||
|
@ -173,6 +175,8 @@ bool Entry::SaveToStream(ByteStream* stream) const
|
||||||
WriteOptionalToStream(stream, display_linear_upscaling) &&
|
WriteOptionalToStream(stream, display_linear_upscaling) &&
|
||||||
WriteOptionalToStream(stream, display_integer_upscaling) &&
|
WriteOptionalToStream(stream, display_integer_upscaling) &&
|
||||||
WriteOptionalToStream(stream, display_force_4_3_for_24bit) &&
|
WriteOptionalToStream(stream, display_force_4_3_for_24bit) &&
|
||||||
|
WriteOptionalToStream(stream, display_aspect_ratio_custom_numerator) &&
|
||||||
|
WriteOptionalToStream(stream, display_aspect_ratio_custom_denominator) &&
|
||||||
WriteOptionalToStream(stream, gpu_resolution_scale) && WriteOptionalToStream(stream, gpu_multisamples) &&
|
WriteOptionalToStream(stream, gpu_resolution_scale) && WriteOptionalToStream(stream, gpu_multisamples) &&
|
||||||
WriteOptionalToStream(stream, gpu_per_sample_shading) && WriteOptionalToStream(stream, gpu_true_color) &&
|
WriteOptionalToStream(stream, gpu_per_sample_shading) && WriteOptionalToStream(stream, gpu_true_color) &&
|
||||||
WriteOptionalToStream(stream, gpu_scaled_dithering) && WriteOptionalToStream(stream, gpu_force_ntsc_timings) &&
|
WriteOptionalToStream(stream, gpu_scaled_dithering) && WriteOptionalToStream(stream, gpu_force_ntsc_timings) &&
|
||||||
|
@ -248,6 +252,18 @@ static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA
|
||||||
cvalue = ini.GetValue(section, "DisplayAspectRatio", nullptr);
|
cvalue = ini.GetValue(section, "DisplayAspectRatio", nullptr);
|
||||||
if (cvalue)
|
if (cvalue)
|
||||||
entry->display_aspect_ratio = Settings::ParseDisplayAspectRatio(cvalue);
|
entry->display_aspect_ratio = Settings::ParseDisplayAspectRatio(cvalue);
|
||||||
|
lvalue = ini.GetLongValue(section, "CustomAspectRatioNumerator", 0);
|
||||||
|
if (lvalue != 0)
|
||||||
|
{
|
||||||
|
entry->display_aspect_ratio_custom_numerator =
|
||||||
|
static_cast<u16>(std::clamp<long>(lvalue, 1, std::numeric_limits<u16>::max()));
|
||||||
|
}
|
||||||
|
lvalue = ini.GetLongValue(section, "CustomAspectRatioDenominator", 0);
|
||||||
|
if (lvalue != 0)
|
||||||
|
{
|
||||||
|
entry->display_aspect_ratio_custom_denominator =
|
||||||
|
static_cast<u16>(std::clamp<long>(lvalue, 1, std::numeric_limits<u16>::max()));
|
||||||
|
}
|
||||||
cvalue = ini.GetValue(section, "GPUDownsampleMode", nullptr);
|
cvalue = ini.GetValue(section, "GPUDownsampleMode", nullptr);
|
||||||
if (cvalue)
|
if (cvalue)
|
||||||
entry->gpu_downsample_mode = Settings::ParseDownsampleModeName(cvalue);
|
entry->gpu_downsample_mode = Settings::ParseDownsampleModeName(cvalue);
|
||||||
|
@ -371,6 +387,16 @@ static void StoreIniSection(const Entry& entry, const char* section, CSimpleIniA
|
||||||
ini.SetValue(section, "DisplayAspectRatio",
|
ini.SetValue(section, "DisplayAspectRatio",
|
||||||
Settings::GetDisplayAspectRatioName(entry.display_aspect_ratio.value()));
|
Settings::GetDisplayAspectRatioName(entry.display_aspect_ratio.value()));
|
||||||
}
|
}
|
||||||
|
if (entry.display_aspect_ratio_custom_numerator.has_value())
|
||||||
|
{
|
||||||
|
ini.SetLongValue(section, "CustomAspectRatioNumerator",
|
||||||
|
static_cast<long>(entry.display_aspect_ratio_custom_numerator.value()));
|
||||||
|
}
|
||||||
|
if (entry.display_aspect_ratio_custom_denominator.has_value())
|
||||||
|
{
|
||||||
|
ini.SetLongValue(section, "CustomAspectRatioDenominator",
|
||||||
|
static_cast<long>(entry.display_aspect_ratio_custom_denominator.value()));
|
||||||
|
}
|
||||||
if (entry.gpu_downsample_mode.has_value())
|
if (entry.gpu_downsample_mode.has_value())
|
||||||
{
|
{
|
||||||
ini.SetValue(section, "GPUDownsampleMode", Settings::GetDownsampleModeName(entry.gpu_downsample_mode.value()));
|
ini.SetValue(section, "GPUDownsampleMode", Settings::GetDownsampleModeName(entry.gpu_downsample_mode.value()));
|
||||||
|
@ -499,6 +525,20 @@ static std::optional<std::string> GetEntryValueForKey(const Entry& entry, const
|
||||||
else
|
else
|
||||||
return Settings::GetDisplayAspectRatioName(entry.display_aspect_ratio.value());
|
return Settings::GetDisplayAspectRatioName(entry.display_aspect_ratio.value());
|
||||||
}
|
}
|
||||||
|
else if (key == "CustomAspectRatioNumerator")
|
||||||
|
{
|
||||||
|
if (!entry.display_aspect_ratio_custom_numerator.has_value())
|
||||||
|
return std::nullopt;
|
||||||
|
else
|
||||||
|
return std::to_string(entry.display_aspect_ratio_custom_numerator.value());
|
||||||
|
}
|
||||||
|
else if (key == "CustomAspectRatioDenominator")
|
||||||
|
{
|
||||||
|
if (!entry.display_aspect_ratio_custom_denominator.has_value())
|
||||||
|
return std::nullopt;
|
||||||
|
else
|
||||||
|
return std::to_string(entry.display_aspect_ratio_custom_denominator.value());
|
||||||
|
}
|
||||||
else if (key == "GPUDownsampleMode")
|
else if (key == "GPUDownsampleMode")
|
||||||
{
|
{
|
||||||
if (!entry.gpu_downsample_mode.has_value())
|
if (!entry.gpu_downsample_mode.has_value())
|
||||||
|
@ -713,6 +753,20 @@ static void SetEntryValueForKey(Entry& entry, const std::string_view& key, const
|
||||||
else
|
else
|
||||||
entry.display_aspect_ratio = Settings::ParseDisplayAspectRatio(value->c_str());
|
entry.display_aspect_ratio = Settings::ParseDisplayAspectRatio(value->c_str());
|
||||||
}
|
}
|
||||||
|
else if (key == "CustomAspectRatioNumerator")
|
||||||
|
{
|
||||||
|
if (!value.has_value())
|
||||||
|
entry.display_aspect_ratio_custom_numerator.reset();
|
||||||
|
else
|
||||||
|
entry.display_aspect_ratio_custom_numerator = StringUtil::FromChars<u16>(value.value());
|
||||||
|
}
|
||||||
|
else if (key == "CustomAspectRatioDenominator")
|
||||||
|
{
|
||||||
|
if (!value.has_value())
|
||||||
|
entry.display_aspect_ratio_custom_denominator.reset();
|
||||||
|
else
|
||||||
|
entry.display_aspect_ratio_custom_denominator = StringUtil::FromChars<u16>(value.value());
|
||||||
|
}
|
||||||
else if (key == "GPUDownsampleMode")
|
else if (key == "GPUDownsampleMode")
|
||||||
{
|
{
|
||||||
if (!value.has_value())
|
if (!value.has_value())
|
||||||
|
@ -1031,6 +1085,10 @@ void Entry::ApplySettings(bool display_osd_messages) const
|
||||||
g_settings.display_crop_mode = display_crop_mode.value();
|
g_settings.display_crop_mode = display_crop_mode.value();
|
||||||
if (display_aspect_ratio.has_value())
|
if (display_aspect_ratio.has_value())
|
||||||
g_settings.display_aspect_ratio = display_aspect_ratio.value();
|
g_settings.display_aspect_ratio = display_aspect_ratio.value();
|
||||||
|
if (display_aspect_ratio_custom_numerator.has_value())
|
||||||
|
g_settings.display_aspect_ratio_custom_numerator = display_aspect_ratio_custom_numerator.value();
|
||||||
|
if (display_aspect_ratio_custom_denominator.has_value())
|
||||||
|
g_settings.display_aspect_ratio_custom_denominator = display_aspect_ratio_custom_denominator.value();
|
||||||
if (gpu_downsample_mode.has_value())
|
if (gpu_downsample_mode.has_value())
|
||||||
g_settings.gpu_downsample_mode = gpu_downsample_mode.value();
|
g_settings.gpu_downsample_mode = gpu_downsample_mode.value();
|
||||||
if (display_linear_upscaling.has_value())
|
if (display_linear_upscaling.has_value())
|
||||||
|
|
|
@ -61,6 +61,8 @@ struct Entry
|
||||||
std::optional<bool> display_linear_upscaling;
|
std::optional<bool> display_linear_upscaling;
|
||||||
std::optional<bool> display_integer_upscaling;
|
std::optional<bool> display_integer_upscaling;
|
||||||
std::optional<bool> display_force_4_3_for_24bit;
|
std::optional<bool> display_force_4_3_for_24bit;
|
||||||
|
std::optional<u16> display_aspect_ratio_custom_numerator;
|
||||||
|
std::optional<u16> display_aspect_ratio_custom_denominator;
|
||||||
std::optional<u32> gpu_resolution_scale;
|
std::optional<u32> gpu_resolution_scale;
|
||||||
std::optional<u32> gpu_multisamples;
|
std::optional<u32> gpu_multisamples;
|
||||||
std::optional<bool> gpu_per_sample_shading;
|
std::optional<bool> gpu_per_sample_shading;
|
||||||
|
|
Loading…
Reference in New Issue