diff --git a/bsnes/nall/platform.hpp b/bsnes/nall/platform.hpp index c0bbc1e6..6855bdd3 100755 --- a/bsnes/nall/platform.hpp +++ b/bsnes/nall/platform.hpp @@ -78,5 +78,57 @@ #define alwaysinline inline #endif +//========================= +//file system functionality +//========================= + +#if defined(_WIN32) + inline char* realpath(const char *filename, char *resolvedname) { + wchar_t fn[_MAX_PATH] = L""; + _wfullpath(fn, nall::utf16_t(filename), _MAX_PATH); + strcpy(resolvedname, nall::utf8_t(fn)); + return resolvedname; + } + + inline char* userpath(char *path) { + wchar_t fp[_MAX_PATH] = L""; + SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp); + strcpy(path, nall::utf8_t(fp)); + return path; + } + + inline char* getcwd(char *path) { + wchar_t fp[_MAX_PATH] = L""; + _wgetcwd(fp, _MAX_PATH); + strcpy(path, nall::utf8_t(fp)); + return path; + } + + inline void initialize_arguments(int &argc, char **&argv) { + wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc); + argv = new char*[argc]; + for(unsigned i = 0; i < argc; i++) { + argv[i] = new char[_MAX_PATH]; + strcpy(argv[i], nall::utf8_t(wargv[i])); + } + } +#else + //realpath() already exists + + inline char* userpath(char *path) { + *path = 0; + struct passwd *userinfo = getpwuid(getuid()); + if(userinfo) strcpy(path, userinfo->pw_dir); + return path; + } + + inline char *getcwd(char *path) { + return getcwd(path, PATH_MAX); + } + + inline void initialize_arguments(int &argc, char **&argv) { + } +#endif + #endif diff --git a/bsnes/phoenix/gtk/gtk.cpp b/bsnes/phoenix/gtk/gtk.cpp index 2d5f423a..109cb6ff 100755 --- a/bsnes/phoenix/gtk/gtk.cpp +++ b/bsnes/phoenix/gtk/gtk.cpp @@ -181,7 +181,7 @@ OS::OS() { gtk_rc_parse_string( "style \"phoenix-gtk\"\n" "{\n" - " GtkComboBox::appears-as-list = 0\n" + " GtkComboBox::appears-as-list = 1\n" " GtkTreeView::vertical-separator = 0\n" "}\n" "class \"GtkComboBox\" style \"phoenix-gtk\"\n" diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 1bbef1e7..19137623 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "068.20"; + static const char Version[] = "068.21"; static const unsigned SerializerVersion = 13; } } diff --git a/bsnes/ui-phoenix/base.hpp b/bsnes/ui-phoenix/base.hpp index 8a2647b1..76e69c30 100755 --- a/bsnes/ui-phoenix/base.hpp +++ b/bsnes/ui-phoenix/base.hpp @@ -14,13 +14,18 @@ using namespace ruby; using namespace phoenix; #include "interface.hpp" +#include "config.hpp" #include "general/general.hpp" #include "settings/settings.hpp" #include "utility/utility.hpp" #include "cartridge/cartridge.hpp" struct Application { - Font font; + array windows; + Font proportionalFont; + Font proportionalFontBold; + Font monospaceFont; + bool quit; void main(int argc, char **argv); }; @@ -30,10 +35,16 @@ extern Application application; struct Style { enum : unsigned { #if defined(PHOENIX_WINDOWS) + ComboBoxHeight = 22, + LabelHeight = 15, SliderHeight = 25, #elif defined(PHOENIX_GTK) + ComboBoxHeight = 22, + LabelHeight = 15, SliderHeight = 22, #elif defined(PHOENIX_QT) + ComboBoxHeight = 22, + LabelHeight = 15, SliderHeight = 22, #endif }; diff --git a/bsnes/ui-phoenix/config.cpp b/bsnes/ui-phoenix/config.cpp new file mode 100755 index 00000000..bc375a02 --- /dev/null +++ b/bsnes/ui-phoenix/config.cpp @@ -0,0 +1,24 @@ +Configuration config; + +void Configuration::load() { + configuration::load(string(path.user, "bsnes-phoenix.cfg")); +} + +void Configuration::save() { + configuration::save(string(path.user, "bsnes-phoenix.cfg")); +} + +void Configuration::create() { + attach(video.driver = "", "video.driver"); + attach(video.synchronize = false, "video.synchronize"); + attach(video.contrast = 100, "video.contrast"); + attach(video.brightness = 100, "video.brightness"); + attach(video.gamma = 100, "video.gamma"); + attach(video.useGammaRamp = true, "video.useGammaRamp"); + + attach(audio.driver = "", "audio.driver"); + attach(audio.synchronize = true, "audio.synchronize"); + attach(audio.mute = false, "audio.mute"); + + attach(input.driver = "", "input.driver"); +} diff --git a/bsnes/ui-phoenix/config.hpp b/bsnes/ui-phoenix/config.hpp new file mode 100755 index 00000000..2f74cdeb --- /dev/null +++ b/bsnes/ui-phoenix/config.hpp @@ -0,0 +1,31 @@ +struct Configuration : public configuration { + struct Path { + string base; + string user; + } path; + + struct Video { + string driver; + bool synchronize; + unsigned contrast; + unsigned brightness; + unsigned gamma; + bool useGammaRamp; + } video; + + struct Audio { + string driver; + bool synchronize; + bool mute; + } audio; + + struct Input { + string driver; + } input; + + void load(); + void save(); + void create(); +}; + +extern Configuration config; diff --git a/bsnes/ui-phoenix/general/main-window.cpp b/bsnes/ui-phoenix/general/main-window.cpp index 6fdb492d..a2d49958 100755 --- a/bsnes/ui-phoenix/general/main-window.cpp +++ b/bsnes/ui-phoenix/general/main-window.cpp @@ -1,10 +1,10 @@ MainWindow mainWindow; void MainWindow::create() { - statusFont.create("Sans", 8, Font::Style::Bold); + application.windows.append(this); Window::create(120, 120, 595, 448, string(SNES::Info::Name, " v", SNES::Info::Version)); - setDefaultFont(application.font); - setFont(statusFont); + setDefaultFont(application.proportionalFont); + setFont(application.proportionalFontBold); setBackgroundColor(0, 0, 0); system.create(*this, "System"); @@ -13,11 +13,20 @@ void MainWindow::create() { systemQuit.create(system, "Quit"); setMenuVisible(true); settings.create(*this, "Settings"); + settingsSynchronizeVideo.create(settings, "Synchronize Video"); + settingsSynchronizeVideo.setChecked(config.video.synchronize); + settingsSynchronizeAudio.create(settings, "Synchronize Audio"); + settingsSynchronizeAudio.setChecked(config.audio.synchronize); + settingsMuteAudio.create(settings, "Mute Audio"); + settingsMuteAudio.setChecked(config.audio.mute); + settingsSeparator.create(settings); settingsVideo.create(settings, "Video Settings ..."); + settingsAdvanced.create(settings, "Advanced Settings ..."); tools.create(*this, "Tools"); help.create(*this, "Help"); viewport.create(*this, 0, 0, 595, 448); + utility.setStatus(""); setStatusVisible(true); systemLoadCartridge.onTick = []() { @@ -28,10 +37,28 @@ void MainWindow::create() { application.quit = true; }; + settingsSynchronizeVideo.onTick = []() { + config.video.synchronize = mainWindow.settingsSynchronizeVideo.checked(); + video.set(Video::Synchronize, config.video.synchronize); + }; + + settingsSynchronizeAudio.onTick = []() { + config.audio.synchronize = mainWindow.settingsSynchronizeAudio.checked(); + audio.set(Audio::Synchronize, config.audio.synchronize); + }; + + settingsMuteAudio.onTick = []() { + config.audio.mute = mainWindow.settingsMuteAudio.checked(); + }; + settingsVideo.onTick = []() { videoSettingsWindow.setVisible(); }; + settingsAdvanced.onTick = []() { + advancedSettingsWindow.setVisible(); + }; + onClose = []() { application.quit = true; return false; diff --git a/bsnes/ui-phoenix/general/main-window.hpp b/bsnes/ui-phoenix/general/main-window.hpp index daa72dab..8f3da0d7 100755 --- a/bsnes/ui-phoenix/general/main-window.hpp +++ b/bsnes/ui-phoenix/general/main-window.hpp @@ -1,11 +1,15 @@ struct MainWindow : Window { - Font statusFont; Menu system; MenuItem systemLoadCartridge; MenuSeparator systemSeparator; MenuItem systemQuit; Menu settings; + MenuCheckItem settingsSynchronizeVideo; + MenuCheckItem settingsSynchronizeAudio; + MenuCheckItem settingsMuteAudio; + MenuSeparator settingsSeparator; MenuItem settingsVideo; + MenuItem settingsAdvanced; Menu tools; Menu help; Viewport viewport; diff --git a/bsnes/ui-phoenix/interface.cpp b/bsnes/ui-phoenix/interface.cpp index faec8ab5..c6951482 100755 --- a/bsnes/ui-phoenix/interface.cpp +++ b/bsnes/ui-phoenix/interface.cpp @@ -9,19 +9,19 @@ const uint8_t Palette::gammaRamp[32] = { }; uint8_t Palette::contrastAdjust(uint8_t input) { - signed contrast = Palette::contrast - 100; + signed contrast = config.video.contrast - 100; signed result = input - contrast + (2 * contrast * input + 127) / 255; return max(0, min(255, result)); } uint8_t Palette::brightnessAdjust(uint8_t input) { - signed brightness = Palette::brightness - 100; + signed brightness = config.video.brightness - 100; signed result = input + brightness; return max(0, min(255, result)); } uint8_t Palette::gammaAdjust(uint8_t input) { - signed result = (signed)(pow(((double)input / 255.0), (double)gamma / 100.0) * 255.0 + 0.5); + signed result = (signed)(pow(((double)input / 255.0), (double)config.video.gamma / 100.0) * 255.0 + 0.5); return max(0, min(255, result)); } @@ -35,25 +35,25 @@ void Palette::update() { g = (g << 3) | (g >> 2); b = (b << 3) | (b >> 2); - if(useGammaRamp) { + if(config.video.useGammaRamp) { r = gammaRamp[r >> 3]; g = gammaRamp[g >> 3]; b = gammaRamp[b >> 3]; } - if(contrast != 100) { + if(config.video.contrast != 100) { r = contrastAdjust(r); g = contrastAdjust(g); b = contrastAdjust(b); } - if(brightness != 100) { + if(config.video.brightness != 100) { r = brightnessAdjust(r); g = brightnessAdjust(g); b = brightnessAdjust(b); } - if(gamma != 100) { + if(config.video.gamma != 100) { r = gammaAdjust(r); g = gammaAdjust(g); b = gammaAdjust(b); @@ -63,14 +63,6 @@ void Palette::update() { } } -Palette::Palette() { - contrast = 100; - brightness = 100; - gamma = 100; - useGammaRamp = true; - update(); -} - void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned height) { bool interlace = (height >= 240); bool overscan = (height == 239 || height == 478); @@ -95,13 +87,14 @@ void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned hei time(¤t); if(current != previous) { - mainWindow.setStatusText(string("FPS: ", frameCounter)); + utility.setStatus(string("FPS: ", frameCounter)); frameCounter = 0; previous = current; } } void Interface::audio_sample(uint16_t left, uint16_t right) { + if(config.audio.mute) left = right = 0; audio.sample(left, right); } diff --git a/bsnes/ui-phoenix/interface.hpp b/bsnes/ui-phoenix/interface.hpp index f12eca1a..e1d54ea1 100755 --- a/bsnes/ui-phoenix/interface.hpp +++ b/bsnes/ui-phoenix/interface.hpp @@ -1,15 +1,10 @@ struct Palette { static const uint8_t gammaRamp[32]; uint32_t color[32768]; - unsigned contrast; - unsigned brightness; - unsigned gamma; - bool useGammaRamp; uint8_t contrastAdjust(uint8_t); uint8_t brightnessAdjust(uint8_t); uint8_t gammaAdjust(uint8_t); void update(); - Palette(); }; struct Interface : public SNES::Interface { diff --git a/bsnes/ui-phoenix/main.cpp b/bsnes/ui-phoenix/main.cpp index a8b45e1c..1adf9717 100755 --- a/bsnes/ui-phoenix/main.cpp +++ b/bsnes/ui-phoenix/main.cpp @@ -1,32 +1,44 @@ #include "base.hpp" #include "interface.cpp" +#include "config.cpp" Application application; -#if defined(PLATFORM_WIN) -static string VideoDriver = "Direct3D"; -static string AudioDriver = "DirectSound"; -static string InputDriver = "RawInput"; -#elif defined(PLATFORM_X) -static string VideoDriver = "OpenGL"; -static string AudioDriver = "ALSA"; -static string InputDriver = "SDL"; -#endif - void Application::main(int argc, char **argv) { + initialize_arguments(argc, argv); + config.create(); + + char temp[PATH_MAX]; + config.path.base = realpath(argv[0], temp); + config.path.base.transform("\\", "/"); + config.path.base = dir(config.path.base); + config.path.user = userpath(temp); + config.path.user.transform("\\", "/"); + if(strend(config.path.user, "/") == false) config.path.user.append("/"); + config.path.user.append(".bsnes/"); + config.load(); + config.save(); + #if defined(PHOENIX_WINDOWS) - font.create("Tahoma", 8); + proportionalFont.create("Tahoma", 8); + proportionalFontBold.create("Tahoma", 8, Font::Style::Bold); + monospaceFont.create("Courier New", 8); #else - font.create("Sans", 8); + proportionalFont.create("Sans", 8); + proportionalFontBold.create("Tahoma", 8, Font::Style::Bold); + monospaceFont.create("Liberation Mono", 8); #endif + palette.update(); mainWindow.create(); videoSettingsWindow.create(); + advancedSettingsWindow.create(); mainWindow.setVisible(); while(os.pending()) os.run(); - video.driver(VideoDriver); + if(config.video.driver == "") config.video.driver = video.default_driver(); + video.driver(config.video.driver); video.set(Video::Handle, mainWindow.viewport.handle()); - video.set(Video::Synchronize, false); + video.set(Video::Synchronize, config.video.synchronize); video.set(Video::Filter, (unsigned)Video::FilterLinear); if(video.init() == false) { MessageWindow::critical(mainWindow, "Failed to initialize video."); @@ -34,9 +46,10 @@ void Application::main(int argc, char **argv) { video.init(); } - audio.driver(AudioDriver); + if(config.audio.driver == "") config.audio.driver = audio.default_driver(); + audio.driver(config.audio.driver); audio.set(Audio::Handle, mainWindow.viewport.handle()); - audio.set(Audio::Synchronize, false); + audio.set(Audio::Synchronize, config.audio.synchronize); audio.set(Audio::Frequency, (unsigned)32000); if(audio.init() == false) { MessageWindow::critical(mainWindow, "Failed to initialize audio."); @@ -44,7 +57,8 @@ void Application::main(int argc, char **argv) { audio.init(); } - input.driver(InputDriver); + if(config.input.driver == "") config.input.driver = video.default_driver(); + input.driver(config.input.driver); input.set(Input::Handle, mainWindow.viewport.handle()); if(input.init() == false) { MessageWindow::critical(mainWindow, "Failed to initialize input."); @@ -69,9 +83,10 @@ void Application::main(int argc, char **argv) { } cartridge.unload(); - mainWindow.setVisible(false); + foreach(window, windows) window->setVisible(false); while(os.pending()) os.run(); SNES::system.term(); + config.save(); video.term(); audio.term(); diff --git a/bsnes/ui-phoenix/settings/advanced.cpp b/bsnes/ui-phoenix/settings/advanced.cpp new file mode 100755 index 00000000..0f2c7d93 --- /dev/null +++ b/bsnes/ui-phoenix/settings/advanced.cpp @@ -0,0 +1,64 @@ +AdvancedSettingsWindow advancedSettingsWindow; + +void AdvancedSettingsWindow::create() { + application.windows.append(this); + Window::create(0, 0, 256, 256, "Advanced Settings"); + setDefaultFont(application.proportionalFont); + + unsigned x = 5, y = 5; + + driverSelectionLabel.create(*this, x, y, 595, Style::LabelHeight, "Driver Selection :."); y += Style::LabelHeight + 5; + driverSelectionLabel.setFont(application.proportionalFontBold); + + videoDriverLabel.create(*this, x, y, 45, Style::ComboBoxHeight, "Video:"); + videoDriverBox.create (*this, x + 45, y, 150, Style::ComboBoxHeight); + audioDriverLabel.create(*this, x + 200, y, 45, Style::ComboBoxHeight, "Audio:"); + audioDriverBox.create (*this, x + 245, y, 150, Style::ComboBoxHeight); + inputDriverLabel.create(*this, x + 400, y, 45, Style::ComboBoxHeight, "Input:"); + inputDriverBox.create (*this, x + 445, y, 150, Style::ComboBoxHeight); y += Style::ComboBoxHeight; + + setGeometry(0, 0, 605, y + 5); + + lstring list; + + list.split(";", video.driver_list()); + for(unsigned i = 0; i < list.size(); i++) { + videoDriverBox.addItem(list[i]); + if(list[i] == config.video.driver) videoDriverBox.setSelection(i); + } + + list.split(";", audio.driver_list()); + for(unsigned i = 0; i < list.size(); i++) { + audioDriverBox.addItem(list[i]); + if(list[i] == config.audio.driver) audioDriverBox.setSelection(i); + } + + list.split(";", input.driver_list()); + for(unsigned i = 0; i < list.size(); i++) { + inputDriverBox.addItem(list[i]); + if(list[i] == config.input.driver) inputDriverBox.setSelection(i); + } + + videoDriverBox.onChange = []() { + lstring list; + list.split(";", video.driver_list()); + config.video.driver = list[advancedSettingsWindow.videoDriverBox.selection()]; + }; + + audioDriverBox.onChange = []() { + lstring list; + list.split(";", audio.driver_list()); + config.audio.driver = list[advancedSettingsWindow.audioDriverBox.selection()]; + }; + + inputDriverBox.onChange = []() { + lstring list; + list.split(";", input.driver_list()); + config.input.driver = list[advancedSettingsWindow.inputDriverBox.selection()]; + }; + + onClose = []() { + advancedSettingsWindow.setVisible(false); + return false; + }; +} diff --git a/bsnes/ui-phoenix/settings/advanced.hpp b/bsnes/ui-phoenix/settings/advanced.hpp new file mode 100755 index 00000000..18052f6e --- /dev/null +++ b/bsnes/ui-phoenix/settings/advanced.hpp @@ -0,0 +1,13 @@ +struct AdvancedSettingsWindow : Window { + Label driverSelectionLabel; + Label videoDriverLabel; + ComboBox videoDriverBox; + Label audioDriverLabel; + ComboBox audioDriverBox; + Label inputDriverLabel; + ComboBox inputDriverBox; + + void create(); +}; + +extern AdvancedSettingsWindow advancedSettingsWindow; diff --git a/bsnes/ui-phoenix/settings/settings.cpp b/bsnes/ui-phoenix/settings/settings.cpp index 81b4513d..b9eaee87 100755 --- a/bsnes/ui-phoenix/settings/settings.cpp +++ b/bsnes/ui-phoenix/settings/settings.cpp @@ -1,2 +1,3 @@ #include "../base.hpp" #include "video.cpp" +#include "advanced.cpp" diff --git a/bsnes/ui-phoenix/settings/settings.hpp b/bsnes/ui-phoenix/settings/settings.hpp index 1e7c33c5..456a376b 100755 --- a/bsnes/ui-phoenix/settings/settings.hpp +++ b/bsnes/ui-phoenix/settings/settings.hpp @@ -1 +1,2 @@ #include "video.hpp" +#include "advanced.hpp" diff --git a/bsnes/ui-phoenix/settings/video.cpp b/bsnes/ui-phoenix/settings/video.cpp index 97321f5c..896ba590 100755 --- a/bsnes/ui-phoenix/settings/video.cpp +++ b/bsnes/ui-phoenix/settings/video.cpp @@ -1,11 +1,15 @@ VideoSettingsWindow videoSettingsWindow; void VideoSettingsWindow::create() { + application.windows.append(this); Window::create(0, 0, 256, 256, "Video Settings"); - setDefaultFont(application.font); + setDefaultFont(application.proportionalFont); unsigned x = 5, y = 5; + colorAdjustmentLabel.create(*this, x, y, 430, Style::LabelHeight, "Color Adjustment :."); y += Style::LabelHeight + 5; + colorAdjustmentLabel.setFont(application.proportionalFontBold); + contrastLabel.create (*this, x, y, 80, Style::SliderHeight, "Contrast:"); contrastValue.create (*this, x + 80, y, 50, Style::SliderHeight, "100%"); contrastSlider.create (*this, x + 130, y, 300, Style::SliderHeight, 201); y += Style::SliderHeight; @@ -22,10 +26,10 @@ void VideoSettingsWindow::create() { setGeometry(0, 0, 440, y + 5); - contrastSlider.setPosition(100); - brightnessSlider.setPosition(100); - gammaSlider.setPosition(100); - gammaRampCheck.setChecked(); + contrastSlider.setPosition(config.video.contrast); + brightnessSlider.setPosition(config.video.brightness); + gammaSlider.setPosition(config.video.gamma); + gammaRampCheck.setChecked(config.video.useGammaRamp); contrastSlider.onChange = brightnessSlider.onChange = gammaSlider.onChange = gammaRampCheck.onTick = { &VideoSettingsWindow::adjust, this }; @@ -41,9 +45,9 @@ void VideoSettingsWindow::adjust() { brightnessValue.setText(string(brightnessSlider.position(), "%")); gammaValue.setText(string(gammaSlider.position(), "%")); - palette.contrast = contrastSlider.position(); - palette.brightness = brightnessSlider.position(); - palette.gamma = gammaSlider.position(); - palette.useGammaRamp = gammaRampCheck.checked(); + config.video.contrast = contrastSlider.position(); + config.video.brightness = brightnessSlider.position(); + config.video.gamma = gammaSlider.position(); + config.video.useGammaRamp = gammaRampCheck.checked(); palette.update(); } diff --git a/bsnes/ui-phoenix/settings/video.hpp b/bsnes/ui-phoenix/settings/video.hpp index 007894b5..8bb75bbf 100755 --- a/bsnes/ui-phoenix/settings/video.hpp +++ b/bsnes/ui-phoenix/settings/video.hpp @@ -1,4 +1,5 @@ struct VideoSettingsWindow : Window { + Label colorAdjustmentLabel; Label contrastLabel; Label contrastValue; HorizontalSlider contrastSlider; diff --git a/bsnes/ui-phoenix/utility/utility.cpp b/bsnes/ui-phoenix/utility/utility.cpp index e1e8faf7..b5700559 100755 --- a/bsnes/ui-phoenix/utility/utility.cpp +++ b/bsnes/ui-phoenix/utility/utility.cpp @@ -9,6 +9,11 @@ void Utility::setTitle(const char *text) { } } +void Utility::setStatus(const char *text) { + static char profile[] = { '[', SNES::Info::Profile[0], ']', ' ', 0 }; + mainWindow.setStatusText(string(profile, text)); +} + void Utility::loadCartridgeNormal() { string filename = os.fileOpen(mainWindow, "SNES cartridges\t*.sfc\nAll files\t*", "/media/sdb1/root/snes_roms"); if(filename != "") { diff --git a/bsnes/ui-phoenix/utility/utility.hpp b/bsnes/ui-phoenix/utility/utility.hpp index 9a25a7a1..dda6efd1 100755 --- a/bsnes/ui-phoenix/utility/utility.hpp +++ b/bsnes/ui-phoenix/utility/utility.hpp @@ -1,5 +1,6 @@ struct Utility { void setTitle(const char *text); + void setStatus(const char *text); void loadCartridgeNormal(); };