diff --git a/SConstruct b/SConstruct index 2a31eb7..29d8740 100644 --- a/SConstruct +++ b/SConstruct @@ -9,7 +9,7 @@ env = Environment(ENV = environ, CPPFLAGS = ['-Wno-unused-value'], CXXFLAGS = flags, LINKFLAGS = flags, - CPPPATH = ['#lib/include', '#src/include'], + CPPPATH = ['#simpleini', '#lib/include', '#src/include'], LIBS = ['SDL2', 'SDL2_image', 'SDL2_ttf']) env.Program('laines', Glob('build/*/*.cpp') + Glob('build/*/*/*.cpp')) diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 0000000..f1c96c0 --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,155 @@ +#include +#include +#include "config.hpp" +#include "gui.hpp" + +namespace GUI { + +/* Settings */ +CSimpleIniA ini(true, false, false); + +/* Window settings */ +int last_window_size = 1; + +/* Controls settings */ +SDL_Scancode KEY_A [] = { SDL_SCANCODE_A, SDL_SCANCODE_ESCAPE }; +SDL_Scancode KEY_B [] = { SDL_SCANCODE_S, SDL_SCANCODE_ESCAPE }; +SDL_Scancode KEY_SELECT[] = { SDL_SCANCODE_SPACE, SDL_SCANCODE_ESCAPE }; +SDL_Scancode KEY_START [] = { SDL_SCANCODE_RETURN, SDL_SCANCODE_ESCAPE }; +SDL_Scancode KEY_UP [] = { SDL_SCANCODE_UP, SDL_SCANCODE_ESCAPE }; +SDL_Scancode KEY_DOWN [] = { SDL_SCANCODE_DOWN, SDL_SCANCODE_ESCAPE }; +SDL_Scancode KEY_LEFT [] = { SDL_SCANCODE_LEFT, SDL_SCANCODE_ESCAPE }; +SDL_Scancode KEY_RIGHT [] = { SDL_SCANCODE_RIGHT, SDL_SCANCODE_ESCAPE }; +int BTN_UP [] = { -1, -1 }; +int BTN_DOWN [] = { -1, -1 }; +int BTN_LEFT [] = { -1, -1 }; +int BTN_RIGHT [] = { -1, -1 }; +int BTN_A [] = { -1, -1 }; +int BTN_B [] = { -1, -1 }; +int BTN_SELECT[] = { -1, -1 }; +int BTN_START [] = { -1, -1 }; +bool useJoystick[] = { false, false }; + + + +/* Ensure config directory exists */ +const char* get_config_path(char * buf, int buflen) +{ + /* Bail on the complex stuff if we don't need it */ + if (!USE_CONFIG_DIR) + { + return CONFIG_FALLBACK; + } + + /* First, get the home directory */ + char homepath[CONFIG_PATH_MAX]; + char path[CONFIG_PATH_MAX]; + char * home = getenv("HOME"); + if (home == NULL) + return CONFIG_FALLBACK; + + snprintf(homepath, sizeof(homepath), "%s/.config", home); + + /* Then, .config as a folder */ + int res = mkdir(homepath, CONFIG_DIR_DEFAULT_MODE); + int err = errno; + + if (res == -1 && err != EEXIST) + return CONFIG_FALLBACK; + + snprintf(path, sizeof(path), "%s/%s", homepath, CONFIG_DIR_NAME); + + /* Finally, CONFIG_DIR_NAME as a sub-folder */ + res = mkdir(path, CONFIG_DIR_DEFAULT_MODE); + err = errno; + + if (res == -1 && err != EEXIST) + return CONFIG_FALLBACK; + + snprintf(buf, buflen, "%s/settings", path); + + return buf; +} + + +/* Load settings */ +void load_settings() +{ + /* Files */ + char path[CONFIG_PATH_MAX]; + ini.LoadFile(get_config_path(path, sizeof(path))); + + /* Screen settings */ + int screen_size = atoi(ini.GetValue("screen", "size", "1")); + if (screen_size < 1 || screen_size > 4) + screen_size = 1; + + set_size(screen_size); + + /* Control settings */ + for (int p = 0; p < 1; p++) + { + const char* section = p==0?"controls p1":"controls p2"; + + useJoystick[p] = (ini.GetValue(section, "usejoy", "no"))[0] == 'y'; + if (useJoystick[p]) + { + BTN_UP[p] = atoi(ini.GetValue(section, "UP", "-1")); + BTN_DOWN[p] = atoi(ini.GetValue(section, "DOWN", "-1")); + BTN_LEFT[p] = atoi(ini.GetValue(section, "LEFT", "-1")); + BTN_RIGHT[p] = atoi(ini.GetValue(section, "RIGHT", "-1")); + BTN_A[p] = atoi(ini.GetValue(section, "A", "-1")); + BTN_B[p] = atoi(ini.GetValue(section, "B", "-1")); + BTN_SELECT[p] = atoi(ini.GetValue(section, "SELECT", "-1")); + BTN_START[p] = atoi(ini.GetValue(section, "START", "-1")); + } else { + KEY_UP[p] = (SDL_Scancode)atoi(ini.GetValue(section, "UP", "82")); + KEY_DOWN[p] = (SDL_Scancode)atoi(ini.GetValue(section, "DOWN", "81")); + KEY_LEFT[p] = (SDL_Scancode)atoi(ini.GetValue(section, "LEFT", "80")); + KEY_RIGHT[p] = (SDL_Scancode)atoi(ini.GetValue(section, "RIGHT", "79")); + KEY_A[p] = (SDL_Scancode)atoi(ini.GetValue(section, "A", "4")); + KEY_B[p] = (SDL_Scancode)atoi(ini.GetValue(section, "B", "22")); + KEY_SELECT[p] = (SDL_Scancode)atoi(ini.GetValue(section, "SELECT", "44")); + KEY_START[p] = (SDL_Scancode)atoi(ini.GetValue(section, "START", "40")); + } + } +} + + +/* Save settings */ +void save_settings() +{ + /* Screen settings */ + char buf[2] = {0}; + sprintf(buf, "%d", last_window_size); + ini.SetValue("screen", "size", buf); + + /* Control settings */ + for (int p = 0; p < 1; p++) + { + const char* section = p==0?"controls p1":"controls p2"; + + sprintf(buf, "%d", useJoystick[p]?BTN_UP[p]:KEY_UP[p]); + ini.SetValue("section", "UP", buf); + sprintf(buf, "%d", useJoystick[p]?BTN_DOWN[p]:KEY_DOWN[p]); + ini.SetValue("section", "DOWN", buf); + sprintf(buf, "%d", useJoystick[p]?BTN_LEFT[p]:KEY_LEFT[p]); + ini.SetValue("section", "LEFT", buf); + sprintf(buf, "%d", useJoystick[p]?BTN_RIGHT[p]:KEY_RIGHT[p]); + ini.SetValue("section", "RIGHT", buf); + sprintf(buf, "%d", useJoystick[p]?BTN_A[p]:KEY_A[p]); + ini.SetValue("section", "A", buf); + sprintf(buf, "%d", useJoystick[p]?BTN_B[p]:KEY_B[p]); + ini.SetValue("section", "B", buf); + sprintf(buf, "%d", useJoystick[p]?BTN_SELECT[p]:KEY_SELECT[p]); + ini.SetValue("section", "SELECT", buf); + sprintf(buf, "%d", useJoystick[p]?BTN_START[p]:KEY_START[p]); + ini.SetValue("section", "START", buf); + ini.SetValue("section", "usejoy", useJoystick[p]?"yes":"no"); + } + + char path[CONFIG_PATH_MAX]; + ini.SaveFile(get_config_path(path, sizeof(path))); +} + +} diff --git a/src/gui.cpp b/src/gui.cpp index 3cc0954..e4890e0 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -7,10 +7,10 @@ #include "cpu.hpp" #include "menu.hpp" #include "gui.hpp" +#include "config.hpp" namespace GUI { - // Screen size: const unsigned WIDTH = 256; const unsigned HEIGHT = 240; @@ -36,28 +36,10 @@ FileMenu* fileMenu; bool pause = true; -// Controls settings: -SDL_Scancode KEY_A [] = { SDL_SCANCODE_A, SDL_SCANCODE_ESCAPE }; -SDL_Scancode KEY_B [] = { SDL_SCANCODE_S, SDL_SCANCODE_ESCAPE }; -SDL_Scancode KEY_SELECT[] = { SDL_SCANCODE_SPACE, SDL_SCANCODE_ESCAPE }; -SDL_Scancode KEY_START [] = { SDL_SCANCODE_RETURN, SDL_SCANCODE_ESCAPE }; -SDL_Scancode KEY_UP [] = { SDL_SCANCODE_UP, SDL_SCANCODE_ESCAPE }; -SDL_Scancode KEY_DOWN [] = { SDL_SCANCODE_DOWN, SDL_SCANCODE_ESCAPE }; -SDL_Scancode KEY_LEFT [] = { SDL_SCANCODE_LEFT, SDL_SCANCODE_ESCAPE }; -SDL_Scancode KEY_RIGHT [] = { SDL_SCANCODE_RIGHT, SDL_SCANCODE_ESCAPE }; -int BTN_UP [] = { -1, -1 }; -int BTN_DOWN [] = { -1, -1 }; -int BTN_LEFT [] = { -1, -1 }; -int BTN_RIGHT [] = { -1, -1 }; -int BTN_A [] = { -1, -1 }; -int BTN_B [] = { -1, -1 }; -int BTN_SELECT[] = { -1, -1 }; -int BTN_START [] = { -1, -1 }; -bool useJoystick[] = { false, false }; - /* Set the window size multiplier */ void set_size(int mul) { + last_window_size = mul; SDL_SetWindowSize(window, WIDTH * mul, HEIGHT * mul); SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); } @@ -80,7 +62,7 @@ void init() // Initialize graphics structures: window = SDL_CreateWindow ("LaiNES", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - WIDTH, HEIGHT, 0); + WIDTH * last_window_size, HEIGHT * last_window_size, 0); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); @@ -110,12 +92,14 @@ void init() settingsMenu->add(new Entry("Video", []{ menu = videoMenu; })); settingsMenu->add(new Entry("Controller 1", []{ menu = useJoystick[0] ? joystickMenu[0] : keyboardMenu[0]; })); settingsMenu->add(new Entry("Controller 2", []{ menu = useJoystick[1] ? joystickMenu[1] : keyboardMenu[1]; })); + settingsMenu->add(new Entry("Save Settings", []{ save_settings(); menu = mainMenu; })); videoMenu = new Menu; videoMenu->add(new Entry("<", []{ menu = settingsMenu; })); videoMenu->add(new Entry("Size 1x", []{ set_size(1); })); videoMenu->add(new Entry("Size 2x", []{ set_size(2); })); videoMenu->add(new Entry("Size 3x", []{ set_size(3); })); + videoMenu->add(new Entry("Size 4x", []{ set_size(4); })); for (int i = 0; i < 2; i++) { diff --git a/src/include/config.hpp b/src/include/config.hpp new file mode 100644 index 0000000..03344df --- /dev/null +++ b/src/include/config.hpp @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include + +#define CONFIG_DIR_DEFAULT_MODE S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH +#define USE_CONFIG_DIR true +#define CONFIG_DIR_NAME "LaiNES" +#define CONFIG_FALLBACK ".laines-settings" +/* PATH_MAX is a portability nightmare. */ +#define CONFIG_PATH_MAX 1024 + +namespace GUI { + +/* Loading and saving */ +void load_settings(); +void save_settings(); +const char* get_config_path(char * buf, int buflen); + +extern int last_window_size; +extern SDL_Scancode KEY_A []; +extern SDL_Scancode KEY_B []; +extern SDL_Scancode KEY_SELECT[]; +extern SDL_Scancode KEY_START []; +extern SDL_Scancode KEY_UP []; +extern SDL_Scancode KEY_DOWN []; +extern SDL_Scancode KEY_LEFT []; +extern SDL_Scancode KEY_RIGHT []; +extern int BTN_UP []; +extern int BTN_DOWN []; +extern int BTN_LEFT []; +extern int BTN_RIGHT []; +extern int BTN_A []; +extern int BTN_B []; +extern int BTN_SELECT[]; +extern int BTN_START []; +extern bool useJoystick[]; + +} diff --git a/src/include/gui.hpp b/src/include/gui.hpp index e9afbed..6926652 100644 --- a/src/include/gui.hpp +++ b/src/include/gui.hpp @@ -23,6 +23,6 @@ void render_texture(SDL_Texture* texture, int x, int y); u8 get_joypad_state(int n); void new_frame(u32* pixels); void new_samples(const blip_sample_t* samples, size_t count); - +void set_size(int mul); } diff --git a/src/main.cpp b/src/main.cpp index 4e0aee0..787b006 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,9 @@ #include "gui.hpp" - +#include "config.hpp" int main(int argc, char *argv[]) { + GUI::load_settings(); GUI::init(); GUI::run();