2018-11-16 00:42:29 +01:00
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System ( TM ) emulator .
This file is licensed under the Snes9x License .
For further information , consult the LICENSE file in the root directory .
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-09-25 17:46:12 +02:00
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <sys/stat.h>
2022-05-03 03:31:22 +02:00
# include <filesystem>
2010-09-25 17:46:12 +02:00
2022-05-03 03:31:22 +02:00
# include "fmt/format.h"
2010-09-25 17:46:12 +02:00
# include "gtk_config.h"
# include "gtk_s9x.h"
# include "gtk_sound.h"
# include "gtk_display.h"
2018-11-02 02:44:06 +01:00
# include "conffile.h"
2020-07-05 00:53:38 +02:00
# include "cheats.h"
# include "apu/apu.h"
# include "netplay.h"
# include "controls.h"
2010-09-25 17:46:12 +02:00
2022-05-03 03:31:22 +02:00
namespace fs = std : : filesystem ;
2017-05-07 01:39:01 +02:00
2020-06-21 22:25:54 +02:00
std : : string get_config_dir ( )
2010-09-25 17:46:12 +02:00
{
2018-11-18 20:08:42 +01:00
// Find config directory
2020-06-21 22:25:54 +02:00
char * env_home = getenv ( " HOME " ) ;
char * env_xdg_config_home = getenv ( " XDG_CONFIG_HOME " ) ;
2010-09-25 17:46:12 +02:00
2018-11-18 20:08:42 +01:00
if ( ! env_home & & ! env_xdg_config_home )
2017-05-07 01:39:01 +02:00
{
2020-07-05 00:53:38 +02:00
return std : : string { " .snes9x " } ;
2017-05-07 01:39:01 +02:00
}
2022-05-03 03:31:22 +02:00
fs : : path config = env_home ;
fs : : path legacy = config ;
2010-09-25 17:46:12 +02:00
2018-11-18 20:08:42 +01:00
// If XDG_CONFIG_HOME is set, use that, otherwise guess default
if ( ! env_xdg_config_home )
2010-09-25 17:46:12 +02:00
{
2022-05-03 03:31:22 +02:00
config / = " .config/snes9x " ;
legacy / = " .snes9x " ;
2010-09-25 17:46:12 +02:00
}
else
2022-05-03 03:31:22 +02:00
{
config = env_xdg_config_home ;
config / = " snes9x " ;
}
if ( fs : : exists ( legacy ) & & ! fs : : exists ( config ) )
2018-11-18 20:08:42 +01:00
return legacy ;
return config ;
2010-09-25 17:46:12 +02:00
}
2020-06-21 22:25:54 +02:00
std : : string get_config_file_name ( )
2010-09-25 17:46:12 +02:00
{
2020-06-21 22:25:54 +02:00
return get_config_dir ( ) + " /snes9x.conf " ;
2010-09-25 17:46:12 +02:00
}
2020-06-21 22:25:54 +02:00
void S9xParsePortConfig ( ConfigFile & conf , int pass )
2010-09-25 17:46:12 +02:00
{
}
2020-06-21 22:25:54 +02:00
Snes9xConfig : : Snes9xConfig ( )
2010-09-25 17:46:12 +02:00
{
2010-10-21 03:55:59 +02:00
joystick_threshold = 40 ;
2010-09-25 17:46:12 +02:00
}
2020-06-21 22:25:54 +02:00
int Snes9xConfig : : load_defaults ( )
2010-09-25 17:46:12 +02:00
{
2018-12-28 23:32:32 +01:00
full_screen_on_open = false ;
change_display_resolution = false ;
2010-09-25 17:46:12 +02:00
xrr_index = 0 ;
2018-12-28 23:32:32 +01:00
scale_to_fit = true ;
maintain_aspect_ratio = true ;
2018-11-02 02:44:06 +01:00
aspect_ratio = 2 ;
2010-09-25 17:46:12 +02:00
scale_method = 0 ;
2018-12-28 23:32:32 +01:00
overscan = false ;
2010-09-25 17:46:12 +02:00
save_sram_after_secs = 0 ;
2018-12-28 23:32:32 +01:00
rom_loaded = false ;
multithreading = false ;
2022-01-31 01:34:51 +01:00
splash_image = SPLASH_IMAGE_STARFIELD ;
2010-09-25 17:46:12 +02:00
hw_accel = 0 ;
2018-12-28 23:32:32 +01:00
allow_opengl = false ;
allow_xv = false ;
allow_xrandr = false ;
force_inverted_byte_order = false ;
2011-01-24 00:07:22 +01:00
hires_effect = HIRES_NORMAL ;
2018-12-28 23:32:32 +01:00
pause_emulation_on_switch = false ;
2010-09-25 17:46:12 +02:00
num_threads = 2 ;
2018-12-28 23:32:32 +01:00
mute_sound = false ;
mute_sound_turbo = false ;
fullscreen = false ;
ui_visible = true ;
2010-09-25 17:46:12 +02:00
default_esc_behavior = 1 ;
2018-12-28 23:32:32 +01:00
prevent_screensaver = false ;
2010-09-25 17:46:12 +02:00
sound_driver = 0 ;
2020-07-05 00:53:38 +02:00
sound_buffer_size = 48 ;
sound_playback_rate = 7 ;
2010-09-25 17:46:12 +02:00
sound_input_rate = 31950 ;
2018-12-28 23:32:32 +01:00
auto_input_rate = true ;
2020-06-21 22:25:54 +02:00
last_directory . clear ( ) ;
last_shader_directory . clear ( ) ;
2010-09-25 17:46:12 +02:00
window_width = - 1 ;
window_height = - 1 ;
preferences_width = - 1 ;
preferences_height = - 1 ;
2019-01-31 23:33:17 +01:00
shader_parameters_width = - 1 ;
shader_parameters_height = - 1 ;
2019-04-16 18:47:35 +02:00
enable_icons = true ;
2019-02-18 03:55:59 +01:00
current_display_tab = 0 ;
2020-06-21 22:25:54 +02:00
sram_directory . clear ( ) ;
export_directory . clear ( ) ;
savestate_directory . clear ( ) ;
cheat_directory . clear ( ) ;
patch_directory . clear ( ) ;
2018-12-28 23:32:32 +01:00
screensaver_needs_reset = false ;
2010-09-25 17:46:12 +02:00
ntsc_setup = snes_ntsc_composite ;
ntsc_scanline_intensity = 1 ;
scanline_filter_intensity = 0 ;
2018-12-28 23:32:32 +01:00
Settings . BilinearFilter = false ;
netplay_activated = false ;
netplay_server_up = false ;
netplay_is_server = false ;
netplay_sync_reset = true ;
netplay_send_rom = false ;
2010-09-25 17:46:12 +02:00
netplay_default_port = 6096 ;
netplay_max_frame_loss = 10 ;
2020-06-21 22:25:54 +02:00
netplay_last_rom . clear ( ) ;
netplay_last_host . clear ( ) ;
2010-09-25 17:46:12 +02:00
netplay_last_port = 6096 ;
2018-12-28 23:32:32 +01:00
modal_dialogs = true ;
2018-11-06 23:30:50 +01:00
current_save_slot = 0 ;
2020-06-21 22:25:54 +02:00
S9xCheatsEnable ( ) ;
2016-10-09 04:33:34 +02:00
rewind_granularity = 5 ;
rewind_buffer_size = 0 ;
2018-12-28 23:32:32 +01:00
Settings . Rewinding = false ;
2010-09-25 17:46:12 +02:00
2018-12-28 23:32:32 +01:00
sync_to_vblank = true ;
use_pbos = true ;
2010-09-25 17:46:12 +02:00
pbo_format = 0 ;
2020-07-05 00:53:38 +02:00
npot_textures = true ;
2018-12-28 23:32:32 +01:00
use_shaders = false ;
2020-06-21 22:25:54 +02:00
shader_filename . clear ( ) ;
2019-03-02 22:25:59 +01:00
use_glfinish = false ;
use_sync_control = false ;
2010-09-25 17:46:12 +02:00
2019-02-18 22:15:28 +01:00
/* Snes9x Variables */
2018-12-28 23:32:32 +01:00
Settings . MouseMaster = true ;
Settings . SuperScopeMaster = true ;
Settings . JustifierMaster = true ;
Settings . MultiPlayer5Master = true ;
Settings . UpAndDown = false ;
2010-09-25 17:46:12 +02:00
Settings . AutoSaveDelay = 0 ;
2018-11-02 02:44:06 +01:00
Settings . SkipFrames = 0 ;
2018-12-28 23:32:32 +01:00
Settings . Transparency = true ;
2019-05-12 05:24:17 +02:00
Settings . DisplayTime = false ;
2018-12-28 23:32:32 +01:00
Settings . DisplayFrameRate = false ;
Settings . SixteenBitSound = true ;
Settings . Stereo = true ;
Settings . ReverseStereo = false ;
2019-02-15 20:06:25 +01:00
Settings . SoundPlaybackRate = 48000 ;
2018-12-28 23:32:32 +01:00
Settings . StopEmulation = true ;
2019-02-27 20:55:19 +01:00
Settings . FrameTimeNTSC = 16639 ;
2010-09-25 17:46:12 +02:00
Settings . FrameTimePAL = 20000 ;
Settings . FrameTime = Settings . FrameTimeNTSC ;
2018-12-28 23:32:32 +01:00
Settings . BlockInvalidVRAMAccessMaster = true ;
Settings . SoundSync = false ;
Settings . DynamicRateControl = false ;
2017-11-24 20:03:24 +01:00
Settings . DynamicRateLimit = 5 ;
2018-08-06 19:31:07 +02:00
Settings . InterpolationMethod = DSP_INTERPOLATION_GAUSSIAN ;
2010-09-25 17:46:12 +02:00
Settings . HDMATimingHack = 100 ;
2018-05-08 00:03:06 +02:00
Settings . SuperFXClockMultiplier = 100 ;
2018-12-28 23:32:32 +01:00
Settings . NetPlay = false ;
NetPlay . Paused = false ;
2018-12-02 02:58:13 +01:00
NetPlay . MaxFrameSkip = 10 ;
2018-12-28 23:32:32 +01:00
Settings . DisplayPressedKeys = false ;
2018-08-12 02:19:04 +02:00
# ifdef ALLOW_CPU_OVERCLOCK
Settings . MaxSpriteTilesPerLine = 34 ;
Settings . OneClockCycle = 6 ;
Settings . OneSlowClockCycle = 8 ;
Settings . TwoClockCycles = 12 ;
# endif
2010-09-25 17:46:12 +02:00
2020-06-20 17:44:11 +02:00
for ( auto & joypad : pad )
{
joypad . data . fill ( Binding ( ) ) ;
}
shortcut . fill ( Binding ( ) ) ;
2010-09-25 17:46:12 +02:00
return 0 ;
}
2020-06-21 22:25:54 +02:00
int Snes9xConfig : : save_config_file ( )
2018-11-02 02:44:06 +01:00
{
ConfigFile cf ;
2020-07-05 00:53:38 +02:00
std : : string section ;
2020-06-21 22:25:54 +02:00
auto outbool = [ & ] ( std : : string name , bool b , std : : string comment = " " ) {
cf . SetBool ( ( section + " :: " + name ) . c_str ( ) , b , " true " , " false " , comment . c_str ( ) ) ;
} ;
auto outstring = [ & ] ( std : : string name , std : : string str , std : : string comment = " " ) {
cf . SetString ( ( section + " :: " + name ) . c_str ( ) , str , comment . c_str ( ) ) ;
} ;
auto outint = [ & ] ( std : : string name , int i , std : : string comment = " " ) {
cf . SetInt ( ( section + " :: " + name ) . c_str ( ) , i , comment . c_str ( ) ) ;
} ;
section = " Display " ;
outbool ( " FullscreenOnOpen " , full_screen_on_open , " Set the screen resolution after opening a ROM " ) ;
outbool ( " ChangeDisplayResolution " , change_display_resolution , " Set the resolution in fullscreen mode " ) ;
outbool ( " ScaleToFit " , scale_to_fit , " Scale the image to fit the window size " ) ;
outbool ( " ShowOverscanArea " , overscan ) ;
outbool ( " MaintainAspectRatio " , maintain_aspect_ratio , " Resize the screen to the proportions set by aspect ratio option " ) ;
outbool ( " Multithreading " , multithreading , " Apply filters using multiple threads " ) ;
outbool ( " BilinearFilter " , Settings . BilinearFilter , " Smoothes scaled image " ) ;
outbool ( " ForceInvertedByteOrder " , force_inverted_byte_order ) ;
outint ( " VideoMode " , xrr_index , " Platform-specific video mode number " ) ;
outint ( " AspectRatio " , aspect_ratio , " 0: uncorrected, 1: uncorrected integer scale, 2: 4:3, 3: 4/3 integer scale, 4: NTSC/PAL, 5: NTSC/PAL integer scale " ) ;
outint ( " SoftwareScaleFilter " , scale_method , " Build-specific number of filter used for software scaling " ) ;
outint ( " ScanlineFilterIntensity " , scanline_filter_intensity , " 0: 0%, 1: 12.5%, 2: 25%, 3: 50%, 4: 100% " ) ;
outint ( " HiresEffect " , hires_effect , " 0: Downscale to low-res, 1: Leave as-is, 2: Upscale low-res screens " ) ;
outint ( " NumberOfThreads " , num_threads ) ;
outint ( " HardwareAcceleration " , hw_accel , " 0: None, 1: OpenGL, 2: XVideo " ) ;
outint ( " SplashBackground " , splash_image , " 0: Black, 1: Color bars, 2: Pattern, 3: Blue, 4: Default " ) ;
section = " NTSC " ;
outstring ( " Hue " , std : : to_string ( ntsc_setup . hue ) ) ;
outstring ( " Saturation " , std : : to_string ( ntsc_setup . saturation ) ) ;
outstring ( " Contrast " , std : : to_string ( ntsc_setup . contrast ) ) ;
outstring ( " Brightness " , std : : to_string ( ntsc_setup . brightness ) ) ;
outstring ( " Sharpness " , std : : to_string ( ntsc_setup . sharpness ) ) ;
outstring ( " Artifacts " , std : : to_string ( ntsc_setup . artifacts ) ) ;
outstring ( " Gamma " , std : : to_string ( ntsc_setup . gamma ) ) ;
outstring ( " Bleed " , std : : to_string ( ntsc_setup . bleed ) ) ;
outstring ( " Fringing " , std : : to_string ( ntsc_setup . fringing ) ) ;
outstring ( " Resolution " , std : : to_string ( ntsc_setup . resolution ) ) ;
outbool ( " MergeFields " , ntsc_setup . merge_fields ) ;
outint ( " ScanlineIntensity " , ntsc_scanline_intensity ) ;
2016-10-09 04:33:34 +02:00
2020-06-21 22:25:54 +02:00
section = " OpenGL " ;
outbool ( " VSync " , sync_to_vblank ) ;
outbool ( " glFinish " , use_glfinish ) ;
outbool ( " SyncControl " , use_sync_control ) ;
outbool ( " UseNonPowerOfTwoTextures " , npot_textures ) ;
outbool ( " EnableCustomShaders " , use_shaders ) ;
outbool ( " UsePixelBufferObjects " , use_pbos ) ;
outint ( " PixelBufferObjectBitDepth " , pbo_format ) ;
outstring ( " ShaderFile " , shader_filename ) ;
2010-09-25 17:46:12 +02:00
2020-06-21 22:25:54 +02:00
section = " Sound " ;
outbool ( " MuteSound " , mute_sound ) ;
outbool ( " MuteSoundDuringTurbo " , mute_sound_turbo ) ;
outint ( " BufferSize " , sound_buffer_size , " Buffer size in milliseconds " ) ;
outint ( " Driver " , sound_driver ) ;
outint ( " InputRate " , sound_input_rate ) ;
outbool ( " DynamicRateControl " , Settings . DynamicRateControl ) ;
outint ( " DynamicRateControlLimit " , Settings . DynamicRateLimit ) ;
outbool ( " AutomaticInputRate " , auto_input_rate , " Guess input rate by asking the monitor what its refresh rate is " ) ;
outint ( " PlaybackRate " , gui_config - > sound_playback_rate , " 1: 8000Hz, 2: 11025Hz, 3: 16000Hz, 4: 22050Hz, 5: 32000Hz, 6: 44100Hz, 7: 48000Hz " ) ;
section = " Files " ;
outstring ( " LastDirectory " , last_directory ) ;
outstring ( " LastShaderDirectory " , last_shader_directory ) ;
outstring ( " SRAMDirectory " , sram_directory ) ;
outstring ( " SaveStateDirectory " , savestate_directory ) ;
outstring ( " CheatDirectory " , cheat_directory ) ;
outstring ( " PatchDirectory " , patch_directory ) ;
outstring ( " ExportDirectory " , export_directory ) ;
section = " Window State " ;
outint ( " MainWidth " , window_width ) ;
outint ( " MainHeight " , window_height ) ;
outint ( " PreferencesWidth " , preferences_width ) ;
outint ( " PreferencesHeight " , preferences_height ) ;
outint ( " ShaderParametersWidth " , shader_parameters_width ) ;
outint ( " ShaderParametersHeight " , shader_parameters_height ) ;
outint ( " CurrentDisplayTab " , current_display_tab ) ;
outbool ( " UIVisible " , ui_visible ) ;
outbool ( " EnableIcons " , enable_icons ) ;
2018-11-02 02:44:06 +01:00
if ( default_esc_behavior ! = ESC_TOGGLE_MENUBAR )
2020-06-21 22:25:54 +02:00
outbool ( " Fullscreen " , 0 ) ;
2018-11-02 02:44:06 +01:00
else
2020-06-21 22:25:54 +02:00
outbool ( " Fullscreen " , fullscreen ) ;
section = " Netplay " ;
outbool ( " ActAsServer " , netplay_is_server ) ;
outbool ( " UseResetToSync " , netplay_sync_reset ) ;
outbool ( " SendROM " , netplay_send_rom ) ;
outint ( " DefaultPort " , netplay_default_port ) ;
outint ( " MaxFrameLoss " , netplay_max_frame_loss ) ;
outint ( " LastUsedPort " , netplay_last_port ) ;
outstring ( " LastUsedROM " , netplay_last_rom ) ;
outstring ( " LastUsedHost " , netplay_last_host ) ;
section = " Behavior " ;
outbool ( " PauseEmulationWhenFocusLost " , pause_emulation_on_switch ) ;
outint ( " DefaultESCKeyBehavior " , default_esc_behavior ) ;
outbool ( " PreventScreensaver " , prevent_screensaver ) ;
outbool ( " UseModalDialogs " , modal_dialogs ) ;
outint ( " RewindBufferSize " , rewind_buffer_size , " Amount of memory (in MB) to use for rewinding " ) ;
outint ( " RewindGranularity " , rewind_granularity , " Only save rewind snapshots every N frames " ) ;
outint ( " CurrentSaveSlot " , current_save_slot ) ;
section = " Emulation " ;
outbool ( " EmulateTransparency " , Settings . Transparency ) ;
outbool ( " DisplayTime " , Settings . DisplayTime ) ;
outbool ( " DisplayFrameRate " , Settings . DisplayFrameRate ) ;
outbool ( " DisplayPressedKeys " , Settings . DisplayPressedKeys ) ;
outint ( " SpeedControlMethod " , Settings . SkipFrames , " 0: Time the frames to 50 or 60Hz, 1: Same, but skip frames if too slow, 2: Synchronize to the sound buffer, 3: Unlimited, except potentially by vsync " ) ;
outint ( " SaveSRAMEveryNSeconds " , Settings . AutoSaveDelay ) ;
outbool ( " BlockInvalidVRAMAccess " , Settings . BlockInvalidVRAMAccessMaster ) ;
outbool ( " AllowDPadContradictions " , Settings . UpAndDown , " Allow the D-Pad to press both up + down at the same time, or left + right " ) ;
section = " Hacks " ;
outint ( " SuperFXClockMultiplier " , Settings . SuperFXClockMultiplier ) ;
outint ( " SoundInterpolationMethod " , Settings . InterpolationMethod , " 0: None, 1: Linear, 2: Gaussian (what the hardware uses), 3: Cubic, 4: Sinc " ) ;
outbool ( " RemoveSpriteLimit " , Settings . MaxSpriteTilesPerLine = = 34 ? 0 : 1 ) ;
outbool ( " OverclockCPU " , Settings . OneClockCycle = = 6 ? 0 : 1 ) ;
outbool ( " EchoBufferHack " , Settings . SeparateEchoBuffer , " Prevents echo buffer from overwriting APU RAM " ) ;
section = " Input " ;
2018-11-08 21:59:24 +01:00
controllers controller = CTL_NONE ;
int8 id [ 4 ] ;
for ( int i = 0 ; i < 2 ; i + + )
{
2020-06-21 22:25:54 +02:00
std : : string name ;
std : : string value ;
name = " ControllerPort " + std : : to_string ( i ) ;
S9xGetController ( i , & controller , & id [ 0 ] , & id [ 1 ] , & id [ 2 ] , & id [ 3 ] ) ;
2018-11-08 21:59:24 +01:00
switch ( controller )
{
case CTL_JOYPAD :
2020-06-21 22:25:54 +02:00
value = " joypad " ;
2018-11-08 21:59:24 +01:00
break ;
case CTL_MOUSE :
2020-06-21 22:25:54 +02:00
value = " mouse " ;
2018-11-08 21:59:24 +01:00
break ;
case CTL_SUPERSCOPE :
2020-06-21 22:25:54 +02:00
value = " superscope " ;
2018-11-08 21:59:24 +01:00
break ;
case CTL_MP5 :
2020-06-21 22:25:54 +02:00
value = " multitap " ;
2018-11-08 21:59:24 +01:00
break ;
case CTL_JUSTIFIER :
2020-06-21 22:25:54 +02:00
value = " justifier " ;
2018-11-08 21:59:24 +01:00
break ;
default :
2020-06-21 22:25:54 +02:00
value = " none " ;
2018-11-08 21:59:24 +01:00
}
2020-06-21 22:25:54 +02:00
outstring ( name , value ) ;
2018-11-08 21:59:24 +01:00
}
2020-06-21 22:25:54 +02:00
outint ( " JoystickThreshold " , joystick_threshold ) ;
2018-11-02 02:44:06 +01:00
2010-09-25 17:46:12 +02:00
for ( int i = 0 ; i < NUM_JOYPADS ; i + + )
{
2020-06-20 17:44:11 +02:00
auto & joypad = pad [ i ] ;
2010-09-25 17:46:12 +02:00
for ( int j = 0 ; j < NUM_JOYPAD_LINKS ; j + + )
{
2020-06-21 22:25:54 +02:00
section = " Joypad " + std : : to_string ( i ) ;
outstring ( b_links [ j ] . snes9x_name , joypad . data [ j ] . as_string ( ) ) ;
2010-09-25 17:46:12 +02:00
}
}
2020-06-21 22:25:54 +02:00
section = " Shortcuts " ;
2010-09-25 17:46:12 +02:00
for ( int i = NUM_JOYPAD_LINKS ; b_links [ i ] . snes9x_name ; i + + )
{
2020-06-21 22:25:54 +02:00
outstring ( b_links [ i ] . snes9x_name , shortcut [ i - NUM_JOYPAD_LINKS ] . as_string ( ) ) ;
2010-09-25 17:46:12 +02:00
}
2020-06-21 22:25:54 +02:00
cf . SetNiceAlignment ( true ) ;
cf . SetShowComments ( true ) ;
cf . SaveTo ( get_config_file_name ( ) . c_str ( ) ) ;
2010-09-25 17:46:12 +02:00
return 0 ;
}
2020-06-21 22:25:54 +02:00
int Snes9xConfig : : load_config_file ( )
2010-09-25 17:46:12 +02:00
{
2020-06-21 22:25:54 +02:00
load_defaults ( ) ;
2010-09-25 17:46:12 +02:00
2022-05-03 03:31:22 +02:00
fs : : path path = get_config_dir ( ) ;
2010-09-25 17:46:12 +02:00
2022-05-03 03:31:22 +02:00
if ( ! fs : : exists ( path ) )
2010-09-25 17:46:12 +02:00
{
2022-05-03 03:31:22 +02:00
if ( ! fs : : create_directory ( path ) )
2010-09-25 17:46:12 +02:00
{
2022-05-03 03:31:22 +02:00
fmt : : print ( stderr , _ ( " Couldn't create config directory: {} \n " ) , path . string ( ) ) ;
2018-11-02 02:44:06 +01:00
return - 1 ;
2010-09-25 17:46:12 +02:00
}
}
else
{
2022-05-03 03:31:22 +02:00
if ( ( fs : : status ( path ) . permissions ( ) & fs : : perms : : owner_write ) = = fs : : perms : : none )
fs : : permissions ( path , fs : : perms : : owner_write , fs : : perm_options : : add ) ;
2010-09-25 17:46:12 +02:00
}
2020-06-21 22:25:54 +02:00
path = get_config_file_name ( ) ;
2010-09-25 17:46:12 +02:00
2022-05-03 03:31:22 +02:00
// Write an on-disk config file if none exists.
if ( ! fs : : exists ( path ) )
2020-06-21 22:25:54 +02:00
save_config_file ( ) ;
2010-09-25 17:46:12 +02:00
2022-05-03 03:31:22 +02:00
ConfigFile cf ;
2020-06-21 22:25:54 +02:00
if ( ! cf . LoadFile ( path . c_str ( ) ) )
2018-11-02 02:44:06 +01:00
return - 1 ;
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
std : : string none ;
2020-06-21 22:25:54 +02:00
std : : string section ;
auto inbool = [ & ] ( std : : string name , auto & b ) {
if ( cf . Exists ( ( section + " :: " + name ) . c_str ( ) ) )
b = cf . GetBool ( ( section + " :: " + name ) . c_str ( ) ) ;
} ;
auto inint = [ & ] ( std : : string name , auto & i ) {
if ( cf . Exists ( ( section + " :: " + name ) . c_str ( ) ) )
i = cf . GetInt ( ( section + " :: " + name ) . c_str ( ) ) ;
} ;
auto indouble = [ & ] ( std : : string name , double & d ) {
if ( cf . Exists ( ( section + " :: " + name ) . c_str ( ) ) )
d = atof ( cf . GetString ( ( section + " :: " + name ) . c_str ( ) ) ) ;
} ;
auto instr = [ & ] ( std : : string name , std : : string & str ) {
str = cf . GetString ( ( section + " :: " + name ) . c_str ( ) , none ) ;
} ;
section = " Display " ;
inbool ( " FullscreenOnOpen " , full_screen_on_open ) ;
inbool ( " ChangeDisplayResolution " , change_display_resolution ) ;
inint ( " VideoMode " , xrr_index ) ;
inbool ( " ScaleToFit " , scale_to_fit ) ;
inbool ( " MaintainAspectRatio " , maintain_aspect_ratio ) ;
inint ( " AspectRatio " , aspect_ratio ) ;
inint ( " SoftwareScaleFilter " , scale_method ) ;
inint ( " ScanlineFilterIntensity " , scanline_filter_intensity ) ;
inbool ( " ShowOverscanArea " , overscan ) ;
inint ( " HiresEffect " , hires_effect ) ;
inbool ( " ForceInvertedByteOrder " , force_inverted_byte_order ) ;
inbool ( " Multithreading " , multithreading ) ;
inint ( " NumberOfThreads " , num_threads ) ;
inint ( " HardwareAcceleration " , hw_accel ) ;
inbool ( " BilinearFilter " , Settings . BilinearFilter ) ;
inint ( " SplashBackground " , splash_image ) ;
section = " NTSC " ;
indouble ( " Hue " , ntsc_setup . hue ) ;
indouble ( " Saturation " , ntsc_setup . saturation ) ;
indouble ( " Contrast " , ntsc_setup . contrast ) ;
indouble ( " Brightness " , ntsc_setup . brightness ) ;
indouble ( " Sharpness " , ntsc_setup . sharpness ) ;
indouble ( " Artifacts " , ntsc_setup . artifacts ) ;
indouble ( " Gamma " , ntsc_setup . gamma ) ;
indouble ( " Bleed " , ntsc_setup . bleed ) ;
indouble ( " Fringing " , ntsc_setup . fringing ) ;
indouble ( " Resolution " , ntsc_setup . resolution ) ;
inbool ( " MergeFields " , ntsc_setup . merge_fields ) ;
inint ( " ScanlineIntensity " , ntsc_scanline_intensity ) ;
2010-09-25 17:46:12 +02:00
2020-06-21 22:25:54 +02:00
section = " OpenGL " ;
inbool ( " VSync " , sync_to_vblank ) ;
inbool ( " glFinish " , use_glfinish ) ;
inbool ( " SyncControl " , use_sync_control ) ;
inbool ( " UsePixelBufferObjects " , use_pbos ) ;
inint ( " PixelBufferObjectBitDepth " , pbo_format ) ;
inbool ( " UseNonPowerOfTwoTextures " , npot_textures ) ;
inbool ( " EnableCustomShaders " , use_shaders ) ;
instr ( " ShaderFile " , shader_filename ) ;
2010-09-25 17:46:12 +02:00
2020-06-21 22:25:54 +02:00
section = " Sound " ;
inbool ( " MuteSound " , mute_sound ) ;
inbool ( " MuteSoundDuringTurbo " , mute_sound_turbo ) ;
inint ( " BufferSize " , sound_buffer_size ) ;
inint ( " Driver " , sound_driver ) ;
inint ( " InputRate " , sound_input_rate ) ;
inbool ( " DynamicRateControl " , Settings . DynamicRateControl ) ;
inint ( " DynamicRateControlLimit " , Settings . DynamicRateLimit ) ;
inbool ( " AutomaticInputRate " , auto_input_rate ) ;
inint ( " PlaybackRate " , gui_config - > sound_playback_rate ) ;
section = " Files " ;
instr ( " LastDirectory " , last_directory ) ;
instr ( " LastShaderDirectory " , last_shader_directory ) ;
instr ( " SRAMDirectory " , sram_directory ) ;
instr ( " SaveStateDirectory " , savestate_directory ) ;
instr ( " CheatDirectory " , cheat_directory ) ;
instr ( " PatchDirectory " , patch_directory ) ;
instr ( " ExportDirectory " , export_directory ) ;
section = " Window State " ;
inint ( " MainWidth " , window_width ) ;
inint ( " MainHeight " , window_height ) ;
inint ( " PreferencesWidth " , preferences_width ) ;
inint ( " PreferencesHeight " , preferences_height ) ;
inint ( " ShaderParametersWidth " , shader_parameters_width ) ;
inint ( " ShaderParametersHeight " , shader_parameters_height ) ;
inint ( " CurrentDisplayTab " , current_display_tab ) ;
inbool ( " UIVisible " , ui_visible ) ;
inbool ( " Fullscreen " , fullscreen ) ;
inbool ( " EnableIcons " , enable_icons ) ;
section = " Netplay " ;
inbool ( " ActAsServer " , netplay_is_server ) ;
inbool ( " UseResetToSync " , netplay_sync_reset ) ;
inbool ( " SendROM " , netplay_send_rom ) ;
inint ( " DefaultPort " , netplay_default_port ) ;
inint ( " MaxFrameLoss " , netplay_max_frame_loss ) ;
inint ( " LastUsedPort " , netplay_last_port ) ;
instr ( " LastUsedROM " , netplay_last_rom ) ;
instr ( " LastUsedHost " , netplay_last_host ) ;
section = " Behavior " ;
inbool ( " PauseEmulationWhenFocusLost " , pause_emulation_on_switch ) ;
inint ( " DefaultESCKeyBehavior " , default_esc_behavior ) ;
inbool ( " PreventScreensaver " , prevent_screensaver ) ;
inbool ( " UseModalDialogs " , modal_dialogs ) ;
inint ( " RewindBufferSize " , rewind_buffer_size ) ;
inint ( " RewindGranularity " , rewind_granularity ) ;
inint ( " CurrentSaveSlot " , current_save_slot ) ;
section = " Emulation " ;
inbool ( " EmulateTransparency " , Settings . Transparency ) ;
inbool ( " DisplayTime " , Settings . DisplayTime ) ;
inbool ( " DisplayFrameRate " , Settings . DisplayFrameRate ) ;
inbool ( " DisplayPressedKeys " , Settings . DisplayPressedKeys ) ;
inint ( " SpeedControlMethod " , Settings . SkipFrames ) ;
inint ( " SaveSRAMEveryNSeconds " , Settings . AutoSaveDelay ) ;
inbool ( " BlockInvalidVRAMAccess " , Settings . BlockInvalidVRAMAccessMaster ) ;
inbool ( " AllowDPadContradictions " , Settings . UpAndDown ) ;
section = " Hacks " ;
inint ( " SuperFXClockMultiplier " , Settings . SuperFXClockMultiplier ) ;
inint ( " SoundInterpolationMethod " , Settings . InterpolationMethod ) ;
2018-11-02 02:44:06 +01:00
2018-12-02 02:58:13 +01:00
bool RemoveSpriteLimit = false ;
2020-06-21 22:25:54 +02:00
inbool ( " RemoveSpriteLimit " , RemoveSpriteLimit ) ;
2018-11-17 19:19:16 +01:00
bool OverclockCPU = false ;
2020-06-21 22:25:54 +02:00
inbool ( " OverclockCPU " , OverclockCPU ) ;
inbool ( " EchoBufferHack " , Settings . SeparateEchoBuffer ) ;
2010-09-25 17:46:12 +02:00
2020-06-21 22:25:54 +02:00
section = " Input " ;
2018-11-08 21:59:24 +01:00
for ( int i = 0 ; i < 2 ; i + + )
{
2020-06-21 22:25:54 +02:00
std : : string name = " ControllerPort " + std : : to_string ( i ) ;
std : : string value ;
instr ( name , value ) ;
if ( value . find ( " joypad " ) ! = std : : string : : npos )
S9xSetController ( i , CTL_JOYPAD , i , 0 , 0 , 0 ) ;
else if ( value . find ( " multitap " ) ! = std : : string : : npos )
S9xSetController ( i , CTL_MP5 , i , i + 1 , i + 2 , i + 3 ) ;
else if ( value . find ( " superscope " ) ! = std : : string : : npos )
S9xSetController ( i , CTL_SUPERSCOPE , 0 , 0 , 0 , 0 ) ;
else if ( value . find ( " mouse " ) ! = std : : string : : npos )
S9xSetController ( i , CTL_MOUSE , i , 0 , 0 , 0 ) ;
else if ( value . find ( " none " ) ! = std : : string : : npos )
S9xSetController ( i , CTL_NONE , 0 , 0 , 0 , 0 ) ;
2018-11-08 21:59:24 +01:00
}
2020-06-21 22:25:54 +02:00
inint ( " JoystickThreshold " , joystick_threshold ) ;
2010-09-25 17:46:12 +02:00
2018-12-29 01:36:23 +01:00
std : : string buffer ;
2018-11-02 02:44:06 +01:00
for ( int i = 0 ; i < NUM_JOYPADS ; i + + )
2010-09-25 17:46:12 +02:00
{
2020-06-20 17:44:11 +02:00
auto & joypad = pad [ i ] ;
2010-09-25 17:46:12 +02:00
2020-06-21 22:25:54 +02:00
section = " Joypad " + std : : to_string ( i ) ;
2018-11-02 02:44:06 +01:00
for ( int j = 0 ; j < NUM_JOYPAD_LINKS ; j + + )
2010-09-25 17:46:12 +02:00
{
2020-06-21 22:25:54 +02:00
instr ( b_links [ j ] . snes9x_name , buffer ) ;
joypad . data [ j ] = Binding ( buffer . c_str ( ) ) ;
2010-09-25 17:46:12 +02:00
}
}
2020-06-21 22:25:54 +02:00
section = " Shortcuts " ;
2018-11-02 02:44:06 +01:00
for ( int i = NUM_JOYPAD_LINKS ; b_links [ i ] . snes9x_name ; i + + )
{
2020-06-21 22:25:54 +02:00
instr ( b_links [ i ] . snes9x_name , buffer ) ;
shortcut [ i - NUM_JOYPAD_LINKS ] = Binding ( buffer . c_str ( ) ) ;
2018-11-02 02:44:06 +01:00
}
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
/* Validation */
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
if ( RemoveSpriteLimit )
Settings . MaxSpriteTilesPerLine = 128 ;
else
Settings . MaxSpriteTilesPerLine = 34 ;
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
if ( OverclockCPU )
2010-09-25 17:46:12 +02:00
{
2018-11-02 02:44:06 +01:00
Settings . OneClockCycle = 4 ;
Settings . OneSlowClockCycle = 5 ;
Settings . TwoClockCycles = 6 ;
2010-09-25 17:46:12 +02:00
}
2010-09-26 11:19:15 +02:00
else
{
2018-11-02 02:44:06 +01:00
Settings . OneClockCycle = 6 ;
Settings . OneSlowClockCycle = 8 ;
Settings . TwoClockCycles = 12 ;
2010-09-25 17:46:12 +02:00
}
2019-04-13 22:54:41 +02:00
# ifndef ALLOW_CPU_OVERCLOCK
2020-06-21 22:25:54 +02:00
Settings . OneClockCycle = 6 ;
Settings . OneSlowClockCycle = 8 ;
Settings . TwoClockCycles = 12 ;
Settings . MaxSpriteTilesPerLine = 34 ;
Settings . SeparateEchoBuffer = false ;
Settings . InterpolationMethod = 2 ;
Settings . BlockInvalidVRAMAccessMaster = true ;
2019-04-13 22:54:41 +02:00
# endif
2018-11-02 02:44:06 +01:00
if ( default_esc_behavior ! = ESC_TOGGLE_MENUBAR )
fullscreen = false ;
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
# ifdef USE_HQ2X
if ( scale_method > = NUM_FILTERS )
scale_method = 0 ;
# else
if ( scale_method > = NUM_FILTERS - 3 )
scale_method = 0 ;
# endif /* USE_HQ2X */
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
# ifdef USE_XBRZ
if ( scale_method > = NUM_FILTERS )
scale_method = 0 ;
# else
if ( scale_method > = NUM_FILTERS - 3 )
scale_method = 0 ;
# endif /* USE_XBRZ */
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
if ( pbo_format ! = 32 )
pbo_format = 16 ;
2010-09-25 17:46:12 +02:00
2018-11-02 02:44:06 +01:00
if ( Settings . SkipFrames = = THROTTLE_SOUND_SYNC )
2018-12-28 23:32:32 +01:00
Settings . SoundSync = true ;
2018-11-02 02:44:06 +01:00
else
2018-12-28 23:32:32 +01:00
Settings . SoundSync = false ;
2010-09-25 17:46:12 +02:00
2020-06-21 22:25:54 +02:00
hires_effect = CLAMP ( hires_effect , 0 , 2 ) ;
Settings . DynamicRateLimit = CLAMP ( Settings . DynamicRateLimit , 1 , 1000 ) ;
Settings . SuperFXClockMultiplier = CLAMP ( Settings . SuperFXClockMultiplier , 50 , 400 ) ;
ntsc_scanline_intensity = MIN ( ntsc_scanline_intensity , 4 ) ;
scanline_filter_intensity = MIN ( scanline_filter_intensity , 3 ) ;
2010-10-22 04:18:56 +02:00
2010-09-25 17:46:12 +02:00
return 0 ;
}
2019-03-21 23:54:27 +01:00
void Snes9xConfig : : rebind_keys ( )
2010-09-25 17:46:12 +02:00
{
s9xcommand_t cmd ;
2019-03-21 23:54:27 +01:00
std : : string string ;
2010-09-25 17:46:12 +02:00
2019-03-21 23:54:27 +01:00
S9xUnmapAllControls ( ) ;
2010-09-25 17:46:12 +02:00
2019-03-21 23:54:27 +01:00
for ( int joypad_i = 0 ; joypad_i < NUM_JOYPADS ; joypad_i + + )
2010-09-25 17:46:12 +02:00
{
2020-06-20 17:44:11 +02:00
auto & bin = pad [ joypad_i ] . data ;
2010-09-25 17:46:12 +02:00
for ( int button_i = 0 ; button_i < NUM_JOYPAD_LINKS ; button_i + + )
{
2019-03-21 23:54:27 +01:00
int dupe ;
for ( dupe = button_i + 1 ; dupe < NUM_JOYPAD_LINKS ; dupe + + )
{
2020-06-20 17:44:11 +02:00
if ( bin [ button_i ] = = bin [ dupe ] & & bin [ button_i ] . hex ( ) ! = 0 )
2019-03-21 23:54:27 +01:00
break ;
}
if ( dupe < NUM_JOYPAD_LINKS | | bin [ button_i ] . hex ( ) = = 0 )
continue ;
2019-03-22 17:59:50 +01:00
string = " Joypad " + std : : to_string ( ( joypad_i % 5 ) + 1 ) + " " ;
2019-03-21 23:54:27 +01:00
string + = b_links [ button_i ] . snes9x_name ;
bool ismulti = false ;
for ( dupe = button_i - 1 ; dupe > 0 ; dupe - - )
{
2020-06-20 17:44:11 +02:00
if ( bin [ button_i ] = = bin [ dupe ] )
2019-03-21 23:54:27 +01:00
{
ismulti = true ;
string + = " ,Joypad " + std : : to_string ( ( joypad_i % 5 ) + 1 ) + " " ;
string + = b_links [ dupe ] . snes9x_name ;
}
}
if ( ismulti )
string = std : : string ( " { " ) + string + " } " ;
cmd = S9xGetPortCommandT ( string . c_str ( ) ) ;
S9xMapButton ( bin [ button_i ] . base_hex ( ) , cmd , false ) ;
2010-09-25 17:46:12 +02:00
}
}
for ( int i = NUM_JOYPAD_LINKS ; b_links [ i ] . snes9x_name ; i + + )
{
2019-03-21 23:54:27 +01:00
cmd = S9xGetPortCommandT ( b_links [ i ] . snes9x_name ) ;
S9xMapButton ( shortcut [ i - NUM_JOYPAD_LINKS ] . base_hex ( ) ,
cmd ,
false ) ;
2010-09-25 17:46:12 +02:00
}
2019-03-21 23:54:27 +01:00
cmd = S9xGetPortCommandT ( " Pointer Mouse1+Superscope+Justifier1 " ) ;
S9xMapPointer ( BINDING_MOUSE_POINTER , cmd , true ) ;
2010-09-25 17:46:12 +02:00
2019-03-21 23:54:27 +01:00
cmd = S9xGetPortCommandT ( " {Mouse1 L,Superscope Fire,Justifier1 Trigger} " ) ;
S9xMapButton ( BINDING_MOUSE_BUTTON0 , cmd , false ) ;
2010-09-25 17:46:12 +02:00
2019-03-21 23:54:27 +01:00
cmd = S9xGetPortCommandT ( " {Justifier1 AimOffscreen Trigger,Superscope AimOffscreen} " ) ;
S9xMapButton ( BINDING_MOUSE_BUTTON1 , cmd , false ) ;
2010-09-25 17:46:12 +02:00
2019-03-21 23:54:27 +01:00
cmd = S9xGetPortCommandT ( " {Mouse1 R,Superscope Cursor,Justifier1 Start} " ) ;
S9xMapButton ( BINDING_MOUSE_BUTTON2 , cmd , false ) ;
2010-09-25 17:46:12 +02:00
}