diff --git a/runner/src/frontend.h b/runner/src/frontend.h index 4199cc6..997e409 100644 --- a/runner/src/frontend.h +++ b/runner/src/frontend.h @@ -304,6 +304,7 @@ bool nds_parse_boot_mode(const std::string& value, NdsBootMode* out); // still be harmless but is rejected anyway, to keep bad CLI input loud). bool nds_parse_instance_index(const std::string& value, uint32_t* out); bool nds_parse_adaptive_screens(const std::string& value, uint8_t* out); +bool nds_parse_widescreen_width(const std::string& value, uint16_t* out); bool nds_parse_supersampling(const std::string& value, uint8_t* out); bool nds_parse_antialiasing(const std::string& value, uint8_t* out); bool nds_parse_internal_resolution(const std::string& value, uint8_t* out); diff --git a/runner/src/frontend_config.cpp b/runner/src/frontend_config.cpp index 691db00..215714a 100644 --- a/runner/src/frontend_config.cpp +++ b/runner/src/frontend_config.cpp @@ -96,6 +96,19 @@ bool nds_parse_adaptive_screens(const std::string& value, uint8_t* out) { return false; } +bool nds_parse_widescreen_width(const std::string& value, uint16_t* out) { + if (!out || value.empty()) return false; + char* end = nullptr; + const long parsed = std::strtol(value.c_str(), &end, 10); + if (!end || *end != '\0' || + (parsed != 256 && parsed != 320 && + parsed != 384 && parsed != 448)) { + return false; + } + *out = static_cast(parsed); + return true; +} + bool nds_parse_supersampling(const std::string& value, uint8_t* out) { if (!out || value.empty()) return false; char* end = nullptr; @@ -544,15 +557,15 @@ bool nds_load_frontend_config(const std::string& path, } if (const auto value = (*display)["adaptive_width"].value()) { - if (*value < 256 || *value > 448 || (*value & 1) != 0) { + uint16_t width = 0; + if (!nds_parse_widescreen_width(std::to_string(*value), &width)) { if (error) { *error = - "display.adaptive_width must be an even value from " - "256 through 448"; + "display.adaptive_width must be 256, 320, 384, " + "or 448"; } return false; } - const uint16_t width = static_cast(*value); if (options->adaptive_supported & NDS_ADAPTIVE_TOP) options->adaptive_max_width[0] = width; if (options->adaptive_supported & NDS_ADAPTIVE_BOTTOM) diff --git a/runner/src/main.cpp b/runner/src/main.cpp index 3d505ec..d8fb527 100644 --- a/runner/src/main.cpp +++ b/runner/src/main.cpp @@ -326,6 +326,7 @@ int main(int argc, char** argv) { std::string cli_screen_layout; std::string cli_fullscreen; std::string cli_adaptive_screens; + std::string cli_widescreen_width; std::string cli_supersampling; std::string cli_internal_resolution; std::string cli_texture_upscale; @@ -445,6 +446,8 @@ int main(int argc, char** argv) { cli_fullscreen = argv[++i]; } else if (a == "--adaptive-widescreen" && i + 1 < argc) { cli_adaptive_screens = argv[++i]; + } else if (a == "--widescreen-width" && i + 1 < argc) { + cli_widescreen_width = argv[++i]; } else if (a == "--supersampling" && i + 1 < argc) { cli_supersampling = argv[++i]; } else if (a == "--internal-resolution" && i + 1 < argc) { @@ -573,6 +576,7 @@ int main(int argc, char** argv) { "[--screen-layout stacked|separate] " "[--fullscreen off|borderless|exclusive] " "[--adaptive-widescreen none|top|bottom|both] " + "[--widescreen-width even:256..448] " "[--supersampling 1|2|3|4] " "[--internal-resolution 1|2|3|4] " "[--texture-upscale 1|2|4] " @@ -672,6 +676,22 @@ int main(int argc, char** argv) { return 2; } } + auto apply_adaptive_width = [&](uint16_t width) { + if (frontend_options.adaptive_supported & NDS_ADAPTIVE_TOP) + frontend_options.adaptive_max_width[0] = width; + if (frontend_options.adaptive_supported & NDS_ADAPTIVE_BOTTOM) + frontend_options.adaptive_max_width[1] = width; + }; + if (const char* value = std::getenv("NDS_WIDESCREEN_WIDTH")) { + uint16_t width = 0; + if (!nds_parse_widescreen_width(value, &width)) { + std::fprintf(stderr, + "invalid NDS_WIDESCREEN_WIDTH " + "(expected 256, 320, 384, or 448)\n"); + return 2; + } + apply_adaptive_width(width); + } if (const char* value = std::getenv("NDS_SUPERSAMPLING")) { if (!nds_parse_supersampling(value, &frontend_options.supersampling)) { @@ -775,6 +795,16 @@ int main(int argc, char** argv) { "(expected none, top, bottom, or both)\n"); return 2; } + if (!cli_widescreen_width.empty()) { + uint16_t width = 0; + if (!nds_parse_widescreen_width(cli_widescreen_width, &width)) { + std::fprintf(stderr, + "invalid --widescreen-width " + "(expected 256, 320, 384, or 448)\n"); + return 2; + } + apply_adaptive_width(width); + } if (!cli_supersampling.empty() && !nds_parse_supersampling(cli_supersampling, &frontend_options.supersampling)) { diff --git a/runner/tests/frontend_config_test.cpp b/runner/tests/frontend_config_test.cpp index 84fbbf9..016de85 100644 --- a/runner/tests/frontend_config_test.cpp +++ b/runner/tests/frontend_config_test.cpp @@ -291,6 +291,32 @@ int main() { if (!require( !nds_load_frontend_config(path.string(), &options, &error))) return 11; + { + std::ofstream file(path); + file << "[game]\n" + "sha1 = \"90164d1ac127ee5f9815ea4ae7de798c7b5fc629\"\n" + "[display]\n" + "adaptive_capability = \"top\"\n" + "adaptive_width = 320\n"; + } + options = {}; + if (!require( + nds_load_frontend_config(path.string(), &options, &error))) + return 25; + if (!require(options.adaptive_max_width[0] == 320)) + return 26; + { + uint16_t width = 0; + if (!require(nds_parse_widescreen_width("448", &width) && + width == 448)) + return 27; + if (!require(!nds_parse_widescreen_width("255", &width))) + return 28; + if (!require(!nds_parse_widescreen_width("449", &width))) + return 29; + if (!require(!nds_parse_widescreen_width("342", &width))) + return 30; + } { std::ofstream file(path);