diff --git a/CMakeLists.txt b/CMakeLists.txt index ca7a086ef..ec6d92f07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -450,7 +450,9 @@ target_sources(${PROJECT_NAME} PRIVATE core/cfg/cfg.h core/cfg/cl.cpp core/cfg/ini.cpp - core/cfg/ini.h) + core/cfg/ini.h + core/cfg/option.cpp + core/cfg/option.h) target_sources(${PROJECT_NAME} PRIVATE core/hw/aica/aica.cpp diff --git a/core/build.h b/core/build.h index f2d95348e..dcfd6132b 100755 --- a/core/build.h +++ b/core/build.h @@ -202,10 +202,6 @@ #define FEAT_DSPREC DYNAREC_NONE #endif -#if defined(TARGET_NO_COREIO_HTTP) -#define FEAT_HAS_COREIO_HTTP 0 -#endif - //defaults #ifndef FEAT_SHREC @@ -232,24 +228,10 @@ #endif #endif -#ifndef FEAT_HAS_COREIO_HTTP - #define FEAT_HAS_COREIO_HTTP 1 -#endif - #if HOST_CPU == CPU_X64 || HOST_CPU == CPU_ARM64 #define HOST_64BIT_CPU #endif -//Depricated build configs -#ifdef HOST_NO_REC -#error Dont use HOST_NO_REC -#endif - -#ifdef HOST_NO_AREC -#error Dont use HOST_NO_AREC -#endif - - // Compiler Related #ifndef _MSC_VER @@ -278,7 +260,7 @@ #define GD_CLOCK 33868800 //GDROM XTAL -- 768fs #define AICA_CORE_CLOCK (GD_CLOCK*4/3) //[45158400] GD->PLL 3:4 -> AICA CORE -- 1024fs -#define ADAC_CLOCK (AICA_CORE_CLOCK/2) //[11289600] 44100*256, AICA CORE -> PLL 4:1 -> ADAC -- 256fs +#define ADAC_CLOCK (AICA_CORE_CLOCK/4) //[11289600] 44100*256, AICA CORE -> PLL 4:1 -> ADAC -- 256fs #define AICA_ARM_CLOCK (AICA_CORE_CLOCK/2) //[22579200] AICA CORE -> PLL 2:1 -> ARM #define AICA_SDRAM_CLOCK (GD_CLOCK*2) //[67737600] GD-> PLL 2 -> SDRAM #define SH4_MAIN_CLOCK (200*1000*1000) //[200000000] XTal(13.5) -> PLL (33.3) -> PLL 1:6 (200) diff --git a/core/cfg/cfg.cpp b/core/cfg/cfg.cpp index c407f1119..0298a06eb 100644 --- a/core/cfg/cfg.cpp +++ b/core/cfg/cfg.cpp @@ -1,9 +1,3 @@ -/* - Config file crap - Supports various things, as virtual config entries and such crap - Works surprisingly well considering how old it is ... -*/ - #include "cfg.h" #include "ini.h" #include "stdclass.h" @@ -15,10 +9,8 @@ static bool save_config = true; static bool autoSave = true; static emucfg::ConfigFile cfgdb; -static std::string game_id; -static bool has_game_specific_config = false; -void savecfgf() +static void saveConfigFile() { FILE* cfgfile = nowide::fopen(cfgPath.c_str(), "wt"); if (!cfgfile) @@ -31,49 +23,13 @@ void savecfgf() std::fclose(cfgfile); } } -void cfgSaveStr(const char * Section, const char * Key, const char * String) +void cfgSaveStr(const std::string& section, const std::string& key, const std::string& string) { - const std::string section(Section); - const std::string key(Key); - const std::string value(String); - if (cfgHasGameSpecificConfig()) - { - if (cfgdb.get(section, key, "") == value) - // Same value as main config: delete entry - cfgdb.delete_entry(game_id, key); - else - cfgdb.set(game_id, key, value); - } - else - cfgdb.set(section, key, value); + cfgdb.set(section, key, string); if (save_config && autoSave) - savecfgf(); + saveConfigFile(); } -//New config code - -/* - I want config to be really flexible .. so , here is the new implementation : - - Functions : - cfgLoadInt : Load an int , if it does not exist save the default value to it and return it - cfgSaveInt : Save an int - cfgLoadStr : Load a str , if it does not exist save the default value to it and return it - cfgSaveStr : Save a str - cfgExists : Returns true if the Section:Key exists. If Key is null , it retuns true if Section exists - - Config parameters can be read from the config file , and can be given at the command line - -cfg section:key=value -> defines a value at command line - If a cfgSave* is made on a value defined by command line , then the command line value is replaced by it - - cfg values set by command line are not written to the cfg file , unless a cfgSave* is used -*/ - -/////////////////////////////// -/* -** This will verify there is a working file @ ./szIniFn -** - if not present, it will write defaults -*/ bool cfgOpen() { @@ -99,7 +55,7 @@ bool cfgOpen() { // Config file didn't exist INFO_LOG(COMMON, "Creating new empty config file at '%s'", cfgPath.c_str()); - savecfgf(); + saveConfigFile(); } else { @@ -111,105 +67,54 @@ bool cfgOpen() return true; } -//Implementations of the interface :) -//Section must be set -//If key is 0 , it looks for the section -//0 : not found -//1 : found section , key was 0 -//2 : found section & key -s32 cfgExists(const char * Section, const char * Key) +std::string cfgLoadStr(const std::string& section, const std::string& key, const std::string& def) { - if(cfgdb.has_entry(std::string(Section), std::string(Key))) - { - return 2; - } - else - { - return (cfgdb.has_section(std::string(Section)) ? 1 : 0); - } + return cfgdb.get(section, key, def); } -void cfgLoadStr(const char * Section, const char * Key, char * Return,const char* Default) +void cfgSaveInt(const std::string& section, const std::string& key, s32 value) { - std::string value = cfgdb.get(Section, Key, Default); - // FIXME: Buffer overflow possible - strcpy(Return, value.c_str()); + cfgSaveStr(section, key, std::to_string(value)); } -std::string cfgLoadStr(const char * Section, const char * Key, const char* Default) +s32 cfgLoadInt(const std::string& section, const std::string& key, s32 def) { - std::string v = cfgdb.get(std::string(Section), std::string(Key), std::string(Default)); - if (cfgHasGameSpecificConfig()) - v = cfgdb.get(game_id, std::string(Key), v); - - return v; + return cfgdb.get_int(section, key, def); } -//These are helpers , mainly :) -void cfgSaveInt(const char * Section, const char * Key, s32 Int) +void cfgSaveBool(const std::string& section, const std::string& key, bool value) { - char str[32]; - sprintf(str, "%d", Int); - cfgSaveStr(Section, Key, str); + cfgSaveStr(section, key, value ? "yes" : "no"); } -s32 cfgLoadInt(const char * Section, const char * Key,s32 Default) +bool cfgLoadBool(const std::string& section, const std::string& key, bool def) { - s32 v = cfgdb.get_int(std::string(Section), std::string(Key), Default); - if (cfgHasGameSpecificConfig()) - v = cfgdb.get_int(game_id, std::string(Key), v); - - return v; + return cfgdb.get_bool(section, key, def); } -void cfgSaveBool(const char * Section, const char * Key, bool BoolValue) +void cfgSetVirtual(const std::string& section, const std::string& key, const std::string& value) { - cfgSaveStr(Section, Key, BoolValue ? "yes" : "no"); + cfgdb.set(section, key, value, true); } -bool cfgLoadBool(const char * Section, const char * Key,bool Default) +bool cfgIsVirtual(const std::string& section, const std::string& key) { - bool v = cfgdb.get_bool(std::string(Section), std::string(Key), Default); - if (cfgHasGameSpecificConfig()) - v = cfgdb.get_bool(game_id, std::string(Key), v); - - return v; + return cfgdb.is_virtual(section, key); } -void cfgSetVirtual(const char * Section, const char * Key, const char * String) +bool cfgHasSection(const std::string& section) { - cfgdb.set(std::string(Section), std::string(Key), std::string(String), true); + return cfgdb.has_section(section); } -void cfgSetGameId(const char *id) +void cfgDeleteSection(const std::string& section) { - game_id = id; -} - -const char *cfgGetGameId() -{ - return game_id.c_str(); -} - -bool cfgHasGameSpecificConfig() -{ - return has_game_specific_config || cfgdb.has_section(game_id); -} - -void cfgMakeGameSpecificConfig() -{ - has_game_specific_config = true; -} - -void cfgDeleteGameSpecificConfig() -{ - has_game_specific_config = false; - cfgdb.delete_section(game_id); + cfgdb.delete_section(section); } void cfgSetAutoSave(bool autoSave) { ::autoSave = autoSave; if (autoSave) - savecfgf(); + saveConfigFile(); } diff --git a/core/cfg/cfg.h b/core/cfg/cfg.h index ccb4ea72f..89ab53a58 100644 --- a/core/cfg/cfg.h +++ b/core/cfg/cfg.h @@ -1,29 +1,19 @@ #pragma once #include "types.h" -/* -** cfg* prototypes, if you pass NULL to a cfgSave* it will wipe out the section -** } if you pass it to lpKey it will wipe out that particular entry -** } if you add write to something it will create it if its not present -** } ** Strings passed to LoadStr should be MAX_PATH in size ! ** -*/ bool cfgOpen(); -s32 cfgLoadInt(const char * lpSection, const char * lpKey,s32 Default); -void cfgSaveInt(const char * lpSection, const char * lpKey, s32 Int); -void cfgLoadStr(const char * lpSection, const char * lpKey, char * lpReturn,const char* lpDefault); -std::string cfgLoadStr(const char * Section, const char * Key, const char* Default); -void cfgSaveStr(const char * lpSection, const char * lpKey, const char * lpString); -void cfgSaveBool(const char * Section, const char * Key, bool BoolValue); -bool cfgLoadBool(const char * Section, const char * Key,bool Default); -s32 cfgExists(const char * Section, const char * Key); -void cfgSetVirtual(const char * lpSection, const char * lpKey, const char * lpString); +s32 cfgLoadInt(const std::string& section, const std::string& key, s32 def); +void cfgSaveInt(const std::string& section, const std::string& key, s32 value); +std::string cfgLoadStr(const std::string& section, const std::string& key, const std::string& def); +void cfgSaveStr(const std::string& section, const std::string& key, const std::string& value); +void cfgSaveBool(const std::string& section, const std::string& key, bool value); +bool cfgLoadBool(const std::string& section, const std::string& key, bool def); +void cfgSetVirtual(const std::string& section, const std::string& key, const std::string& value); +bool cfgIsVirtual(const std::string& section, const std::string& key); -bool ParseCommandLine(int argc,char* argv[]); +bool ParseCommandLine(int argc, char *argv[]); -void cfgSetGameId(const char *id); -const char *cfgGetGameId(); -bool cfgHasGameSpecificConfig(); -void cfgMakeGameSpecificConfig(); -void cfgDeleteGameSpecificConfig(); void cfgSetAutoSave(bool autoSave); +bool cfgHasSection(const std::string& section); +void cfgDeleteSection(const std::string& section); diff --git a/core/cfg/ini.cpp b/core/cfg/ini.cpp index 507b5b9a2..16c36493e 100644 --- a/core/cfg/ini.cpp +++ b/core/cfg/ini.cpp @@ -299,5 +299,13 @@ void ConfigFile::delete_entry(const std::string& section_name, const std::string section->delete_entry(entry_name); } +bool ConfigFile::is_virtual(const std::string& section_name, const std::string& entry_name) +{ + ConfigSection *section = get_section(section_name, true); + if (section == nullptr) + return false; + return section->has_entry(entry_name); +} + } // namespace emucfg diff --git a/core/cfg/ini.h b/core/cfg/ini.h index e9951723d..763b75112 100644 --- a/core/cfg/ini.h +++ b/core/cfg/ini.h @@ -31,6 +31,7 @@ struct ConfigFile { public: bool has_section(const std::string& name); bool has_entry(const std::string& section_name, const std::string& entry_name); + bool is_virtual(const std::string& section_name, const std::string& entry_name); void parse(FILE* fd); void save(FILE* fd); diff --git a/core/cfg/option.cpp b/core/cfg/option.cpp new file mode 100644 index 000000000..5c4827342 --- /dev/null +++ b/core/cfg/option.cpp @@ -0,0 +1,141 @@ +/* + Copyright 2021 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "option.h" + +namespace config { + +// Dynarec + +Option DynarecEnabled("Dynarec.Enabled", true); +Option DynarecIdleSkip("Dynarec.idleskip", true); +Option DynarecUnstableOpt("Dynarec.unstable-opt"); +Option DynarecSafeMode("Dynarec.safe-mode"); +Option DisableVmem32("Dynarec.DisableVmem32"); + +// General + +Option Cable("Dreamcast.Cable", 3); // TV Composite +Option Region("Dreamcast.Region", 1); // USA +Option Broadcast("Dreamcast.Broadcast", 0); // NTSC +Option Language("Dreamcast.Language", 1); // English +Option FullMMU("Dreamcast.FullMMU"); +Option ForceWindowsCE("Dreamcast.ForceWindowsCE"); +Option AutoSavestate("Dreamcast.AutoSavestate"); + +// Sound + +Option LimitFPS("aica.LimitFPS", true); +Option DSPEnabled("aica.DSPEnabled", false); +Option DisableSound("aica.NoSound"); +#if HOST_CPU == CPU_ARM +Option AudioBufferSize("aica.BufferSize", 5644); // 128 ms +#else +Option AudioBufferSize("aica.BufferSize", 2822); // 64 ms +#endif + +OptionString AudioBackend("backend", "auto", "audio"); + +// Rendering + +RendererOption RendererType; +Option UseMipmaps("rend.UseMipmaps", true); +Option Widescreen("rend.WideScreen"); +Option ShowFPS("rend.ShowFPS"); +Option RenderToTextureBuffer("rend.RenderToTextureBuffer"); +Option RenderToTextureUpscale("rend.RenderToTextureUpscale", 1); +Option TranslucentPolygonDepthMask("rend.TranslucentPolygonDepthMask"); +Option ModifierVolumes("rend.ModifierVolumes", true); +Option Clipping("rend.Clipping", true); +Option TextureUpscale("rend.TextureUpscale", 1); +Option MaxFilteredTextureSize("rend.MaxFilteredTextureSize", 256); +Option ExtraDepthScale("rend.ExtraDepthScale", 1.f); +Option CustomTextures("rend.CustomTextures"); +Option DumpTextures("rend.DumpTextures"); +Option ScreenScaling("rend.ScreenScaling", 100); +Option ScreenStretching("rend.ScreenStretching", 100); +Option Fog("rend.Fog", true); +Option FloatVMUs("rend.FloatVMUs"); +Option Rotate90("rend.Rotate90"); +Option PerStripSorting("rend.PerStripSorting"); +Option DelayFrameSwapping("rend.DelayFrameSwapping"); +Option WidescreenGameHacks("rend.WidescreenGameHacks"); +std::array, 4> CrosshairColor { + Option("rend.CrossHairColor1"), + Option("rend.CrossHairColor2"), + Option("rend.CrossHairColor3"), + Option("rend.CrossHairColor4"), +}; +Option SkipFrame("ta.skip"); +Option MaxThreads("pvr.MaxThreads", 3); +Option AutoSkipFrame("pvr.AutoSkipFrame", 0); + +// Misc + +Option SerialConsole("Debug.SerialConsoleEnabled"); +Option SerialPTY("Debug.SerialPTY"); +Option UseReios("UseReios"); + +Option OpenGlChecks("OpenGlChecks", false, "validate"); + +Option, false> ContentPath("Dreamcast.ContentPath"); +Option HideLegacyNaomiRoms("Dreamcast.HideLegacyNaomiRoms", true); + +// Network + +Option NetworkEnable("Enable", false, "network"); +Option ActAsServer("ActAsServer", false, "network"); +OptionString DNS("DNS", "46.101.91.123", "network"); +OptionString NetworkServer("server", "", "network"); +Option EmulateBBA("EmulateBBA", false, "network"); + +#ifdef SUPPORT_DISPMANX +Option DispmanxMaintainAspect("maintain_aspect", true, "dispmanx"); +#endif + +#ifdef USE_OMX +Option OmxAudioLatency("audio_latency", 100, "omx"); +Option OmxAudioHdmi("audio_hdmi", true, "omx"); +#endif + +// Maple + +Option MouseSensitivity("MouseSensitivity", 100, "input"); +Option VirtualGamepadVibration("VirtualGamepadVibration", 20, "input"); + +std::array, 4> MapleMainDevices { + Option("device1", MDT_SegaController, "input"), + Option("device2", MDT_None, "input"), + Option("device3", MDT_None, "input"), + Option("device4", MDT_None, "input"), +}; +std::array, 2>, 4> MapleExpansionDevices { + Option("device1.1", MDT_SegaVMU, "input"), + Option("device1.2", MDT_SegaVMU, "input"), + + Option("device2.1", MDT_None, "input"), + Option("device2.2", MDT_None, "input"), + + Option("device3.1", MDT_None, "input"), + Option("device3.2", MDT_None, "input"), + + Option("device4.1", MDT_None, "input"), + Option("device4.2", MDT_None, "input"), +}; + +} // namespace config diff --git a/core/cfg/option.h b/core/cfg/option.h new file mode 100644 index 000000000..030b1e058 --- /dev/null +++ b/core/cfg/option.h @@ -0,0 +1,402 @@ +/* + Copyright 2021 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#pragma once +#include +#include +#include +#include "cfg.h" +#include "hw/maple/maple_cfg.h" + +extern int renderer_changed; + +namespace config { + +class BaseOption { +public: + virtual ~BaseOption() {} + virtual void save() const = 0; + virtual void load() = 0; + virtual void reset() = 0; +}; + +class Settings { +public: + void reset() { + for (const auto& o : options) + o->reset(); + gameId.clear(); + perGameConfig = false; + } + + void load(bool gameSpecific) { + if (gameSpecific) + { + if (gameId.empty()) + return; + if (!cfgHasSection(gameId)) + return; + perGameConfig = true; + } + for (const auto& o : options) + o->load(); + } + + void save() { + cfgSetAutoSave(false); + for (const auto& o : options) + o->save(); + cfgSetAutoSave(true); + } + + const std::string& getGameId() const { + return gameId; + } + + void setGameId(const std::string& gameId) { + this->gameId = gameId; + } + + bool hasPerGameConfig() const { + return perGameConfig; + } + void setPerGameConfig(bool perGameConfig) { + this->perGameConfig = perGameConfig; + if (!perGameConfig) { + if (!gameId.empty()) + cfgDeleteSection(gameId); + reset(); + } + } + + static Settings& instance() { + static Settings *_instance = new Settings(); + return *_instance; + } + +private: + std::vector options; + std::string gameId; + bool perGameConfig = false; + + template + friend class Option; +}; + +// Missing in C++11 +template +using enable_if_t = typename std::enable_if::type; + +template +class Option : public BaseOption { +public: + Option(const std::string& name, T defaultValue = T(), const std::string& section = "config") + : section(section), name(name), value(defaultValue), defaultValue(defaultValue), + settings(Settings::instance()) + { + settings.options.push_back(this); + } + + virtual void reset() override { + value = defaultValue; + overridden = false; + } + + virtual void load() override { + if (PerGameOption && settings.hasPerGameConfig()) + set(doLoad(settings.getGameId(), section + "." + name)); + else + { + set(doLoad(section, name)); + if (cfgIsVirtual(section, name)) + override(value); + } + } + + virtual void save() const override + { + if (overridden) { + if (value == overriddenDefault) + return; + if (!settings.hasPerGameConfig()) + // overridden options can only be saved in per-game settings + return; + } + else if (PerGameOption && settings.hasPerGameConfig()) + { + if (value == doLoad(section, name)) + return; + } + if (PerGameOption && settings.hasPerGameConfig()) + doSave(settings.getGameId(), section + "." + name); + else + doSave(section, name); + } + + T& get() { return value; } + void set(T v) { value = v; } + + void override(T v) { + verify(PerGameOption); + overriddenDefault = v; + overridden = true; + value = v; + } + bool isReadOnly() const { + return overridden && !settings.hasPerGameConfig(); + } + + explicit operator T() const { return value; } + operator T&() { return value; } + T& operator=(const T& v) { set(v); return value; } + +protected: + template + enable_if_t::value, T> + doLoad(const std::string& section, const std::string& name) const + { + return cfgLoadBool(section, name, value); + } + + template + enable_if_t<(std::is_integral::value || std::is_enum::value) + && !std::is_same::value, T> + doLoad(const std::string& section, const std::string& name) const + { + return (T)cfgLoadInt(section, name, (int)value); + } + + template + enable_if_t::value, T> + doLoad(const std::string& section, const std::string& name) const + { + return cfgLoadStr(section, name, value); + } + + template + enable_if_t::value, T> + doLoad(const std::string& section, const std::string& name) const + { + std::string strValue = cfgLoadStr(section, name, ""); + if (strValue.empty()) + return value; + else + return atof(strValue.c_str()); + } + + template + enable_if_t, U>::value, T> + doLoad(const std::string& section, const std::string& name) const + { + std::string paths = cfgLoadStr(section, name, ""); + if (paths.empty()) + return value; + std::string::size_type start = 0; + std::vector newValue; + while (true) + { + std::string::size_type end = paths.find(';', start); + if (end == std::string::npos) + end = paths.size(); + if (start != end) + newValue.push_back(paths.substr(start, end - start)); + if (end == paths.size()) + break; + start = end + 1; + } + return newValue; + } + + template + enable_if_t::value> + doSave(const std::string& section, const std::string& name) const + { + cfgSaveBool(section, name, value); + } + + template + enable_if_t<(std::is_integral::value || std::is_enum::value) + && !std::is_same::value> + doSave(const std::string& section, const std::string& name) const + { + cfgSaveInt(section, name, (int)value); + } + + template + enable_if_t::value> + doSave(const std::string& section, const std::string& name) const + { + cfgSaveStr(section, name, value); + } + + template + enable_if_t::value> + doSave(const std::string& section, const std::string& name) const + { + char buf[64]; + snprintf(buf, sizeof(buf), "%f", value); + cfgSaveStr(section, name, buf); + } + + template + enable_if_t, U>::value> + doSave(const std::string& section, const std::string& name) const + { + std::string s; + for (auto& v : value) + { + if (s.empty()) + s = v; + else + s += ";" + v; + } + cfgSaveStr(section, name, s); + } + + std::string section; + std::string name; + T value; + T defaultValue; + T overriddenDefault = T(); + bool overridden = false; + Settings& settings; +}; + +using OptionString = Option; + +// Dynarec + +extern Option DynarecEnabled; +extern Option DynarecIdleSkip; +extern Option DynarecUnstableOpt; +extern Option DynarecSafeMode; +extern Option DisableVmem32; + +// General + +extern Option Cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV Composite +extern Option Region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default +extern Option Broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default +extern Option Language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default +extern Option FullMMU; +extern Option ForceWindowsCE; +extern Option AutoSavestate; + +// Sound + +extern Option LimitFPS; +extern Option DSPEnabled; +extern Option DisableSound; +extern Option AudioBufferSize; //In samples ,*4 for bytes (1024) + +extern OptionString AudioBackend; + +// Rendering + +class RendererOption : public Option { +public: + RendererOption() + : Option("pvr.rend", RenderType::OpenGL) {} + + bool isOpenGL() const { + return value == RenderType::OpenGL || value == RenderType::OpenGL_OIT; + } + RenderType& operator=(const RenderType& v) { set(v); return value; } + + virtual void load() override { + RenderType current = value; + Option::load(); + if (current != value) { + ::renderer_changed = (int)value; + value = current; + } + } + + virtual void reset() override { + RenderType current = value; + Option::reset(); + if (current != value) { + ::renderer_changed = (int)value; + value = current; + } + } +}; +extern RendererOption RendererType; +extern Option UseMipmaps; +extern Option Widescreen; +extern Option ShowFPS; +extern Option RenderToTextureBuffer; +extern Option RenderToTextureUpscale; +extern Option TranslucentPolygonDepthMask; +extern Option ModifierVolumes; +extern Option Clipping; +extern Option TextureUpscale; +extern Option MaxFilteredTextureSize; +extern Option ExtraDepthScale; +extern Option CustomTextures; +extern Option DumpTextures; +extern Option ScreenScaling; // in percent. 50 means half the native resolution +extern Option ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3 +extern Option Fog; +extern Option FloatVMUs; +extern Option Rotate90; +extern Option PerStripSorting; +extern Option DelayFrameSwapping; // Delay swapping frame until FB_R_SOF matches FB_W_SOF +extern Option WidescreenGameHacks; +extern std::array, 4> CrosshairColor; +extern Option SkipFrame; +extern Option MaxThreads; +extern Option AutoSkipFrame; // 0: none, 1: some, 2: more + +// Misc + +extern Option SerialConsole; +extern Option SerialPTY; +extern Option UseReios; + +extern Option OpenGlChecks; + +extern Option, false> ContentPath; +extern Option HideLegacyNaomiRoms; + +// Network + +extern Option NetworkEnable; +extern Option ActAsServer; +extern OptionString DNS; +extern OptionString NetworkServer; +extern Option EmulateBBA; + +#ifdef SUPPORT_DISPMANX +extern Option DispmanxMaintainAspect; +#endif + +#ifdef USE_OMX +extern Option OmxAudioLatency; +extern Option OmxAudioHdmi; +#endif + +// Maple + +extern Option MouseSensitivity; +extern Option VirtualGamepadVibration; +extern std::array, 4> MapleMainDevices; +extern std::array, 2>, 4> MapleExpansionDevices; + +} // namespace config + diff --git a/core/cheats.cpp b/core/cheats.cpp index 242aebdb2..c415fd8e1 100644 --- a/core/cheats.cpp +++ b/core/cheats.cpp @@ -234,8 +234,8 @@ const Cheat CheatManager::_widescreen_cheats[] = { "T9103M ", nullptr, { 0x25C714, 0x25C744, 0 }, { 0x43F00000, 0x3F400000 } }, // Sorcerian - Shichisei Mahou no Shito { "T1401D 50", nullptr, { 0x2D6138, 0 }, { 0x3F400000 } }, // Soul Calibur (PAL) { "T1401N ", nullptr, { 0x266C28, 0 }, { 0x3F400000 } }, // Soul Calibur (USA) - { "T36802N ", nullptr, { 0x129FA0, 0x12A9BC, 0x1C9FDC, 0 }, - { 0x3EF00000, 0x3EF00000, 0x000000F0 } }, // Soul Reaver (PAL) Code 2 is a Render Fix + { "T36802N ", " E ", { 0x129FA0, 0x12A9BC, 0x1C9FDC, 0 }, + { 0x3EF55555, 0x3EF55555, 0x000000F0 } }, // Soul Reaver (PAL) Code 2 is a Render Fix { "HDR-0190 ", nullptr, { 0x14D3E0, 0 }, { 0x3F400000 } }, // Space Channel 5 Part 2 (JP) { "T1216M ", nullptr, { 0x017C38, 0x17F00, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.003 (JP) { "T1216N ", nullptr, { 0x017C58, 0x17F20, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (US) @@ -305,7 +305,7 @@ CheatManager cheatManager; bool CheatManager::Reset() { _widescreen_cheat = nullptr; - if (!settings.rend.WidescreenGameHacks) + if (!config::WidescreenGameHacks) return false; if (settings.platform.system == DC_PLATFORM_DREAMCAST) { diff --git a/core/dispframe.cpp b/core/dispframe.cpp index 61910e225..ef767517a 100755 --- a/core/dispframe.cpp +++ b/core/dispframe.cpp @@ -24,7 +24,8 @@ void *dc_run(void*) rend_set_fb_scale(1.0, 1.0); char frame_path[512]; - cfgLoadStr("config", "image", frame_path, "null"); + std::string s = cfgLoadStr("config", "image", "null"); + strcpy(frame_path, s.c_str()); printf("Loading %s\n", frame_path); diff --git a/core/emulator.h b/core/emulator.h index 228abf39a..436c79d4a 100644 --- a/core/emulator.h +++ b/core/emulator.h @@ -23,8 +23,7 @@ #include #include -void InitSettings(); -void LoadSettings(bool game_specific); +void LoadGameSpecificSettings(); void SaveSettings(); extern std::atomic loading_canceled; @@ -35,6 +34,7 @@ void dc_init(); void* dc_run(void*); void dc_term(); void dc_stop(); +void dc_term_game(); void dc_request_reset(); void dc_exit(); void dc_resume(); diff --git a/core/hw/aica/aica.cpp b/core/hw/aica/aica.cpp index 6ba1e857d..ac40b7c15 100644 --- a/core/hw/aica/aica.cpp +++ b/core/hw/aica/aica.cpp @@ -89,7 +89,7 @@ const int AICA_TICK = 145125; // 44.1 KHz / 32 static int AicaUpdate(int tag, int c, int j) { arm_Run(32); - if (!settings.aica.NoBatch && !settings.aica.DSPEnabled) + if (!settings.aica.NoBatch) AICA_Sample32(); return AICA_TICK; @@ -105,7 +105,7 @@ void libAICA_TimeStep() SCIPD->SAMPLE_DONE = 1; MCIPD->SAMPLE_DONE = 1; - if (settings.aica.NoBatch || settings.aica.DSPEnabled) + if (settings.aica.NoBatch) AICA_Sample(); //Make sure sh4/arm interrupt system is up to date :) diff --git a/core/hw/aica/sgc_if.cpp b/core/hw/aica/sgc_if.cpp index c47421d32..d85bcb224 100755 --- a/core/hw/aica/sgc_if.cpp +++ b/core/hw/aica/sgc_if.cpp @@ -25,6 +25,7 @@ #include "dsp.h" #include "oslib/audiostream.h" #include "hw/gdrom/gdrom_if.h" +#include "cfg/option.h" #include #include @@ -532,7 +533,7 @@ struct ChannelEx Step(oLeft, oRight, oDsp); *VolMix.DSPOut += oDsp; - if (oLeft + oRight == 0 && !settings.aica.DSPEnabled) + if (oLeft + oRight == 0 && !config::DSPEnabled) oLeft = oRight = oDsp >> 4; mixl+=oLeft; @@ -1406,15 +1407,12 @@ void AICA_Sample32() //Add CDDA / DSP effect(s) //CDDA - if (settings.aica.CDDAMute==0) - { - VOLPAN(EXTS0L,dsp_out_vol[16].EFSDL,dsp_out_vol[16].EFPAN,mixl,mixr); - VOLPAN(EXTS0R,dsp_out_vol[17].EFSDL,dsp_out_vol[17].EFPAN,mixl,mixr); - } + VOLPAN(EXTS0L, dsp_out_vol[16].EFSDL, dsp_out_vol[16].EFPAN, mixl, mixr); + VOLPAN(EXTS0R, dsp_out_vol[17].EFSDL, dsp_out_vol[17].EFPAN, mixl, mixr); /* no dsp for now -- needs special handling of oDSP for ch paraller version ... - if (settings.aica.DSPEnabled) + if (config::DSPEnabled) { dsp_step(); @@ -1460,7 +1458,7 @@ void AICA_Sample32() clip16(mixl); clip16(mixr); - if (!fast_forward_mode && !settings.aica.NoSound) + if (!fast_forward_mode && !config::DisableSound) WriteSample(mixr,mixl); } } @@ -1490,20 +1488,13 @@ void AICA_Sample() //Add CDDA / DSP effect(s) //CDDA - if (settings.aica.CDDAMute==0) - { - VOLPAN(EXTS0L,dsp_out_vol[16].EFSDL,dsp_out_vol[16].EFPAN,mixl,mixr); - VOLPAN(EXTS0R,dsp_out_vol[17].EFSDL,dsp_out_vol[17].EFPAN,mixl,mixr); + VOLPAN(EXTS0L, dsp_out_vol[16].EFSDL, dsp_out_vol[16].EFPAN, mixl, mixr); + VOLPAN(EXTS0R, dsp_out_vol[17].EFSDL, dsp_out_vol[17].EFPAN, mixl, mixr); - DSPData->EXTS[0] = EXTS0L; - DSPData->EXTS[1] = EXTS0R; - } - else - { - DSPData->EXTS[0] = 0; - DSPData->EXTS[1] = 0; - } - if (settings.aica.DSPEnabled) + DSPData->EXTS[0] = EXTS0L; + DSPData->EXTS[1] = EXTS0R; + + if (config::DSPEnabled) { dsp_step(); @@ -1511,7 +1502,7 @@ void AICA_Sample() VOLPAN(*(s16*)&DSPData->EFREG[i], dsp_out_vol[i].EFSDL, dsp_out_vol[i].EFPAN, mixl, mixr); } - if (fast_forward_mode || settings.aica.NoSound) + if (fast_forward_mode || config::DisableSound) return; //Mono ! diff --git a/core/hw/holly/sb.cpp b/core/hw/holly/sb.cpp index 6b0e6e4ff..914993303 100644 --- a/core/hw/holly/sb.cpp +++ b/core/hw/holly/sb.cpp @@ -13,6 +13,7 @@ #include "hw/pvr/pvr_sb_regs.h" #include "emulator.h" #include "hw/bba/bba.h" +#include "cfg/option.h" std::array sb_regs; @@ -581,7 +582,7 @@ void sb_Init() maple_Init(); aica_sb_Init(); - if (settings.network.EmulateBBA) + if (config::EmulateBBA) bba_Init(); else ModemInit(); @@ -598,7 +599,7 @@ void sb_Reset(bool hard) SB_FFST_rc = 0; SB_FFST = 0; - if (settings.network.EmulateBBA) + if (config::EmulateBBA) bba_Reset(hard); else ModemTerm(); @@ -615,7 +616,7 @@ void sb_Reset(bool hard) void sb_Term() { - if (settings.network.EmulateBBA) + if (config::EmulateBBA) bba_Term(); else ModemTerm(); diff --git a/core/hw/holly/sb_mem.cpp b/core/hw/holly/sb_mem.cpp index 11ee1c229..d60751c46 100644 --- a/core/hw/holly/sb_mem.cpp +++ b/core/hw/holly/sb_mem.cpp @@ -15,6 +15,7 @@ #include "hw/sh4/sh4_mem.h" #include "reios/reios.h" #include "hw/bba/bba.h" +#include "cfg/option.h" MemChip *sys_rom; MemChip *sys_nvmem; @@ -110,20 +111,20 @@ void FixUpFlash() static_cast(sys_nvmem)->Validate(); // overwrite factory flash settings - if (settings.dreamcast.region <= 2) + if (config::Region <= 2) { - sys_nvmem->data[0x1a002] = '0' + settings.dreamcast.region; - sys_nvmem->data[0x1a0a2] = '0' + settings.dreamcast.region; + sys_nvmem->data[0x1a002] = '0' + config::Region; + sys_nvmem->data[0x1a0a2] = '0' + config::Region; } - if (settings.dreamcast.language <= 5) + if (config::Language <= 5) { - sys_nvmem->data[0x1a003] = '0' + settings.dreamcast.language; - sys_nvmem->data[0x1a0a3] = '0' + settings.dreamcast.language; + sys_nvmem->data[0x1a003] = '0' + config::Language; + sys_nvmem->data[0x1a0a3] = '0' + config::Language; } - if (settings.dreamcast.broadcast <= 3) + if (config::Broadcast <= 3) { - sys_nvmem->data[0x1a004] = '0' + settings.dreamcast.broadcast; - sys_nvmem->data[0x1a0a4] = '0' + settings.dreamcast.broadcast; + sys_nvmem->data[0x1a004] = '0' + config::Broadcast; + sys_nvmem->data[0x1a0a4] = '0' + config::Broadcast; } // overwrite user settings @@ -143,8 +144,8 @@ void FixUpFlash() u32 now = GetRTC_now(); syscfg.time_lo = now & 0xffff; syscfg.time_hi = now >> 16; - if (settings.dreamcast.language <= 5) - syscfg.lang = settings.dreamcast.language; + if (config::Language <= 5) + syscfg.lang = config::Language; if (static_cast(sys_nvmem)->WriteBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg) != 1) WARN_LOG(FLASHROM, "Failed to save time and language to flash RAM"); @@ -208,7 +209,7 @@ void SaveRomFiles() bool LoadHle() { if (!nvmem_load()) - WARN_LOG(FLASHROM, "No nvmem loaded\n"); + WARN_LOG(FLASHROM, "No nvmem loaded"); reios_reset(sys_rom->data); @@ -313,7 +314,7 @@ T DYNACALL ReadMem_area0(u32 addr) { if (settings.platform.system != DC_PLATFORM_DREAMCAST) return (T)libExtDevice_ReadMem_A0_006(addr, sz); - else if (!settings.network.EmulateBBA) + else if (!config::EmulateBBA) return (T)ModemReadMem_A0_006(addr, sz); else return (T)0; @@ -344,7 +345,7 @@ T DYNACALL ReadMem_area0(u32 addr) { if (settings.platform.system == DC_PLATFORM_NAOMI) return (T)libExtDevice_ReadMem_A0_010(addr, sz); - else if (settings.network.EmulateBBA) + else if (config::EmulateBBA) return (T)bba_ReadMem(addr, sz); else return (T)0; @@ -404,7 +405,7 @@ void DYNACALL WriteMem_area0(u32 addr,T data) { if (settings.platform.system != DC_PLATFORM_DREAMCAST) libExtDevice_WriteMem_A0_006(addr, data, sz); - else if (!settings.network.EmulateBBA) + else if (!config::EmulateBBA) ModemWriteMem_A0_006(addr, data, sz); } //map 0x0060 to 0x006F @@ -432,7 +433,7 @@ void DYNACALL WriteMem_area0(u32 addr,T data) { if (settings.platform.system == DC_PLATFORM_NAOMI) libExtDevice_WriteMem_A0_010(addr, data, sz); - else if (settings.network.EmulateBBA) + else if (config::EmulateBBA) bba_WriteMem(addr, data, sz); } else diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index fcf015b86..9d693bb2b 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -3,6 +3,7 @@ #include "maple_if.h" #include "hw/naomi/naomi_cart.h" #include "input/gamepad_device.h" +#include "cfg/option.h" static u8 GetBtFromSgn(s8 val) { @@ -242,14 +243,14 @@ void mcfg_CreateDevices() { for (int bus = 0; bus < MAPLE_PORTS; ++bus) { - switch ((MapleDeviceType)settings.input.maple_devices[bus]) + switch (config::MapleMainDevices[bus]) { case MDT_SegaController: mcfg_Create(MDT_SegaController, bus, 5); - if (settings.input.maple_expansion_devices[bus][0] != MDT_None) - mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0); - if (settings.input.maple_expansion_devices[bus][1] != MDT_None) - mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][1], bus, 1); + if (config::MapleExpansionDevices[bus][0] != MDT_None) + mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); + if (config::MapleExpansionDevices[bus][1] != MDT_None) + mcfg_Create(config::MapleExpansionDevices[bus][1], bus, 1); break; case MDT_Keyboard: @@ -262,27 +263,27 @@ void mcfg_CreateDevices() case MDT_LightGun: mcfg_Create(MDT_LightGun, bus, 5); - if (settings.input.maple_expansion_devices[bus][0] != MDT_None) - mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0); + if (config::MapleExpansionDevices[bus][0] != MDT_None) + mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); break; case MDT_TwinStick: mcfg_Create(MDT_TwinStick, bus, 5); - if (settings.input.maple_expansion_devices[bus][0] != MDT_None) - mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0); + if (config::MapleExpansionDevices[bus][0] != MDT_None) + mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); break; case MDT_AsciiStick: mcfg_Create(MDT_AsciiStick, bus, 5); - if (settings.input.maple_expansion_devices[bus][0] != MDT_None) - mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0); + if (config::MapleExpansionDevices[bus][0] != MDT_None) + mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); break; case MDT_None: break; default: - WARN_LOG(MAPLE, "Invalid device type %d for port %d", settings.input.maple_devices[bus], bus); + WARN_LOG(MAPLE, "Invalid device type %d for port %d", (MapleDeviceType)config::MapleMainDevices[bus], bus); break; } } diff --git a/core/hw/maple/maple_cfg.h b/core/hw/maple/maple_cfg.h index 4e818c8be..18e43c5f5 100644 --- a/core/hw/maple/maple_cfg.h +++ b/core/hw/maple/maple_cfg.h @@ -1,6 +1,25 @@ #pragma once #include "types.h" +enum MapleDeviceType +{ + MDT_SegaController, + + MDT_SegaVMU, + MDT_Microphone, + MDT_PurupuruPack, + MDT_AsciiStick, + MDT_Keyboard, + MDT_Mouse, + MDT_LightGun, + MDT_TwinStick, + + MDT_NaomiJamma, + + MDT_None, + MDT_Count +}; + enum PlainJoystickAxisId { PJAI_X1 = 0, diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index 16632a8dc..f5b0a25b3 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -4,6 +4,7 @@ #include "hw/pvr/spg.h" #include "stdclass.h" #include "oslib/audiostream.h" +#include "cfg/option.h" #include @@ -1362,3 +1363,60 @@ maple_device* maple_Create(MapleDeviceType type) return rv; } + +void SetMousePosition(int x, int y, int width, int height, u32 mouseId) +{ + if (mouseId == 0) + { + mo_x_phy = x; + mo_y_phy = y; + } + + if (config::Rotate90) + { + int t = y; + y = x; + x = height - t; + std::swap(width, height); + } + float fx, fy; + if ((float)width / height >= 640.f / 480.f) + { + float scale = 480.f / height; + fy = y * scale; + scale /= config::ScreenStretching / 100.f; + fx = (x - (width - 640.f / scale) / 2.f) * scale; + } + else + { + float scale = 640.f / width; + fx = x * scale; + scale /= config::ScreenStretching / 100.f; + fy = (y - (height - 480.f / scale) / 2.f) * scale; + } + mo_x_abs[mouseId] = (int)std::round(fx); + mo_y_abs[mouseId] = (int)std::round(fy); + + if (mo_x_prev[mouseId] != -1) + { + mo_x_delta[mouseId] += (f32)(x - mo_x_prev[mouseId]) * config::MouseSensitivity / 100.f; + mo_y_delta[mouseId] += (f32)(y - mo_y_prev[mouseId]) * config::MouseSensitivity / 100.f; + } + mo_x_prev[mouseId] = x; + mo_y_prev[mouseId] = y; +} + +void SetRelativeMousePosition(int xrel, int yrel, u32 mouseId) +{ + if (config::Rotate90) + { + std::swap(xrel, yrel); + xrel = -xrel; + } + float dx = (float)xrel * config::MouseSensitivity / 100.f; + float dy = (float)yrel * config::MouseSensitivity / 100.f; + mo_x_delta[mouseId] += dx; + mo_y_delta[mouseId] += dy; + mo_x_abs[mouseId] += (int)std::round(dx); + mo_y_abs[mouseId] += (int)std::round(dy); +} diff --git a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h index 505ab035b..392c04724 100755 --- a/core/hw/maple/maple_devs.h +++ b/core/hw/maple/maple_devs.h @@ -6,25 +6,6 @@ #include #include "input/gamepad.h" -enum MapleDeviceType -{ - MDT_SegaController, - - MDT_SegaVMU, - MDT_Microphone, - MDT_PurupuruPack, - MDT_AsciiStick, - MDT_Keyboard, - MDT_Mouse, - MDT_LightGun, - MDT_TwinStick, - - MDT_NaomiJamma, - - MDT_None, - MDT_Count -}; - enum MapleFunctionID { MFID_0_Input = 0x01000000, //DC Controller, Lightgun buttons, arcade stick .. stuff like that @@ -199,62 +180,8 @@ extern s32 mo_y_phy; extern s32 mo_x_prev[4]; extern s32 mo_y_prev[4]; -static inline void SetMousePosition(int x, int y, int width, int height, u32 mouseId = 0) -{ - if (mouseId == 0) - { - mo_x_phy = x; - mo_y_phy = y; - } - - if (settings.rend.Rotate90) - { - int t = y; - y = x; - x = height - t; - std::swap(width, height); - } - float fx, fy; - if ((float)width / height >= 640.f / 480.f) - { - float scale = 480.f / height; - fy = y * scale; - scale /= settings.rend.ScreenStretching / 100.f; - fx = (x - (width - 640.f / scale) / 2.f) * scale; - } - else - { - float scale = 640.f / width; - fx = x * scale; - scale /= settings.rend.ScreenStretching / 100.f; - fy = (y - (height - 480.f / scale) / 2.f) * scale; - } - mo_x_abs[mouseId] = (int)std::round(fx); - mo_y_abs[mouseId] = (int)std::round(fy); - - if (mo_x_prev[mouseId] != -1) - { - mo_x_delta[mouseId] += (f32)(x - mo_x_prev[mouseId]) * settings.input.MouseSensitivity / 100.f; - mo_y_delta[mouseId] += (f32)(y - mo_y_prev[mouseId]) * settings.input.MouseSensitivity / 100.f; - } - mo_x_prev[mouseId] = x; - mo_y_prev[mouseId] = y; -} - -static inline void SetRelativeMousePosition(int xrel, int yrel, u32 mouseId = 0) -{ - if (settings.rend.Rotate90) - { - std::swap(xrel, yrel); - xrel = -xrel; - } - float dx = (float)xrel * settings.input.MouseSensitivity / 100.f; - float dy = (float)yrel * settings.input.MouseSensitivity / 100.f; - mo_x_delta[mouseId] += dx; - mo_y_delta[mouseId] += dy; - mo_x_abs[mouseId] += (int)std::round(dx); - mo_y_abs[mouseId] += (int)std::round(dy); -} +void SetMousePosition(int x, int y, int width, int height, u32 mouseId = 0); +void SetRelativeMousePosition(int xrel, int yrel, u32 mouseId = 0); #define SWAP32(a) ((((a) & 0xff) << 24) | (((a) & 0xff00) << 8) | (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff)) diff --git a/core/hw/mem/vmem32.cpp b/core/hw/mem/vmem32.cpp index 69f91ed03..ef8f95b93 100644 --- a/core/hw/mem/vmem32.cpp +++ b/core/hw/mem/vmem32.cpp @@ -372,7 +372,7 @@ bool vmem32_init() #ifdef _WIN32 return false; #else - if (settings.dynarec.disable_vmem32 || !_nvmem_4gb_space()) + if (config::DisableVmem32 || !_nvmem_4gb_space()) return false; vmem32_inited = true; vmem32_flush_mmu(); diff --git a/core/hw/naomi/naomi_cart.cpp b/core/hw/naomi/naomi_cart.cpp index 38b746631..638185a70 100644 --- a/core/hw/naomi/naomi_cart.cpp +++ b/core/hw/naomi/naomi_cart.cpp @@ -35,34 +35,18 @@ #include "stdclass.h" #include "emulator.h" #include "rend/gui.h" +#include "cfg/option.h" Cartridge *CurrentCartridge; bool bios_loaded = false; -#ifdef _WIN32 - #include - typedef HANDLE fd_t; - #define INVALID_FD INVALID_HANDLE_VALUE -#else - typedef int fd_t; - #define INVALID_FD -1 - - #include - #include - #include -#endif - -fd_t* RomCacheMap = NULL; -u32 RomCacheMapCount; - char naomi_game_id[33]; InputDescriptors *NaomiGameInputs; u8 *naomi_default_eeprom; -bool naomi_rotate_screen; extern MemChip *sys_rom; -static bool naomi_LoadBios(const char *filename, Archive *child_archive, Archive *parent_archive, int region) +static bool loadBios(const char *filename, Archive *child_archive, Archive *parent_archive, int region) { int biosid = 0; for (; BIOS[biosid].name != NULL; biosid++) @@ -166,31 +150,50 @@ static bool naomi_LoadBios(const char *filename, Archive *child_archive, Archive static Game *FindGame(const char *filename) { - const char *p = strrchr(filename, '/'); -#ifdef _WIN32 - const char *p2 = strrchr(filename, '\\'); - if (p2 > p) - p = p2; -#endif - if (p == NULL) - p = filename; - else - p++; - char game_name[128]; - strncpy(game_name, p, sizeof(game_name) - 1); - game_name[sizeof(game_name) - 1] = 0; - char *dot = strrchr(game_name, '.'); - if (dot != NULL) - *dot = 0; + std::string gameName = get_file_basename(filename); + size_t folder_pos = get_last_slash_pos(gameName); + if (folder_pos != std::string::npos) + gameName = gameName.substr(folder_pos + 1); - int gameid = 0; - for (; Games[gameid].name != NULL; gameid++) - if (!stricmp(Games[gameid].name, game_name)) - break; - if (Games[gameid].name == NULL) - return NULL; + for (int i = 0; Games[i].name != nullptr; i++) + if (gameName == Games[i].name) + return &Games[i]; - return &Games[gameid]; + return nullptr; +} + +void naomi_cart_LoadBios(const char *filename) +{ + Game *game = FindGame(filename); + if (game == nullptr) + return; + + // Open archive and parent archive if any + std::unique_ptr archive(OpenArchive(filename)); + + std::unique_ptr parent_archive; + if (game->parent_name != NULL) + parent_archive.reset(OpenArchive((get_game_dir() + game->parent_name).c_str())); + + const char *bios = "naomi"; + if (game->bios != nullptr) + bios = game->bios; + u32 region_flag = std::min((int)config::Region, (int)game->region_flag); + if (game->region_flag == REGION_EXPORT_ONLY) + region_flag = REGION_EXPORT; + if (!loadBios(bios, archive.get(), parent_archive.get(), region_flag)) + { + WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", region_flag, bios); + if (!loadBios(bios, archive.get(), parent_archive.get(), -1)) + { + // If a specific BIOS is needed for this game, fail. + if (game->bios != NULL || !bios_loaded) + throw NaomiCartException(std::string("Error: cannot load BIOS ") + (game->bios != NULL ? game->bios : "naomi.zip")); + + // otherwise use the default BIOS + } + } + bios_loaded = true; } static void naomi_cart_LoadZip(const char *filename) @@ -221,27 +224,7 @@ static void naomi_cart_LoadZip(const char *filename) } // Load the BIOS - const char *bios = "naomi"; - if (game->bios != NULL) - bios = game->bios; - u32 region_flag = settings.dreamcast.region; - if (region_flag > game->region_flag) - region_flag = game->region_flag; - if (game->region_flag == REGION_EXPORT_ONLY) - region_flag = REGION_EXPORT; - if (!naomi_LoadBios(bios, archive.get(), parent_archive.get(), region_flag)) - { - WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", region_flag, bios); - if (!naomi_LoadBios(bios, archive.get(), parent_archive.get(), -1)) - { - // If a specific BIOS is needed for this game, fail. - if (game->bios != NULL || !bios_loaded) - throw NaomiCartException(std::string("Error: cannot load BIOS ") + (game->bios != NULL ? game->bios : "naomi.zip")); - - // otherwise use the default BIOS - } - } - bios_loaded = true; + naomi_cart_LoadBios(filename); // Now load the cartridge data try { @@ -370,7 +353,8 @@ static void naomi_cart_LoadZip(const char *filename) return; if (naomi_default_eeprom == NULL && game->eeprom_dump != NULL) naomi_default_eeprom = game->eeprom_dump; - naomi_rotate_screen = game->rotation_flag == ROT270; + if (game->rotation_flag == ROT270) + config::Rotate90.override(true); CurrentCartridge->Init(); if (loading_canceled) @@ -381,7 +365,7 @@ static void naomi_cart_LoadZip(const char *filename) strcpy(naomi_game_id, game->name); NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id); - } catch (ReicastException& ex) { + } catch (const ReicastException& ex) { delete CurrentCartridge; CurrentCartridge = NULL; @@ -389,68 +373,48 @@ static void naomi_cart_LoadZip(const char *filename) } } -#ifdef _WIN32 -#define CloseFile(f) CloseHandle(f) -#else -#define CloseFile(f) close(f) -#endif - void naomi_cart_LoadRom(const char* file) { - INFO_LOG(NAOMI, "nullDC-Naomi rom loader v1.2"); - naomi_cart_Close(); - size_t folder_pos = strlen(file) - 1; - while (folder_pos>1 && (file[folder_pos] != '\\' && file[folder_pos] != '/')) - folder_pos--; + std::string extension = get_file_extension(file); - folder_pos++; - - // FIXME: Data loss if buffer is too small - char t[512]; - strncpy(t, file, sizeof(t)); - t[sizeof(t) - 1] = '\0'; - - std::vector files; - std::vector fstart; - std::vector fsize; - u32 setsize = 0; - bool raw_bin_file = false; - - const char *pdot = strrchr(file, '.'); - - if (pdot != NULL - && (!strcmp(pdot, ".zip") || !strcmp(pdot, ".ZIP") - || !strcmp(pdot, ".7z") || !strcmp(pdot, ".7Z"))) + if (extension == "zip" || extension == "7z") { naomi_cart_LoadZip(file); return; } // Try to load BIOS from naomi.zip - if (!naomi_LoadBios("naomi", NULL, NULL, settings.dreamcast.region)) + if (!loadBios("naomi", NULL, NULL, config::Region)) { - WARN_LOG(NAOMI, "Warning: Region %d bios not found in naomi.zip", settings.dreamcast.region); - if (!naomi_LoadBios("naomi", NULL, NULL, -1)) + WARN_LOG(NAOMI, "Warning: Region %d bios not found in naomi.zip", config::Region.get()); + if (!loadBios("naomi", NULL, NULL, -1)) { if (!bios_loaded) throw new ReicastException("Error: cannot load BIOS from naomi.zip"); } } - u8* RomPtr; - u32 RomSize; + std::string folder; + std::vector files; + std::vector fstart; + std::vector fsize; + u32 romSize = 0; - if (pdot != NULL && (!strcmp(pdot, ".lst") || !strcmp(pdot, ".LST"))) + if (extension == "lst") { // LST file + size_t folder_pos = get_last_slash_pos(file); + if (folder_pos != std::string::npos) + folder = std::string(file).substr(0, folder_pos + 1); - FILE* fl = nowide::fopen(t, "r"); + FILE *fl = nowide::fopen(file, "r"); if (!fl) - throw new ReicastException("Error: can't open " + std::string(t)); + throw new ReicastException("Error: can't open " + std::string(file)); - char* line = std::fgets(t, 512, fl); + char t[512]; + char* line = std::fgets(t, sizeof(t), fl); if (!line) { std::fclose(fl); @@ -461,19 +425,18 @@ void naomi_cart_LoadRom(const char* file) if (!eon) DEBUG_LOG(NAOMI, "+Loading naomi rom that has no name"); else + { *eon = 0; + DEBUG_LOG(NAOMI, "+Loading naomi rom : %s", line); + } - DEBUG_LOG(NAOMI, "+Loading naomi rom : %s", line); - - line = std::fgets(t, 512, fl); + line = std::fgets(t, sizeof(t), fl); if (!line) { std::fclose(fl); throw new ReicastException("Error: Invalid LST file"); } - RomSize = 0; - while (line) { char filename[512]; @@ -483,147 +446,86 @@ void naomi_cart_LoadRom(const char* file) files.push_back(filename); fstart.push_back(addr); fsize.push_back(sz); - setsize += sz; - RomSize = std::max(RomSize, (addr + sz)); + romSize = std::max(romSize, (addr + sz)); } else if (line[0] != 0 && line[0] != '\n' && line[0] != '\r') WARN_LOG(NAOMI, "Warning: invalid line in .lst file: %s", line); - line = std::fgets(t, 512, fl); + line = std::fgets(t, sizeof(t), fl); } std::fclose(fl); } else { // BIN loading - FILE* fp = nowide::fopen(t, "rb"); + FILE* fp = nowide::fopen(file, "rb"); if (fp == NULL) - throw new ReicastException("Error: can't open " + std::string(t)); + throw new ReicastException("Error: can't open " + std::string(file)); std::fseek(fp, 0, SEEK_END); - u32 file_size = std::ftell(fp); + u32 file_size = (u32)std::ftell(fp); std::fclose(fp); - files.push_back(t); + files.push_back(file); fstart.push_back(0); fsize.push_back(file_size); - setsize = file_size; - RomSize = file_size; - raw_bin_file = true; + romSize = file_size; } - INFO_LOG(NAOMI, "+%zd romfiles, %.2f MB set size, %.2f MB set address space", files.size(), setsize / 1024.f / 1024.f, RomSize / 1024.f / 1024.f); + INFO_LOG(NAOMI, "+%zd romfiles, %.2f MB set address space", files.size(), romSize / 1024.f / 1024.f); - if (RomCacheMap) - { - for (u32 i = 0; i < RomCacheMapCount; i++) - if (RomCacheMap[i] != INVALID_FD) - CloseFile(RomCacheMap[i]); - RomCacheMapCount = 0; - delete[] RomCacheMap; - } - - RomCacheMapCount = (u32)files.size(); - RomCacheMap = new fd_t[files.size()](); - - //Allocate space for the ram, so we are sure we have a segment of continuous ram - RomPtr = (u8*)mem_region_reserve(NULL, RomSize); - verify(RomPtr != NULL); + // Allocate space for the rom + u8 *romBase = (u8 *)malloc(romSize); + verify(romBase != nullptr); bool load_error = false; - //Create File Mapping Objects for (size_t i = 0; iGetGameId().c_str()); NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id); } @@ -635,15 +537,6 @@ void naomi_cart_Close() delete CurrentCartridge; CurrentCartridge = NULL; } - if (RomCacheMap != NULL) - { - for (u32 i = 0; i < RomCacheMapCount; i++) - if (RomCacheMap[i] != INVALID_FD) - CloseFile(RomCacheMap[i]); - RomCacheMapCount = 0; - delete[] RomCacheMap; - RomCacheMap = NULL; - } bios_loaded = false; } @@ -732,9 +625,6 @@ void* NaomiCartridge::GetDmaPtr(u32& size) return GetPtr(DmaOffset, size); } -void NaomiCartridge::AdvancePtr(u32 size) { -} - u32 NaomiCartridge::ReadMem(u32 address, u32 size) { verify(size!=1); @@ -805,36 +695,6 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size) DEBUG_LOG(NAOMI, "naomi ReadBoardId: %X, %d", address, size); return 1; - case NAOMI_COMM2_CTRL_addr & 255: - DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL read"); - return comm_ctrl; - - case NAOMI_COMM2_OFFSET_addr & 255: - DEBUG_LOG(NAOMI, "NAOMI_COMM2_OFFSET read"); - return comm_offset; - - case NAOMI_COMM2_DATA_addr & 255: - { - DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA read @ %04x", comm_offset); - u16 value; - if (comm_ctrl & 1) - value = m68k_ram[comm_offset / 2]; - else { - // TODO u16 *commram = (u16*)membank("comm_ram")->base(); - value = comm_ram[comm_offset / 2]; - } - comm_offset += 2; - return value; - } - - case NAOMI_COMM2_STATUS0_addr & 255: - DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS0 read"); - return comm_status0; - - case NAOMI_COMM2_STATUS1_addr & 255: - DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS1 read"); - return comm_status1; - default: break; } @@ -953,37 +813,6 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size) DEBUG_LOG(NAOMI, "naomi WriteMem: %X <= %X, %d", address, data, size); return; - case NAOMI_COMM2_CTRL_addr & 255: - comm_ctrl = (u16)data; - DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL set to %x", comm_ctrl); - return; - - case NAOMI_COMM2_OFFSET_addr & 255: - comm_offset = (u16)data; - DEBUG_LOG(NAOMI, "NAOMI_COMM2_OFFSET set to %x", comm_offset); - return; - - case NAOMI_COMM2_DATA_addr & 255: - DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA written @ %04x %04x", comm_offset, (u16)data); - if (comm_ctrl & 1) - m68k_ram[comm_offset / 2] = (u16)data; - else { - // TODO u16 *commram = (u16*)membank("comm_ram")->base(); - comm_ram[comm_offset / 2] = (u16)data; - } - comm_offset += 2; - return; - - case NAOMI_COMM2_STATUS0_addr & 255: - comm_status0 = (u16)data; - DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS0 set to %x", comm_status0); - return; - - case NAOMI_COMM2_STATUS1_addr & 255: - comm_status1 = (u16)data; - DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS1 set to %x", comm_status1); - return; - default: break; } DEBUG_LOG(NAOMI, "naomi?WTF? WriteMem: %X <= %X, %d", address, data, size); @@ -1103,11 +932,3 @@ void M2Cartridge::Unserialize(void** data, unsigned int* total_size) { REICAST_US(naomi_cart_ram); NaomiCartridge::Unserialize(data, total_size); } - -DecryptedCartridge::~DecryptedCartridge() -{ - // TODO this won't work on windows -> need to unmap each file first - mem_region_release(RomPtr, RomSize); - // Avoid crash when freeing vmem - RomPtr = NULL; -} diff --git a/core/hw/naomi/naomi_cart.h b/core/hw/naomi/naomi_cart.h index 7331edb06..a8a5dd622 100644 --- a/core/hw/naomi/naomi_cart.h +++ b/core/hw/naomi/naomi_cart.h @@ -38,7 +38,7 @@ public: virtual u32 ReadMem(u32 address, u32 size) override; virtual void WriteMem(u32 address, u32 data, u32 size) override; virtual void* GetDmaPtr(u32 &size) override; - virtual void AdvancePtr(u32 size) override; + virtual void AdvancePtr(u32 size) override {} virtual void Serialize(void** data, unsigned int* total_size) override; virtual void Unserialize(void** data, unsigned int* total_size) override; @@ -52,20 +52,12 @@ protected: u32 DmaOffset; u32 DmaCount; u32 key = 0; - // Naomi 840-0001E communication board - u16 comm_ctrl = 0xC000; - u16 comm_offset = 0; - u16 comm_status0 = 0; - u16 comm_status1 = 0; - u16 m68k_ram[128 * 1024 / sizeof(u16)]; - u16 comm_ram[64 * 1024 / sizeof(u16)]; }; class DecryptedCartridge : public NaomiCartridge { public: DecryptedCartridge(u8 *rom_ptr, u32 size) : NaomiCartridge(size) { free(RomPtr); RomPtr = rom_ptr; } - virtual ~DecryptedCartridge() override; }; class M2Cartridge : public NaomiCartridge @@ -94,10 +86,10 @@ public: void naomi_cart_LoadRom(const char* file); void naomi_cart_Close(); int naomi_cart_GetPlatform(const char *path); +void naomi_cart_LoadBios(const char *filename); extern char naomi_game_id[]; extern u8 *naomi_default_eeprom; -extern bool naomi_rotate_screen; extern Cartridge *CurrentCartridge; diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index 363a3176c..1bbf38612 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -5,6 +5,7 @@ #include "hw/pvr/pvr_mem.h" #include "oslib/oslib.h" #include "rend/TexCache.h" +#include "cfg/option.h" #include #include @@ -225,7 +226,7 @@ bool rend_single_frame(const bool& enabled) { { std::lock_guard lock(swap_mutex); - if (settings.rend.DelayFrameSwapping && !_pvrrc->rend.isRenderFramebuffer && fb_w_cur != FB_R_SOF1 && !do_swap) + if (config::DelayFrameSwapping && !_pvrrc->rend.isRenderFramebuffer && fb_w_cur != FB_R_SOF1 && !do_swap) // Delay swap frame_rendered = false; else @@ -257,7 +258,7 @@ static void rend_create_renderer() #ifdef NO_REND renderer = rend_norend(); #else - switch (settings.pvr.rend) + switch (config::RendererType) { default: case RenderType::OpenGL: diff --git a/core/hw/pvr/ta_ctx.cpp b/core/hw/pvr/ta_ctx.cpp index 07049dfc1..336f7703d 100644 --- a/core/hw/pvr/ta_ctx.cpp +++ b/core/hw/pvr/ta_ctx.cpp @@ -1,6 +1,7 @@ #include "ta_ctx.h" #include "spg.h" #include "oslib/oslib.h" +#include "cfg/option.h" extern u32 fskip; extern u32 FrameCount; @@ -77,10 +78,10 @@ bool QueueRender(TA_context* ctx) bool skipFrame = false; RenderCount++; - if (RenderCount % (settings.pvr.ta_skip + 1) != 0) + if (RenderCount % (config::SkipFrame + 1) != 0) skipFrame = true; - else if (rqueue && (settings.pvr.AutoSkipFrame == 0 - || (settings.pvr.AutoSkipFrame == 1 && SH4FastEnough))) + else if (rqueue && (config::AutoSkipFrame == 0 + || (config::AutoSkipFrame == 1 && SH4FastEnough))) // The previous render hasn't completed yet so we wait. // If autoskipframe is enabled (normal level), we only do so if the CPU is running // fast enough over the last frames diff --git a/core/hw/sh4/dyna/decoder.cpp b/core/hw/sh4/dyna/decoder.cpp index aa0fb976e..e804fb586 100644 --- a/core/hw/sh4/dyna/decoder.cpp +++ b/core/hw/sh4/dyna/decoder.cpp @@ -14,6 +14,7 @@ #include "hw/sh4/sh4_core.h" #include "hw/sh4/sh4_mem.h" #include "decoder_opcodes.h" +#include "cfg/option.h" #define BLOCK_MAX_SH_OPS_SOFT 500 #define BLOCK_MAX_SH_OPS_HARD 511 @@ -623,7 +624,7 @@ static u32 MatchDiv32(u32 pc , Sh4RegType ®1,Sh4RegType ®2 , Sh4RegType &r static bool MatchDiv32u(u32 op,u32 pc) { - if (settings.dynarec.safemode) + if (config::DynarecSafeMode) return false; div_som_reg1=NoReg; @@ -645,7 +646,7 @@ static bool MatchDiv32u(u32 op,u32 pc) static bool MatchDiv32s(u32 op,u32 pc) { - if (settings.dynarec.safemode) + if (config::DynarecSafeMode) return false; u32 n = GetN(op); @@ -1095,7 +1096,7 @@ _end: #endif //cycle tricks - if (settings.dynarec.idleskip) + if (config::DynarecIdleSkip) { //Experimental hash-id based idle skip if (!mmu_enabled() && strstr(idle_hash, blk->hash())) diff --git a/core/hw/sh4/dyna/driver.cpp b/core/hw/sh4/dyna/driver.cpp index 5286a8a68..b3b5b03a1 100644 --- a/core/hw/sh4/dyna/driver.cpp +++ b/core/hw/sh4/dyna/driver.cpp @@ -8,6 +8,7 @@ #include "hw/sh4/sh4_mem.h" #include "hw/sh4/modules/mmu.h" +#include "cfg/option.h" #include #include @@ -70,7 +71,7 @@ static void recSh4_Run() sh4_dyna_rcb=(u8*)&Sh4cntx + sizeof(Sh4cntx); INFO_LOG(DYNAREC, "cntx // fpcb offset: %td // pc offset: %td // pc %08X", (u8*)&sh4rcb.fpcb - sh4_dyna_rcb, (u8*)&sh4rcb.cntx.pc - sh4_dyna_rcb, sh4rcb.cntx.pc); - if (settings.dynarec.unstable_opt) + if (config::DynarecUnstableOpt) NOTICE_LOG(DYNAREC, "Warning: Unstable optimizations is on"); verify(rcb_noffs(&next_pc)==-184); diff --git a/core/hw/sh4/modules/bsc.cpp b/core/hw/sh4/modules/bsc.cpp index 42ceca626..4447768f3 100644 --- a/core/hw/sh4/modules/bsc.cpp +++ b/core/hw/sh4/modules/bsc.cpp @@ -4,6 +4,7 @@ #include "hw/sh4/sh4_mmr.h" #include "hw/naomi/naomi.h" +#include "cfg/option.h" BSC_PDTRA_type BSC_PDTRA; @@ -52,7 +53,7 @@ u32 read_BSC_PDTRA(u32 addr) else if ((tpctra&0xf) == 0xC && (tpdtra&0xf) == 2) tfinal = 3; - tfinal |= settings.dreamcast.cable <<8; + tfinal |= config::Cable << 8; return tfinal; } diff --git a/core/hw/sh4/modules/ccn.cpp b/core/hw/sh4/modules/ccn.cpp index 9adb898a8..84919c37c 100644 --- a/core/hw/sh4/modules/ccn.cpp +++ b/core/hw/sh4/modules/ccn.cpp @@ -84,13 +84,13 @@ void CCN_CCR_write(u32 addr, u32 value) if (temp.ICI) { DEBUG_LOG(SH4, "Sh4: i-cache invalidation %08X", curr_pc); //Shikigami No Shiro II uses ICI frequently - if (!settings.dynarec.Enable) + if (!config::DynarecEnabled) icache.Invalidate(); temp.ICI = 0; } if (temp.OCI) { DEBUG_LOG(SH4, "Sh4: o-cache invalidation %08X", curr_pc); - if (!settings.dynarec.Enable) + if (!config::DynarecEnabled) ocache.Invalidate(); temp.OCI = 0; } diff --git a/core/hw/sh4/modules/mmu.cpp b/core/hw/sh4/modules/mmu.cpp index 731d62b36..1789b1a47 100644 --- a/core/hw/sh4/modules/mmu.cpp +++ b/core/hw/sh4/modules/mmu.cpp @@ -648,7 +648,7 @@ retry_ITLB_Match: void mmu_set_state() { - if (CCN_MMUCR.AT == 1 && settings.dreamcast.FullMMU) + if (CCN_MMUCR.AT == 1 && config::FullMMU) { NOTICE_LOG(SH4, "Enabling Full MMU support"); _vmem_enable_mmu(true); @@ -745,7 +745,7 @@ template void mmu_WriteMem(u32 adr, u64 data); bool mmu_TranslateSQW(u32 adr, u32* out) { - if (!settings.dreamcast.FullMMU) + if (!config::FullMMU) { //This will only work for 1 mb pages .. hopefully nothing else is used //*FIXME* to work for all page sizes ? diff --git a/core/hw/sh4/modules/mmu.h b/core/hw/sh4/modules/mmu.h index 91f0e3d17..0efee7117 100644 --- a/core/hw/sh4/modules/mmu.h +++ b/core/hw/sh4/modules/mmu.h @@ -2,6 +2,7 @@ #include "types.h" #include "hw/sh4/sh4_mmr.h" #include "hw/mem/_vmem.h" +#include "cfg/option.h" //Translation Types //Opcode read @@ -51,7 +52,7 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am); static INLINE bool mmu_enabled() { #ifndef NO_MMU - return settings.dreamcast.FullMMU && CCN_MMUCR.AT == 1; + return config::FullMMU && CCN_MMUCR.AT == 1; #else return false; #endif diff --git a/core/hw/sh4/modules/serial.cpp b/core/hw/sh4/modules/serial.cpp index c3251ff92..db4be916e 100644 --- a/core/hw/sh4/modules/serial.cpp +++ b/core/hw/sh4/modules/serial.cpp @@ -14,6 +14,7 @@ #include "types.h" #include "hw/sh4/sh4_mmr.h" #include "hw/sh4/sh4_interrupts.h" +#include "cfg/option.h" static int tty = 1; // stdout by default @@ -65,7 +66,7 @@ static void Serial_UpdateInterrupts() static void SerialWrite(u32 addr, u32 data) { - if (settings.debug.SerialConsole) + if (config::SerialConsole) write(tty, &data, 1); SCIF_SCFSR2.TDFE = 1; @@ -79,7 +80,7 @@ static u32 ReadSerialStatus(u32 addr) { #if HOST_OS == OS_LINUX || defined(__APPLE__) int count = 0; - if (settings.debug.SerialConsole && tty != 1 + if (config::SerialConsole && tty != 1 && ioctl(tty, FIONREAD, &count) == 0 && count > 0) { return SCIF_SCFSR2.full | 2; @@ -169,7 +170,7 @@ void serial_init() sh4_rio_reg(SCIF,SCIF_SCLSR2_addr,RIO_DATA,16); #if HOST_OS == OS_LINUX || defined(__APPLE__) - if (settings.debug.SerialConsole && settings.debug.SerialPTY) + if (config::SerialConsole && config::SerialPTY) { tty = open("/dev/ptmx", O_RDWR | O_NDELAY | O_NOCTTY | O_NONBLOCK); if (tty < 0) diff --git a/core/hw/sh4/sh4_core.h b/core/hw/sh4/sh4_core.h index 7545f2d5b..478112ed8 100644 --- a/core/hw/sh4/sh4_core.h +++ b/core/hw/sh4/sh4_core.h @@ -1,7 +1,7 @@ #pragma once #include "types.h" #include "sh4_if.h" - +#include "cfg/option.h" #define r Sh4cntx.r #define r_bank Sh4cntx.r_bank @@ -107,7 +107,7 @@ struct SH4ThrownException { static INLINE void RaiseFPUDisableException() { #if !defined(NO_MMU) - if (settings.dreamcast.FullMMU) + if (config::FullMMU) { SH4ThrownException ex = { next_pc - 2, 0x800, 0x100 }; throw ex; @@ -126,7 +126,7 @@ static INLINE void AdjustDelaySlotException(SH4ThrownException& ex) ex.expEvn = 0x1A0; // Slot illegal instruction exception } -// The SH4 sets the signaling bit to 0 for qNaN (unlike all recent CPUs). Some games relies on this. +// The SH4 sets the signaling bit to 0 for qNaN (unlike all recent CPUs). Some games rely on this. static INLINE f32 fixNaN(f32 f) { #ifdef STRICT_MODE diff --git a/core/hw/sh4/sh4_mem.cpp b/core/hw/sh4/sh4_mem.cpp index 17d345d50..938b45012 100644 --- a/core/hw/sh4/sh4_mem.cpp +++ b/core/hw/sh4/sh4_mem.cpp @@ -314,14 +314,14 @@ void SetMemoryHandlers() { #ifndef NO_MMU #ifdef STRICT_MODE - if (settings.dynarec.Enable && interpreterRunning) + if (config::DynarecEnabled && interpreterRunning) { // Flush caches when interp -> dynarec ocache.WriteBackAll(); icache.Invalidate(); } - if (!settings.dynarec.Enable) + if (!config::DynarecEnabled) { interpreterRunning = true; IReadMem16 = &IReadCachedMem; @@ -339,7 +339,7 @@ void SetMemoryHandlers() } interpreterRunning = false; #endif - if (CCN_MMUCR.AT == 1 && settings.dreamcast.FullMMU) + if (CCN_MMUCR.AT == 1 && config::FullMMU) { IReadMem16 = &mmu_IReadMem16; ReadMem8 = &mmu_ReadMem; diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index 72a264eb0..972c52bc4 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -409,7 +409,7 @@ static FILE *get_record_input(bool write) void GamepadDevice::Register(std::shared_ptr gamepad) { int maple_port = cfgLoadInt("input", - (MAPLE_PORT_CFG_PREFIX + gamepad->unique_id()).c_str(), 12345); + MAPLE_PORT_CFG_PREFIX + gamepad->unique_id(), 12345); if (maple_port != 12345) gamepad->set_maple_port(maple_port); #ifdef TEST_AUTOMATION @@ -443,11 +443,12 @@ void GamepadDevice::SaveMaplePorts() { std::shared_ptr gamepad = GamepadDevice::GetGamepad(i); if (gamepad != NULL && !gamepad->unique_id().empty()) - cfgSaveInt("input", (MAPLE_PORT_CFG_PREFIX + gamepad->unique_id()).c_str(), gamepad->maple_port()); + cfgSaveInt("input", MAPLE_PORT_CFG_PREFIX + gamepad->unique_id(), gamepad->maple_port()); } } #ifdef TEST_AUTOMATION +#include "cfg/option.h" static bool replay_inited; FILE *replay_file; u64 next_event; @@ -463,10 +464,10 @@ void replay_input() replay_inited = true; } u64 now = sh4_sched_now64(); - if (settings.bios.UseReios) + if (config::UseReios) { // Account for the swirl time - if (settings.dreamcast.broadcast == 0) + if (config::Broadcast == 0) now = std::max((int64_t)now - 2152626532L, 0L); else now = std::max((int64_t)now - 2191059108L, 0L); diff --git a/core/linux-dist/dispmanx.cpp b/core/linux-dist/dispmanx.cpp index e0f714bdf..2a3afe2d8 100644 --- a/core/linux-dist/dispmanx.cpp +++ b/core/linux-dist/dispmanx.cpp @@ -2,6 +2,7 @@ #include "dispmanx.h" #include "types.h" #include "wsi/context.h" +#include "cfg/option.h" #include #include @@ -25,8 +26,8 @@ void dispmanx_window_create() graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height); - window_width = settings.dispmanx.Width; - window_height = settings.dispmanx.Height; + window_width = cfgLoadInt("window", "width", 0); + window_height = cfgLoadInt("window", "height", 0); if(window_width < 1) window_width = screen_width; @@ -38,7 +39,7 @@ void dispmanx_window_create() src_rect.width = window_width << 16; src_rect.height = window_height << 16; - if(settings.dispmanx.Keep_Aspect) + if (config::DispmanxMaintainAspect) { float screen_aspect = (float)screen_width / screen_height; float window_aspect = (float)window_width / window_height; diff --git a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp index 4e76c2cf9..96016fe74 100644 --- a/core/linux-dist/main.cpp +++ b/core/linux-dist/main.cpp @@ -365,8 +365,6 @@ int main(int argc, char* argv[]) common_linux_setup(); - settings.profile.run_counts=0; - if (reicast_init(argc, argv)) die("Reicast initialization failed\n"); diff --git a/core/linux/common.cpp b/core/linux/common.cpp index 7cd1d7060..05ecc0f5f 100644 --- a/core/linux/common.cpp +++ b/core/linux/common.cpp @@ -200,8 +200,6 @@ void common_linux_setup() install_fault_handler(); signal(SIGINT, exit); - settings.profile.run_counts=0; - DEBUG_LOG(BOOT, "Linux paging: %ld %08X %08X", sysconf(_SC_PAGESIZE), PAGE_SIZE, PAGE_MASK); verify(PAGE_MASK==(sysconf(_SC_PAGESIZE)-1)); } diff --git a/core/network/naomi_network.cpp b/core/network/naomi_network.cpp index 5d9db8902..320f514aa 100644 --- a/core/network/naomi_network.cpp +++ b/core/network/naomi_network.cpp @@ -27,6 +27,7 @@ #include "rend/gui.h" #include "hw/naomi/naomi_cart.h" #include "hw/naomi/naomi_flashrom.h" +#include "cfg/option.h" #ifdef _MSC_VER #if defined(_WIN64) @@ -67,7 +68,7 @@ sock_t NaomiNetwork::createAndBind(int protocol) bool NaomiNetwork::init() { - if (!settings.network.Enable) + if (!config::NetworkEnable) return false; #ifdef _WIN32 WSADATA wsaData; @@ -77,7 +78,7 @@ bool NaomiNetwork::init() return false; } #endif - if (settings.network.ActAsServer) + if (config::ActAsServer) { miniupnp.Init(); miniupnp.AddPortMapping(SERVER_PORT, true); @@ -223,7 +224,7 @@ bool NaomiNetwork::startNetwork() using namespace std::chrono; const auto timeout = seconds(20); - if (settings.network.ActAsServer) + if (config::ActAsServer) { NOTICE_LOG(NETWORK, "Waiting for slave connections"); steady_clock::time_point start_time = steady_clock::now(); @@ -338,11 +339,11 @@ bool NaomiNetwork::startNetwork() } else { - if (!settings.network.server.empty()) + if (!config::NetworkServer.get().empty()) { struct addrinfo *resultAddr; - if (getaddrinfo(settings.network.server.c_str(), 0, nullptr, &resultAddr)) - WARN_LOG(NETWORK, "Server %s is unknown", settings.network.server.c_str()); + if (getaddrinfo(config::NetworkServer.get().c_str(), 0, nullptr, &resultAddr)) + WARN_LOG(NETWORK, "Server %s is unknown", config::NetworkServer.get().c_str()); else for (struct addrinfo *ptr = resultAddr; ptr != nullptr; ptr = ptr->ai_next) if (ptr->ai_family == AF_INET) @@ -408,7 +409,7 @@ bool NaomiNetwork::syncNetwork() using namespace std::chrono; const auto timeout = seconds(10); - if (settings.network.ActAsServer) + if (config::ActAsServer) { steady_clock::time_point start_time = steady_clock::now(); @@ -622,7 +623,7 @@ void NaomiNetwork::shutdown() void NaomiNetwork::terminate() { shutdown(); - if (settings.network.ActAsServer) + if (config::ActAsServer) miniupnp.Term(); if (VALID(beacon_sock)) closeSocket(beacon_sock); @@ -713,7 +714,7 @@ bool NaomiNetworkSupported() "HEAVY METAL JAPAN", "OUTTRIGGER JAPAN", "SLASHOUT JAPAN VERSION", "SPAWN JAPAN", "SPIKERS BATTLE JAPAN VERSION", "VIRTUAL-ON ORATORIO TANGRAM", "WAVE RUNNER GP", "WORLD KICKS" }; - if (!settings.network.Enable) + if (!config::NetworkEnable) return false; for (auto game : games) if (!strcmp(game, naomi_game_id)) diff --git a/core/network/picoppp.cpp b/core/network/picoppp.cpp index 851ecc828..c54df0baa 100644 --- a/core/network/picoppp.cpp +++ b/core/network/picoppp.cpp @@ -46,6 +46,7 @@ extern "C" { #include "miniupnp.h" #include "reios/reios.h" #include "hw/naomi/naomi_cart.h" +#include "cfg/option.h" #include #include @@ -892,11 +893,11 @@ static void *pico_thread_func(void *) } u32 addr; - pico_string_to_ipv4(settings.network.dns.c_str(), &addr); + pico_string_to_ipv4(config::DNS.get().c_str(), &addr); memcpy(&dnsaddr.addr, &addr, sizeof(addr)); // Create ppp/eth device - if (!settings.network.EmulateBBA) + if (!config::EmulateBBA) { // PPP pico_dev = pico_ppp_create(); @@ -1041,7 +1042,7 @@ static void *pico_thread_func(void *) if (pico_dev) { - if (!settings.network.EmulateBBA) + if (!config::EmulateBBA) { pico_ppp_destroy(pico_dev); } diff --git a/core/nullDC.cpp b/core/nullDC.cpp index a62797022..6a6ad5daa 100644 --- a/core/nullDC.cpp +++ b/core/nullDC.cpp @@ -4,7 +4,6 @@ #include #include -//initialse Emu #include "types.h" #include "emulator.h" #include "oslib/oslib.h" @@ -12,6 +11,7 @@ #include "hw/mem/_vmem.h" #include "stdclass.h" #include "cfg/cfg.h" +#include "cfg/option.h" #include "hw/maple/maple_cfg.h" #include "hw/sh4/sh4_mem.h" @@ -38,25 +38,16 @@ #include "archive/rzip.h" void FlushCache(); -static void LoadCustom(); extern bool fast_forward_mode; settings_t settings; -// Set if game has corresponding option by default, so that it's not saved in the config -static bool rtt_to_buffer_game; -static bool safemode_game; -static bool tr_poly_depth_mask_game; -static bool extra_depth_game; -static bool disable_vmem32_game; -static int forced_game_region = -1; -static int forced_game_cable = -1; -static int saved_screen_stretching = -1; cThread emu_thread(&dc_run, NULL); static std::future loading_done; std::atomic loading_canceled; +static bool init_done; static s32 plugins_Init() { @@ -104,22 +95,15 @@ static void LoadSpecialSettings() prod_id = trim_trailing_ws(prod_id); NOTICE_LOG(BOOT, "Game ID is [%s]", prod_id.c_str()); - rtt_to_buffer_game = false; - safemode_game = false; - tr_poly_depth_mask_game = false; - extra_depth_game = false; - disable_vmem32_game = false; - forced_game_region = -1; - forced_game_cable = -1; - if (ip_meta.isWindowsCE() || settings.dreamcast.ForceWindowsCE + if (ip_meta.isWindowsCE() || config::ForceWindowsCE || prod_id == "T26702N") // PBA Tour Bowling 2001 { INFO_LOG(BOOT, "Enabling Full MMU and Extra depth scaling for Windows CE game"); - settings.rend.ExtraDepthScale = 0.1; // taxi 2 needs 0.01 for FMV (amd, per-tri) - extra_depth_game = true; - settings.dreamcast.FullMMU = true; - settings.aica.NoBatch = true; + config::ExtraDepthScale.override(0.1); // taxi 2 needs 0.01 for FMV (amd, per-tri) + config::FullMMU.override(true); + if (!config::ForceWindowsCE) + config::ForceWindowsCE.override(true); } // Tony Hawk's Pro Skater 2 @@ -148,36 +132,31 @@ static void LoadSpecialSettings() || prod_id == "T-45001D05") { INFO_LOG(BOOT, "Enabling render to texture buffer for game %s", prod_id.c_str()); - settings.rend.RenderToTextureBuffer = 1; - rtt_to_buffer_game = true; + config::RenderToTextureBuffer.override(true); } if (prod_id == "HDR-0176" || prod_id == "RDC-0057") { INFO_LOG(BOOT, "Enabling translucent depth multipass for game %s", prod_id.c_str()); // Cosmic Smash - settings.rend.TranslucentPolygonDepthMask = 1; - tr_poly_depth_mask_game = true; + config::TranslucentPolygonDepthMask.override(true); } // NHL 2K2 if (prod_id == "MK-51182") { INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", prod_id.c_str()); - settings.rend.ExtraDepthScale = 1000000; // Mali needs 1M, 10K is enough for others - extra_depth_game = true; + config::ExtraDepthScale.override(1000000.f); // Mali needs 1M, 10K is enough for others } // Re-Volt (US, EU) else if (prod_id == "T-8109N" || prod_id == "T8107D 50") { INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", prod_id.c_str()); - settings.rend.ExtraDepthScale = 100; - extra_depth_game = true; + config::ExtraDepthScale.override(100.f); } // Samurai Shodown 6 dc port else if (prod_id == "T0002M") { INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", prod_id.c_str()); - settings.rend.ExtraDepthScale = 1e26; - extra_depth_game = true; + config::ExtraDepthScale.override(1e26f); } // Super Producers if (prod_id == "T14303M" @@ -211,8 +190,7 @@ static void LoadSpecialSettings() || prod_id == "T26702N") { INFO_LOG(BOOT, "Disabling 32-bit virtual memory for game %s", prod_id.c_str()); - settings.dynarec.disable_vmem32 = true; - disable_vmem32_game = true; + config::DisableVmem32.override(true); } std::string areas(ip_meta.area_symbols, sizeof(ip_meta.area_symbols)); bool region_usa = areas.find('U') != std::string::npos; @@ -220,52 +198,47 @@ static void LoadSpecialSettings() bool region_japan = areas.find('J') != std::string::npos; if (region_usa || region_eu || region_japan) { - switch (settings.dreamcast.region) + switch (config::Region) { case 0: // Japan if (!region_japan) { NOTICE_LOG(BOOT, "Japan region not supported. Using %s instead", region_usa ? "USA" : "Europe"); - settings.dreamcast.region = region_usa ? 1 : 2; - forced_game_region = settings.dreamcast.region; + config::Region.override(region_usa ? 1 : 2); } break; case 1: // USA if (!region_usa) { NOTICE_LOG(BOOT, "USA region not supported. Using %s instead", region_eu ? "Europe" : "Japan"); - settings.dreamcast.region = region_eu ? 2 : 0; - forced_game_region = settings.dreamcast.region; + config::Region.override(region_eu ? 2 : 0); } break; case 2: // Europe if (!region_eu) { NOTICE_LOG(BOOT, "Europe region not supported. Using %s instead", region_usa ? "USA" : "Japan"); - settings.dreamcast.region = region_usa ? 1 : 0; - forced_game_region = settings.dreamcast.region; + config::Region.override(region_usa ? 1 : 0); } break; case 3: // Default if (region_usa) - settings.dreamcast.region = 1; + config::Region.override(1); else if (region_eu) - settings.dreamcast.region = 2; + config::Region.override(2); else - settings.dreamcast.region = 0; - forced_game_region = settings.dreamcast.region; + config::Region.override(0); break; } } else WARN_LOG(BOOT, "No region specified in IP.BIN"); - if (settings.dreamcast.cable <= 1 && !ip_meta.supportsVGA()) + if (config::Cable <= 1 && !ip_meta.supportsVGA()) { NOTICE_LOG(BOOT, "Game doesn't support VGA. Using TV Composite instead"); - settings.dreamcast.cable = 3; - forced_game_cable = settings.dreamcast.cable; + config::Cable.override(3); } - if (settings.dreamcast.cable == 2 && + if (config::Cable == 2 && (prod_id == "T40602N" // Centipede || prod_id == "T9710N" // Gauntlet Legends (US) || prod_id == "MK-51152" // World Series Baseball 2K2 @@ -279,8 +252,7 @@ static void LoadSpecialSettings() || prod_id == "T1235M")) // Vampire Chronicle for Matching Service { NOTICE_LOG(BOOT, "Game doesn't support RGB. Using TV Composite instead"); - settings.dreamcast.cable = 3; - forced_game_cable = settings.dreamcast.cable; + config::Cable.override(3); } } else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE) @@ -289,16 +261,15 @@ static void LoadSpecialSettings() if (!strcmp("SAMURAI SPIRITS 6", naomi_game_id)) { INFO_LOG(BOOT, "Enabling Extra depth scaling for game %s", naomi_game_id); - settings.rend.ExtraDepthScale = 1e26; - extra_depth_game = true; + config::ExtraDepthScale.override(1e26f); } if (!strcmp("COSMIC SMASH IN JAPAN", naomi_game_id)) { INFO_LOG(BOOT, "Enabling translucent depth multipass for game %s", naomi_game_id); - settings.rend.TranslucentPolygonDepthMask = true; - tr_poly_depth_mask_game = true; + config::TranslucentPolygonDepthMask.override(true); } // Input configuration + settings.input.JammaSetup = JVS::Default; if (!strcmp("DYNAMIC GOLF", naomi_game_id) || !strcmp("SHOOTOUT POOL", naomi_game_id) || !strcmp("SHOOTOUT POOL MEDAL", naomi_game_id) @@ -393,7 +364,6 @@ static void LoadSpecialSettings() INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id); settings.input.JammaSetup = JVS::TouchDeUno; } - settings.rend.Rotate90 = naomi_rotate_screen; } } @@ -403,8 +373,6 @@ void dc_reset(bool hard) mem_Reset(hard); sh4_cpu.Reset(hard); - if (hard) - EventManager::event(Event::Terminate); } static bool reset_requested; @@ -424,7 +392,7 @@ int reicast_init(int argc, char* argv[]) { return 69; } - InitSettings(); + config::Settings::instance().reset(); LogManager::Shutdown(); if (!cfgOpen()) { @@ -435,9 +403,8 @@ int reicast_init(int argc, char* argv[]) else { LogManager::Init(); - LoadSettings(false); + config::Settings::instance().load(false); } - settings.pvr.rend = (RenderType)cfgLoadInt("config", "pvr.rend", (int)settings.pvr.rend); os_CreateWindow(); os_SetupInput(); @@ -492,8 +459,6 @@ static void set_platform(int platform) void dc_init() { - static bool init_done; - if (init_done) return; @@ -508,7 +473,7 @@ void dc_init() #if FEAT_SHREC != DYNAREC_NONE Get_Sh4Recompiler(&sh4_cpu); sh4_cpu.Init(); // Also initialize the interpreter - if(settings.dynarec.Enable) + if(config::DynarecEnabled) { INFO_LOG(DYNAREC, "Using Recompiler"); } @@ -543,52 +508,28 @@ static int get_game_platform(const char *path) static void dc_start_game(const char *path) { DEBUG_LOG(BOOT, "Loading game %s", path == nullptr ? "(nil)" : path); - bool forced_bios_file = false; - if (path != NULL) - { + if (path != nullptr) strcpy(settings.imgread.ImagePath, path); - } else - { - // Booting the BIOS requires a BIOS file - forced_bios_file = true; settings.imgread.ImagePath[0] = '\0'; - } dc_init(); set_platform(get_game_platform(path)); mem_map_default(); - InitSettings(); + config::Settings::instance().reset(); dc_reset(true); - LoadSettings(false); + config::Settings::instance().load(false); if (settings.platform.system == DC_PLATFORM_DREAMCAST) { - if ((settings.bios.UseReios && !forced_bios_file) || !LoadRomFiles()) - { - if (forced_bios_file) - throw ReicastException("No BIOS file found"); - - if (!LoadHle()) - throw ReicastException("Failed to initialize HLE BIOS"); - - NOTICE_LOG(BOOT, "Did not load BIOS, using reios"); - } - } - else - { - LoadRomFiles(); - } - if (settings.platform.system == DC_PLATFORM_DREAMCAST) - { - mcfg_CreateDevices(); - if (path == NULL) { // Boot BIOS + if (!LoadRomFiles()) + throw ReicastException("No BIOS file found"); TermDrive(); InitDrive(); } @@ -598,26 +539,41 @@ static void dc_start_game(const char *path) if (extension != "elf") { if (InitDrive()) - LoadCustom(); + { + LoadGameSpecificSettings(); + if (config::UseReios || !LoadRomFiles()) + { + LoadHle(); + NOTICE_LOG(BOOT, "Did not load BIOS, using reios"); + } + } else { // Content load failed. Boot the BIOS settings.imgread.ImagePath[0] = '\0'; - forced_bios_file = true; if (!LoadRomFiles()) throw ReicastException("No BIOS file found"); InitDrive(); } } + else + { + // Elf only supported with HLE BIOS + LoadHle(); + } } + mcfg_CreateDevices(); FixUpFlash(); } else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE) { + LoadRomFiles(); naomi_cart_LoadRom(path); if (loading_canceled) return; - LoadCustom(); + LoadGameSpecificSettings(); + // Reload the BIOS in case a game-specific region is set + naomi_cart_LoadBios(path); if (settings.platform.system == DC_PLATFORM_NAOMI) { mcfg_CreateNAOMIJamma(); @@ -629,20 +585,11 @@ static void dc_start_game(const char *path) if (cheatManager.Reset()) { gui_display_notification("Widescreen cheat activated", 1000); - if (saved_screen_stretching == -1) - saved_screen_stretching = settings.rend.ScreenStretching; - settings.rend.ScreenStretching = 133; // 4:3 -> 16:9 - } - else - { - if (saved_screen_stretching != -1) - { - settings.rend.ScreenStretching = saved_screen_stretching; - saved_screen_stretching = -1; - } + config::ScreenStretching.override(134); // 4:3 -> 16:9 } fast_forward_mode = false; EventManager::event(Event::Start); + settings.gameStarted = true; } bool dc_is_running() @@ -655,7 +602,7 @@ void* dc_run(void*) { InitAudio(); - if (settings.dynarec.Enable) + if (config::DynarecEnabled) { Get_Sh4Recompiler(&sh4_cpu); INFO_LOG(DYNAREC, "Using Recompiler"); @@ -671,10 +618,9 @@ void* dc_run(void*) sh4_cpu.Run(); SaveRomFiles(); + if (reset_requested) - { dc_reset(false); - } } while (reset_requested); TermAudio(); @@ -683,8 +629,23 @@ void* dc_run(void*) } #endif +void dc_term_game() +{ + if (settings.gameStarted) + { + settings.gameStarted = false; + EventManager::event(Event::Terminate); + } + if (init_done) + dc_reset(true); + + config::Settings::instance().reset(); + config::Settings::instance().load(false); +} + void dc_term() { + dc_term_game(); dc_cancel_load(); sh4_cpu.Term(); if (settings.platform.system != DC_PLATFORM_DREAMCAST) @@ -700,10 +661,12 @@ void dc_term() void dc_stop() { + bool running = dc_is_running(); sh4_cpu.Stop(); rend_cancel_emu_wait(); emu_thread.WaitToEnd(); - EventManager::event(Event::Pause); + if (running) + EventManager::event(Event::Pause); } // Called on the emulator thread for soft reset @@ -719,232 +682,7 @@ void dc_exit() mainui_stop(); } -void InitSettings() -{ - settings.dynarec.Enable = true; - settings.dynarec.idleskip = true; - settings.dynarec.unstable_opt = false; - settings.dynarec.safemode = false; - settings.dynarec.disable_vmem32 = false; - settings.dreamcast.cable = 3; // TV composite - settings.dreamcast.region = 3; // default - settings.dreamcast.broadcast = 4; // default - settings.dreamcast.language = 6; // default - settings.dreamcast.FullMMU = false; - settings.dreamcast.ForceWindowsCE = false; - settings.dreamcast.HideLegacyNaomiRoms = true; - settings.aica.DSPEnabled = false; - settings.aica.LimitFPS = true; - settings.aica.NoBatch = false; - settings.aica.NoSound = false; - settings.audio.backend = "auto"; - settings.rend.UseMipmaps = true; - settings.rend.WideScreen = false; - settings.rend.ShowFPS = false; - settings.rend.RenderToTextureBuffer = false; - settings.rend.RenderToTextureUpscale = 1; - settings.rend.TranslucentPolygonDepthMask = false; - settings.rend.ModifierVolumes = true; - settings.rend.Clipping = true; - settings.rend.TextureUpscale = 1; - settings.rend.MaxFilteredTextureSize = 256; - settings.rend.ExtraDepthScale = 1.f; - settings.rend.CustomTextures = false; - settings.rend.DumpTextures = false; - settings.rend.ScreenScaling = 100; - settings.rend.ScreenStretching = 100; - settings.rend.Fog = true; - settings.rend.FloatVMUs = false; - settings.rend.Rotate90 = false; - settings.rend.PerStripSorting = false; - settings.rend.DelayFrameSwapping = false; - settings.rend.WidescreenGameHacks = false; - memset(settings.rend.CrosshairColor, 0, sizeof(settings.rend.CrosshairColor)); - - settings.pvr.ta_skip = 0; - - settings.pvr.MaxThreads = 3; - settings.pvr.AutoSkipFrame = 0; - - settings.debug.SerialConsole = false; - settings.debug.SerialPTY = false; - - settings.bios.UseReios = false; - - settings.validate.OpenGlChecks = false; - - settings.input.MouseSensitivity = 100; - settings.input.JammaSetup = JVS::Default; - settings.input.VirtualGamepadVibration = 20; - for (int i = 0; i < MAPLE_PORTS; i++) - { - settings.input.maple_devices[i] = i == 0 ? MDT_SegaController : MDT_None; - settings.input.maple_expansion_devices[i][0] = i == 0 ? MDT_SegaVMU : MDT_None; - settings.input.maple_expansion_devices[i][1] = i == 0 ? MDT_SegaVMU : MDT_None; - } - settings.network.Enable = false; - settings.network.ActAsServer = false; - settings.network.dns = "46.101.91.123"; // Dreamcast Live DNS - settings.network.server = ""; - settings.network.EmulateBBA = false; - -#if SUPPORT_DISPMANX - settings.dispmanx.Width = 0; - settings.dispmanx.Height = 0; - settings.dispmanx.Keep_Aspect = true; -#endif - -#if HOST_CPU == CPU_ARM - settings.aica.BufferSize = 5644; // 128 ms -#else - settings.aica.BufferSize = 2822; // 64 ms -#endif - -#if USE_OMX - settings.omx.Audio_Latency = 100; - settings.omx.Audio_HDMI = true; -#endif -} - -void LoadSettings(bool game_specific) -{ - const char *config_section = game_specific ? cfgGetGameId() : "config"; - const char *input_section = game_specific ? cfgGetGameId() : "input"; - const char *audio_section = game_specific ? cfgGetGameId() : "audio"; - - settings.dynarec.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable); - settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip); - settings.dynarec.unstable_opt = cfgLoadBool(config_section, "Dynarec.unstable-opt", settings.dynarec.unstable_opt); - settings.dynarec.safemode = cfgLoadBool(config_section, "Dynarec.safe-mode", settings.dynarec.safemode); - settings.dynarec.disable_vmem32 = cfgLoadBool(config_section, "Dynarec.DisableVmem32", settings.dynarec.disable_vmem32); - //disable_nvmem can't be loaded, because nvmem init is before cfg load - settings.dreamcast.cable = cfgLoadInt(config_section, "Dreamcast.Cable", settings.dreamcast.cable); - settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region); - settings.dreamcast.broadcast = cfgLoadInt(config_section, "Dreamcast.Broadcast", settings.dreamcast.broadcast); - settings.dreamcast.language = cfgLoadInt(config_section, "Dreamcast.Language", settings.dreamcast.language); - settings.dreamcast.FullMMU = cfgLoadBool(config_section, "Dreamcast.FullMMU", settings.dreamcast.FullMMU); - settings.dreamcast.ForceWindowsCE = cfgLoadBool(config_section, "Dreamcast.ForceWindowsCE", settings.dreamcast.ForceWindowsCE); - if (settings.dreamcast.ForceWindowsCE) - settings.aica.NoBatch = true; - settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS) - || cfgLoadInt(config_section, "aica.LimitFPS", 0) == 2; - settings.aica.DSPEnabled = cfgLoadBool(config_section, "aica.DSPEnabled", settings.aica.DSPEnabled); - settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound); - settings.aica.BufferSize = cfgLoadInt(config_section, "aica.BufferSize", settings.aica.BufferSize); - settings.aica.BufferSize = std::max(512u, settings.aica.BufferSize); - settings.audio.backend = cfgLoadStr(audio_section, "backend", settings.audio.backend.c_str()); - settings.rend.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps); - settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen); - settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS); - settings.rend.RenderToTextureBuffer = cfgLoadBool(config_section, "rend.RenderToTextureBuffer", settings.rend.RenderToTextureBuffer); - settings.rend.RenderToTextureUpscale = cfgLoadInt(config_section, "rend.RenderToTextureUpscale", settings.rend.RenderToTextureUpscale); - settings.rend.TranslucentPolygonDepthMask = cfgLoadBool(config_section, "rend.TranslucentPolygonDepthMask", settings.rend.TranslucentPolygonDepthMask); - settings.rend.ModifierVolumes = cfgLoadBool(config_section, "rend.ModifierVolumes", settings.rend.ModifierVolumes); - settings.rend.Clipping = cfgLoadBool(config_section, "rend.Clipping", settings.rend.Clipping); - settings.rend.TextureUpscale = cfgLoadInt(config_section, "rend.TextureUpscale", settings.rend.TextureUpscale); - settings.rend.MaxFilteredTextureSize = cfgLoadInt(config_section,"rend.MaxFilteredTextureSize", settings.rend.MaxFilteredTextureSize); - std::string extra_depth_scale_str = cfgLoadStr(config_section,"rend.ExtraDepthScale", ""); - if (!extra_depth_scale_str.empty()) - { - settings.rend.ExtraDepthScale = atof(extra_depth_scale_str.c_str()); - if (settings.rend.ExtraDepthScale == 0) - settings.rend.ExtraDepthScale = 1.f; - } - settings.rend.CustomTextures = cfgLoadBool(config_section, "rend.CustomTextures", settings.rend.CustomTextures); - settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures); - settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling); - settings.rend.ScreenScaling = std::min(std::max(1, settings.rend.ScreenScaling), 800); - settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching); - settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog); - settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs); - settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90); - settings.rend.PerStripSorting = cfgLoadBool(config_section, "rend.PerStripSorting", settings.rend.PerStripSorting); - settings.rend.DelayFrameSwapping = cfgLoadBool(config_section, "rend.DelayFrameSwapping", settings.rend.DelayFrameSwapping); - settings.rend.WidescreenGameHacks = cfgLoadBool(config_section, "rend.WidescreenGameHacks", settings.rend.WidescreenGameHacks); - for (u32 i = 0; i < ARRAY_SIZE(settings.rend.CrosshairColor); i++) - { - std::string name = "rend.CrossHairColor" + std::to_string(i + 1); - settings.rend.CrosshairColor[i] = cfgLoadInt(config_section, name.c_str(), settings.rend.CrosshairColor[i]); - } - - settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip); - - settings.pvr.MaxThreads = cfgLoadInt(config_section, "pvr.MaxThreads", settings.pvr.MaxThreads); - if (game_specific) - settings.pvr.AutoSkipFrame = cfgLoadInt(config_section, "pvr.AutoSkipFrame", settings.pvr.AutoSkipFrame); - else - { - // compatibility with previous SynchronousRendering option - int autoskip = cfgLoadInt(config_section, "pvr.AutoSkipFrame", 99); - if (autoskip == 99) - autoskip = cfgLoadBool(config_section, "pvr.SynchronousRendering", true) ? 1 : 2; - settings.pvr.AutoSkipFrame = autoskip; - } - - settings.debug.SerialConsole = cfgLoadBool(config_section, "Debug.SerialConsoleEnabled", settings.debug.SerialConsole); - settings.debug.SerialPTY = cfgLoadBool(config_section, "Debug.SerialPTY", settings.debug.SerialPTY); - - settings.bios.UseReios = cfgLoadBool(config_section, "bios.UseReios", settings.bios.UseReios); - - settings.validate.OpenGlChecks = cfgLoadBool(game_specific ? cfgGetGameId() : "validate", "OpenGlChecks", settings.validate.OpenGlChecks); - - settings.input.MouseSensitivity = cfgLoadInt(input_section, "MouseSensitivity", settings.input.MouseSensitivity); - settings.input.JammaSetup = (JVS)cfgLoadInt(input_section, "JammaSetup", (int)settings.input.JammaSetup); - settings.input.VirtualGamepadVibration = cfgLoadInt(input_section, "VirtualGamepadVibration", settings.input.VirtualGamepadVibration); - for (int i = 0; i < MAPLE_PORTS; i++) - { - char device_name[32]; - sprintf(device_name, "device%d", i + 1); - settings.input.maple_devices[i] = (MapleDeviceType)cfgLoadInt(input_section, device_name, settings.input.maple_devices[i]); - sprintf(device_name, "device%d.1", i + 1); - settings.input.maple_expansion_devices[i][0] = (MapleDeviceType)cfgLoadInt(input_section, device_name, settings.input.maple_expansion_devices[i][0]); - sprintf(device_name, "device%d.2", i + 1); - settings.input.maple_expansion_devices[i][1] = (MapleDeviceType)cfgLoadInt(input_section, device_name, settings.input.maple_expansion_devices[i][1]); - } - settings.network.Enable = cfgLoadBool("network", "Enable", settings.network.Enable); - settings.network.ActAsServer = cfgLoadBool("network", "ActAsServer", settings.network.ActAsServer); - settings.network.dns = cfgLoadStr("network", "DNS", settings.network.dns.c_str()); - settings.network.server = cfgLoadStr("network", "server", settings.network.server.c_str()); - settings.network.EmulateBBA = cfgLoadBool("network", "EmulateBBA", settings.network.EmulateBBA); - -#if SUPPORT_DISPMANX - settings.dispmanx.Width = cfgLoadInt(game_specific ? cfgGetGameId() : "dispmanx", "width", settings.dispmanx.Width); - settings.dispmanx.Height = cfgLoadInt(game_specific ? cfgGetGameId() : "dispmanx", "height", settings.dispmanx.Height); - settings.dispmanx.Keep_Aspect = cfgLoadBool(game_specific ? cfgGetGameId() : "dispmanx", "maintain_aspect", settings.dispmanx.Keep_Aspect); -#endif - -#if USE_OMX - settings.omx.Audio_Latency = cfgLoadInt(game_specific ? cfgGetGameId() : "omx", "audio_latency", settings.omx.Audio_Latency); - settings.omx.Audio_HDMI = cfgLoadBool(game_specific ? cfgGetGameId() : "omx", "audio_hdmi", settings.omx.Audio_HDMI); -#endif - - if (!game_specific) - { - settings.dreamcast.ContentPath.clear(); - std::string paths = cfgLoadStr(config_section, "Dreamcast.ContentPath", ""); - std::string::size_type start = 0; - while (true) - { - std::string::size_type end = paths.find(';', start); - if (end == std::string::npos) - end = paths.size(); - if (start != end) - settings.dreamcast.ContentPath.push_back(paths.substr(start, end - start)); - if (end == paths.size()) - break; - start = end + 1; - } - settings.dreamcast.HideLegacyNaomiRoms = cfgLoadBool(config_section, "Dreamcast.HideLegacyNaomiRoms", settings.dreamcast.HideLegacyNaomiRoms); - } -/* - //make sure values are valid - settings.dreamcast.cable = std::min(std::max(settings.dreamcast.cable, 0),3); - settings.dreamcast.region = std::min(std::max(settings.dreamcast.region, 0),3); - settings.dreamcast.broadcast = std::min(std::max(settings.dreamcast.broadcast,0),4); -*/ -} - -static void LoadCustom() +void LoadGameSpecificSettings() { char *reios_id; if (settings.platform.system == DC_PLATFORM_DREAMCAST) @@ -969,124 +707,27 @@ static void LoadCustom() // Default per-game settings LoadSpecialSettings(); - cfgSetGameId(reios_id); + config::Settings::instance().setGameId(reios_id); // Reload per-game settings - LoadSettings(true); + config::Settings::instance().load(true); } void SaveSettings() { - cfgSetAutoSave(false); - cfgSaveBool("config", "Dynarec.Enabled", settings.dynarec.Enable); - if (forced_game_cable == -1 || forced_game_cable != (int)settings.dreamcast.cable) - cfgSaveInt("config", "Dreamcast.Cable", settings.dreamcast.cable); - if (forced_game_region == -1 || forced_game_region != (int)settings.dreamcast.region) - cfgSaveInt("config", "Dreamcast.Region", settings.dreamcast.region); - cfgSaveInt("config", "Dreamcast.Broadcast", settings.dreamcast.broadcast); - cfgSaveBool("config", "Dreamcast.ForceWindowsCE", settings.dreamcast.ForceWindowsCE); - cfgSaveBool("config", "Dynarec.idleskip", settings.dynarec.idleskip); - cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt); - if (!safemode_game || !settings.dynarec.safemode) - cfgSaveBool("config", "Dynarec.safe-mode", settings.dynarec.safemode); - cfgSaveBool("config", "bios.UseReios", settings.bios.UseReios); - -// if (!disable_vmem32_game || !settings.dynarec.disable_vmem32) -// cfgSaveBool("config", "Dynarec.DisableVmem32", settings.dynarec.disable_vmem32); - cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language); - cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS); - cfgSaveBool("config", "aica.DSPEnabled", settings.aica.DSPEnabled); - cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound); - cfgSaveInt("config", "aica.BufferSize", settings.aica.BufferSize); - cfgSaveStr("audio", "backend", settings.audio.backend.c_str()); - - // Write backend specific settings - // std::map> - for (const auto& pair : settings.audio.options) - { - const std::string& section = pair.first; - const auto& options = pair.second; - for (const auto& option : options) - cfgSaveStr(section.c_str(), option.first.c_str(), option.second.c_str()); - } - - cfgSaveBool("config", "rend.WideScreen", settings.rend.WideScreen); - cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS); - if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer) - cfgSaveBool("config", "rend.RenderToTextureBuffer", settings.rend.RenderToTextureBuffer); - cfgSaveInt("config", "rend.RenderToTextureUpscale", settings.rend.RenderToTextureUpscale); - cfgSaveBool("config", "rend.ModifierVolumes", settings.rend.ModifierVolumes); - cfgSaveBool("config", "rend.Clipping", settings.rend.Clipping); - cfgSaveInt("config", "rend.TextureUpscale", settings.rend.TextureUpscale); - cfgSaveInt("config", "rend.MaxFilteredTextureSize", settings.rend.MaxFilteredTextureSize); - cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures); - cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures); - cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling); - if (saved_screen_stretching != -1) - cfgSaveInt("config", "rend.ScreenStretching", saved_screen_stretching); - else - cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching); - cfgSaveBool("config", "rend.Fog", settings.rend.Fog); - cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs); - if (!naomi_rotate_screen || !settings.rend.Rotate90) - cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90); - cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip); - cfgSaveInt("config", "pvr.rend", (int)settings.pvr.rend); - cfgSaveBool("config", "rend.PerStripSorting", settings.rend.PerStripSorting); - cfgSaveBool("config", "rend.DelayFrameSwapping", settings.rend.DelayFrameSwapping); - cfgSaveBool("config", "rend.WidescreenGameHacks", settings.rend.WidescreenGameHacks); - for (u32 i = 0; i < ARRAY_SIZE(settings.rend.CrosshairColor); i++) - { - std::string name = "rend.CrossHairColor" + std::to_string(i + 1); - cfgSaveInt("config", name.c_str(), settings.rend.CrosshairColor[i]); - } - - cfgSaveInt("config", "pvr.MaxThreads", settings.pvr.MaxThreads); - cfgSaveInt("config", "pvr.AutoSkipFrame", settings.pvr.AutoSkipFrame); - - cfgSaveBool("config", "Debug.SerialConsoleEnabled", settings.debug.SerialConsole); - cfgSaveBool("config", "Debug.SerialPTY", settings.debug.SerialPTY); - cfgSaveInt("input", "MouseSensitivity", settings.input.MouseSensitivity); - cfgSaveInt("input", "VirtualGamepadVibration", settings.input.VirtualGamepadVibration); - for (int i = 0; i < MAPLE_PORTS; i++) - { - char device_name[32]; - sprintf(device_name, "device%d", i + 1); - cfgSaveInt("input", device_name, (s32)settings.input.maple_devices[i]); - sprintf(device_name, "device%d.1", i + 1); - cfgSaveInt("input", device_name, (s32)settings.input.maple_expansion_devices[i][0]); - sprintf(device_name, "device%d.2", i + 1); - cfgSaveInt("input", device_name, (s32)settings.input.maple_expansion_devices[i][1]); - } - // FIXME This should never be a game-specific setting - std::string paths; - for (auto& path : settings.dreamcast.ContentPath) - { - if (!paths.empty()) - paths += ";"; - paths += path; - } - cfgSaveStr("config", "Dreamcast.ContentPath", paths.c_str()); - cfgSaveBool("config", "Dreamcast.HideLegacyNaomiRoms", settings.dreamcast.HideLegacyNaomiRoms); - cfgSaveBool("network", "Enable", settings.network.Enable); - cfgSaveBool("network", "ActAsServer", settings.network.ActAsServer); - cfgSaveStr("network", "DNS", settings.network.dns.c_str()); - cfgSaveStr("network", "server", settings.network.server.c_str()); - cfgSaveBool("network", "EmulateBBA", settings.network.EmulateBBA); - + config::Settings::instance().save(); GamepadDevice::SaveMaplePorts(); #ifdef __ANDROID__ void SaveAndroidSettings(); SaveAndroidSettings(); #endif - - cfgSetAutoSave(true); } void dc_resume() { SetMemoryHandlers(); + settings.aica.NoBatch = config::ForceWindowsCE || config::DSPEnabled; EventManager::event(Event::Resume); if (!emu_thread.thread.joinable()) emu_thread.Start(); @@ -1126,8 +767,6 @@ void dc_savestate() unsigned int total_size = 0 ; void *data = NULL ; - dc_stop(); - if ( ! dc_serialize(&data, &total_size) ) { WARN_LOG(SAVESTATE, "Failed to save state - could not initialize total size") ; diff --git a/core/oslib/audiobackend_alsa.cpp b/core/oslib/audiobackend_alsa.cpp index a83c82c07..2964a6ca1 100644 --- a/core/oslib/audiobackend_alsa.cpp +++ b/core/oslib/audiobackend_alsa.cpp @@ -112,7 +112,7 @@ static void alsa_init() } // Sample buffer size - buffer_size = settings.aica.BufferSize; + buffer_size = config::AudioBufferSize; rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size); if (rc < 0) { diff --git a/core/oslib/audiobackend_coreaudio.cpp b/core/oslib/audiobackend_coreaudio.cpp index cb6f850c3..985a2ad2b 100644 --- a/core/oslib/audiobackend_coreaudio.cpp +++ b/core/oslib/audiobackend_coreaudio.cpp @@ -120,7 +120,7 @@ static void coreaudio_init() err = AudioUnitInitialize(audioUnit); verify(err == noErr); - BUFSIZE = settings.aica.BufferSize * 4; + BUFSIZE = config::AudioBufferSize * 4; samples_temp = new u8[BUFSIZE](); samples_rptr = 0; samples_wptr = 0; diff --git a/core/oslib/audiobackend_omx.cpp b/core/oslib/audiobackend_omx.cpp index 6295c7a2b..3913882cc 100644 --- a/core/oslib/audiobackend_omx.cpp +++ b/core/oslib/audiobackend_omx.cpp @@ -87,8 +87,8 @@ static void omx_init() } // Initialize settings - latency_max = settings.omx.Audio_Latency; - buffer_size = settings.aica.BufferSize * 4; + latency_max = config::OmxAudioLatency; + buffer_size = config::AudioBufferSize * 4; buffer_count = 2 + OUTPUT_FREQ * latency_max / (buffer_size * 1000); OMX_CALLBACKTYPE callbacks; @@ -224,7 +224,7 @@ static void omx_init() } const char* output_device = "local"; - if(settings.omx.Audio_HDMI) + if (config::OmxAudioHdmi) output_device = (const char*)"hdmi"; // Set audio destination diff --git a/core/oslib/audiobackend_pulseaudio.cpp b/core/oslib/audiobackend_pulseaudio.cpp index b28c6e635..2b5e46c7c 100644 --- a/core/oslib/audiobackend_pulseaudio.cpp +++ b/core/oslib/audiobackend_pulseaudio.cpp @@ -210,7 +210,7 @@ static void pulseaudio_init() pa_buffer_attr buffer_attr; buffer_attr.maxlength = -1; - buffer_attr.tlength = pa_usec_to_bytes(settings.aica.BufferSize * PA_USEC_PER_SEC / 44100, &spec); + buffer_attr.tlength = pa_usec_to_bytes(config::AudioBufferSize * PA_USEC_PER_SEC / 44100, &spec); buffer_attr.prebuf = -1; buffer_attr.minreq = -1; buffer_attr.fragsize = -1; diff --git a/core/oslib/audiostream.cpp b/core/oslib/audiostream.cpp index 4b99e0822..f4757037a 100644 --- a/core/oslib/audiostream.cpp +++ b/core/oslib/audiostream.cpp @@ -1,5 +1,4 @@ #include "audiostream.h" -#include "cfg/cfg.h" #include #include @@ -19,7 +18,7 @@ static bool eight_khz; u32 GetAudioBackendCount() { - return audiobackends != nullptr ? audiobackends->size() : 0; + return audiobackends != nullptr ? (u32)audiobackends->size() : 0; } audiobackend_t* GetAudioBackend(int num) @@ -98,7 +97,7 @@ void WriteSample(s16 r, s16 l) WritePtr=ptr; if (WritePtr == SAMPLE_COUNT - 1) - PushAudio(RingBuffer,SAMPLE_COUNT, settings.aica.LimitFPS); + PushAudio(RingBuffer,SAMPLE_COUNT, config::LimitFPS); } void InitAudio() @@ -114,7 +113,7 @@ void InitAudio() SortAudioBackends(); - std::string audiobackend_slug = settings.audio.backend; + std::string audiobackend_slug = config::AudioBackend; audiobackend_current = GetAudioBackend(audiobackend_slug); if (audiobackend_current == nullptr) { INFO_LOG(AUDIO, "WARNING: Running without audio!"); diff --git a/core/oslib/audiostream.h b/core/oslib/audiostream.h index 462b8941b..32c4ad203 100644 --- a/core/oslib/audiostream.h +++ b/core/oslib/audiostream.h @@ -1,5 +1,6 @@ #pragma once #include "types.h" +#include "cfg/option.h" typedef std::vector (*audio_option_callback_t)(); enum audio_option_type diff --git a/core/rec-ARM/rec_arm.cpp b/core/rec-ARM/rec_arm.cpp index 032e84ef0..087e1ab6f 100644 --- a/core/rec-ARM/rec_arm.cpp +++ b/core/rec-ARM/rec_arm.cpp @@ -10,6 +10,7 @@ #include "hw/sh4/sh4_core.h" #include "hw/sh4/dyna/ngen.h" #include "hw/sh4/sh4_mem.h" +#include "cfg/option.h" #define _DEVEL 1 #include "arm_emitter/arm_emitter.h" @@ -949,7 +950,7 @@ u32* ngen_readm_fail_v2(u32* ptrv,u32* regs,u32 fault_addr) //fault offset must always be the addr from ubfx (sanity check) verify((fault_offs==0) || fault_offs==(0x1FFFFFFF&sh4_addr)); - if (settings.dynarec.unstable_opt && is_sq) //THPS2 uses cross area SZ_32F so this is disabled for now + if (config::DynarecUnstableOpt && is_sq) //THPS2 uses cross area SZ_32F so this is disabled for now { //SQ ! s32 sq_offs=sq_both-sh4_ctr; @@ -2210,14 +2211,6 @@ void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool s //StoreImms(r0,r1,(u32)&last_run_block,(u32)code); //useful when code jumps to random locations ... ++blockno; - if (settings.profile.run_counts) - { - MOV32(r1,(u32)&block->runs); - LDR(r0,r1); - ADD(r0,r0,1); - STR(r0,r1); - } - //reg alloc reg.DoAlloc(block,alloc_regs,alloc_fpu); diff --git a/core/rend/CustomTexture.cpp b/core/rend/CustomTexture.cpp index e782e99ec..7d88acf0c 100644 --- a/core/rend/CustomTexture.cpp +++ b/core/rend/CustomTexture.cpp @@ -19,6 +19,7 @@ #include "CustomTexture.h" #include "cfg/cfg.h" #include "oslib/directory.h" +#include "cfg/option.h" #include #define STB_IMAGE_IMPLEMENTATION @@ -82,7 +83,7 @@ void CustomTexture::LoaderThread() std::string CustomTexture::GetGameId() { - std::string game_id(cfgGetGameId()); + std::string game_id(config::Settings::instance().getGameId()); const size_t str_end = game_id.find_last_not_of(' '); if (str_end == std::string::npos) return ""; diff --git a/core/rend/TexCache.cpp b/core/rend/TexCache.cpp index 7840e8210..977d854e4 100644 --- a/core/rend/TexCache.cpp +++ b/core/rend/TexCache.cpp @@ -270,7 +270,7 @@ static inline int getThreadCount() int tcount = omp_get_num_procs() - 1; if (tcount < 1) tcount = 1; - return std::min(tcount, (int)settings.pvr.MaxThreads); + return std::min(tcount, (int)config::MaxThreads); } template @@ -563,7 +563,7 @@ void BaseTextureCacheData::Update() return; } } - if (settings.rend.CustomTextures) + if (config::CustomTextures) custom_texture.LoadCustomTextureAsync(this); void *temp_tex_buffer = NULL; @@ -575,9 +575,9 @@ void BaseTextureCacheData::Update() PixelBuffer pb8; // Figure out if we really need to use a 32-bit pixel buffer - bool textureUpscaling = settings.rend.TextureUpscale > 1 + bool textureUpscaling = config::TextureUpscale > 1 // Don't process textures that are too big - && (int)(w * h) <= settings.rend.MaxFilteredTextureSize * settings.rend.MaxFilteredTextureSize + && (int)(w * h) <= config::MaxFilteredTextureSize * config::MaxFilteredTextureSize // Don't process YUV textures && tcw.PixelFmt != PixelYUV; bool need_32bit_buffer = true; @@ -588,7 +588,7 @@ void BaseTextureCacheData::Update() need_32bit_buffer = false; // TODO avoid upscaling/depost. textures that change too often - bool mipmapped = IsMipmapped() && !settings.rend.DumpTextures; + bool mipmapped = IsMipmapped() && !config::DumpTextures; if (texconv32 != NULL && need_32bit_buffer) { @@ -636,15 +636,15 @@ void BaseTextureCacheData::Update() if (textureUpscaling) { PixelBuffer tmp_buf; - tmp_buf.init(w * settings.rend.TextureUpscale, h * settings.rend.TextureUpscale); + tmp_buf.init(w * config::TextureUpscale, h * config::TextureUpscale); if (tcw.PixelFmt == Pixel1555 || tcw.PixelFmt == Pixel4444) // Alpha channel formats. Palettes with alpha are already handled has_alpha = true; - UpscalexBRZ(settings.rend.TextureUpscale, pb32.data(), tmp_buf.data(), w, h, has_alpha); + UpscalexBRZ(config::TextureUpscale, pb32.data(), tmp_buf.data(), w, h, has_alpha); pb32.steal_data(tmp_buf); - upscaled_w *= settings.rend.TextureUpscale; - upscaled_h *= settings.rend.TextureUpscale; + upscaled_w *= config::TextureUpscale; + upscaled_h *= config::TextureUpscale; } } temp_tex_buffer = pb32.data(); @@ -720,7 +720,7 @@ void BaseTextureCacheData::Update() lock_block = libCore_vramlock_Lock(sa_tex,sa+size-1,this); UploadToGPU(upscaled_w, upscaled_h, (u8*)temp_tex_buffer, IsMipmapped(), mipmapped); - if (settings.rend.DumpTextures) + if (config::DumpTextures) { ComputeHash(); custom_texture.DumpTexture(texture_hash, upscaled_w, upscaled_h, tex_type, temp_tex_buffer); diff --git a/core/rend/TexCache.h b/core/rend/TexCache.h index 8b8ecedb3..e4e70c75d 100644 --- a/core/rend/TexCache.h +++ b/core/rend/TexCache.h @@ -1,6 +1,7 @@ #pragma once #include "oslib/oslib.h" #include "hw/pvr/Renderer_if.h" +#include "cfg/option.h" #include #include @@ -700,7 +701,7 @@ public: bool IsMipmapped() { - return tcw.MipMapped != 0 && tcw.ScanOrder == 0 && settings.rend.UseMipmaps; + return tcw.MipMapped != 0 && tcw.ScanOrder == 0 && config::UseMipmaps; } const char* GetPixelFormatName() @@ -739,8 +740,8 @@ public: // This is currently limited to textures using nearest filtering and not mipmapped. // Enabling texture upscaling or dumping also disables this mode. return (tcw.PixelFmt == PixelPal4 || tcw.PixelFmt == PixelPal8) - && settings.rend.TextureUpscale == 1 - && !settings.rend.DumpTextures + && config::TextureUpscale == 1 + && !config::DumpTextures && tsp.FilterMode == 0 && !tcw.MipMapped && !tcw.VQ_Comp; diff --git a/core/rend/game_scanner.h b/core/rend/game_scanner.h index 9e889a06c..e6b381b60 100644 --- a/core/rend/game_scanner.h +++ b/core/rend/game_scanner.h @@ -26,6 +26,7 @@ #include "stdclass.h" #include "hw/naomi/naomi_roms.h" #include "oslib/directory.h" +#include "cfg/option.h" struct GameMedia { std::string name; @@ -70,6 +71,9 @@ class GameScanner DirectoryTree tree(path); for (const DirectoryTree::item& item : tree) { + if (item.name.substr(0, 2) == "._") + // Ignore Mac OS turds + continue; std::string name(item.name); std::string child_path = item.parentPath + "/" + name; #ifdef __APPLE__ @@ -95,7 +99,7 @@ class GameScanner if (arcade_gdroms.count(basename) != 0) continue; } - else if ((settings.dreamcast.HideLegacyNaomiRoms + else if ((config::HideLegacyNaomiRoms || (extension != "bin" && extension != "lst" && extension != "dat")) && extension != "cdi" && extension != "cue") continue; @@ -143,7 +147,7 @@ public: std::lock_guard guard(mutex); game_list.clear(); } - for (const auto& path : settings.dreamcast.ContentPath) + for (const auto& path : config::ContentPath.get()) { add_game_directory(path); if (!running) diff --git a/core/rend/gl4/gldraw.cpp b/core/rend/gl4/gldraw.cpp index 3dce771c4..551862391 100644 --- a/core/rend/gl4/gldraw.cpp +++ b/core/rend/gl4/gldraw.cpp @@ -127,7 +127,7 @@ static void SetGPState(const PolyParam* gp) bool two_volumes_mode = (gp->tsp1.full != (u32)-1) && Type != ListType_Translucent; bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff); - int fog_ctrl = settings.rend.Fog ? gp->tsp.FogCtrl : 2; + int fog_ctrl = config::Fog ? gp->tsp.FogCtrl : 2; palette = BaseTextureCacheData::IsGpuHandledPaletted(gp->tsp, gp->tcw); CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0, @@ -212,7 +212,7 @@ static void SetGPState(const PolyParam* gp) { //bilinear filtering //PowerVR supports also trilinear via two passes, but we ignore that for now - bool mipmapped = gp->tcw.MipMapped != 0 && gp->tcw.ScanOrder == 0 && settings.rend.UseMipmaps; + bool mipmapped = gp->tcw.MipMapped != 0 && gp->tcw.ScanOrder == 0 && config::UseMipmaps; glSamplerParameteri(texSamplers[i], GL_TEXTURE_MIN_FILTER, mipmapped ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); glSamplerParameteri(texSamplers[i], GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (mipmapped) @@ -528,7 +528,7 @@ void gl4DrawStrips(GLuint output_fbo, int width, int height) DrawList(pvrrc.global_param_pt, previous_pass.pt_count, current_pass.pt_count - previous_pass.pt_count); // Modifier volumes - if (settings.rend.ModifierVolumes) + if (config::ModifierVolumes) DrawModVols(previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count); // @@ -591,7 +591,7 @@ void gl4DrawStrips(GLuint output_fbo, int width, int height) DrawList(pvrrc.global_param_tr, previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); // Translucent modifier volumes - if (settings.rend.ModifierVolumes) + if (config::ModifierVolumes) { SetBaseClipping(); DrawTranslucentModVols(previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count); diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index 46858b706..fa2f70904 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -563,7 +563,7 @@ static bool gl4_init() initABuffer(); - if (settings.rend.TextureUpscale > 1) + if (config::TextureUpscale > 1) { // Trick to preload the tables used by xBRZ u32 src[] { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }; @@ -628,12 +628,12 @@ static bool RenderFrame() /* Handle Dc to screen scaling */ - const float screen_scaling = settings.rend.ScreenScaling / 100.f; + const float screen_scaling = config::ScreenScaling / 100.f; int rendering_width; int rendering_height; if (is_rtt) { - int scaling = settings.rend.RenderToTextureBuffer ? 1 : settings.rend.RenderToTextureUpscale; + int scaling = config::RenderToTextureBuffer ? 1 : config::RenderToTextureUpscale; rendering_width = matrices.GetDreamcastViewport().x * scaling; rendering_height = matrices.GetDreamcastViewport().y * scaling; } @@ -661,7 +661,7 @@ static bool RenderFrame() u8* fog_density=(u8*)&FOG_DENSITY; float fog_den_mant=fog_density[1]/128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 s32 fog_den_exp=(s8)fog_density[0]; - gl4ShaderUniforms.fog_den_float = fog_den_mant * powf(2.0f,fog_den_exp) * settings.rend.ExtraDepthScale; + gl4ShaderUniforms.fog_den_float = fog_den_mant * powf(2.0f,fog_den_exp) * config::ExtraDepthScale; gl4ShaderUniforms.fog_clamp_min[0] = ((pvrrc.fog_clamp_min >> 16) & 0xFF) / 255.0f; gl4ShaderUniforms.fog_clamp_min[1] = ((pvrrc.fog_clamp_min >> 8) & 0xFF) / 255.0f; @@ -673,7 +673,7 @@ static bool RenderFrame() gl4ShaderUniforms.fog_clamp_max[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f; gl4ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f; - if (fog_needs_update && settings.rend.Fog) + if (fog_needs_update && config::Fog) { fog_needs_update = false; UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE5, GL_RED); @@ -735,7 +735,7 @@ static bool RenderFrame() } else { - if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) + if (config::ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) { output_fbo = init_output_framebuffer(rendering_width, rendering_height); } @@ -772,7 +772,7 @@ static bool RenderFrame() glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(struct PolyParam) * pvrrc.global_param_tr.used(), pvrrc.global_param_tr.head(), GL_STATIC_DRAW); glCheck(); - if (is_rtt || !settings.rend.WideScreen || matrices.IsClipped() || settings.rend.Rotate90) + if (is_rtt || !config::Widescreen || matrices.IsClipped() || config::Rotate90) { float width; float height; @@ -829,12 +829,12 @@ static bool RenderFrame() height = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; min_x = pvrrc.fb_X_CLIP.min; min_y = pvrrc.fb_Y_CLIP.min; - if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureUpscale > 1 && !config::RenderToTextureBuffer) { - min_x *= settings.rend.RenderToTextureUpscale; - min_y *= settings.rend.RenderToTextureUpscale; - width *= settings.rend.RenderToTextureUpscale; - height *= settings.rend.RenderToTextureUpscale; + min_x *= config::RenderToTextureUpscale; + min_y *= config::RenderToTextureUpscale; + width *= config::RenderToTextureUpscale; + height *= config::RenderToTextureUpscale; } } gl4ShaderUniforms.base_clipping.enabled = true; @@ -866,7 +866,7 @@ static bool RenderFrame() if (is_rtt) ReadRTTBuffer(); - else if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) + else if (config::ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) gl4_render_output_framebuffer(); return !is_rtt; @@ -885,7 +885,7 @@ struct OpenGL4Renderer : OpenGLRenderer { screen_width=w; screen_height=h; - resize((int)lroundf(w * settings.rend.ScreenScaling / 100.f), (int)lroundf(h * settings.rend.ScreenScaling / 100.f)); + resize((int)lroundf(w * config::ScreenScaling / 100.f), (int)lroundf(h * config::ScreenScaling / 100.f)); } void Term() override diff --git a/core/rend/gl4/gltex.cpp b/core/rend/gl4/gltex.cpp index 9201d64b4..982b04e8c 100644 --- a/core/rend/gl4/gltex.cpp +++ b/core/rend/gl4/gltex.cpp @@ -16,12 +16,12 @@ GLuint gl4BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) while (fbw2 < fbw) fbw2 *= 2; - if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureUpscale > 1 && !config::RenderToTextureBuffer) { - fbw *= settings.rend.RenderToTextureUpscale; - fbh *= settings.rend.RenderToTextureUpscale; - fbw2 *= settings.rend.RenderToTextureUpscale; - fbh2 *= settings.rend.RenderToTextureUpscale; + fbw *= config::RenderToTextureUpscale; + fbh *= config::RenderToTextureUpscale; + fbw2 *= config::RenderToTextureUpscale; + fbh2 *= config::RenderToTextureUpscale; } // Create a texture for rendering to diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index 7ea04fabb..854dfa437 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -116,7 +116,7 @@ __forceinline ShaderUniforms.trilinear_alpha = 1.f; bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff); - int fog_ctrl = settings.rend.Fog ? gp->tsp.FogCtrl : 2; + int fog_ctrl = config::Fog ? gp->tsp.FogCtrl : 2; int clip_rect[4] = {}; TileClipping clipmode = GetTileClip(gp->tileclip, ViewportMatrix, clip_rect); @@ -180,7 +180,7 @@ __forceinline { //bilinear filtering //PowerVR supports also trilinear via two passes, but we ignore that for now - bool mipmapped = gp->tcw.MipMapped != 0 && gp->tcw.ScanOrder == 0 && settings.rend.UseMipmaps; + bool mipmapped = gp->tcw.MipMapped != 0 && gp->tcw.ScanOrder == 0 && config::UseMipmaps; glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmapped ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #ifdef GL_TEXTURE_LOD_BIAS @@ -213,7 +213,7 @@ __forceinline glcache.DepthFunc(Zfunction[gp->isp.DepthMode]); } - if (SortingEnabled && !settings.rend.PerStripSorting) + if (SortingEnabled && !config::PerStripSorting) glcache.DepthMask(GL_FALSE); else { @@ -332,7 +332,7 @@ void DrawSorted(bool multipass) params++; } - if (multipass && settings.rend.TranslucentPolygonDepthMask) + if (multipass && config::TranslucentPolygonDepthMask) { // Write to the depth buffer now. The next render pass might need it. (Cosmic Smash) glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -610,14 +610,14 @@ void DrawStrips() DrawList(pvrrc.global_param_pt, previous_pass.pt_count, current_pass.pt_count - previous_pass.pt_count); // Modifier volumes - if (settings.rend.ModifierVolumes) + if (config::ModifierVolumes) DrawModVols(previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count); //Alpha blended { if (current_pass.autosort) { - if (!settings.rend.PerStripSorting) + if (!config::PerStripSorting) { SortTriangles(previous_pass.tr_count, current_pass.tr_count - previous_pass.tr_count); DrawSorted(render_pass < pvrrc.render_passes.used() - 1); diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 297555a4b..da0065104 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -912,7 +912,7 @@ bool gles_init() #endif glCheck(); - if (settings.rend.TextureUpscale > 1) + if (config::TextureUpscale > 1) { // Trick to preload the tables used by xBRZ u32 src[] { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }; @@ -1121,7 +1121,7 @@ bool RenderFrame() u8* fog_density = (u8*)&FOG_DENSITY; float fog_den_mant = fog_density[1] / 128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 s32 fog_den_exp = (s8)fog_density[0]; - ShaderUniforms.fog_den_float = fog_den_mant * powf(2.0f, fog_den_exp) * settings.rend.ExtraDepthScale; + ShaderUniforms.fog_den_float = fog_den_mant * powf(2.0f, fog_den_exp) * config::ExtraDepthScale; ShaderUniforms.fog_clamp_min[0] = ((pvrrc.fog_clamp_min >> 16) & 0xFF) / 255.0f; ShaderUniforms.fog_clamp_min[1] = ((pvrrc.fog_clamp_min >> 8) & 0xFF) / 255.0f; @@ -1133,7 +1133,7 @@ bool RenderFrame() ShaderUniforms.fog_clamp_max[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f; ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f; - if (fog_needs_update && settings.rend.Fog) + if (fog_needs_update && config::Fog) { fog_needs_update = false; UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE1, gl.single_channel_format); @@ -1158,7 +1158,7 @@ bool RenderFrame() ShaderUniforms.Set(&it.second); } - const float screen_scaling = settings.rend.ScreenScaling / 100.f; + const float screen_scaling = config::ScreenScaling / 100.f; //setup render target first if (is_rtt) @@ -1202,7 +1202,7 @@ bool RenderFrame() } else { - if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) + if (config::ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) { init_output_framebuffer((int)lroundf(screen_width * screen_scaling), (int)lroundf(screen_height * screen_scaling)); } @@ -1216,7 +1216,7 @@ bool RenderFrame() } } - bool wide_screen_on = !is_rtt && settings.rend.WideScreen && !matrices.IsClipped() && !settings.rend.Rotate90; + bool wide_screen_on = !is_rtt && config::Widescreen && !matrices.IsClipped() && !config::Rotate90; //Color is cleared by the background plane @@ -1304,12 +1304,12 @@ bool RenderFrame() height = pvrrc.fb_Y_CLIP.max - pvrrc.fb_Y_CLIP.min + 1; min_x = pvrrc.fb_X_CLIP.min; min_y = pvrrc.fb_Y_CLIP.min; - if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureUpscale > 1 && !config::RenderToTextureBuffer) { - min_x *= settings.rend.RenderToTextureUpscale; - min_y *= settings.rend.RenderToTextureUpscale; - width *= settings.rend.RenderToTextureUpscale; - height *= settings.rend.RenderToTextureUpscale; + min_x *= config::RenderToTextureUpscale; + min_y *= config::RenderToTextureUpscale; + width *= config::RenderToTextureUpscale; + height *= config::RenderToTextureUpscale; } } ShaderUniforms.base_clipping.enabled = true; @@ -1336,7 +1336,7 @@ bool RenderFrame() if (is_rtt) ReadRTTBuffer(); - else if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) + else if (config::ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) render_output_framebuffer(); return !is_rtt; diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index 30d6b585e..179438bff 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -8,7 +8,7 @@ #include #include -#define glCheck() do { if (unlikely(settings.validate.OpenGlChecks)) { verify(glGetError()==GL_NO_ERROR); } } while(0) +#define glCheck() do { if (unlikely(config::OpenGlChecks)) { verify(glGetError()==GL_NO_ERROR); } } while(0) #define VERTEX_POS_ARRAY 0 #define VERTEX_COL_BASE_ARRAY 1 diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 8daad6403..13162f20c 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -136,12 +136,12 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt) while (fbw2 < fbw) fbw2 *= 2; - if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureUpscale > 1 && !config::RenderToTextureBuffer) { - fbw *= settings.rend.RenderToTextureUpscale; - fbh *= settings.rend.RenderToTextureUpscale; - fbw2 *= settings.rend.RenderToTextureUpscale; - fbh2 *= settings.rend.RenderToTextureUpscale; + fbw *= config::RenderToTextureUpscale; + fbh *= config::RenderToTextureUpscale; + fbw2 *= config::RenderToTextureUpscale; + fbh2 *= config::RenderToTextureUpscale; } // Get the currently bound frame buffer object. On most platforms this just gives 0. //glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_i32OriginalFbo); @@ -215,7 +215,7 @@ void ReadRTTBuffer() { const u8 fb_packmode = FB_W_CTRL.fb_packmode; - if (settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureBuffer) { u32 tex_addr = gl.rtt.TexAddr << 3; @@ -257,7 +257,7 @@ void ReadRTTBuffer() { //dumpRtTexture(fb_rtt.TexAddr, w, h); - if (w > 1024 || h > 1024 || settings.rend.RenderToTextureBuffer) { + if (w > 1024 || h > 1024 || config::RenderToTextureBuffer) { glcache.DeleteTextures(1, &gl.rtt.tex); } else diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 0f288da02..1a25a14d8 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -53,7 +53,7 @@ int screen_dpi = 96; static bool inited = false; float scaling = 1; -GuiState gui_state = Main; +GuiState gui_state = GuiState::Main; static bool settings_opening; #ifdef __ANDROID__ static bool touch_up; @@ -77,8 +77,22 @@ float gui_get_scaling() static void emuEventCallback(Event event) { - if (event == Event::Resume) + switch (event) + { + case Event::Resume: game_started = true; + break; + case Event::Start: + if (config::AutoSavestate) + dc_loadstate(); + break; + case Event::Terminate: + if (config::AutoSavestate) + dc_savestate(); + break; + default: + break; + } } void gui_init() @@ -133,7 +147,7 @@ void gui_init() #endif // Setup Platform/Renderer bindings - if (settings.pvr.IsOpenGL()) + if (config::RendererType.isOpenGL()) ImGui_ImplOpenGL3_Init(); // Load Fonts @@ -231,11 +245,13 @@ void gui_init() INFO_LOG(RENDERER, "Screen DPI is %d, size %d x %d. Scaling by %.2f", screen_dpi, screen_width, screen_height, scaling); EventManager::listen(Event::Resume, emuEventCallback); + EventManager::listen(Event::Start, emuEventCallback); + EventManager::listen(Event::Terminate, emuEventCallback); } void ImGui_Impl_NewFrame() { - if (settings.pvr.IsOpenGL()) + if (config::RendererType.isOpenGL()) ImGui_ImplOpenGL3_NewFrame(); ImGui::GetIO().DisplaySize.x = screen_width; ImGui::GetIO().DisplaySize.y = screen_height; @@ -337,40 +353,26 @@ void gui_plot_render_time(int width, int height) } #endif -// Helper to display a little (?) mark which shows a tooltip when hovered. -static void ShowHelpMarker(const char* desc) -{ - ImGui::TextDisabled("(?)"); - if (ImGui::IsItemHovered()) - { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted(desc); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } -} - void gui_open_settings() { - if (gui_state == Closed) + if (gui_state == GuiState::Closed) { - gui_state = Commands; + gui_state = GuiState::Commands; settings_opening = true; HideOSD(); } - else if (gui_state == VJoyEdit) + else if (gui_state == GuiState::VJoyEdit) { - gui_state = VJoyEditCommands; + gui_state = GuiState::VJoyEditCommands; } - else if (gui_state == Loading) + else if (gui_state == GuiState::Loading) { dc_cancel_load(); - gui_state = Main; + gui_state = GuiState::Main; } - else if (gui_state == Commands) + else if (gui_state == GuiState::Commands) { - gui_state = Closed; + gui_state = GuiState::Closed; dc_resume(); } } @@ -378,7 +380,7 @@ void gui_open_settings() static void gui_start_game(const std::string& path) { scanner.stop(); - gui_state = Loading; + gui_state = GuiState::Loading; static std::string path_copy; path_copy = path; // path may be a local var @@ -391,10 +393,10 @@ static void gui_display_commands() ImGui_Impl_NewFrame(); ImGui::NewFrame(); - if (!settings_opening && settings.pvr.IsOpenGL()) + if (!settings_opening && config::RendererType.isOpenGL()) ImGui_ImplOpenGL3_DrawBackground(); - if (!settings.rend.FloatVMUs) + if (!config::FloatVMUs) // If floating VMUs, they are already visible on the background display_vmus(); @@ -406,25 +408,25 @@ static void gui_display_commands() ImGui::Columns(2, "buttons", false); if (ImGui::Button("Load State", ImVec2(150 * scaling, 50 * scaling))) { - gui_state = Closed; + gui_state = GuiState::Closed; dc_loadstate(); } ImGui::NextColumn(); if (ImGui::Button("Save State", ImVec2(150 * scaling, 50 * scaling))) { - gui_state = Closed; + gui_state = GuiState::Closed; dc_savestate(); } ImGui::NextColumn(); if (ImGui::Button("Settings", ImVec2(150 * scaling, 50 * scaling))) { - gui_state = Settings; + gui_state = GuiState::Settings; } ImGui::NextColumn(); if (ImGui::Button("Resume", ImVec2(150 * scaling, 50 * scaling))) { - gui_state = Closed; + gui_state = GuiState::Closed; } ImGui::NextColumn(); @@ -433,22 +435,22 @@ static void gui_display_commands() { if (libGDR_GetDiscType() == Open) { - gui_state = SelectDisk; + gui_state = GuiState::SelectDisk; } else { DiscOpenLid(); - gui_state = Closed; + gui_state = GuiState::Closed; } } ImGui::NextColumn(); if (ImGui::Button("Exit", ImVec2(150 * scaling, 50 * scaling))) { // Exit to main menu - gui_state = Main; + dc_term_game(); + gui_state = GuiState::Main; game_started = false; settings.imgread.ImagePath[0] = '\0'; - dc_reset(true); } ImGui::End(); @@ -825,7 +827,7 @@ static void contentpath_warning_popup() scanner.content_path_looks_incorrect = false; ImGui::CloseCurrentPopup(); scanner.stop(); - settings.dreamcast.ContentPath.clear(); + config::ContentPath.get().clear(); } ImGui::SetItemDefaultFocus(); ImGui::PopStyleVar(); @@ -841,8 +843,8 @@ static void contentpath_warning_popup() show_contentpath_selection = false; if (!cancelled) { - settings.dreamcast.ContentPath.clear(); - settings.dreamcast.ContentPath.push_back(selection); + config::ContentPath.get().clear(); + config::ContentPath.get().push_back(selection); } scanner.refresh(); }); @@ -854,7 +856,7 @@ void directory_selected_callback(bool cancelled, std::string selection) if (!cancelled) { scanner.stop(); - settings.dreamcast.ContentPath.push_back(selection); + config::ContentPath.get().push_back(selection); scanner.refresh(); } } @@ -866,9 +868,8 @@ static void gui_display_settings() ImGui_Impl_NewFrame(); ImGui::NewFrame(); - int dynarec_enabled = settings.dynarec.Enable; - RenderType pvr_rend = settings.pvr.rend; - bool vulkan = !settings.pvr.IsOpenGL(); + RenderType pvr_rend = config::RendererType; + bool vulkan = !config::RendererType.isOpenGL(); ImGui::SetNextWindowPos(ImVec2(0, 0)); ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height)); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0); @@ -879,9 +880,9 @@ static void gui_display_settings() if (ImGui::Button("Done", ImVec2(100 * scaling, 30 * scaling))) { if (game_started) - gui_state = Commands; + gui_state = GuiState::Commands; else - gui_state = Main; + gui_state = GuiState::Main; if (maple_devices_changed) { maple_devices_changed = false; @@ -897,19 +898,19 @@ static void gui_display_settings() { ImGui::SameLine(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(16 * scaling, normal_padding.y)); - if (cfgHasGameSpecificConfig()) + if (config::Settings::instance().hasPerGameConfig()) { if (ImGui::Button("Delete Game Config", ImVec2(0, 30 * scaling))) { - cfgDeleteGameSpecificConfig(); - InitSettings(); - LoadSettings(false); + config::Settings::instance().setPerGameConfig(false); + config::Settings::instance().load(false); + LoadGameSpecificSettings(); } } else { if (ImGui::Button("Make Game Config", ImVec2(0, 30 * scaling))) - cfgMakeGameSpecificConfig(); + config::Settings::instance().setPerGameConfig(true); } ImGui::PopStyleVar(); } @@ -922,86 +923,56 @@ static void gui_display_settings() { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding); const char *languages[] = { "Japanese", "English", "German", "French", "Spanish", "Italian", "Default" }; - if (ImGui::BeginCombo("Language", languages[settings.dreamcast.language], ImGuiComboFlags_None)) - { - for (int i = 0; i < IM_ARRAYSIZE(languages); i++) - { - bool is_selected = (int)settings.dreamcast.language == i; - if (ImGui::Selectable(languages[i], &is_selected)) - settings.dreamcast.language = i; - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - ImGui::SameLine(); - ShowHelpMarker("The language as configured in the Dreamcast BIOS"); + OptionComboBox("Language", config::Language, languages, ARRAY_SIZE(languages), + "The language as configured in the Dreamcast BIOS"); const char *broadcast[] = { "NTSC", "PAL", "PAL/M", "PAL/N", "Default" }; - if (ImGui::BeginCombo("Broadcast", broadcast[settings.dreamcast.broadcast], ImGuiComboFlags_None)) - { - for (int i = 0; i < IM_ARRAYSIZE(broadcast); i++) - { - bool is_selected = (int)settings.dreamcast.broadcast == i; - if (ImGui::Selectable(broadcast[i], &is_selected)) - settings.dreamcast.broadcast = i; - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - ImGui::SameLine(); - ShowHelpMarker("TV broadcasting standard for non-VGA modes"); + OptionComboBox("Broadcast", config::Broadcast, broadcast, ARRAY_SIZE(broadcast), + "TV broadcasting standard for non-VGA modes"); const char *region[] = { "Japan", "USA", "Europe", "Default" }; - if (ImGui::BeginCombo("Region", region[settings.dreamcast.region], ImGuiComboFlags_None)) - { - for (int i = 0; i < IM_ARRAYSIZE(region); i++) - { - bool is_selected = (int)settings.dreamcast.region == i; - if (ImGui::Selectable(region[i], &is_selected)) - settings.dreamcast.region = i; - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - ImGui::SameLine(); - ShowHelpMarker("BIOS region"); + OptionComboBox("Region", config::Region, region, ARRAY_SIZE(region), + "BIOS region"); const char *cable[] = { "VGA", "RGB Component", "TV Composite" }; - if (ImGui::BeginCombo("Cable", cable[settings.dreamcast.cable == 0 ? 0 : settings.dreamcast.cable - 1], ImGuiComboFlags_None)) + if (config::Cable.isReadOnly()) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + if (ImGui::BeginCombo("Cable", cable[config::Cable == 0 ? 0 : config::Cable - 1], ImGuiComboFlags_None)) { for (int i = 0; i < IM_ARRAYSIZE(cable); i++) { - bool is_selected = i == 0 ? (int)settings.dreamcast.cable <= 1 : (int)settings.dreamcast.cable - 1 == i; + bool is_selected = i == 0 ? config::Cable <= 1 : config::Cable - 1 == i; if (ImGui::Selectable(cable[i], &is_selected)) - settings.dreamcast.cable = i == 0 ? 0 : i + 1; + config::Cable = i == 0 ? 0 : i + 1; if (is_selected) ImGui::SetItemDefaultFocus(); } ImGui::EndCombo(); } + if (config::Cable.isReadOnly()) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } ImGui::SameLine(); ShowHelpMarker("Video connection type"); - std::vector paths; - for (auto& path : settings.dreamcast.ContentPath) - paths.push_back(path.c_str()); - ImVec2 size; size.x = 0.0f; size.y = (ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().FramePadding.y * 2.f) - * (settings.dreamcast.ContentPath.size() + 1) ;//+ ImGui::GetStyle().FramePadding.y * 2.f; + * (config::ContentPath.get().size() + 1) ;//+ ImGui::GetStyle().FramePadding.y * 2.f; if (ImGui::ListBoxHeader("Content Location", size)) { int to_delete = -1; - for (u32 i = 0; i < settings.dreamcast.ContentPath.size(); i++) + for (u32 i = 0; i < config::ContentPath.get().size(); i++) { - ImGui::PushID(settings.dreamcast.ContentPath[i].c_str()); + ImGui::PushID(config::ContentPath.get()[i].c_str()); ImGui::AlignTextToFramePadding(); - ImGui::Text("%s", settings.dreamcast.ContentPath[i].c_str()); + ImGui::Text("%s", config::ContentPath.get()[i].c_str()); ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("X").x - ImGui::GetStyle().FramePadding.x); if (ImGui::Button("X")) to_delete = i; @@ -1017,7 +988,7 @@ static void gui_display_settings() if (to_delete >= 0) { scanner.stop(); - settings.dreamcast.ContentPath.erase(settings.dreamcast.ContentPath.begin() + to_delete); + config::ContentPath.get().erase(config::ContentPath.get().begin() + to_delete); scanner.refresh(); } } @@ -1031,16 +1002,17 @@ static void gui_display_settings() #ifdef __ANDROID__ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("Change").x - ImGui::GetStyle().FramePadding.x); if (ImGui::Button("Change")) - gui_state = Onboarding; + gui_state = GuiState::Onboarding; #endif ImGui::ListBoxFooter(); } ImGui::SameLine(); ShowHelpMarker("The directory where reicast saves configuration files and VMUs. BIOS files should be in a subfolder named \"data\""); - if (ImGui::Checkbox("Hide Legacy Naomi Roms", &settings.dreamcast.HideLegacyNaomiRoms)) - scanner.refresh(); - ImGui::SameLine(); - ShowHelpMarker("Hide .bin, .dat and .lst files from the content browser"); + if (OptionCheckbox("Hide Legacy Naomi Roms", config::HideLegacyNaomiRoms, + "Hide .bin, .dat and .lst files from the content browser")) + scanner.refresh(); + OptionCheckbox("Auto load/save state", config::AutoSavestate, + "Automatically save the state of the game when stopping and load it at start up."); ImGui::PopStyleVar(); ImGui::EndTabItem(); @@ -1058,14 +1030,14 @@ static void gui_display_settings() sprintf(device_name, "##device%d", bus); float w = ImGui::CalcItemWidth() / 3; ImGui::PushItemWidth(w); - if (ImGui::BeginCombo(device_name, maple_device_name((MapleDeviceType)settings.input.maple_devices[bus]), ImGuiComboFlags_None)) + if (ImGui::BeginCombo(device_name, maple_device_name(config::MapleMainDevices[bus]), ImGuiComboFlags_None)) { for (int i = 0; i < IM_ARRAYSIZE(maple_device_types); i++) { - bool is_selected = settings.input.maple_devices[bus] == maple_device_type_from_index(i); + bool is_selected = config::MapleMainDevices[bus] == maple_device_type_from_index(i); if (ImGui::Selectable(maple_device_types[i], &is_selected)) { - settings.input.maple_devices[bus] = maple_device_type_from_index(i); + config::MapleMainDevices[bus] = maple_device_type_from_index(i); maple_devices_changed = true; } if (is_selected) @@ -1073,22 +1045,22 @@ static void gui_display_settings() } ImGui::EndCombo(); } - int port_count = settings.input.maple_devices[bus] == MDT_SegaController ? 2 - : settings.input.maple_devices[bus] == MDT_LightGun || settings.input.maple_devices[bus] == MDT_TwinStick || settings.input.maple_devices[bus] == MDT_AsciiStick ? 1 + int port_count = config::MapleMainDevices[bus] == MDT_SegaController ? 2 + : config::MapleMainDevices[bus] == MDT_LightGun || config::MapleMainDevices[bus] == MDT_TwinStick || config::MapleMainDevices[bus] == MDT_AsciiStick ? 1 : 0; for (int port = 0; port < port_count; port++) { ImGui::SameLine(); sprintf(device_name, "##device%d.%d", bus, port + 1); ImGui::PushID(device_name); - if (ImGui::BeginCombo(device_name, maple_expansion_device_name((MapleDeviceType)settings.input.maple_expansion_devices[bus][port]), ImGuiComboFlags_None)) + if (ImGui::BeginCombo(device_name, maple_expansion_device_name(config::MapleExpansionDevices[bus][port]), ImGuiComboFlags_None)) { for (int i = 0; i < IM_ARRAYSIZE(maple_expansion_device_types); i++) { - bool is_selected = settings.input.maple_expansion_devices[bus][port] == maple_expansion_device_type_from_index(i); + bool is_selected = config::MapleExpansionDevices[bus][port] == maple_expansion_device_type_from_index(i); if (ImGui::Selectable(maple_expansion_device_types[i], &is_selected)) { - settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i); + config::MapleExpansionDevices[bus][port] = maple_expansion_device_type_from_index(i); maple_devices_changed = true; } if (is_selected) @@ -1098,12 +1070,12 @@ static void gui_display_settings() } ImGui::PopID(); } - if (settings.input.maple_devices[bus] == MDT_LightGun) + if (config::MapleMainDevices[bus] == MDT_LightGun) { ImGui::SameLine(); sprintf(device_name, "##device%d.xhair", bus); ImGui::PushID(device_name); - u32 color = settings.rend.CrosshairColor[bus]; + u32 color = config::CrosshairColor[bus]; float xhairColor[4] { (color & 0xff) / 255.f, ((color >> 8) & 0xff) / 255.f, @@ -1117,16 +1089,16 @@ static void gui_display_settings() ImGui::Checkbox("Crosshair", &enabled); if (enabled) { - settings.rend.CrosshairColor[bus] = (u8)(xhairColor[0] * 255.f) + config::CrosshairColor[bus] = (u8)(xhairColor[0] * 255.f) | ((u8)(xhairColor[1] * 255.f) << 8) | ((u8)(xhairColor[2] * 255.f) << 16) | ((u8)(xhairColor[3] * 255.f) << 24); - if (settings.rend.CrosshairColor[bus] == 0) - settings.rend.CrosshairColor[bus] = 0xC0FFFFFF; + if (config::CrosshairColor[bus] == 0) + config::CrosshairColor[bus] = 0xC0FFFFFF; } else { - settings.rend.CrosshairColor[bus] = 0; + config::CrosshairColor[bus] = 0; } ImGui::PopID(); } @@ -1136,7 +1108,7 @@ static void gui_display_settings() } if (ImGui::CollapsingHeader("Physical Devices", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Columns(4, "renderers", false); + ImGui::Columns(4, "physicalDevices", false); ImGui::Text("System"); ImGui::SetColumnWidth(-1, ImGui::CalcTextSize("System").x + ImGui::GetStyle().FramePadding.x * 2.0f + ImGui::GetStyle().ItemSpacing.x); ImGui::NextColumn(); @@ -1187,10 +1159,10 @@ static void gui_display_settings() if (ImGui::Button("Edit")) { vjoy_start_editing(); - gui_state = VJoyEdit; + gui_state = GuiState::VJoyEdit; } ImGui::SameLine(); - ImGui::SliderInt("Haptic", &settings.input.VirtualGamepadVibration, 0, 60); + OptionSlider("Haptic", config::VirtualGamepadVibration, 0, 60); } #endif ImGui::NextColumn(); @@ -1200,7 +1172,7 @@ static void gui_display_settings() ImGui::Columns(1, NULL, false); ImGui::Spacing(); - ImGui::SliderInt("Mouse sensitivity", (int *)&settings.input.MouseSensitivity, 1, 500); + OptionSlider("Mouse sensitivity", config::MouseSensitivity, 1, 500); ImGui::PopStyleVar(); ImGui::EndTabItem(); @@ -1221,7 +1193,7 @@ static void gui_display_settings() #endif if (ImGui::CollapsingHeader("Transparent Sorting", ImGuiTreeNodeFlags_DefaultOpen)) { - int renderer = (pvr_rend == RenderType::OpenGL_OIT || pvr_rend == RenderType::Vulkan_OIT) ? 2 : settings.rend.PerStripSorting ? 1 : 0; + int renderer = (pvr_rend == RenderType::OpenGL_OIT || pvr_rend == RenderType::Vulkan_OIT) ? 2 : config::PerStripSorting ? 1 : 0; ImGui::Columns(has_per_pixel ? 3 : 2, "renderers", false); ImGui::RadioButton("Per Triangle", &renderer, 0); ImGui::SameLine(); @@ -1245,14 +1217,14 @@ static void gui_display_settings() pvr_rend = RenderType::OpenGL; // regular Open GL else pvr_rend = RenderType::Vulkan; // regular Vulkan - settings.rend.PerStripSorting = false; + config::PerStripSorting.set(false); break; case 1: if (!vulkan) pvr_rend = RenderType::OpenGL; else pvr_rend = RenderType::Vulkan; - settings.rend.PerStripSorting = true; + config::PerStripSorting.set(true); break; case 2: if (!vulkan) @@ -1266,50 +1238,32 @@ static void gui_display_settings() { ImGui::Text("Automatic Frame Skipping:"); ImGui::Columns(3, "autoskip", false); - ImGui::RadioButton("Disabled", &settings.pvr.AutoSkipFrame, 0); - ImGui::SameLine(); - ShowHelpMarker("No frame skipping"); + OptionRadioButton("Disabled", config::AutoSkipFrame, 0, "No frame skipping"); ImGui::NextColumn(); - ImGui::RadioButton("Normal", &settings.pvr.AutoSkipFrame, 1); - ImGui::SameLine(); - ShowHelpMarker("Skip a frame when the GPU and CPU are both running slow"); + OptionRadioButton("Normal", config::AutoSkipFrame, 1, "Skip a frame when the GPU and CPU are both running slow"); ImGui::NextColumn(); - ImGui::RadioButton("Maximum", &settings.pvr.AutoSkipFrame, 2); - ImGui::SameLine(); - ShowHelpMarker("Skip a frame when the GPU is running slow"); + OptionRadioButton("Maximum", config::AutoSkipFrame, 2, "Skip a frame when the GPU is running slow"); ImGui::Columns(1, nullptr, false); - ImGui::Checkbox("Clipping", &settings.rend.Clipping); - ImGui::SameLine(); - ShowHelpMarker("Enable clipping. May produce graphical errors when disabled"); - ImGui::Checkbox("Shadows", &settings.rend.ModifierVolumes); - ImGui::SameLine(); - ShowHelpMarker("Enable modifier volumes, usually used for shadows"); - ImGui::Checkbox("Fog", &settings.rend.Fog); - ImGui::SameLine(); - ShowHelpMarker("Enable fog effects"); - ImGui::Checkbox("Widescreen", &settings.rend.WideScreen); - ImGui::SameLine(); - ShowHelpMarker("Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas"); - ImGui::Checkbox("Widescreen Game Cheats", &settings.rend.WidescreenGameHacks); - ImGui::SameLine(); - ShowHelpMarker("Modify the game so that it displays in 16:9 anamorphic format and use horizontal screen stretching. Only some games are supported."); - ImGui::Checkbox("Show FPS Counter", &settings.rend.ShowFPS); - ImGui::SameLine(); - ShowHelpMarker("Show on-screen frame/sec counter"); - ImGui::Checkbox("Show VMU In-game", &settings.rend.FloatVMUs); - ImGui::SameLine(); - ShowHelpMarker("Show the VMU LCD screens while in-game"); - ImGui::Checkbox("Rotate Screen 90°", &settings.rend.Rotate90); - ImGui::SameLine(); - ShowHelpMarker("Rotate the screen 90° counterclockwise"); - ImGui::Checkbox("Delay Frame Swapping", &settings.rend.DelayFrameSwapping); - ImGui::SameLine(); - ShowHelpMarker("Useful to avoid flashing screen or glitchy videos. Not recommended on slow platforms"); - ImGui::Checkbox("Use Vulkan Renderer", &vulkan); + OptionCheckbox("Clipping", config::Clipping, + "Enable clipping. May produce graphical errors when disabled"); + OptionCheckbox("Shadows", config::ModifierVolumes, + "Enable modifier volumes, usually used for shadows"); + OptionCheckbox("Fog", config::Fog, "Enable fog effects"); + OptionCheckbox("Widescreen", config::Widescreen, + "Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas"); + OptionCheckbox("Widescreen Game Cheats", config::WidescreenGameHacks, + "Modify the game so that it displays in 16:9 anamorphic format and use horizontal screen stretching. Only some games are supported."); + OptionCheckbox("Show FPS Counter", config::ShowFPS, "Show on-screen frame/sec counter"); + OptionCheckbox("Show VMU In-game", config::FloatVMUs, "Show the VMU LCD screens while in-game"); + OptionCheckbox("Rotate Screen 90°", config::Rotate90, "Rotate the screen 90° counterclockwise"); + OptionCheckbox("Delay Frame Swapping", config::DelayFrameSwapping, + "Useful to avoid flashing screen or glitchy videos. Not recommended on slow platforms"); +#ifdef USE_VULKAN + ImGui::Checkbox("Use Vulkan Renderer", &vulkan); ImGui::SameLine(); ShowHelpMarker("Use Vulkan instead of Open GL/GLES"); - +#endif const std::map scalings { { 10, "0.1"}, { 20, "0.2" }, { 30, "0.3" }, { 40, "0.4" }, { 50, "0.5" }, { 60, "0.6" }, { 70, "0.7" }, { 80, "0.8" }, { 90, "0.9" }, @@ -1317,20 +1271,20 @@ static void gui_display_settings() { 400, "4.0 (4x SSAA)" }, { 600, "6.0 (6x SSAA)" }, { 800, "8.0 (8x SSAA)" } }; - if (scalings.count(settings.rend.ScreenScaling) == 0) - settings.rend.ScreenScaling = 100; - auto scalings_it = scalings.find(settings.rend.ScreenScaling); + if (scalings.count(config::ScreenScaling) == 0) + config::ScreenScaling.set(100); + auto scalings_it = scalings.find(config::ScreenScaling); ImGuiStyle& scaling_style = ImGui::GetStyle(); float scaling_spacing = scaling_style.ItemInnerSpacing.x; ImGui::PushItemWidth(ImGui::CalcItemWidth() - scaling_spacing * 2.0f - ImGui::GetFrameHeight() * 2.0f); - if (ImGui::BeginCombo("##Scaling", scalings.at(settings.rend.ScreenScaling), ImGuiComboFlags_NoArrowButton)) + if (ImGui::BeginCombo("##Scaling", scalings.at(config::ScreenScaling), ImGuiComboFlags_NoArrowButton)) { for (const auto& kv : scalings) { - bool is_selected = (kv.first == settings.rend.ScreenScaling); + bool is_selected = (kv.first == config::ScreenScaling); if (ImGui::Selectable(kv.second, is_selected)) - settings.rend.ScreenScaling = kv.first; + config::ScreenScaling.set(kv.first); if (is_selected) ImGui::SetItemDefaultFocus(); } @@ -1342,13 +1296,13 @@ static void gui_display_settings() if (ImGui::ArrowButton("##Decrease Scaling", ImGuiDir_Left)) { if (scalings_it != scalings.begin()) - settings.rend.ScreenScaling = (--scalings_it)->first; + config::ScreenScaling.set((--scalings_it)->first); } ImGui::SameLine(0, scaling_spacing); if (ImGui::ArrowButton("##Increase Scaling", ImGuiDir_Right)) { if (scalings_it != (--scalings.end())) - settings.rend.ScreenScaling = (++scalings_it)->first; + config::ScreenScaling.set((++scalings_it)->first); } ImGui::SameLine(0, scaling_style.ItemInnerSpacing.x); @@ -1356,36 +1310,28 @@ static void gui_display_settings() ImGui::SameLine(); ShowHelpMarker("Downscaling/Upscaling factor relative to native screen resolution. Higher is better but more demanding"); - ImGui::SliderInt("Horizontal Stretching", (int *)&settings.rend.ScreenStretching, 100, 150); - ImGui::SameLine(); - ShowHelpMarker("Stretch the screen horizontally"); - ImGui::SliderInt("Frame Skipping", (int *)&settings.pvr.ta_skip, 0, 6); - ImGui::SameLine(); - ShowHelpMarker("Number of frames to skip between two actually rendered frames"); + OptionSlider("Horizontal Stretching", config::ScreenStretching, 100, 150, + "Stretch the screen horizontally"); + OptionSlider("Frame Skipping", config::SkipFrame, 0, 6, + "Number of frames to skip between two actually rendered frames"); } if (ImGui::CollapsingHeader("Render to Texture", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Checkbox("Copy to VRAM", &settings.rend.RenderToTextureBuffer); - ImGui::SameLine(); - ShowHelpMarker("Copy rendered-to textures back to VRAM. Slower but accurate"); - ImGui::SliderInt("Render to Texture Upscaling", (int *)&settings.rend.RenderToTextureUpscale, 1, 8); - ImGui::SameLine(); - ShowHelpMarker("Upscale rendered-to textures. Should be the same as the screen or window upscale ratio, or lower for slow platforms"); + OptionCheckbox("Copy to VRAM", config::RenderToTextureBuffer, + "Copy rendered-to textures back to VRAM. Slower but accurate"); + OptionSlider("Render to Texture Upscaling", config::RenderToTextureUpscale, 1, 8, + "Upscale rendered-to textures. Should be the same as the screen or window upscale ratio, or lower for slow platforms"); } if (ImGui::CollapsingHeader("Texture Upscaling", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::SliderInt("Texture Upscaling", (int *)&settings.rend.TextureUpscale, 1, 8); - ImGui::SameLine(); - ShowHelpMarker("Upscale textures with the xBRZ algorithm. Only on fast platforms and for certain 2D games"); - ImGui::SliderInt("Upscaled Texture Max Size", (int *)&settings.rend.MaxFilteredTextureSize, 8, 1024); - ImGui::SameLine(); - ShowHelpMarker("Textures larger than this dimension squared will not be upscaled"); - ImGui::SliderInt("Max Threads", (int *)&settings.pvr.MaxThreads, 1, 8); - ImGui::SameLine(); - ShowHelpMarker("Maximum number of threads to use for texture upscaling. Recommended: number of physical cores minus one"); - ImGui::Checkbox("Load Custom Textures", &settings.rend.CustomTextures); - ImGui::SameLine(); - ShowHelpMarker("Load custom/high-res textures from data/textures/"); + OptionSlider("Texture Upscaling", config::TextureUpscale, 1, 8, + "Upscale textures with the xBRZ algorithm. Only on fast platforms and for certain 2D games"); + OptionSlider("Upscaled Texture Max Size", config::MaxFilteredTextureSize, 8, 1024, + "Textures larger than this dimension squared will not be upscaled"); + OptionSlider("Max Threads", config::MaxThreads, 1, 8, + "Maximum number of threads to use for texture upscaling. Recommended: number of physical cores minus one"); + OptionCheckbox("Load Custom Textures", config::CustomTextures, + "Load custom/high-res textures from data/textures/"); } ImGui::PopStyleVar(); ImGui::EndTabItem(); @@ -1393,28 +1339,24 @@ static void gui_display_settings() if (ImGui::BeginTabItem("Audio")) { ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding); - ImGui::Checkbox("Disable Sound", &settings.aica.NoSound); - ImGui::SameLine(); - ShowHelpMarker("Disable the emulator sound output"); - ImGui::Checkbox("Enable DSP", &settings.aica.DSPEnabled); - ImGui::SameLine(); - ShowHelpMarker("Enable the Dreamcast Digital Sound Processor. Only recommended on fast platforms"); - ImGui::Checkbox("Limit Emulator Speed", &settings.aica.LimitFPS); - ImGui::SameLine(); - ShowHelpMarker("Whether to limit the emulator speed using the audio output. Recommended"); + OptionCheckbox("Disable Sound", config::DisableSound, "Disable the emulator sound output"); + OptionCheckbox("Enable DSP", config::DSPEnabled, + "Enable the Dreamcast Digital Sound Processor. Only recommended on fast platforms"); + OptionCheckbox("Limit Emulator Speed", config::LimitFPS, + "Whether to limit the emulator speed using the audio output. Recommended"); #if !defined(__ANDROID__) && !defined(_WIN32) - int latency = (int)roundf(settings.aica.BufferSize * 1000.f / 44100.f); + int latency = (int)roundf(config::AudioBufferSize * 1000.f / 44100.f); ImGui::SliderInt("Latency", &latency, 12, 512, "%d ms"); - settings.aica.BufferSize = (int)roundf(latency * 44100.f / 1000.f); + config::AudioBufferSize = (int)roundf(latency * 44100.f / 1000.f); ImGui::SameLine(); ShowHelpMarker("Sets the maximum audio latency. Not supported by all audio drivers."); #endif audiobackend_t* backend = nullptr; - std::string backend_name = settings.audio.backend; + std::string backend_name = config::AudioBackend; if (backend_name != "auto") { - backend = GetAudioBackend(settings.audio.backend); + backend = GetAudioBackend(config::AudioBackend); if (backend != NULL) backend_name = backend->slug; } @@ -1422,20 +1364,20 @@ static void gui_display_settings() audiobackend_t* current_backend = backend; if (ImGui::BeginCombo("Audio Driver", backend_name.c_str(), ImGuiComboFlags_None)) { - bool is_selected = (settings.audio.backend == "auto"); + bool is_selected = (config::AudioBackend.get() == "auto"); if (ImGui::Selectable("auto - Automatic driver selection", &is_selected)) - settings.audio.backend = "auto"; + config::AudioBackend.set("auto"); for (u32 i = 0; i < GetAudioBackendCount(); i++) { backend = GetAudioBackend(i); - is_selected = (settings.audio.backend == backend->slug); + is_selected = (config::AudioBackend.get() == backend->slug); if (is_selected) current_backend = backend; if (ImGui::Selectable((backend->slug + " - " + backend->name).c_str(), &is_selected)) - settings.audio.backend = backend->slug; + config::AudioBackend.set(backend->slug); if (is_selected) ImGui::SetItemDefaultFocus(); } @@ -1450,47 +1392,36 @@ static void gui_display_settings() int option_count; audio_option_t* options = current_backend->get_options(&option_count); - // initialize options if not already done - std::map* cfg_entries = &settings.audio.options[current_backend->slug]; - bool populate_entries = (cfg_entries->size() == 0); - for (int o = 0; o < option_count; o++) { - std::string value; - if (populate_entries) - { - value = cfgLoadStr(current_backend->slug.c_str(), options->cfg_name.c_str(), ""); - (*cfg_entries)[options->cfg_name] = value; - } - value = (*cfg_entries)[options->cfg_name]; + std::string value = cfgLoadStr(current_backend->slug, options->cfg_name, ""); if (options->type == integer) { int val = stoi(value); - ImGui::SliderInt(options->caption.c_str(), &val, options->min_value, options->max_value); - (*cfg_entries)[options->cfg_name] = std::to_string(val); + if (ImGui::SliderInt(options->caption.c_str(), &val, options->min_value, options->max_value)) + { + std::string s = std::to_string(val); + cfgSaveStr(current_backend->slug, options->cfg_name, s); + } } else if (options->type == checkbox) { - bool check = (value == "1"); - ImGui::Checkbox(options->caption.c_str(), &check); - std::string cur = check ? "1" : "0"; - (*cfg_entries)[options->cfg_name] = cur; + bool check = value == "1"; + if (ImGui::Checkbox(options->caption.c_str(), &check)) + cfgSaveStr(current_backend->slug, options->cfg_name, + check ? "1" : "0"); } else if (options->type == ::list) { if (ImGui::BeginCombo(options->caption.c_str(), value.c_str(), ImGuiComboFlags_None)) { bool is_selected = false; - std::vector list_items = options->list_callback(); - for (std::vector::iterator it = list_items.begin() ; it != list_items.end(); ++it) + for (const auto& cur : options->list_callback()) { - std::string cur = (std::string)*it; - is_selected = (value == cur); + is_selected = value == cur; if (ImGui::Selectable(cur.c_str(), &is_selected)) - { - (*cfg_entries)[options->cfg_name] = cur; - } + cfgSaveStr(current_backend->slug, options->cfg_name, cur); if (is_selected) ImGui::SetItemDefaultFocus(); @@ -1515,66 +1446,55 @@ static void gui_display_settings() if (ImGui::CollapsingHeader("CPU Mode", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Columns(2, "cpu_modes", false); - ImGui::RadioButton("Dynarec", &dynarec_enabled, 1); - ImGui::SameLine(); - ShowHelpMarker("Use the dynamic recompiler. Recommended in most cases"); + OptionRadioButton("Dynarec", config::DynarecEnabled, true, + "Use the dynamic recompiler. Recommended in most cases"); ImGui::NextColumn(); - ImGui::RadioButton("Interpreter", &dynarec_enabled, 0); - ImGui::SameLine(); - ShowHelpMarker("Use the interpreter. Very slow but may help in case of a dynarec problem"); + OptionRadioButton("Interpreter", config::DynarecEnabled, false, + "Use the interpreter. Very slow but may help in case of a dynarec problem"); ImGui::Columns(1, NULL, false); } - if (ImGui::CollapsingHeader("Dynarec Options", dynarec_enabled ? ImGuiTreeNodeFlags_DefaultOpen : ImGuiTreeNodeFlags_None)) + if (config::DynarecEnabled && ImGui::CollapsingHeader("Dynarec Options", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Checkbox("Safe Mode", &settings.dynarec.safemode); - ImGui::SameLine(); - ShowHelpMarker("Do not optimize integer division. Not recommended"); + OptionCheckbox("Safe Mode", config::DynarecSafeMode, + "Do not optimize integer division. Not recommended"); #if HOST_CPU == CPU_ARM - ImGui::Checkbox("Unstable Optimizations", &settings.dynarec.unstable_opt); - ImGui::SameLine(); - ShowHelpMarker("Enable unsafe optimizations. Will cause crash or environmental disaster"); + OptionCheckbox("Unstable Optimizations", config::DynarecUnstableOpt, + "Enable unsafe optimizations. Will cause crash or environmental disaster"); #endif - ImGui::Checkbox("Idle Skip", &settings.dynarec.idleskip); - ImGui::SameLine(); - ShowHelpMarker("Skip wait loops. Recommended"); + OptionCheckbox("Idle Skip", config::DynarecIdleSkip, "Skip wait loops. Recommended"); } if (ImGui::CollapsingHeader("Network", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Checkbox("Broadband Adapter Emulation", &settings.network.EmulateBBA); - ImGui::SameLine(); - ShowHelpMarker("Emulate the Ethernet Broadband Adapter (BBA) instead of the Modem"); - ImGui::Checkbox("Enable Naomi Networking", &settings.network.Enable); - ImGui::SameLine(); - ShowHelpMarker("Enable networking for supported Naomi games"); - if (settings.network.Enable) + OptionCheckbox("Broadband Adapter Emulation", config::EmulateBBA, + "Emulate the Ethernet Broadband Adapter (BBA) instead of the Modem"); + OptionCheckbox("Enable Naomi Networking", config::NetworkEnable, + "Enable networking for supported Naomi games"); + if (config::NetworkEnable) { - ImGui::Checkbox("Act as Server", &settings.network.ActAsServer); - ImGui::SameLine(); - ShowHelpMarker("Create a local server for Naomi network games"); - char server_name[256]; - strcpy(server_name, settings.network.server.c_str()); - ImGui::InputText("Server", server_name, sizeof(server_name), ImGuiInputTextFlags_CharsNoBlank, nullptr, nullptr); - ImGui::SameLine(); - ShowHelpMarker("The server to connect to. Leave blank to find a server automatically"); - settings.network.server = server_name; + OptionCheckbox("Act as Server", config::ActAsServer, + "Create a local server for Naomi network games"); + if (!config::ActAsServer) + { + char server_name[256]; + strcpy(server_name, config::NetworkServer.get().c_str()); + ImGui::InputText("Server", server_name, sizeof(server_name), ImGuiInputTextFlags_CharsNoBlank, nullptr, nullptr); + ImGui::SameLine(); + ShowHelpMarker("The server to connect to. Leave blank to find a server automatically"); + config::NetworkServer.set(server_name); + } } } if (ImGui::CollapsingHeader("Other", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Checkbox("HLE BIOS", &settings.bios.UseReios); - ImGui::SameLine(); - ShowHelpMarker("Force high-level BIOS emulation"); - ImGui::Checkbox("Force Windows CE", &settings.dreamcast.ForceWindowsCE); - ImGui::SameLine(); - ShowHelpMarker("Enable full MMU emulation and other Windows CE settings. Do not enable unless necessary"); + OptionCheckbox("HLE BIOS", config::UseReios, "Force high-level BIOS emulation"); + OptionCheckbox("Force Windows CE", config::ForceWindowsCE, + "Enable full MMU emulation and other Windows CE settings. Do not enable unless necessary"); #ifndef __ANDROID - ImGui::Checkbox("Serial Console", &settings.debug.SerialConsole); - ImGui::SameLine(); - ShowHelpMarker("Dump the Dreamcast serial console to stdout"); + OptionCheckbox("Serial Console", config::SerialConsole, + "Dump the Dreamcast serial console to stdout"); #endif - ImGui::Checkbox("Dump Textures", &settings.rend.DumpTextures); - ImGui::SameLine(); - ShowHelpMarker("Dump all textures into data/texdump/"); + OptionCheckbox("Dump Textures", config::DumpTextures, + "Dump all textures into data/texdump/"); bool logToFile = cfgLoadBool("log", "LogToFile", false); bool newLogToFile = logToFile; @@ -1647,7 +1567,7 @@ static void gui_display_settings() #endif ); } - if (settings.pvr.IsOpenGL()) + if (config::RendererType.isOpenGL()) { if (ImGui::CollapsingHeader("Open GL", ImGuiTreeNodeFlags_DefaultOpen)) { @@ -1690,11 +1610,10 @@ static void gui_display_settings() ImGui::Render(); ImGui_impl_RenderDrawData(ImGui::GetDrawData(), false); - if (vulkan != !settings.pvr.IsOpenGL()) + if (vulkan != !config::RendererType.isOpenGL()) pvr_rend = !vulkan ? RenderType::OpenGL - : settings.pvr.rend == RenderType::OpenGL_OIT ? RenderType::Vulkan_OIT : RenderType::Vulkan; + : config::RendererType == RenderType::OpenGL_OIT ? RenderType::Vulkan_OIT : RenderType::Vulkan; renderer_changed = (int)pvr_rend; - settings.dynarec.Enable = (bool)dynarec_enabled; } void gui_display_notification(const char *msg, int duration) @@ -1744,11 +1663,11 @@ static void gui_display_content() ImGui::SameLine(0, 32 * scaling); filter.Draw("Filter"); } - if (gui_state != SelectDisk) + if (gui_state != GuiState::SelectDisk) { ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize("Settings").x - ImGui::GetStyle().FramePadding.x * 2.0f /*+ ImGui::GetStyle().ItemSpacing.x*/); if (ImGui::Button("Settings"))//, ImVec2(0, 30 * scaling))) - gui_state = Settings; + gui_state = GuiState::Settings; } ImGui::PopStyleVar(); @@ -1762,7 +1681,7 @@ static void gui_display_content() ImGui::PushID("bios"); if (ImGui::Selectable("Dreamcast BIOS")) { - gui_state = Closed; + gui_state = GuiState::Closed; gui_start_game(""); } ImGui::PopID(); @@ -1771,7 +1690,7 @@ static void gui_display_content() scanner.get_mutex().lock(); for (const auto& game : scanner.get_game_list()) { - if (gui_state == SelectDisk) + if (gui_state == GuiState::SelectDisk) { std::string extension = get_file_extension(game.path); if (extension != "gdi" && extension != "chd" @@ -1784,16 +1703,16 @@ static void gui_display_content() ImGui::PushID(game.path.c_str()); if (ImGui::Selectable(game.name.c_str())) { - if (gui_state == SelectDisk) + if (gui_state == GuiState::SelectDisk) { strcpy(settings.imgread.ImagePath, game.path.c_str()); DiscSwap(); - gui_state = Closed; + gui_state = GuiState::Closed; } else { scanner.get_mutex().unlock(); - gui_state = Closed; + gui_state = GuiState::Closed; gui_start_game(game.path); scanner.get_mutex().lock(); } @@ -1838,14 +1757,14 @@ static void systemdir_selected_callback(bool cancelled, std::string selection) if (cfgOpen()) { - LoadSettings(false); + config::Settings::instance().load(false); // Make sure the renderer type doesn't change mid-flight - settings.pvr.rend = RenderType::OpenGL; - gui_state = Main; - if (settings.dreamcast.ContentPath.empty()) + config::RendererType = RenderType::OpenGL; + gui_state = GuiState::Main; + if (config::ContentPath.get().empty()) { scanner.stop(); - settings.dreamcast.ContentPath.push_back(selection); + config::ContentPath.get().push_back(selection); } SaveSettings(); } @@ -1869,7 +1788,7 @@ static std::future networkStatus; static void start_network() { networkStatus = naomiNetwork.startNetworkAsync(); - gui_state = NetworkStart; + gui_state = GuiState::NetworkStart; } static void gui_network_start() @@ -1890,19 +1809,19 @@ static void gui_network_start() { if (networkStatus.get()) { - gui_state = Closed; + gui_state = GuiState::Closed; ImGui::Text("STARTING..."); } else { - gui_state = Main; + gui_state = GuiState::Main; settings.imgread.ImagePath[0] = '\0'; } } else { ImGui::Text("STARTING NETWORK..."); - if (settings.network.ActAsServer) + if (config::ActAsServer) ImGui::Text("Press Start to start the game now."); } ImGui::Text("%s", get_notification().c_str()); @@ -1914,7 +1833,7 @@ static void gui_network_start() { naomiNetwork.terminate(); networkStatus.get(); - gui_state = Main; + gui_state = GuiState::Main; settings.imgread.ImagePath[0] = '\0'; } ImGui::PopStyleVar(); @@ -1951,7 +1870,7 @@ static void gui_display_loadscreen() } else { - gui_state = Closed; + gui_state = GuiState::Closed; ImGui::Text("STARTING..."); } } catch (const ReicastException& ex) { @@ -1960,7 +1879,7 @@ static void gui_display_loadscreen() #ifdef TEST_AUTOMATION die("Game load failed"); #endif - gui_state = Main; + gui_state = GuiState::Main; settings.imgread.ImagePath[0] = '\0'; } } @@ -1976,7 +1895,7 @@ static void gui_display_loadscreen() if (ImGui::Button("Cancel", ImVec2(100.f * scaling, 0.f))) { dc_cancel_load(); - gui_state = Main; + gui_state = GuiState::Main; } } ImGui::PopStyleVar(); @@ -1991,13 +1910,13 @@ void gui_display_ui() { switch (gui_state) { - case Settings: + case GuiState::Settings: gui_display_settings(); break; - case Commands: + case GuiState::Commands: gui_display_commands(); break; - case Main: + case GuiState::Main: //gui_display_demo(); { std::string game_file = settings.imgread.ImagePath; @@ -2007,25 +1926,25 @@ void gui_display_ui() gui_display_content(); } break; - case Closed: + case GuiState::Closed: break; - case Onboarding: + case GuiState::Onboarding: gui_display_onboarding(); break; - case VJoyEdit: + case GuiState::VJoyEdit: break; - case VJoyEditCommands: + case GuiState::VJoyEditCommands: #ifdef __ANDROID__ gui_display_vjoy_commands(screen_width, screen_height, scaling); #endif break; - case SelectDisk: + case GuiState::SelectDisk: gui_display_content(); break; - case Loading: + case GuiState::Loading: gui_display_loadscreen(); break; - case NetworkStart: + case GuiState::NetworkStart: gui_network_start(); break; default: @@ -2033,7 +1952,7 @@ void gui_display_ui() break; } - if (gui_state == Closed) + if (gui_state == GuiState::Closed) dc_resume(); } @@ -2045,7 +1964,7 @@ extern bool fast_forward_mode; static std::string getFPSNotification() { - if (settings.rend.ShowFPS) + if (config::ShowFPS) { double now = os_GetSeconds(); if (now - LastFPSTime >= 1.0) { @@ -2065,13 +1984,13 @@ static std::string getFPSNotification() void gui_display_osd() { - if (gui_state == VJoyEdit) + if (gui_state == GuiState::VJoyEdit) return; std::string message = get_notification(); if (message.empty()) message = getFPSNotification(); - if (!message.empty() || settings.rend.FloatVMUs || crosshairsNeeded()) + if (!message.empty() || config::FloatVMUs || crosshairsNeeded()) { ImGui_Impl_NewFrame(); ImGui::NewFrame(); @@ -2089,7 +2008,7 @@ void gui_display_osd() ImGui::End(); } displayCrosshairs(); - if (settings.rend.FloatVMUs) + if (config::FloatVMUs) display_vmus(); // gui_plot_render_time(screen_width, screen_height); @@ -2100,7 +2019,7 @@ void gui_display_osd() void gui_open_onboarding() { - gui_state = Onboarding; + gui_state = GuiState::Onboarding; } void gui_term() @@ -2109,7 +2028,7 @@ void gui_term() { inited = false; term_vmus(); - if (settings.pvr.IsOpenGL()) + if (config::RendererType.isOpenGL()) ImGui_ImplOpenGL3_Shutdown(); ImGui::DestroyContext(); EventManager::unlisten(Event::Resume, emuEventCallback); @@ -2175,7 +2094,7 @@ static void display_vmus() { if (!game_started) return; - if (!settings.pvr.IsOpenGL()) + if (!config::RendererType.isOpenGL()) return; ImGui::SetNextWindowBgAlpha(0); ImGui::SetNextWindowPos(ImVec2(0, 0)); @@ -2248,7 +2167,7 @@ std::pair getCrosshairPosition(int playerNum) float fy = mo_y_abs[playerNum]; int width = screen_width; int height = screen_height; - if (settings.rend.Rotate90) + if (config::Rotate90) { float t = fy; fy = width - fx; @@ -2259,14 +2178,14 @@ std::pair getCrosshairPosition(int playerNum) { float scale = 480.f / height; fy /= scale; - scale *= settings.rend.ScreenStretching / 100.f; + scale *= config::ScreenStretching / 100.f; fx = fx / scale + (width - 640.f / scale) / 2.f; } else { float scale = 640.f / width; fx /= scale; - scale *= settings.rend.ScreenStretching / 100.f; + scale *= config::ScreenStretching / 100.f; fy = fy / scale + (height - 480.f / scale) / 2.f; } return std::make_pair(fx, fy); @@ -2276,7 +2195,7 @@ static void displayCrosshairs() { if (!game_started) return; - if (!settings.pvr.IsOpenGL()) + if (!config::RendererType.isOpenGL()) return; if (!crosshairsNeeded()) return; @@ -2289,11 +2208,11 @@ static void displayCrosshairs() ImGui::Begin("xhair-window", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoFocusOnAppearing); - for (u32 i = 0; i < ARRAY_SIZE(settings.rend.CrosshairColor); i++) + for (u32 i = 0; i < config::CrosshairColor.size(); i++) { - if (settings.rend.CrosshairColor[i] == 0) + if (config::CrosshairColor[i] == 0) continue; - if (settings.platform.system == DC_PLATFORM_DREAMCAST && settings.input.maple_devices[i] != MDT_LightGun) + if (settings.platform.system == DC_PLATFORM_DREAMCAST && config::MapleMainDevices[i] != MDT_LightGun) continue; ImVec2 pos; @@ -2302,7 +2221,7 @@ static void displayCrosshairs() pos.y += XHAIR_WIDTH / 2.f; ImVec2 pos_b(pos.x + XHAIR_WIDTH, pos.y - XHAIR_HEIGHT); - ImGui::GetWindowDrawList()->AddImage(crosshairTexId, pos, pos_b, ImVec2(0, 1), ImVec2(1, 0), settings.rend.CrosshairColor[i]); + ImGui::GetWindowDrawList()->AddImage(crosshairTexId, pos, pos_b, ImVec2(0, 1), ImVec2(1, 0), config::CrosshairColor[i]); } ImGui::End(); } @@ -2315,7 +2234,7 @@ static void reset_vmus() static void term_vmus() { - if (!settings.pvr.IsOpenGL()) + if (!config::RendererType.isOpenGL()) return; for (u32 i = 0; i < ARRAY_SIZE(vmu_lcd_status); i++) { diff --git a/core/rend/gui.h b/core/rend/gui.h index ce5b3c2ba..d5a4a1a7e 100644 --- a/core/rend/gui.h +++ b/core/rend/gui.h @@ -18,6 +18,7 @@ */ #pragma once #include "types.h" +#include "cfg/option.h" void gui_init(); void gui_open_settings(); @@ -34,7 +35,7 @@ extern u32 vmu_lcd_data[8][48 * 32]; extern bool vmu_lcd_status[8]; extern bool vmu_lcd_changed[8]; -typedef enum { +enum class GuiState { Closed, Commands, Settings, @@ -45,17 +46,17 @@ typedef enum { SelectDisk, Loading, NetworkStart -} GuiState; +}; extern GuiState gui_state; void ImGui_Impl_NewFrame(); static inline bool gui_is_open() { - return gui_state != Closed && gui_state != VJoyEdit; + return gui_state != GuiState::Closed && gui_state != GuiState::VJoyEdit; } static inline bool gui_is_content_browser() { - return gui_state == Main; + return gui_state == GuiState::Main; } float gui_get_scaling(); @@ -63,8 +64,8 @@ float gui_get_scaling(); #define XHAIR_HEIGHT (40 * scaling) static inline bool crosshairsNeeded() { - if (settings.rend.CrosshairColor[0] == 0 && settings.rend.CrosshairColor[1] == 0 - && settings.rend.CrosshairColor[3] == 0 && settings.rend.CrosshairColor[3] == 0) + if (config::CrosshairColor[0] == 0 && config::CrosshairColor[1] == 0 + && config::CrosshairColor[3] == 0 && config::CrosshairColor[3] == 0) return false; if (settings.platform.system != DC_PLATFORM_DREAMCAST && settings.input.JammaSetup != JVS::LightGun diff --git a/core/rend/gui_android.cpp b/core/rend/gui_android.cpp index d23ff77f7..88310b115 100644 --- a/core/rend/gui_android.cpp +++ b/core/rend/gui_android.cpp @@ -42,20 +42,20 @@ void gui_display_vjoy_commands(int screen_width, int screen_height, float scalin if (ImGui::Button("Save", ImVec2(150 * scaling, 50 * scaling))) { vjoy_stop_editing(false); - gui_state = Settings; + gui_state = GuiState::Settings; } ImGui::SameLine(); if (ImGui::Button("Reset", ImVec2(150 * scaling, 50 * scaling))) { vjoy_reset_editing(); - gui_state = VJoyEdit; + gui_state = GuiState::VJoyEdit; } ImGui::SameLine(); if (ImGui::Button("Cancel", ImVec2(150 * scaling, 50 * scaling))) { vjoy_stop_editing(true); - gui_state = Settings; + gui_state = GuiState::Settings; } ImGui::End(); diff --git a/core/rend/gui_util.cpp b/core/rend/gui_util.cpp index d21de4a35..691238fc4 100644 --- a/core/rend/gui_util.cpp +++ b/core/rend/gui_util.cpp @@ -174,7 +174,7 @@ void select_directory_popup(const char *prompt, float scaling, StringCallback ca else { std::string extension = get_file_extension(name); - if ( extension == "zip" || extension == "7z" || extension == "chd" || extension == "gdi" || ((settings.dreamcast.HideLegacyNaomiRoms + if (extension == "zip" || extension == "7z" || extension == "chd" || extension == "gdi" || ((config::HideLegacyNaomiRoms || (extension != "bin" && extension != "lst" && extension != "dat")) && extension != "cdi" && extension != "cue") == false ) display_files.push_back(name); @@ -545,3 +545,127 @@ const ImWchar* GetGlyphRangesChineseTraditionalOfficial() } return &full_ranges[0]; } + +// Helper to display a little (?) mark which shows a tooltip when hovered. +void ShowHelpMarker(const char* desc) +{ + ImGui::TextDisabled("(?)"); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(desc); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } +} + +template +bool OptionCheckbox(const char *name, config::Option& option, const char *help) +{ + bool b = option; + if (option.isReadOnly()) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + bool pressed = ImGui::Checkbox(name, &b); + if (option.isReadOnly()) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + if (pressed) + option.set(b); + if (help != nullptr) + { + ImGui::SameLine(); + ShowHelpMarker(help); + } + return pressed; +} +template bool OptionCheckbox(const char *name, config::Option& option, const char *help); +template bool OptionCheckbox(const char *name, config::Option& option, const char *help); + +bool OptionSlider(const char *name, config::Option& option, int min, int max, const char *help) +{ + int v = option; + if (option.isReadOnly()) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + bool valueChanged = ImGui::SliderInt(name, &v, min, max); + if (option.isReadOnly()) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + else if (valueChanged) + option.set(v); + if (help != nullptr) + { + ImGui::SameLine(); + ShowHelpMarker(help); + } + return valueChanged; +} + +template +bool OptionRadioButton(const char *name, config::Option& option, T value, const char *help) +{ + int v = (int)option; + if (option.isReadOnly()) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + bool pressed = ImGui::RadioButton(name, &v, (int)value); + if (option.isReadOnly()) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + if (pressed) + option.set((T)v); + if (help != nullptr) + { + ImGui::SameLine(); + ShowHelpMarker(help); + } + return pressed; +} +template bool OptionRadioButton(const char *name, config::Option& option, bool value, const char *help); +template bool OptionRadioButton(const char *name, config::Option& option, int value, const char *help); + +void OptionComboBox(const char *name, config::Option& option, const char *values[], int count, + const char *help) +{ + if (option.isReadOnly()) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } + if (ImGui::BeginCombo(name, values[option], ImGuiComboFlags_None)) + { + for (int i = 0; i < count; i++) + { + bool is_selected = option == i; + if (ImGui::Selectable(values[i], &is_selected)) + option = i; + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + if (option.isReadOnly()) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } + if (help != nullptr) + { + ImGui::SameLine(); + ShowHelpMarker(help); + } +} diff --git a/core/rend/gui_util.h b/core/rend/gui_util.h index 08a5e5635..0aff4b141 100644 --- a/core/rend/gui_util.h +++ b/core/rend/gui_util.h @@ -22,6 +22,7 @@ #include "types.h" #include "imgui/imgui.h" +#include "imgui/imgui_internal.h" #include "vulkan/imgui_impl_vulkan.h" #include "gles/imgui_impl_opengl3.h" #include "vulkan/vulkan_context.h" @@ -34,7 +35,7 @@ void select_directory_popup(const char *prompt, float scaling, StringCallback ca static inline void ImGui_impl_RenderDrawData(ImDrawData *draw_data, bool save_background = false) { #ifdef USE_VULKAN - if (!settings.pvr.IsOpenGL()) + if (!config::RendererType.isOpenGL()) { VulkanContext *context = VulkanContext::Instance(); if (!context->IsValid()) @@ -68,3 +69,13 @@ void ScrollWhenDraggingOnVoid(const ImVec2& delta, ImGuiMouseButton mouse_button IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedOfficial();// Default + Half-Width + Japanese Hiragana/Katakana + set of 7800 CJK Unified Ideographs from General Standard Chinese Characters IMGUI_API const ImWchar* GetGlyphRangesChineseTraditionalOfficial();// Default + Half-Width + Japanese Hiragana/Katakana + set of 4700 CJK Unified Ideographs from Hong Kong's List of Graphemes of Commonly-Used Chinese Characters + +// Helper to display a little (?) mark which shows a tooltip when hovered. +void ShowHelpMarker(const char* desc); +template +bool OptionCheckbox(const char *name, config::Option& option, const char *help = nullptr); +bool OptionSlider(const char *name, config::Option& option, int min, int max, const char *help = nullptr); +template +bool OptionRadioButton(const char *name, config::Option& option, T value, const char *help = nullptr); +void OptionComboBox(const char *name, config::Option& option, const char *values[], int count, + const char *help = nullptr); diff --git a/core/rend/mainui.cpp b/core/rend/mainui.cpp index e97e7f3ba..a50519d40 100644 --- a/core/rend/mainui.cpp +++ b/core/rend/mainui.cpp @@ -23,6 +23,7 @@ #include "gui.h" #include "oslib/oslib.h" #include "wsi/context.h" +#include "cfg/option.h" bool mainui_enabled; int renderer_changed = -1; // Signals the renderer thread to switch renderer @@ -34,11 +35,11 @@ bool mainui_rend_frame() { os_DoEvents(); - if (gui_is_open() || gui_state == VJoyEdit) + if (gui_is_open() || gui_state == GuiState::VJoyEdit) { gui_display_ui(); // TODO refactor android vjoy out of renderer - if (gui_state == VJoyEdit && renderer != NULL) + if (gui_state == GuiState::VJoyEdit && renderer != NULL) renderer->DrawOSD(true); std::this_thread::sleep_for(std::chrono::milliseconds(16)); } @@ -68,14 +69,14 @@ void mainui_term() void mainui_loop() { mainui_enabled = true; - renderer_changed = (int)settings.pvr.rend; + renderer_changed = (int)(RenderType)config::RendererType; mainui_init(); while (mainui_enabled) { if (mainui_rend_frame()) { - if (settings.pvr.IsOpenGL()) + if (config::RendererType.isOpenGL()) theGLContext.Swap(); #ifdef USE_VULKAN else @@ -83,20 +84,20 @@ void mainui_loop() #endif } - if (renderer_changed != (int)settings.pvr.rend) + if (renderer_changed != (int)(RenderType)config::RendererType) { mainui_term(); if (renderer_changed == -1 - || settings.pvr.IsOpenGL() != ((RenderType)renderer_changed == RenderType::OpenGL || (RenderType)renderer_changed == RenderType::OpenGL_OIT)) + || config::RendererType.isOpenGL() != ((RenderType)renderer_changed == RenderType::OpenGL || (RenderType)renderer_changed == RenderType::OpenGL_OIT)) { // Switch between vulkan and opengl (or full reinit) - SwitchRenderApi(renderer_changed == -1 ? settings.pvr.rend : (RenderType)renderer_changed); + SwitchRenderApi(renderer_changed == -1 ? config::RendererType : (RenderType)renderer_changed); } else { - settings.pvr.rend = (RenderType)renderer_changed; + config::RendererType = (RenderType)renderer_changed; } - renderer_changed = (int)settings.pvr.rend; + renderer_changed = (int)(RenderType)config::RendererType; mainui_init(); } } diff --git a/core/rend/tileclip.h b/core/rend/tileclip.h index 07255ee29..8b9cf96a6 100644 --- a/core/rend/tileclip.h +++ b/core/rend/tileclip.h @@ -21,6 +21,7 @@ #include "types.h" #include "hw/pvr/Renderer_if.h" +#include "cfg/option.h" enum class TileClipping { Inside, // Render stuff outside the region @@ -31,7 +32,7 @@ enum class TileClipping { // clip_rect[] will contain x, y, width, height static inline TileClipping GetTileClip(u32 val, const glm::mat4& viewport, int *clip_rect) { - if (!settings.rend.Clipping) + if (!config::Clipping) return TileClipping::Off; u32 clipmode = val >> 28; @@ -68,12 +69,12 @@ static inline TileClipping GetTileClip(u32 val, const glm::mat4& viewport, int * cey = clip_end[1]; cex = clip_end[0]; } - else if (!settings.rend.RenderToTextureBuffer) + else if (!config::RenderToTextureBuffer) { - csx *= settings.rend.RenderToTextureUpscale; - csy *= settings.rend.RenderToTextureUpscale; - cex *= settings.rend.RenderToTextureUpscale; - cey *= settings.rend.RenderToTextureUpscale; + csx *= config::RenderToTextureUpscale; + csy *= config::RenderToTextureUpscale; + cex *= config::RenderToTextureUpscale; + cey *= config::RenderToTextureUpscale; } clip_rect[0] = std::max(0, (int)lroundf(csx)); clip_rect[1] = std::max(0, (int)lroundf(std::min(csy, cey))); diff --git a/core/rend/transform_matrix.h b/core/rend/transform_matrix.h index 11d1fc255..ba2b38607 100644 --- a/core/rend/transform_matrix.h +++ b/core/rend/transform_matrix.h @@ -21,6 +21,7 @@ #pragma once #include "TexCache.h" #include "hw/pvr/ta_ctx.h" +#include "cfg/option.h" #include #include @@ -127,7 +128,7 @@ public: normalMatrix = glm::translate(glm::vec3(startx, starty, 0)); scissorMatrix = normalMatrix; - const float screen_stretching = settings.rend.ScreenStretching / 100.f; + const float screen_stretching = config::ScreenStretching / 100.f; float scissoring_scale_x, scissoring_scale_y; GetFramebufferScaling(true, scissoring_scale_x, scissoring_scale_y); @@ -135,7 +136,7 @@ public: float y_coef; glm::mat4 trans_rot; - if (settings.rend.Rotate90) + if (config::Rotate90) { float dc2s_scale_h = screen_height / 640.0f; if (screen_width / 480.f < dc2s_scale_h) @@ -184,7 +185,7 @@ public: * glm::scale(glm::vec3(x_coef * scissoring_scale_x, y_coef * scissoring_scale_y, 1.f)) * scissorMatrix; } - normalMatrix = glm::scale(glm::vec3(1, 1, 1 / settings.rend.ExtraDepthScale)) + normalMatrix = glm::scale(glm::vec3(1, 1, 1 / config::ExtraDepthScale)) * normalMatrix; glm::mat4 vp_trans = glm::translate(glm::vec3(1, 1, 0)); @@ -195,7 +196,7 @@ public: } else { - float screen_scaling = settings.rend.ScreenScaling / 100.f; + float screen_scaling = config::ScreenScaling / 100.f; vp_trans = glm::scale(glm::vec3(screen_width * screen_scaling / 2, screen_height * screen_scaling / 2, 1.f)) * vp_trans; } diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp index e52c0ce36..7ecf84a37 100644 --- a/core/rend/vulkan/drawer.cpp +++ b/core/rend/vulkan/drawer.cpp @@ -62,8 +62,8 @@ TileClipping BaseDrawer::SetTileClip(u32 val, vk::Rect2D& clipRect) void BaseDrawer::SetBaseScissor() { - bool wide_screen_on = settings.rend.WideScreen && !pvrrc.isRenderFramebuffer - && !matrices.IsClipped() && !settings.rend.Rotate90; + bool wide_screen_on = config::Widescreen && !pvrrc.isRenderFramebuffer + && !matrices.IsClipped() && !config::Rotate90; if (!wide_screen_on) { float width; @@ -99,8 +99,8 @@ void BaseDrawer::SetBaseScissor() } else { - u32 w = lroundf(screen_width * settings.rend.ScreenScaling / 100.f); - u32 h = lroundf(screen_height * settings.rend.ScreenScaling / 100.f); + u32 w = lroundf(screen_width * config::ScreenScaling / 100.f); + u32 h = lroundf(screen_height * config::ScreenScaling / 100.f); baseScissor = { 0, 0, w, h }; } } @@ -201,7 +201,7 @@ void Drawer::DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sor void Drawer::DrawModVols(const vk::CommandBuffer& cmdBuffer, int first, int count) { - if (count == 0 || pvrrc.modtrig.used() == 0 || !settings.rend.ModifierVolumes) + if (count == 0 || pvrrc.modtrig.used() == 0 || !config::ModifierVolumes) return; vk::Buffer buffer = GetMainBuffer(0)->buffer.get(); @@ -355,7 +355,7 @@ bool Drawer::Draw(const Texture *fogTexture, const Texture *paletteTexture) DrawModVols(cmdBuffer, previous_pass.mvo_count, current_pass.mvo_count - previous_pass.mvo_count); if (current_pass.autosort) { - if (!settings.rend.PerStripSorting) + if (!config::PerStripSorting) { DrawSorted(cmdBuffer, sortedPolys[render_pass]); } @@ -401,12 +401,12 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass() while (widthPow2 < upscaledWidth) widthPow2 *= 2; - if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureUpscale > 1 && !config::RenderToTextureBuffer) { - upscaledWidth *= settings.rend.RenderToTextureUpscale; - upscaledHeight *= settings.rend.RenderToTextureUpscale; - widthPow2 *= settings.rend.RenderToTextureUpscale; - heightPow2 *= settings.rend.RenderToTextureUpscale; + upscaledWidth *= config::RenderToTextureUpscale; + upscaledHeight *= config::RenderToTextureUpscale; + widthPow2 *= config::RenderToTextureUpscale; + heightPow2 *= config::RenderToTextureUpscale; } rttPipelineManager->CheckSettingsChange(); @@ -430,7 +430,7 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass() vk::ImageView colorImageView; vk::ImageLayout colorImageCurrentLayout; - if (!settings.rend.RenderToTextureBuffer) + if (!config::RenderToTextureBuffer) { // TexAddr : fb_rtt.TexAddr, Reserved : 0, StrideSel : 0, ScanOrder : 1 TCW tcw = { { textureAddr >> 3, 0, 0, 1 } }; @@ -534,7 +534,7 @@ void TextureDrawer::EndRenderPass() // Happens for Virtua Tennis clippedWidth = stride / 2; - if (settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureBuffer) { vk::BufferImageCopy copyRegion(0, clippedWidth, clippedHeight, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), vk::Extent3D(vk::Extent2D(clippedWidth, clippedHeight), 1)); @@ -557,7 +557,7 @@ void TextureDrawer::EndRenderPass() currentCommandBuffer = nullptr; commandPool->EndFrame(); - if (settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureBuffer) { vk::Fence fence = commandPool->GetCurrentFence(); GetContext()->GetDevice().waitForFences(1, &fence, true, UINT64_MAX); @@ -583,7 +583,7 @@ void TextureDrawer::EndRenderPass() void ScreenDrawer::Init(SamplerManager *samplerManager, ShaderManager *shaderManager) { this->shaderManager = shaderManager; - currentScreenScaling = settings.rend.ScreenScaling; + currentScreenScaling = config::ScreenScaling; vk::Extent2D viewport = GetContext()->GetViewPort(); viewport.width = lroundf(viewport.width * currentScreenScaling / 100.f); viewport.height = lroundf(viewport.height * currentScreenScaling / 100.f); @@ -682,7 +682,7 @@ void ScreenDrawer::Init(SamplerManager *samplerManager, ShaderManager *shaderMan vk::CommandBuffer ScreenDrawer::BeginRenderPass() { - if (currentScreenScaling != settings.rend.ScreenScaling) + if (currentScreenScaling != config::ScreenScaling) Init(samplerManager, shaderManager); vk::CommandBuffer commandBuffer = commandPool->Allocate(); diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h index 7727384f9..cbf3b3586 100644 --- a/core/rend/vulkan/drawer.h +++ b/core/rend/vulkan/drawer.h @@ -77,7 +77,7 @@ protected: u8* fog_density = (u8*)&FOG_DENSITY; float fog_den_mant = fog_density[1] / 128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 s32 fog_den_exp = (s8)fog_density[0]; - fragUniforms.sp_FOG_DENSITY = fog_den_mant * powf(2.0f, fog_den_exp) * settings.rend.ExtraDepthScale; + fragUniforms.sp_FOG_DENSITY = fog_den_mant * powf(2.0f, fog_den_exp) * config::ExtraDepthScale; fragUniforms.colorClampMin[0] = ((pvrrc.fog_clamp_min >> 16) & 0xFF) / 255.0f; fragUniforms.colorClampMin[1] = ((pvrrc.fog_clamp_min >> 8) & 0xFF) / 255.0f; @@ -114,9 +114,9 @@ protected: { GetCurrentDescSet().Reset(); imageIndex = (imageIndex + 1) % GetSwapChainSize(); - if (perStripSorting != settings.rend.PerStripSorting) + if (perStripSorting != config::PerStripSorting) { - perStripSorting = settings.rend.PerStripSorting; + perStripSorting = config::PerStripSorting; pipelineManager->Reset(); } renderPass = 0; diff --git a/core/rend/vulkan/oit/oit_drawer.cpp b/core/rend/vulkan/oit/oit_drawer.cpp index 768ad80ef..9528a0ec3 100644 --- a/core/rend/vulkan/oit/oit_drawer.cpp +++ b/core/rend/vulkan/oit/oit_drawer.cpp @@ -104,7 +104,7 @@ void OITDrawer::DrawList(const vk::CommandBuffer& cmdBuffer, u32 listType, bool template void OITDrawer::DrawModifierVolumes(const vk::CommandBuffer& cmdBuffer, int first, int count) { - if (count == 0 || pvrrc.modtrig.used() == 0 || !settings.rend.ModifierVolumes) + if (count == 0 || pvrrc.modtrig.used() == 0 || !config::ModifierVolumes) return; vk::Buffer buffer = GetMainBuffer(0)->buffer.get(); @@ -456,9 +456,9 @@ void OITDrawer::MakeBuffers(int width, int height) void OITScreenDrawer::MakeFramebuffers() { - if (currentScreenScaling == settings.rend.ScreenScaling) + if (currentScreenScaling == config::ScreenScaling) return; - currentScreenScaling = settings.rend.ScreenScaling; + currentScreenScaling = config::ScreenScaling; viewport.offset.x = 0; viewport.offset.y = 0; viewport.extent = GetContext()->GetViewPort(); @@ -509,12 +509,12 @@ vk::CommandBuffer OITTextureDrawer::NewFrame() while (widthPow2 < upscaledWidth) widthPow2 *= 2; - if (settings.rend.RenderToTextureUpscale > 1 && !settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureUpscale > 1 && !config::RenderToTextureBuffer) { - upscaledWidth *= settings.rend.RenderToTextureUpscale; - upscaledHeight *= settings.rend.RenderToTextureUpscale; - widthPow2 *= settings.rend.RenderToTextureUpscale; - heightPow2 *= settings.rend.RenderToTextureUpscale; + upscaledWidth *= config::RenderToTextureUpscale; + upscaledHeight *= config::RenderToTextureUpscale; + widthPow2 *= config::RenderToTextureUpscale; + heightPow2 *= config::RenderToTextureUpscale; } rttPipelineManager->CheckSettingsChange(); @@ -529,7 +529,7 @@ vk::CommandBuffer OITTextureDrawer::NewFrame() vk::ImageView colorImageView; vk::ImageLayout colorImageCurrentLayout; - if (!settings.rend.RenderToTextureBuffer) + if (!config::RenderToTextureBuffer) { // TexAddr : fb_rtt.TexAddr, Reserved : 0, StrideSel : 0, ScanOrder : 1 TCW tcw = { { textureAddr >> 3, 0, 0, 1 } }; @@ -633,7 +633,7 @@ void OITTextureDrawer::EndFrame() // Happens for Virtua Tennis clippedWidth = stride / 2; - if (settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureBuffer) { vk::BufferImageCopy copyRegion(0, clippedWidth, clippedHeight, vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1), vk::Offset3D(0, 0, 0), @@ -658,7 +658,7 @@ void OITTextureDrawer::EndFrame() currentCommandBuffer = nullptr; commandPool->EndFrame(); - if (settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureBuffer) { vk::Fence fence = commandPool->GetCurrentFence(); GetContext()->GetDevice().waitForFences(1, &fence, true, UINT64_MAX); diff --git a/core/rend/vulkan/oit/oit_pipeline.cpp b/core/rend/vulkan/oit/oit_pipeline.cpp index 9bb787614..243812282 100644 --- a/core/rend/vulkan/oit/oit_pipeline.cpp +++ b/core/rend/vulkan/oit/oit_pipeline.cpp @@ -147,7 +147,7 @@ void OITPipelineManager::CreatePipeline(u32 listType, bool autosort, const PolyP params.bumpmap = pp.tcw.PixelFmt == PixelBumpMap; params.clamping = pp.tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff); params.insideClipTest = (pp.tileclip >> 28) == 3; - params.fog = settings.rend.Fog ? pp.tsp.FogCtrl : 2; + params.fog = config::Fog ? pp.tsp.FogCtrl : 2; params.gouraud = pp.pcw.Gouraud; params.ignoreTexAlpha = pp.tsp.IgnoreTexA || pp.tcw.PixelFmt == Pixel565; params.offset = pp.pcw.Offset; diff --git a/core/rend/vulkan/oit/oit_pipeline.h b/core/rend/vulkan/oit/oit_pipeline.h index 342e25e84..ca01d7951 100644 --- a/core/rend/vulkan/oit/oit_pipeline.h +++ b/core/rend/vulkan/oit/oit_pipeline.h @@ -347,7 +347,7 @@ private: { bool ignoreTexAlpha = pp->tsp.IgnoreTexA || pp->tcw.PixelFmt == Pixel565; hash |= (pp->tsp.ShadInstr << 7) | (ignoreTexAlpha << 9) | (pp->tsp.UseAlpha << 10) - | (pp->tsp.ColorClamp << 11) | ((settings.rend.Fog ? pp->tsp.FogCtrl : 2) << 12) + | (pp->tsp.ColorClamp << 11) | ((config::Fog ? pp->tsp.FogCtrl : 2) << 12) | (pp->tsp.SrcInstr << 14) | (pp->tsp.DstInstr << 17); } hash |= (pp->isp.ZWriteDis << 20) | (pp->isp.CullMode << 21) | ((autosort ? 6 : pp->isp.DepthMode) << 23); @@ -421,12 +421,12 @@ public: this->oitBuffers = oitBuffers; OITPipelineManager::Init(shaderManager, oitBuffers); - renderToTextureBuffer = settings.rend.RenderToTextureBuffer; + renderToTextureBuffer = config::RenderToTextureBuffer; rttRenderPasses.Reset(); } void CheckSettingsChange() { - if (renderToTextureBuffer != settings.rend.RenderToTextureBuffer) + if (renderToTextureBuffer != config::RenderToTextureBuffer) { Init(shaderManager, oitBuffers); } diff --git a/core/rend/vulkan/oit/oit_renderpass.h b/core/rend/vulkan/oit/oit_renderpass.h index 35819898d..133c6bc7f 100644 --- a/core/rend/vulkan/oit/oit_renderpass.h +++ b/core/rend/vulkan/oit/oit_renderpass.h @@ -70,13 +70,13 @@ protected: vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eUndefined, - settings.rend.RenderToTextureBuffer && last ? vk::ImageLayout::eTransferSrcOptimal : vk::ImageLayout::eShaderReadOnlyOptimal); + config::RenderToTextureBuffer && last ? vk::ImageLayout::eTransferSrcOptimal : vk::ImageLayout::eShaderReadOnlyOptimal); } virtual vk::Format GetColorFormat() const override { return vk::Format::eR8G8B8A8Unorm; } virtual std::vector GetSubpassDependencies() const override { std::vector deps; - if (settings.rend.RenderToTextureBuffer) + if (config::RenderToTextureBuffer) deps.emplace_back(2, VK_SUBPASS_EXTERNAL, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost, vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eHostRead); diff --git a/core/rend/vulkan/overlay.cpp b/core/rend/vulkan/overlay.cpp index 6a3ffd57e..e09a38e60 100644 --- a/core/rend/vulkan/overlay.cpp +++ b/core/rend/vulkan/overlay.cpp @@ -22,6 +22,7 @@ #include "rend/gui.h" #include "hw/maple/maple_devs.h" #include "overlay.h" +#include "cfg/option.h" VulkanOverlay::~VulkanOverlay() { @@ -129,11 +130,11 @@ void VulkanOverlay::Draw(vk::Extent2D viewport, float scaling, bool vmu, bool cr if (crosshair && crosshairsNeeded()) { alphaPipeline->BindPipeline(commandBuffer); - for (size_t i = 0; i < ARRAY_SIZE(settings.rend.CrosshairColor); i++) + for (size_t i = 0; i < config::CrosshairColor.size(); i++) { - if (settings.rend.CrosshairColor[i] == 0) + if (config::CrosshairColor[i] == 0) continue; - if (settings.platform.system == DC_PLATFORM_DREAMCAST && settings.input.maple_devices[i] != MDT_LightGun) + if (settings.platform.system == DC_PLATFORM_DREAMCAST && config::MapleMainDevices[i] != MDT_LightGun) continue; float x, y; @@ -143,7 +144,7 @@ void VulkanOverlay::Draw(vk::Extent2D viewport, float scaling, bool vmu, bool cr vk::Viewport viewport(x, y, XHAIR_WIDTH, XHAIR_HEIGHT); commandBuffer.setViewport(0, 1, &viewport); commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(x, y), vk::Extent2D(XHAIR_WIDTH, XHAIR_HEIGHT))); - u32 color = settings.rend.CrosshairColor[i]; + u32 color = config::CrosshairColor[i]; float xhairColor[4] { (color & 0xff) / 255.f, ((color >> 8) & 0xff) / 255.f, diff --git a/core/rend/vulkan/pipeline.cpp b/core/rend/vulkan/pipeline.cpp index b1cd5faad..e61914eec 100644 --- a/core/rend/vulkan/pipeline.cpp +++ b/core/rend/vulkan/pipeline.cpp @@ -174,7 +174,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol // Input assembly state vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), - sortTriangles && !settings.rend.PerStripSorting ? vk::PrimitiveTopology::eTriangleList : vk::PrimitiveTopology::eTriangleStrip); + sortTriangles && !config::PerStripSorting ? vk::PrimitiveTopology::eTriangleList : vk::PrimitiveTopology::eTriangleStrip); // Viewport and scissor states vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); @@ -205,7 +205,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol else depthOp = depthOps[pp.isp.DepthMode]; bool depthWriteEnable; - if (sortTriangles && !settings.rend.PerStripSorting) + if (sortTriangles && !config::PerStripSorting) // FIXME temporary work-around for intel driver bug depthWriteEnable = GetContext()->GetVendorID() == VENDOR_INTEL; else @@ -295,7 +295,7 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol params.bumpmap = pp.tcw.PixelFmt == PixelBumpMap; params.clamping = pp.tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff); params.insideClipTest = (pp.tileclip >> 28) == 3; - params.fog = settings.rend.Fog ? pp.tsp.FogCtrl : 2; + params.fog = config::Fog ? pp.tsp.FogCtrl : 2; params.gouraud = pp.pcw.Gouraud; params.ignoreTexAlpha = pp.tsp.IgnoreTexA || pp.tcw.PixelFmt == Pixel565; params.offset = pp.pcw.Offset; diff --git a/core/rend/vulkan/pipeline.h b/core/rend/vulkan/pipeline.h index b0f9d7693..71e4c590d 100644 --- a/core/rend/vulkan/pipeline.h +++ b/core/rend/vulkan/pipeline.h @@ -227,7 +227,7 @@ private: hash |= ((listType >> 1) << 5); bool ignoreTexAlpha = pp->tsp.IgnoreTexA || pp->tcw.PixelFmt == Pixel565; hash |= (pp->tsp.ShadInstr << 7) | (ignoreTexAlpha << 9) | (pp->tsp.UseAlpha << 10) - | (pp->tsp.ColorClamp << 11) | ((settings.rend.Fog ? pp->tsp.FogCtrl : 2) << 12) | (pp->tsp.SrcInstr << 14) + | (pp->tsp.ColorClamp << 11) | ((config::Fog ? pp->tsp.FogCtrl : 2) << 12) | (pp->tsp.SrcInstr << 14) | (pp->tsp.DstInstr << 17); hash |= (pp->isp.ZWriteDis << 20) | (pp->isp.CullMode << 21) | (pp->isp.DepthMode << 23); hash |= ((u32)sortTriangles << 26) | ((u32)BaseTextureCacheData::IsGpuHandledPaletted(pp->tsp, pp->tcw) << 27); @@ -287,7 +287,7 @@ public: void Init(ShaderManager *shaderManager) { // RTT render pass - renderToTextureBuffer = settings.rend.RenderToTextureBuffer; + renderToTextureBuffer = config::RenderToTextureBuffer; vk::AttachmentDescription attachmentDescriptions[] = { vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, @@ -320,7 +320,7 @@ public: void CheckSettingsChange() { - if (renderToTextureBuffer != settings.rend.RenderToTextureBuffer) + if (renderToTextureBuffer != config::RenderToTextureBuffer) Init(shaderManager); } diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index be7603df6..fcb387e62 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -873,14 +873,14 @@ void VulkanContext::PresentFrame(vk::ImageView imageView, vk::Extent2D extent) n { try { NewFrame(); - auto overlayCmdBuffers = PrepareOverlay(settings.rend.FloatVMUs, true); + auto overlayCmdBuffers = PrepareOverlay(config::FloatVMUs, true); BeginRenderPass(); if (lastFrameView) // Might have been nullified if swap chain recreated DrawFrame(imageView, extent); - DrawOverlay(gui_get_scaling(), settings.rend.FloatVMUs, true); + DrawOverlay(gui_get_scaling(), config::FloatVMUs, true); renderer->DrawOSD(false); EndFrame(overlayCmdBuffers); } catch (const InvalidVulkanContext& err) { diff --git a/core/rend/vulkan/vulkan_renderer.h b/core/rend/vulkan/vulkan_renderer.h index 9b50d097d..6c15f05d8 100644 --- a/core/rend/vulkan/vulkan_renderer.h +++ b/core/rend/vulkan/vulkan_renderer.h @@ -288,7 +288,7 @@ protected: fogTexture->tex_type = TextureType::_8; fog_needs_update = true; } - if (!fog_needs_update || !settings.rend.Fog) + if (!fog_needs_update || !config::Fog) return; fog_needs_update = false; u8 texData[256]; diff --git a/core/serialize.cpp b/core/serialize.cpp index 0f05a3e72..58efbd3b8 100644 --- a/core/serialize.cpp +++ b/core/serialize.cpp @@ -20,6 +20,7 @@ #include "hw/naomi/naomi_cart.h" #include "hw/sh4/sh4_cache.h" #include "hw/bba/bba.h" +#include "cfg/option.h" extern "C" void DYNACALL TAWriteSQ(u32 address,u8* sqb); @@ -439,8 +440,8 @@ bool dc_serialize(void **data, unsigned int *total_size) REICAST_S(sch_list[vblank_schid].start) ; REICAST_S(sch_list[vblank_schid].end) ; - REICAST_S(settings.network.EmulateBBA); - if (settings.network.EmulateBBA) + REICAST_S(config::EmulateBBA.get()); + if (config::EmulateBBA) { bba_Serialize(data, total_size); } @@ -474,9 +475,9 @@ bool dc_serialize(void **data, unsigned int *total_size) naomi_Serialize(data, total_size); - REICAST_S(settings.dreamcast.broadcast); - REICAST_S(settings.dreamcast.cable); - REICAST_S(settings.dreamcast.region); + REICAST_S(config::Broadcast.get()); + REICAST_S(config::Cable.get()); + REICAST_S(config::Region.get()); if (CurrentCartridge != NULL) CurrentCartridge->Serialize(data, total_size); @@ -732,14 +733,14 @@ static bool dc_unserialize_libretro(void **data, unsigned int *total_size) naomi_Unserialize(data, total_size, VCUR_LIBRETRO); - REICAST_US(settings.dreamcast.broadcast); - REICAST_US(settings.dreamcast.cable); - REICAST_US(settings.dreamcast.region); + REICAST_US(config::Broadcast.get()); + REICAST_US(config::Cable.get()); + REICAST_US(config::Region.get()); if (CurrentCartridge != NULL) CurrentCartridge->Unserialize(data, total_size); gd_hle_state.Unserialize(data, total_size); - settings.network.EmulateBBA = false; + config::EmulateBBA.override(false); DEBUG_LOG(SAVESTATE, "Loaded %d bytes (libretro compat)", *total_size); @@ -1013,10 +1014,10 @@ bool dc_unserialize(void **data, unsigned int *total_size) } if (version >= V13) - REICAST_S(settings.network.EmulateBBA); + REICAST_US(config::EmulateBBA.get()); else - settings.network.EmulateBBA = false; - if (settings.network.EmulateBBA) + config::EmulateBBA.override(false); + if (config::EmulateBBA) { bba_Unserialize(data, total_size); } @@ -1086,12 +1087,12 @@ bool dc_unserialize(void **data, unsigned int *total_size) REICAST_SKIP(4); REICAST_SKIP(4); } - REICAST_US(settings.dreamcast.broadcast); - verify(settings.dreamcast.broadcast <= 4); - REICAST_US(settings.dreamcast.cable); - verify(settings.dreamcast.cable <= 3); - REICAST_US(settings.dreamcast.region); - verify(settings.dreamcast.region <= 3); + REICAST_US(config::Broadcast.get()); + verify(config::Broadcast <= 4); + REICAST_US(config::Cable.get()); + verify(config::Cable <= 3); + REICAST_US(config::Region.get()); + verify(config::Region <= 3); if (CurrentCartridge != NULL) CurrentCartridge->Unserialize(data, total_size); diff --git a/core/types.h b/core/types.h index 569810389..59e63fceb 100644 --- a/core/types.h +++ b/core/types.h @@ -319,139 +319,27 @@ struct settings_t u32 bbsram_size; } platform; - struct { - bool UseReios; - } bios; - struct { - bool UseMipmaps; - bool WideScreen; - bool ShowFPS; - bool RenderToTextureBuffer; - int RenderToTextureUpscale; - bool TranslucentPolygonDepthMask; - bool ModifierVolumes; - bool Clipping; - int TextureUpscale; - int MaxFilteredTextureSize; - f32 ExtraDepthScale; - bool CustomTextures; - bool DumpTextures; - int ScreenScaling; // in percent. 50 means half the native resolution - int ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3 - bool Fog; - bool FloatVMUs; - bool Rotate90; // Rotate the screen 90 deg CC - bool PerStripSorting; - bool DelayFrameSwapping; // Delay swapping frame until FB_R_SOF matches FB_W_SOF - bool WidescreenGameHacks; - u32 CrosshairColor[4]; - } rend; - - struct - { - bool Enable; - bool idleskip; - bool unstable_opt; - bool safemode; bool disable_nvmem; - bool disable_vmem32; } dynarec; struct { - u32 run_counts; - } profile; - - struct - { - u32 cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV - u32 region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default - u32 broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default - u32 language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default - std::vector ContentPath; - bool FullMMU; - bool ForceWindowsCE; - bool HideLegacyNaomiRoms; - } dreamcast; - - struct - { - u32 BufferSize; //In samples ,*4 for bytes (1024) - bool LimitFPS; - u32 CDDAMute; - bool DSPEnabled; bool NoBatch; - bool NoSound; } aica; - struct{ - std::string backend; - - // slug<> - std::map> options; - } audio; - - -#if USE_OMX - struct - { - u32 Audio_Latency; - bool Audio_HDMI; - } omx; -#endif - -#if SUPPORT_DISPMANX - struct - { - u32 Width; - u32 Height; - bool Keep_Aspect; - } dispmanx; -#endif - struct { bool PatchRegion; char ImagePath[512]; } imgread; - struct - { - u32 ta_skip; - RenderType rend; - - u32 MaxThreads; - int AutoSkipFrame; // 0: none, 1: some, 2: more - - bool IsOpenGL() { return rend == RenderType::OpenGL || rend == RenderType::OpenGL_OIT; } - } pvr; - struct { - bool SerialConsole; - bool SerialPTY; - } debug; - - struct { - bool OpenGlChecks; - } validate; - - struct { - u32 MouseSensitivity; JVS JammaSetup; - int maple_devices[4]; - int maple_expansion_devices[4][2]; - int VirtualGamepadVibration; } input; - struct { - bool Enable; - bool ActAsServer; - std::string dns; - std::string server; - bool EmulateBBA; - } network; + bool gameStarted; }; extern settings_t settings; diff --git a/core/wsi/switcher.cpp b/core/wsi/switcher.cpp index 4e8d9303b..8b08645bd 100644 --- a/core/wsi/switcher.cpp +++ b/core/wsi/switcher.cpp @@ -20,6 +20,7 @@ */ #include "context.h" #include "rend/gui.h" +#include "cfg/option.h" #ifdef USE_VULKAN VulkanContext theVulkanContext; @@ -28,13 +29,13 @@ VulkanContext theVulkanContext; void InitRenderApi() { #ifdef USE_VULKAN - if (!settings.pvr.IsOpenGL()) + if (!config::RendererType.isOpenGL()) { if (theVulkanContext.Init()) return; // Fall back to Open GL WARN_LOG(RENDERER, "Vulkan init failed. Falling back to Open GL."); - settings.pvr.rend = RenderType::OpenGL; + config::RendererType = RenderType::OpenGL; } #endif if (!theGLContext.Init()) @@ -44,7 +45,7 @@ void InitRenderApi() void SwitchRenderApi(RenderType newApi) { TermRenderApi(); - settings.pvr.rend = newApi; + config::RendererType = newApi; InitRenderApi(); } diff --git a/core/wsi/xgl.cpp b/core/wsi/xgl.cpp index eaed5d10b..d29af2e0d 100644 --- a/core/wsi/xgl.cpp +++ b/core/wsi/xgl.cpp @@ -74,11 +74,14 @@ bool XGLGraphicsContext::Init() glXMakeCurrent(this->display, this->window, context); - screen_width = 640; - screen_height = 480; if (gl3wInit() == -1 || !gl3wIsSupported(3, 1)) return false; + Window win; + int temp; + unsigned int tempu; + XGetGeometry(display, window, &win, &temp, &temp, (u32 *)&screen_width, (u32 *)&screen_height, &tempu, &tempu); + PostInit(); return true; diff --git a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java index 6afae8be8..608fce594 100644 --- a/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java +++ b/shell/android-studio/reicast/src/main/java/com/reicast/emulator/emu/JNIdc.java @@ -31,7 +31,7 @@ public final class JNIdc public static native void setupMic(SipEmulator sip); public static native int getVirtualGamepadVibration(); - public static native int getAicaBufferSize(); + public static native int getAudioBufferSize(); public static native void screenDpi(int screenDpi); public static native void guiOpenSettings(); diff --git a/shell/android-studio/reicast/src/main/jni/src/Android.cpp b/shell/android-studio/reicast/src/main/jni/src/Android.cpp index 5ee9bfe0e..bcb938520 100644 --- a/shell/android-studio/reicast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/reicast/src/main/jni/src/Android.cpp @@ -28,6 +28,7 @@ #include "wsi/context.h" #include "emulator.h" #include "rend/mainui.h" +#include "cfg/option.h" JavaVM* g_jvm; @@ -75,11 +76,11 @@ static thread_local JVMAttacher jvm_attacher; #include "android_gamepad.h" -#define SETTINGS_ACCESSORS(jsetting, csetting, type) \ -JNIEXPORT type JNICALL Java_com_reicast_emulator_emu_JNIdc_get ## jsetting(JNIEnv *env, jobject obj) __attribute__((visibility("default"))); \ -JNIEXPORT type JNICALL Java_com_reicast_emulator_emu_JNIdc_get ## jsetting(JNIEnv *env, jobject obj) \ +#define SETTINGS_ACCESSORS(setting, type) \ +JNIEXPORT type JNICALL Java_com_reicast_emulator_emu_JNIdc_get ## setting(JNIEnv *env, jobject obj) __attribute__((visibility("default"))); \ +JNIEXPORT type JNICALL Java_com_reicast_emulator_emu_JNIdc_get ## setting(JNIEnv *env, jobject obj) \ { \ - return settings.csetting; \ + return (type)config::setting; \ } extern "C" @@ -107,8 +108,8 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_getControllers(JNIEnv JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setupMic(JNIEnv *env,jobject obj,jobject sip) __attribute__((visibility("default"))); -SETTINGS_ACCESSORS(VirtualGamepadVibration, input.VirtualGamepadVibration, jint); -SETTINGS_ACCESSORS(AicaBufferSize, aica.BufferSize, jint); +SETTINGS_ACCESSORS(VirtualGamepadVibration, jint); +SETTINGS_ACCESSORS(AudioBufferSize, jint); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_screenDpi(JNIEnv *env,jobject obj, jint screenDpi) __attribute__((visibility("default"))); JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiOpenSettings(JNIEnv *env,jobject obj) __attribute__((visibility("default"))); @@ -277,7 +278,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setGameUri(JNIEnv *en // TODO game paused/settings/... if (game_started) { dc_stop(); - gui_state = Main; + gui_state = GuiState::Main; dc_reset(true); } } @@ -311,6 +312,8 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_pause(JNIEnv *env,job { dc_stop(); game_started = true; // restart when resumed + if (config::AutoSavestate) + dc_savestate(); } } @@ -322,8 +325,14 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_resume(JNIEnv *env,jo JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_stop(JNIEnv *env,jobject obj) { - if (dc_is_running()) + if (dc_is_running()) { dc_stop(); + if (config::AutoSavestate) + dc_savestate(); + } + dc_term_game(); + gui_state = GuiState::Main; + settings.imgread.ImagePath[0] = '\0'; } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,jobject obj) @@ -340,19 +349,6 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_send(JNIEnv *env,jobj KillTex=true; INFO_LOG(RENDERER, "Killing texture cache"); } - - if (param==1) - { - settings.pvr.ta_skip^=1; - INFO_LOG(RENDERER, "settings.pvr.ta_skip: %d", settings.pvr.ta_skip); - } - if (param==2) - { -#if FEAT_SHREC != DYNAREC_NONE - print_stats=true; - INFO_LOG(DYNAREC, "Storing blocks ..."); -#endif - } } return 0; } @@ -439,15 +435,16 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_hideOsd(JNIEnv * env, JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_getControllers(JNIEnv *env, jobject obj, jintArray controllers, jobjectArray peripherals) { jint *controllers_body = env->GetIntArrayElements(controllers, 0); - memcpy(controllers_body, settings.input.maple_devices, sizeof(settings.input.maple_devices)); + for (u32 i = 0; i < config::MapleMainDevices.size(); i++) + controllers_body[i] = (MapleDeviceType)config::MapleMainDevices[i]; env->ReleaseIntArrayElements(controllers, controllers_body, 0); int obj_len = env->GetArrayLength(peripherals); for (int i = 0; i < obj_len; ++i) { jintArray port = (jintArray) env->GetObjectArrayElement(peripherals, i); jint *items = env->GetIntArrayElements(port, 0); - items[0] = settings.input.maple_expansion_devices[i][0]; - items[1] = settings.input.maple_expansion_devices[i][1]; + items[0] = (MapleDeviceType)config::MapleExpansionDevices[i][0]; + items[1] = (MapleDeviceType)config::MapleExpansionDevices[i][1]; env->ReleaseIntArrayElements(port, items, 0); env->DeleteLocalRef(port); } diff --git a/shell/apple/emulator-ios/emulator/ios_main.mm b/shell/apple/emulator-ios/emulator/ios_main.mm index 0c7d3d2c2..5a63de845 100644 --- a/shell/apple/emulator-ios/emulator/ios_main.mm +++ b/shell/apple/emulator-ios/emulator/ios_main.mm @@ -58,8 +58,6 @@ extern "C" int reicast_main(int argc, char* argv[]) common_linux_setup(); - settings.profile.run_counts=0; - dc_init(argc,argv); dc_run(); diff --git a/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj b/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj index 3d062fb2a..01f7df074 100644 --- a/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj +++ b/shell/apple/emulator-osx/reicast-osx.xcodeproj/project.pbxproj @@ -304,6 +304,7 @@ AE8C274321122E2500D4D8F4 /* xbrz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE8C273D21122E2500D4D8F4 /* xbrz.cpp */; }; AE90679B235B6F6400CE473C /* gl_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE90679A235B6F6400CE473C /* gl_context.cpp */; }; AE90679D235DF80400CE473C /* osd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE90679C235DF80400CE473C /* osd.cpp */; }; + AE9125CC25E3BBDC00ED4594 /* option.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AE9125CB25E3BBDC00ED4594 /* option.cpp */; }; AEA93E51259BA2180076297F /* audiobackend_sdl2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEA93E50259BA2170076297F /* audiobackend_sdl2.cpp */; }; AEA93E5C259BCD530076297F /* rtl8139c.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEA93E56259BCD530076297F /* rtl8139c.cpp */; }; AEA93E60259BCD530076297F /* bba.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEA93E5A259BCD530076297F /* bba.cpp */; }; @@ -915,6 +916,8 @@ AE8C274021122E2500D4D8F4 /* xbrz_tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xbrz_tools.h; sourceTree = ""; }; AE90679A235B6F6400CE473C /* gl_context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gl_context.cpp; sourceTree = ""; }; AE90679C235DF80400CE473C /* osd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = osd.cpp; sourceTree = ""; }; + AE9125CA25E3BBDC00ED4594 /* option.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = option.h; sourceTree = ""; }; + AE9125CB25E3BBDC00ED4594 /* option.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = option.cpp; sourceTree = ""; }; AEA93E50259BA2170076297F /* audiobackend_sdl2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audiobackend_sdl2.cpp; sourceTree = ""; }; AEA93E53259BCD530076297F /* rtl8139c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtl8139c.h; sourceTree = ""; }; AEA93E55259BCD530076297F /* bba.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bba.h; sourceTree = ""; }; @@ -1254,6 +1257,8 @@ 84B7BD131B72720100F9733F /* cfg */ = { isa = PBXGroup; children = ( + AE9125CB25E3BBDC00ED4594 /* option.cpp */, + AE9125CA25E3BBDC00ED4594 /* option.h */, 8491687D1B782B2D00F3F2B4 /* ini.cpp */, 8491687E1B782B2D00F3F2B4 /* ini.h */, 84B7BD141B72720100F9733F /* cfg.cpp */, @@ -2950,6 +2955,7 @@ AEFF7F56214D9D590068CE11 /* pico_ethernet.c in Sources */, AEE6277E220D7B7E00EC7E89 /* imgui_widgets.cpp in Sources */, 84B7BF771B72720200F9733F /* reios_elf.cpp in Sources */, + AE9125CC25E3BBDC00ED4594 /* option.cpp in Sources */, 84B7BF5C1B72720200F9733F /* common.cpp in Sources */, AE82C6BE25B64AE200C79BC2 /* zip_source_crc.c in Sources */, 84B7BF681B72720200F9733F /* audiobackend_directsound.cpp in Sources */, @@ -3056,7 +3062,6 @@ GCC_FAST_MATH = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - TARGET_NO_COREIO_HTTP, TARGET_NO_OPENMP, CHD5_LZMA, _7ZIP_ST, @@ -3109,7 +3114,6 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_FAST_MATH = YES; GCC_PREPROCESSOR_DEFINITIONS = ( - TARGET_NO_COREIO_HTTP, TARGET_NO_OPENMP, CHD5_LZMA, _7ZIP_ST, diff --git a/tests/src/serialize_test.cpp b/tests/src/serialize_test.cpp index d335cfc2f..0d57778bb 100644 --- a/tests/src/serialize_test.cpp +++ b/tests/src/serialize_test.cpp @@ -4,6 +4,7 @@ #include "hw/maple/maple_cfg.h" #include "hw/maple/maple_devs.h" #include "emulator.h" +#include "cfg/option.h" class SerializeTest : public ::testing::Test { protected: @@ -17,13 +18,14 @@ protected: TEST_F(SerializeTest, SizeTest) { - InitSettings(); - settings.input.maple_devices[0] = MDT_SegaController; - settings.input.maple_expansion_devices[0][0] = MDT_SegaVMU; - settings.input.maple_expansion_devices[0][1] = MDT_SegaVMU; - settings.input.maple_devices[1] = MDT_SegaController; - settings.input.maple_expansion_devices[1][0] = MDT_SegaVMU; - settings.input.maple_expansion_devices[1][1] = MDT_SegaVMU; + using namespace config; + Settings::instance().reset(); + MapleMainDevices[0] = MDT_SegaController; + MapleExpansionDevices[0][0] = MDT_SegaVMU; + MapleExpansionDevices[0][1] = MDT_SegaVMU; + MapleMainDevices[1] = MDT_SegaController; + MapleExpansionDevices[1][0] = MDT_SegaVMU; + MapleExpansionDevices[1][1] = MDT_SegaVMU; mcfg_CreateDevices(); unsigned int total_size = 0;