Lime3DS/src/citra_libretro/core_settings.cpp
OpenSauce04 9b045bf837 libretro: Replace render_touchscreen setting with enable_touch_pointer_timeout
Touch pointer rendering is now always enabled, but unless a controller is being used to move the touchscreen cursor, it will be hidden due to the timeout which is also enabled by default.
2026-03-23 13:07:39 +00:00

1069 lines
36 KiB
C++

// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <boost/hana/string.hpp>
#include "citra_libretro/core_settings.h"
#include "citra_libretro/environment.h"
#include "common/file_util.h"
#include "common/settings.h"
#include "core/hle/service/cfg/cfg.h"
namespace BaseKeys = Settings::HKeys;
namespace LibRetro {
CoreSettings settings = {};
namespace config {
template <typename HanaString>
constexpr const char* citra_setting(HanaString key) {
return (BOOST_HANA_STRING("citra_") + key).c_str();
}
static constexpr const char* enabled = "enabled";
static constexpr const char* disabled = "disabled";
namespace category {
static constexpr const char* cpu = "cpu";
static constexpr const char* system = "system";
static constexpr const char* audio = "audio";
static constexpr const char* graphics = "graphics";
static constexpr const char* layout = "layout";
static constexpr const char* storage = "storage";
static constexpr const char* input = "input";
} // namespace category
namespace cpu {
static constexpr const char* use_cpu_jit = citra_setting(BaseKeys::use_cpu_jit);
static constexpr const char* cpu_clock_percentage = citra_setting(BaseKeys::cpu_clock_percentage);
} // namespace cpu
namespace system {
static constexpr const char* is_new_3ds = citra_setting(BaseKeys::is_new_3ds);
static constexpr const char* region_value = citra_setting(BaseKeys::region_value);
static constexpr const char* language_value = citra_setting(BaseKeys::language_value);
} // namespace system
namespace audio {
static constexpr const char* audio_emulation = citra_setting(BaseKeys::audio_emulation);
static constexpr const char* input_type = citra_setting(BaseKeys::input_type);
} // namespace audio
namespace graphics {
static constexpr const char* graphics_api = citra_setting(BaseKeys::graphics_api);
static constexpr const char* use_hw_shader = citra_setting(BaseKeys::use_hw_shader);
static constexpr const char* use_shader_jit = citra_setting(BaseKeys::use_shader_jit);
static constexpr const char* shaders_accurate_mul = citra_setting(BaseKeys::shaders_accurate_mul);
static constexpr const char* use_disk_shader_cache = citra_setting(BaseKeys::use_disk_shader_cache);
static constexpr const char* resolution_factor = citra_setting(BaseKeys::resolution_factor);
static constexpr const char* texture_filter = citra_setting(BaseKeys::texture_filter);
static constexpr const char* texture_sampling = citra_setting(BaseKeys::texture_sampling);
static constexpr const char* custom_textures = citra_setting(BaseKeys::custom_textures);
static constexpr const char* dump_textures = citra_setting(BaseKeys::dump_textures);
} // namespace graphics
namespace layout {
static constexpr const char* layout_option = citra_setting(BaseKeys::layout_option);
static constexpr const char* swap_screen = citra_setting(BaseKeys::swap_screen);
static constexpr const char* swap_screen_mode = citra_setting(BaseKeys::swap_screen_mode);
static constexpr const char* large_screen_proportion =
citra_setting(BaseKeys::large_screen_proportion);
} // namespace layout
namespace storage {
static constexpr const char* use_virtual_sd = citra_setting(BaseKeys::use_virtual_sd);
static constexpr const char* use_libretro_save_path =
citra_setting(BaseKeys::use_libretro_save_path);
} // namespace storage
namespace input {
static constexpr const char* analog_function = citra_setting(BaseKeys::analog_function);
static constexpr const char* analog_deadzone = citra_setting(BaseKeys::analog_deadzone);
static constexpr const char* enable_mouse_touchscreen =
citra_setting(BaseKeys::enable_mouse_touchscreen);
static constexpr const char* enable_touch_touchscreen =
citra_setting(BaseKeys::enable_touch_touchscreen);
static constexpr const char* enable_touch_pointer_timeout =
citra_setting(BaseKeys::enable_touch_pointer_timeout);
static constexpr const char* enable_motion = citra_setting(BaseKeys::enable_motion);
static constexpr const char* motion_sensitivity = citra_setting(BaseKeys::motion_sensitivity);
} // namespace input
} // namespace config
// clang-format off
static constexpr retro_core_option_v2_category option_categories[] = {
{
config::category::cpu,
"CPU",
"Settings related to CPU emulation performance and accuracy."
},
{
config::category::system,
"System",
"Nintendo 3DS system configuration and region settings."
},
{
config::category::audio,
"Audio",
"Audio emulation and microphone settings."
},
{
config::category::graphics,
"Graphics",
"Graphics API, rendering, and visual enhancement settings."
},
{
config::category::layout,
"Layout",
"Screen layout and display positioning options."
},
{
config::category::storage,
"Storage",
"Save data and virtual SD card settings."
},
{
config::category::input,
"Input",
"Controller and touchscreen input configuration."
},
{ nullptr, nullptr, nullptr }
};
// ============================================================================
// Option Definitions
// ============================================================================
static constexpr retro_core_option_v2_definition option_definitions[] = {
// CPU Category
{
config::cpu::use_cpu_jit,
"Enable CPU JIT",
"CPU JIT",
"Enable Just-In-Time compilation for ARM CPU emulation. "
"Significantly improves performance but may reduce accuracy. "
"Restart required.",
nullptr,
config::category::cpu,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::cpu::cpu_clock_percentage,
"CPU Clock Speed",
"CPU Clock Speed",
"Adjust the emulated 3DS CPU clock speed as a percentage of normal speed. "
"Higher values may improve performance in some games but can cause issues. "
"Lower values can help with games that run too fast.",
nullptr,
config::category::cpu,
{
{ "25", "25%" }, { "50", "50%" }, { "75", "75%" }, { "100", "100% (Default)" },
{ "125", "125%" }, { "150", "150%" }, { "175", "175%" }, { "200", "200%" },
{ "225", "225%" }, { "250", "250%" }, { "275", "275%" }, { "300", "300%" },
{ "325", "325%" }, { "350", "350%" }, { "375", "375%" }, { "400", "400%" },
{ nullptr, nullptr }
},
"100"
},
// System Category
{
config::system::is_new_3ds,
"3DS System Model",
"System Model",
"Select whether to emulate the original 3DS or New 3DS. "
"New 3DS has additional CPU power and memory, required for some games. "
"Restart required.",
nullptr,
config::category::system,
{
{ "New 3DS", "New 3DS" },
{ "Old 3DS", "Original 3DS" },
{ nullptr, nullptr }
},
"New 3DS"
},
{
config::system::region_value,
"3DS System Region",
"System Region",
"Set the 3DS system region. Auto-select will choose based on the game. "
"Some games are region-locked and require matching regions.",
nullptr,
config::category::system,
{
{ "Auto", "Auto" },
{ "Japan", "Japan" },
{ "USA", "USA" },
{ "Europe", "Europe" },
{ "Australia", "Australia" },
{ "China", "China" },
{ "Korea", "Korea" },
{ "Taiwan", "Taiwan" },
{ nullptr, nullptr }
},
"Auto"
},
{
config::system::language_value,
"3DS System Language",
"System Language",
"Set the system language for the emulated 3DS. "
"This affects in-game text language when supported.",
nullptr,
config::category::system,
{
{ "English", "English" },
{ "Japanese", "Japanese" },
{ "French", "French" },
{ "Spanish", "Spanish" },
{ "German", "German" },
{ "Italian", "Italian" },
{ "Dutch", "Dutch" },
{ "Portuguese", "Portuguese" },
{ "Russian", "Russian" },
{ "Korean", "Korean" },
{ "Traditional Chinese", "Traditional Chinese" },
{ "Simplified Chinese", "Simplified Chinese" },
{ nullptr, nullptr }
},
"english"
},
// Audio Category
{
config::audio::audio_emulation,
"Audio Emulation",
"Audio Emulation",
"Select audio emulation method. HLE is faster, LLE is more accurate.",
nullptr,
config::category::audio,
{
{ "hle", "HLE (Fast)" },
{ "lle", "LLE (Accurate)" },
{ "lle_multithread", "LLE Multithreaded" },
{ nullptr, nullptr }
},
"hle"
},
{
config::audio::input_type,
"Microphone Input Type",
"Microphone Input",
"Select how microphone input is handled for games that support it.",
nullptr,
config::category::audio,
{
{ "auto", "Auto" },
{ "none", "None" },
{ "static_noise", "Static Noise" },
{ "frontend", "Frontend" },
{ nullptr, nullptr }
},
"auto"
},
// Graphics Category
{
config::graphics::graphics_api,
"Graphics API",
"Graphics API",
"Select the graphics rendering API. Auto will choose the best available option. "
"Restart required.",
nullptr,
config::category::graphics,
{
{ "Auto", "Auto" },
#ifdef ENABLE_VULKAN
{ "Vulkan", "Vulkan" },
#endif
#ifdef ENABLE_OPENGL
{ "OpenGL", "OpenGL" },
#endif
{ "Software", "Software" },
{ nullptr, nullptr }
},
"auto"
},
{
config::graphics::use_hw_shader,
"Enable Hardware Shaders",
"Hardware Shaders",
"Use GPU hardware to accelerate shader processing. "
"Significantly improves performance but may reduce accuracy.",
nullptr,
config::category::graphics,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::graphics::use_shader_jit,
"Enable Shader JIT",
"Shader JIT",
"Use Just-In-Time compilation for shaders. "
"Improves performance but may cause graphical issues in some games.",
nullptr,
config::category::graphics,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::graphics::shaders_accurate_mul,
"Accurate Shader Multiplication",
"Accurate Multiplication",
"Use accurate multiplication in shaders. "
"More accurate but can reduce performance. Only works with hardware shaders.",
nullptr,
config::category::graphics,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::graphics::use_disk_shader_cache,
"Hardware Shader Cache",
"Shader Cache",
"Save compiled shaders to disk to reduce loading times on subsequent runs.",
nullptr,
config::category::graphics,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::graphics::resolution_factor,
"Internal Resolution",
"Internal Resolution",
"Render the 3DS screens at a higher resolution. "
"Higher values improve visual quality but significantly impact performance.",
nullptr,
config::category::graphics,
{
{ "1", "1x (Native 400x240)" },
{ "2", "2x (800x480)" },
{ "3", "3x (1200x720)" },
{ "4", "4x (1600x960)" },
{ "5", "5x (2000x1200)" },
{ "6", "6x (2400x1440)" },
{ "7", "7x (2800x1680)" },
{ "8", "8x (3200x1920)" },
{ "9", "9x (3600x2160)" },
{ "10", "10x (4000x2400)" },
{ nullptr, nullptr }
},
"1"
},
{
config::graphics::texture_filter,
"Texture Filter",
"Texture Filter",
"Apply texture filtering to enhance visual quality. "
"Some filters may significantly impact performance.",
nullptr,
config::category::graphics,
{
{ "none", "None" },
{ "Anime4K Ultrafast", "Anime4K Ultrafast" },
{ "Bicubic", "Bicubic" },
{ "ScaleForce", "ScaleForce" },
{ "xBRZ", "xBRZ" },
{ "MMPX", "MMPX" },
{ nullptr, nullptr }
},
"none"
},
{
config::graphics::texture_sampling,
"Texture Sampling",
"Texture Sampling",
"Control how textures are sampled and filtered.",
nullptr,
config::category::graphics,
{
{ "GameControlled", "Game Controlled" },
{ "NearestNeighbor", "Nearest Neighbor" },
{ "Linear", "Linear" },
{ nullptr, nullptr }
},
"GameControlled"
},
{
config::graphics::custom_textures,
"Custom Textures",
"Custom Textures",
"Enable loading of custom texture packs to replace original game textures.",
nullptr,
config::category::graphics,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::disabled
},
{
config::graphics::dump_textures,
"Dump Game Textures",
"Dump Textures",
"Save original game textures to disk for creating custom texture packs. "
"May impact performance.",
nullptr,
config::category::graphics,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::disabled
},
// Layout Category
{
config::layout::layout_option,
"Screen Layout",
"Screen Layout",
"Choose how the 3DS screens are arranged in the display.",
nullptr,
config::category::layout,
{
{ "default", "Default Top-Bottom" },
{ "single_screen", "Single Screen Only" },
{ "large_screen", "Large Screen, Small Screen" },
{ "side_by_side", "Side by Side" },
{ nullptr, nullptr }
},
"default"
},
{
config::layout::swap_screen,
"Prominent 3DS Screen",
"Prominent Screen",
"Choose which screen is displayed prominently in single screen or large screen layouts.",
nullptr,
config::category::layout,
{
{ "Top", "Top Screen" },
{ "Bottom", "Bottom Screen" },
{ nullptr, nullptr }
},
"Top"
},
{
config::layout::swap_screen_mode,
"Screen Swap Mode",
"Swap Mode",
"How screen swapping behaves when using the screen swap hotkey.",
nullptr,
config::category::layout,
{
{ "Toggle", "Toggle" },
{ "Hold", "Hold" },
{ nullptr, nullptr }
},
"Toggle"
},
{
config::layout::large_screen_proportion,
"Large Screen Proportion",
"Large Screen Proportion",
"How many times larger the main screen is compared to the small screen "
"in the Large Screen layout.",
nullptr,
config::category::layout,
{
{ "1.00", "1.00x (Equal Size)" },
{ "1.25", "1.25x" },
{ "1.50", "1.50x" },
{ "1.75", "1.75x" },
{ "2.00", "2.00x" },
{ "2.25", "2.25x" },
{ "2.50", "2.50x" },
{ "2.75", "2.75x" },
{ "3.00", "3.00x" },
{ "3.25", "3.25x" },
{ "3.50", "3.50x" },
{ "3.75", "3.75x" },
{ "4.00", "4.00x (Default)" },
{ "4.25", "4.25x" },
{ "4.50", "4.50x" },
{ "4.75", "4.75x" },
{ "5.00", "5.00x" },
{ "5.25", "5.25x" },
{ "5.50", "5.50x" },
{ "5.75", "5.75x" },
{ "6.00", "6.00x" },
{ nullptr, nullptr }
},
"4.00"
},
// Storage Category
{
config::storage::use_virtual_sd,
"Enable Virtual SD Card",
"Virtual SD Card",
"Enable virtual SD card support for homebrew and some commercial games.",
nullptr,
config::category::storage,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::storage::use_libretro_save_path,
"Save Data Location",
"Save Location",
"Choose where save data and system files are stored.",
nullptr,
config::category::storage,
{
{ "LibRetro Default", "LibRetro Default" },
{ "Azahar Default", "Azahar Default" },
{ nullptr, nullptr }
},
"LibRetro Default"
},
// Input Category
{
config::input::analog_function,
"Right Analog Function",
"Right Analog Function",
"Configure what the right analog stick controls.",
nullptr,
config::category::input,
{
{ "c_stick_and_touchscreen", "C-Stick and Touchscreen Pointer" },
{ "touchscreen_pointer", "Touchscreen Pointer" },
{ "c_stick", "C-Stick" },
{ nullptr, nullptr }
},
"c_stick_and_touchscreen"
},
{
config::input::analog_deadzone,
"Analog Deadzone",
"Analog Deadzone",
"Set the deadzone percentage for analog input to reduce drift.",
nullptr,
config::category::input,
{
{ "0", "0%" }, { "5", "5%" }, { "10", "10%" }, { "15", "15%" },
{ "20", "20%" }, { "25", "25%" }, { "30", "30%" }, { "35", "35%" },
{ nullptr, nullptr }
},
"15"
},
{
config::input::enable_mouse_touchscreen,
"Mouse Touchscreen Support",
"Mouse Touchscreen",
"Enable mouse input for touchscreen interactions.",
nullptr,
config::category::input,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::input::enable_touch_touchscreen,
"Touch Device Support",
"Touch Support",
"Enable touch device input for touchscreen interactions.",
nullptr,
config::category::input,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::input::enable_touch_pointer_timeout,
"Touch Pointer Timeout",
"Touch Pointer Timeout",
"Whether or not the touchscreen pointer should disappear during inactivity.",
nullptr,
config::category::input,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::input::enable_motion,
"Gyroscope/Accelerometer Support",
"Motion Support",
"Enable gyroscope and accelerometer input for games that support motion controls.",
nullptr,
config::category::input,
{
{ config::enabled, "Enabled" },
{ config::disabled, "Disabled" },
{ nullptr, nullptr }
},
config::enabled
},
{
config::input::motion_sensitivity,
"Motion Sensitivity",
"Motion Sensitivity",
"Adjust sensitivity of motion controls (gyroscope/accelerometer).",
nullptr,
config::category::input,
{
{ "0.1", "10%" },
{ "0.25", "25%" },
{ "0.5", "50%" },
{ "0.75", "75%" },
{ "1.0", "100%" },
{ "1.25", "125%" },
{ "1.5", "150%" },
{ "2.0", "200%" },
{ nullptr, nullptr }
},
"1.0"
},
// Terminator
{ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, { { nullptr, nullptr } }, nullptr }
};
// clang-format on
static const retro_core_options_v2 options_v2 = {
const_cast<retro_core_option_v2_category*>(option_categories),
const_cast<retro_core_option_v2_definition*>(option_definitions)};
void RegisterCoreOptions(void) {
// Try v2 first, then fallback to v1 and v0 if needed
unsigned version = 0;
if (!LibRetro::GetCoreOptionsVersion(&version)) {
version = 0;
}
LOG_INFO(Frontend, "Frontend reports core options version: {}", version);
if (version >= 2) {
if (LibRetro::SetCoreOptionsV2(&options_v2)) {
LOG_INFO(Frontend, "V2 core options set successfully");
return;
}
}
LOG_WARNING(Frontend, "V2 core options not supported, trying V1");
// Count number of options
unsigned num_options = 0;
while (option_definitions[num_options].key != nullptr) {
num_options++;
}
if (version >= 1) {
// Create V1 options array
std::vector<retro_core_option_definition> options_v1(num_options + 1);
// Copy parameters from V2 to V1
for (unsigned i = 0; i < num_options; i++) {
const auto& v2_option = option_definitions[i];
auto& v1_option = options_v1[i];
v1_option.key = v2_option.key;
v1_option.desc = v2_option.desc;
v1_option.info = v2_option.info;
v1_option.default_value = v2_option.default_value;
std::memcpy(v1_option.values, v2_option.values, sizeof(v1_option.values));
}
// Null terminator
std::memset(&options_v1.back(), 0, sizeof(retro_core_option_definition));
if (LibRetro::SetCoreOptionsV1(options_v1.data())) {
LOG_INFO(Frontend, "V1 core options set successfully");
return;
}
}
LOG_WARNING(Frontend, "V1 core options not supported, trying V0");
// Create V0 variables array
std::vector<retro_variable> variables(num_options + 1);
std::vector<std::string> values_buffer(num_options);
for (unsigned i = 0; i < num_options; i++) {
const auto& option = option_definitions[i];
std::string desc = option.desc ? option.desc : "";
std::string default_value = option.default_value ? option.default_value : "";
values_buffer[i] = "";
if (!desc.empty()) {
// Count number of values
size_t num_values = 0;
size_t default_index = 0;
while (option.values[num_values].value != nullptr) {
if (!default_value.empty() &&
std::string(option.values[num_values].value) == default_value) {
default_index = num_values;
}
num_values++;
}
// Build values string: "Description; default_value|other_value1|other_value2"
if (num_values > 0) {
values_buffer[i] = desc + "; " + option.values[default_index].value;
// Add remaining values
for (size_t j = 0; j < num_values; j++) {
if (j != default_index) {
values_buffer[i] += "|" + std::string(option.values[j].value);
}
}
}
}
variables[i].key = option.key;
variables[i].value = values_buffer[i].c_str();
}
// Null terminator
std::memset(&variables.back(), 0, sizeof(retro_variable));
// Set V0 variables
if (LibRetro::SetVariables(variables.data())) {
LOG_INFO(Frontend, "V0 core options set successfully");
} else {
LOG_ERROR(Frontend, "Failed to set core options with any version");
}
}
static void ParseCpuOptions(void) {
Settings::values.use_cpu_jit =
LibRetro::FetchVariable(config::cpu::use_cpu_jit, config::enabled) == config::enabled;
#if defined(IOS)
if (!LibRetro::CanUseJIT())
Settings::values.use_cpu_jit = false;
#endif
auto cpu_clock = LibRetro::FetchVariable(config::cpu::cpu_clock_percentage, "100");
Settings::values.cpu_clock_percentage = std::stoi(cpu_clock);
}
static int GetRegionValue(const std::string& name) {
if (name == "Japan")
return 0;
if (name == "USA")
return 1;
if (name == "Europe")
return 2;
if (name == "Australia")
return 3;
if (name == "China")
return 4;
if (name == "Korea")
return 5;
if (name == "Taiwan")
return 6;
return -1; // Auto
}
static Service::CFG::SystemLanguage GetLanguageValue(const std::string& name) {
if (name == "Japanese")
return Service::CFG::LANGUAGE_JP;
if (name == "French")
return Service::CFG::LANGUAGE_FR;
if (name == "Spanish")
return Service::CFG::LANGUAGE_ES;
if (name == "German")
return Service::CFG::LANGUAGE_DE;
if (name == "Italian")
return Service::CFG::LANGUAGE_IT;
if (name == "Dutch")
return Service::CFG::LANGUAGE_NL;
if (name == "Portuguese")
return Service::CFG::LANGUAGE_PT;
if (name == "Russian")
return Service::CFG::LANGUAGE_RU;
if (name == "Korean")
return Service::CFG::LANGUAGE_KO;
if (name == "Traditional Chinese")
return Service::CFG::LANGUAGE_TW;
if (name == "Simplified Chinese")
return Service::CFG::LANGUAGE_ZH;
return Service::CFG::LANGUAGE_EN; // English default
}
static void ParseSystemOptions(void) {
Settings::values.is_new_3ds =
LibRetro::FetchVariable(config::system::is_new_3ds, "New 3DS") == "New 3DS";
Settings::values.region_value =
GetRegionValue(LibRetro::FetchVariable(config::system::region_value, "Auto"));
LibRetro::settings.language_value =
GetLanguageValue(LibRetro::FetchVariable(config::system::language_value, "English"));
}
static Settings::AudioEmulation GetAudioEmulation(const std::string& name) {
if (name == "lle")
return Settings::AudioEmulation::LLE;
if (name == "lle_multithread")
return Settings::AudioEmulation::LLEMultithreaded;
return Settings::AudioEmulation::HLE; // Default
}
static void ParseAudioOptions(void) {
Settings::values.audio_emulation =
GetAudioEmulation(LibRetro::FetchVariable(config::audio::audio_emulation, "hle"));
auto input_type = LibRetro::FetchVariable(config::audio::input_type, "auto");
if (input_type == "none") {
Settings::values.input_type = AudioCore::InputType::Null;
} else if (input_type == "static_noise") {
Settings::values.input_type = AudioCore::InputType::Static;
} else if (input_type == "frontend") {
Settings::values.input_type = AudioCore::InputType::LibRetro;
} else {
Settings::values.input_type = AudioCore::InputType::Auto;
}
}
static Settings::TextureFilter GetTextureFilter(const std::string& name) {
if (name == "Anime4K Ultrafast")
return Settings::TextureFilter::Anime4K;
if (name == "Bicubic")
return Settings::TextureFilter::Bicubic;
if (name == "ScaleForce")
return Settings::TextureFilter::ScaleForce;
if (name == "xBRZ freescale")
return Settings::TextureFilter::xBRZ;
if (name == "MMPX")
return Settings::TextureFilter::MMPX;
return Settings::TextureFilter::NoFilter;
}
static Settings::TextureSampling GetTextureSampling(const std::string& name) {
if (name == "NearestNeighbor")
return Settings::TextureSampling::NearestNeighbor;
if (name == "Linear")
return Settings::TextureSampling::Linear;
return Settings::TextureSampling::GameControlled;
}
static Settings::GraphicsAPI GetGraphicsAPI(const std::string& name) {
if (name == "Software")
return Settings::GraphicsAPI::Software;
#ifdef ENABLE_VULKAN
if (name == "Vulkan")
return Settings::GraphicsAPI::Vulkan;
#endif
#ifdef ENABLE_OPENGL
if (name == "OpenGL")
return Settings::GraphicsAPI::OpenGL;
#endif
// Auto selection
return LibRetro::GetPreferredRenderer();
}
static void ParseGraphicsOptions(void) {
Settings::values.graphics_api =
GetGraphicsAPI(LibRetro::FetchVariable(config::graphics::graphics_api, "auto"));
Settings::values.use_hw_shader = LibRetro::FetchVariable(config::graphics::use_hw_shader,
config::enabled) == config::enabled;
Settings::values.use_shader_jit = LibRetro::FetchVariable(config::graphics::use_shader_jit,
config::enabled) == config::enabled;
#if defined(IOS)
if (!LibRetro::CanUseJIT())
Settings::values.use_shader_jit = false;
#endif
Settings::values.shaders_accurate_mul =
LibRetro::FetchVariable(config::graphics::shaders_accurate_mul, config::enabled) ==
config::enabled;
Settings::values.use_disk_shader_cache =
LibRetro::FetchVariable(config::graphics::use_disk_shader_cache, config::enabled) ==
config::enabled;
auto resolution = LibRetro::FetchVariable(config::graphics::resolution_factor, "1");
Settings::values.resolution_factor = std::stoi(resolution);
Settings::values.texture_filter =
GetTextureFilter(LibRetro::FetchVariable(config::graphics::texture_filter, "none"));
Settings::values.texture_sampling = GetTextureSampling(
LibRetro::FetchVariable(config::graphics::texture_sampling, "GameControlled"));
Settings::values.custom_textures = LibRetro::FetchVariable(config::graphics::custom_textures,
config::disabled) == config::enabled;
Settings::values.dump_textures = LibRetro::FetchVariable(config::graphics::dump_textures,
config::disabled) == config::enabled;
}
static Settings::LayoutOption GetLayoutOption(const std::string& name) {
if (name == "single_screen" || name == "Single Screen Only")
return Settings::LayoutOption::SingleScreen;
if (name == "large_screen" || name == "Large Screen, Small Screen")
return Settings::LayoutOption::LargeScreen;
if (name == "side_by_side" || name == "Side by Side")
return Settings::LayoutOption::SideScreen;
return Settings::LayoutOption::Default;
}
static void ParseLayoutOptions(void) {
Settings::values.layout_option =
GetLayoutOption(LibRetro::FetchVariable(config::layout::layout_option, "default"));
Settings::values.swap_screen =
LibRetro::FetchVariable(config::layout::swap_screen, "Top") == "Bottom";
LibRetro::settings.swap_screen_mode =
LibRetro::FetchVariable(config::layout::swap_screen_mode, "Toggle");
auto large_screen_proportion =
LibRetro::FetchVariable(config::layout::large_screen_proportion, "4.00");
Settings::values.large_screen_proportion = std::stof(large_screen_proportion);
}
static void ParseStorageOptions(void) {
Settings::values.use_virtual_sd = LibRetro::FetchVariable(config::storage::use_virtual_sd,
config::enabled) == config::enabled;
// Configure the file storage location
auto use_libretro_saves = LibRetro::FetchVariable(config::storage::use_libretro_save_path,
"LibRetro Default") == "LibRetro Default";
if (use_libretro_saves) {
auto target_dir = LibRetro::GetSaveDir();
if (target_dir.empty()) {
LOG_INFO(Frontend, "No save dir provided; trying system dir...");
target_dir = LibRetro::GetSystemDir();
}
if (!target_dir.empty()) {
if (!target_dir.ends_with("/"))
target_dir += "/";
target_dir += "Azahar/";
// Ensure that this new dir exists
if (!FileUtil::CreateDir(target_dir)) {
LOG_ERROR(Frontend, "Failed to create \"{}\". Using Azahar's default paths.",
target_dir);
} else {
FileUtil::SetUserPath(target_dir);
const auto& target_dir_result = FileUtil::GetUserPath(FileUtil::UserPath::UserDir);
LOG_INFO(Frontend, "User dir set to \"{}\".", target_dir_result);
}
}
}
}
static LibRetro::CStickFunction GetAnalogFunction(const std::string& name) {
if (name == "c_stick" || name == "C-Stick")
return LibRetro::CStickFunction::CStick;
if (name == "touchscreen_pointer" || name == "Touchscreen Pointer")
return LibRetro::CStickFunction::Touchscreen;
return LibRetro::CStickFunction::Both; // Default
}
static void ParseInputOptions(void) {
LibRetro::settings.analog_function = GetAnalogFunction(
LibRetro::FetchVariable(config::input::analog_function, "c_stick_and_touchscreen"));
if (LibRetro::settings.analog_function != LibRetro::CStickFunction::Touchscreen) {
Settings::values.current_input_profile.analogs[1] = "axis:1,joystick:0,engine:libretro";
} else {
Settings::values.current_input_profile.analogs[1] = "";
}
auto analog_deadzone = LibRetro::FetchVariable(config::input::analog_deadzone, "15");
LibRetro::settings.analog_deadzone = static_cast<float>(std::stoi(analog_deadzone)) / 100.0f;
LibRetro::settings.enable_mouse_touchscreen =
LibRetro::FetchVariable(config::input::enable_mouse_touchscreen, config::enabled) ==
config::enabled;
LibRetro::settings.enable_touch_touchscreen =
LibRetro::FetchVariable(config::input::enable_touch_touchscreen, config::enabled) ==
config::enabled;
LibRetro::settings.enable_touch_pointer_timeout =
LibRetro::FetchVariable(config::input::enable_touch_pointer_timeout, config::enabled) ==
config::enabled;
LibRetro::settings.enable_motion =
LibRetro::FetchVariable(config::input::enable_motion, config::enabled) == config::enabled;
auto motion_sens = LibRetro::FetchVariable(config::input::motion_sensitivity, "1.0");
LibRetro::settings.motion_sensitivity = std::stof(motion_sens);
// Configure motion device based on user settings
if (LibRetro::settings.enable_motion) {
Settings::values.current_input_profile.motion_device =
"port:0,sensitivity:" + std::to_string(LibRetro::settings.motion_sensitivity) +
",engine:libretro";
} else {
Settings::values.current_input_profile.motion_device = "engine:motion_emu";
}
}
void ParseCoreOptions(void) {
// Override default values that aren't user-selectable and aren't correct for the core
Settings::values.enable_audio_stretching = false;
Settings::values.frame_limit = 0;
#if defined(USING_GLES)
Settings::values.use_gles = true;
#else
Settings::values.use_gles = false;
#endif
Settings::values.filter_mode = false;
ParseCpuOptions();
ParseSystemOptions();
ParseAudioOptions();
ParseGraphicsOptions();
ParseLayoutOptions();
ParseStorageOptions();
ParseInputOptions();
}
} // namespace LibRetro