Skip to content

Commit

Permalink
Options: Move resolutions list init to display.cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
glebm committed Jan 23, 2025
1 parent 254181f commit bae54d0
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 133 deletions.
2 changes: 2 additions & 0 deletions Source/controls/padmapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <array>

#include "controller.h"
#include "game_controls.h"
#include "options.h"

namespace devilution {
Expand Down
131 changes: 9 additions & 122 deletions Source/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@

namespace devilution {

#ifndef DEFAULT_WIDTH
#define DEFAULT_WIDTH 640
#endif
#ifndef DEFAULT_HEIGHT
#define DEFAULT_HEIGHT 480
#endif
#ifndef DEFAULT_AUDIO_SAMPLE_RATE
#define DEFAULT_AUDIO_SAMPLE_RATE 22050
#endif
Expand Down Expand Up @@ -488,139 +482,32 @@ OptionEntryResolution::OptionEntryResolution()
}
void OptionEntryResolution::LoadFromIni(std::string_view category)
{
size = { ini->getInt(category, "Width", DEFAULT_WIDTH), ini->getInt(category, "Height", DEFAULT_HEIGHT) };
size_ = { ini->getInt(category, "Width", DEFAULT_WIDTH), ini->getInt(category, "Height", DEFAULT_HEIGHT) };
}
void OptionEntryResolution::SaveToIni(std::string_view category) const
{
ini->set(category, "Width", size.width);
ini->set(category, "Height", size.height);
}

void OptionEntryResolution::InvalidateList()
{
resolutions.clear();
}

void OptionEntryResolution::CheckResolutionsAreInitialized() const
{
if (!resolutions.empty())
return;

std::vector<Size> sizes;
float scaleFactor = GetDpiScalingFactor();

// Add resolutions
bool supportsAnyResolution = false;
#ifdef USE_SDL1
auto *modes = SDL_ListModes(nullptr, SDL_FULLSCREEN | SDL_HWPALETTE);
// SDL_ListModes returns -1 if any resolution is allowed (for example returned on 3DS)
if (modes == (SDL_Rect **)-1) {
supportsAnyResolution = true;
} else if (modes != nullptr) {
for (size_t i = 0; modes[i] != nullptr; i++) {
if (modes[i]->w < modes[i]->h) {
std::swap(modes[i]->w, modes[i]->h);
}
sizes.emplace_back(Size {
static_cast<int>(modes[i]->w * scaleFactor),
static_cast<int>(modes[i]->h * scaleFactor) });
}
}
#else
int displayModeCount = SDL_GetNumDisplayModes(0);
for (int i = 0; i < displayModeCount; i++) {
SDL_DisplayMode mode;
if (SDL_GetDisplayMode(0, i, &mode) != 0) {
ErrSdl();
}
if (mode.w < mode.h) {
std::swap(mode.w, mode.h);
}
sizes.emplace_back(Size {
static_cast<int>(mode.w * scaleFactor),
static_cast<int>(mode.h * scaleFactor) });
}
supportsAnyResolution = *GetOptions().Graphics.upscale;
#endif

if (supportsAnyResolution && sizes.size() == 1) {
// Attempt to provide sensible options for 4:3 and the native aspect ratio
const int width = sizes[0].width;
const int height = sizes[0].height;
const int commonHeights[] = { 480, 540, 720, 960, 1080, 1440, 2160 };
for (int commonHeight : commonHeights) {
if (commonHeight > height)
break;
sizes.emplace_back(Size { commonHeight * 4 / 3, commonHeight });
if (commonHeight * width % height == 0)
sizes.emplace_back(Size { commonHeight * width / height, commonHeight });
}
}
// Ensures that the ini specified resolution is present in resolution list even if it doesn't match a monitor resolution (for example if played in window mode)
sizes.push_back(this->size);
// Ensures that the platform's preferred default resolution is always present
sizes.emplace_back(Size { DEFAULT_WIDTH, DEFAULT_HEIGHT });
// Ensures that the vanilla Diablo resolution is present on systems that would support it
if (supportsAnyResolution)
sizes.emplace_back(Size { 640, 480 });

#ifndef USE_SDL1
if (*GetOptions().Graphics.fitToScreen) {
SDL_DisplayMode mode;
if (SDL_GetDesktopDisplayMode(0, &mode) != 0) {
ErrSdl();
}
for (auto &size : sizes) {
// Ensure that the ini specified resolution remains present in the resolution list
if (size.height == this->size.height)
size.width = this->size.width;
else
size.width = size.height * mode.w / mode.h;
}
}
#endif

// Sort by width then by height
c_sort(sizes, [](const Size &x, const Size &y) -> bool {
if (x.width == y.width)
return x.height > y.height;
return x.width > y.width;
});
// Remove duplicate entries
sizes.erase(std::unique(sizes.begin(), sizes.end()), sizes.end());

for (auto &size : sizes) {
#ifndef USE_SDL1
if (*GetOptions().Graphics.fitToScreen) {
resolutions.emplace_back(size, StrCat(size.height, "p"));
continue;
}
#endif
resolutions.emplace_back(size, StrCat(size.width, "x", size.height));
}
ini->set(category, "Width", size_.width);
ini->set(category, "Height", size_.height);
}

size_t OptionEntryResolution::GetListSize() const
{
CheckResolutionsAreInitialized();
return resolutions.size();
return resolutions_.size();
}
std::string_view OptionEntryResolution::GetListDescription(size_t index) const
{
CheckResolutionsAreInitialized();
return resolutions[index].second;
return resolutions_[index].second;
}
size_t OptionEntryResolution::GetActiveListIndex() const
{
CheckResolutionsAreInitialized();
auto found = c_find_if(resolutions, [this](const auto &x) { return x.first == this->size; });
if (found == resolutions.end())
auto found = c_find_if(resolutions_, [this](const auto &x) { return x.first == size_; });
if (found == resolutions_.end())
return 0;
return std::distance(resolutions.begin(), found);
return std::distance(resolutions_.begin(), found);
}
void OptionEntryResolution::SetActiveListIndex(size_t index)
{
size = resolutions[index].first;
size_ = resolutions_[index].first;
NotifyValueChanged();
}

Expand Down
29 changes: 20 additions & 9 deletions Source/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <forward_list>
#include <functional>
#include <initializer_list>
#include <optional>
#include <string>
#include <string_view>
#include <utility>

#include <SDL_version.h>
#include <ankerl/unordered_dense.h>
#include <function_ref.hpp>

#include "controls/controller.h"
#include "appfat.h"
#include "controls/controller_buttons.h"
#include "controls/game_controls.h"
#include "engine/size.hpp"
#include "engine/sound_defs.hpp"
#include "pack.h"
#include "quick_messages.hpp"
Expand All @@ -22,6 +27,13 @@

namespace devilution {

#ifndef DEFAULT_WIDTH
#define DEFAULT_WIDTH 640
#endif
#ifndef DEFAULT_HEIGHT
#define DEFAULT_HEIGHT 480
#endif

enum class StartUpGameMode : uint8_t {
/** @brief If hellfire is present, asks the user what game they want to start. */
Ask = 0,
Expand Down Expand Up @@ -338,19 +350,18 @@ class OptionEntryResolution : public OptionEntryListBase {
[[nodiscard]] std::string_view GetListDescription(size_t index) const override;
[[nodiscard]] size_t GetActiveListIndex() const override;
void SetActiveListIndex(size_t index) override;
void InvalidateList();

Size operator*() const
void setAvailableResolutions(std::vector<std::pair<Size, std::string>> &&resolutions)
{
return size;
resolutions_ = std::move(resolutions);
}

Size operator*() const { return size_; }

private:
/** @brief View size. */
Size size;
mutable std::vector<std::pair<Size, std::string>> resolutions;

void CheckResolutionsAreInitialized() const;
Size size_;
std::vector<std::pair<Size, std::string>> resolutions_;
};

class OptionEntryResampler : public OptionEntryListBase {
Expand Down
113 changes: 111 additions & 2 deletions Source/utils/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <utility>

#ifdef __vita__
#include <psp2/power.h>
Expand Down Expand Up @@ -207,12 +208,115 @@ void OptionGrabInputChanged()
}
const auto OptionChangeHandlerGrabInput = (GetOptions().Gameplay.grabInput.SetValueChangedCallback(OptionGrabInputChanged), true);

void UpdateAvailableResolutions()
{
GraphicsOptions &graphicsOptions = GetOptions().Graphics;

std::vector<Size> sizes;
float scaleFactor = GetDpiScalingFactor();

// Add resolutions
bool supportsAnyResolution = false;
#ifdef USE_SDL1
auto *modes = SDL_ListModes(nullptr, SDL_FULLSCREEN | SDL_HWPALETTE);
// SDL_ListModes returns -1 if any resolution is allowed (for example returned on 3DS)
if (modes == (SDL_Rect **)-1) {
supportsAnyResolution = true;
} else if (modes != nullptr) {
for (size_t i = 0; modes[i] != nullptr; i++) {
if (modes[i]->w < modes[i]->h) {
std::swap(modes[i]->w, modes[i]->h);
}
sizes.emplace_back(Size {
static_cast<int>(modes[i]->w * scaleFactor),
static_cast<int>(modes[i]->h * scaleFactor) });
}
}
#else
int displayModeCount = SDL_GetNumDisplayModes(0);
for (int i = 0; i < displayModeCount; i++) {
SDL_DisplayMode mode;
if (SDL_GetDisplayMode(0, i, &mode) != 0) {
ErrSdl();
}
if (mode.w < mode.h) {
std::swap(mode.w, mode.h);
}
sizes.emplace_back(Size {
static_cast<int>(mode.w * scaleFactor),
static_cast<int>(mode.h * scaleFactor) });
}
supportsAnyResolution = *GetOptions().Graphics.upscale;
#endif

if (supportsAnyResolution && sizes.size() == 1) {
// Attempt to provide sensible options for 4:3 and the native aspect ratio
const int width = sizes[0].width;
const int height = sizes[0].height;
const int commonHeights[] = { 480, 540, 720, 960, 1080, 1440, 2160 };
for (int commonHeight : commonHeights) {
if (commonHeight > height)
break;
sizes.emplace_back(Size { commonHeight * 4 / 3, commonHeight });
if (commonHeight * width % height == 0)
sizes.emplace_back(Size { commonHeight * width / height, commonHeight });
}
}

const Size configuredSize = *graphicsOptions.resolution;

// Ensures that the ini specified resolution is present in resolution list even if it doesn't match a monitor resolution (for example if played in window mode)
sizes.push_back(configuredSize);
// Ensures that the platform's preferred default resolution is always present
sizes.emplace_back(Size { DEFAULT_WIDTH, DEFAULT_HEIGHT });
// Ensures that the vanilla Diablo resolution is present on systems that would support it
if (supportsAnyResolution)
sizes.emplace_back(Size { 640, 480 });

#ifndef USE_SDL1
if (*graphicsOptions.fitToScreen) {
SDL_DisplayMode mode;
if (SDL_GetDesktopDisplayMode(0, &mode) != 0) {
ErrSdl();
}
for (auto &size : sizes) {
// Ensure that the ini specified resolution remains present in the resolution list
if (size.height == configuredSize.height)
size.width = configuredSize.width;
else
size.width = size.height * mode.w / mode.h;
}
}
#endif

// Sort by width then by height
c_sort(sizes, [](const Size &x, const Size &y) -> bool {
if (x.width == y.width)
return x.height > y.height;
return x.width > y.width;
});
// Remove duplicate entries
sizes.erase(std::unique(sizes.begin(), sizes.end()), sizes.end());

std::vector<std::pair<Size, std::string>> resolutions;
for (auto &size : sizes) {
#ifndef USE_SDL1
if (*graphicsOptions.fitToScreen) {
resolutions.emplace_back(size, StrCat(size.height, "p"));
continue;
}
#endif
resolutions.emplace_back(size, StrCat(size.width, "x", size.height));
}
graphicsOptions.resolution.setAvailableResolutions(std::move(resolutions));
}

#if !defined(USE_SDL1) || defined(__3DS__)
void ResizeWindowAndUpdateResolutionOptions()
{
ResizeWindow();
#ifndef __3DS__
GetOptions().Graphics.resolution.InvalidateList();
UpdateAvailableResolutions();
#endif
}
const auto OptionChangeHandlerFitToScreen = (GetOptions().Graphics.fitToScreen.SetValueChangedCallback(ResizeWindowAndUpdateResolutionOptions), true);
Expand Down Expand Up @@ -405,7 +509,12 @@ bool SpawnWindow(const char *lpWindowName)

ReinitializeRenderer();

return ghMainWnd != nullptr;
if (ghMainWnd != nullptr) {
UpdateAvailableResolutions();
return true;
}

return false;
}

#ifndef USE_SDL1
Expand Down

0 comments on commit bae54d0

Please sign in to comment.