rexglue-skate3/include/rex/graphics/video_mode_util.h
2026-05-18 22:41:13 +01:00

122 lines
3.3 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2026 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#pragma once
#include <charconv>
#include <cctype>
#include <cstdint>
#include <string>
#include <string_view>
#include <rex/cvar.h>
#include <rex/graphics/flags.h>
namespace rex::graphics::video_mode_util {
inline bool TryParsePositiveInt32(std::string_view value, int32_t& value_out) {
if (value.empty()) {
return false;
}
int32_t parsed_value = 0;
auto [parse_end, parse_error] =
std::from_chars(value.data(), value.data() + value.size(), parsed_value);
if (parse_error != std::errc() || parse_end != value.data() + value.size() || parsed_value <= 0) {
return false;
}
value_out = parsed_value;
return true;
}
inline bool TryParseResolutionPreset(std::string_view resolution_value, int32_t& width_out,
int32_t& height_out) {
std::string normalized;
normalized.reserve(resolution_value.size());
for (char c : resolution_value) {
unsigned char c_unsigned = static_cast<unsigned char>(c);
if (std::isspace(c_unsigned) || c == '_' || c == '-') {
continue;
}
normalized.push_back(char(std::tolower(c_unsigned)));
}
if (normalized.empty()) {
return false;
}
size_t x_position = normalized.find('x');
if (x_position != std::string::npos && x_position > 0 && x_position + 1 < normalized.size()) {
int32_t parsed_width = 0;
int32_t parsed_height = 0;
if (!TryParsePositiveInt32(std::string_view(normalized).substr(0, x_position), parsed_width) ||
!TryParsePositiveInt32(std::string_view(normalized).substr(x_position + 1),
parsed_height)) {
return false;
}
width_out = parsed_width;
height_out = parsed_height;
return true;
}
if (normalized == "480p") {
width_out = 640;
height_out = 480;
return true;
}
if (normalized == "540p") {
width_out = 960;
height_out = 540;
return true;
}
if (normalized == "720p") {
width_out = 1280;
height_out = 720;
return true;
}
if (normalized == "900p") {
width_out = 1600;
height_out = 900;
return true;
}
if (normalized == "1080p") {
width_out = 1920;
height_out = 1080;
return true;
}
if (normalized == "1440p") {
width_out = 2560;
height_out = 1440;
return true;
}
if (normalized == "1800p") {
width_out = 3200;
height_out = 1800;
return true;
}
if (normalized == "2160p" || normalized == "4k") {
width_out = 3840;
height_out = 2160;
return true;
}
return false;
}
inline bool TryGetResolutionPresetFromCVar(int32_t& width_out, int32_t& height_out) {
if (!rex::cvar::HasNonDefaultValue("resolution")) {
return false;
}
const std::string& resolution_value = REXCVAR_GET(resolution);
if (resolution_value.empty()) {
return false;
}
return TryParseResolutionPreset(resolution_value, width_out, height_out);
}
} // namespace rex::graphics::video_mode_util