From 80ec3ea21f3bc5ced532d0328886659dd8c81e18 Mon Sep 17 00:00:00 2001 From: rdanbrook <1869094+rdanbrook@users.noreply.github.com> Date: Sun, 21 Mar 2021 16:15:21 -0400 Subject: [PATCH] Switch from GTK to FLTK --- .gitignore | 11 +- Makefile.am | 78 +- configure.ac | 10 +- source/common/input.cpp | 257 ---- source/common/input.h | 37 - source/{common => fltkui}/audio.cpp | 28 +- source/{common => fltkui}/audio.h | 0 source/{common => fltkui}/cheats.cpp | 76 +- source/{common => fltkui}/cheats.h | 0 source/{common => fltkui}/cli.cpp | 46 +- source/{common => fltkui}/cli.h | 0 source/{common => fltkui}/config.cpp | 38 +- source/{common => fltkui}/config.h | 9 +- source/fltkui/fltkui.cpp | 536 +++++++ source/fltkui/fltkui.h | 33 + source/fltkui/fltkui_archive.cpp | 125 ++ source/fltkui/fltkui_archive.h | 6 + source/fltkui/fltkui_config.cpp | 666 +++++++++ source/fltkui/fltkui_config.h | 31 + source/{common => fltkui}/font.h | 0 source/{common => fltkui}/homebrew.cpp | 0 source/{common => fltkui}/homebrew.h | 0 source/{common => fltkui}/ini.cpp | 0 source/{common => fltkui}/ini.h | 0 .../{common/sdlinput.cpp => fltkui/input.cpp} | 645 ++++++-- source/{common/sdlinput.h => fltkui/input.h} | 150 +- source/{common => fltkui}/nstcommon.cpp | 228 +-- source/{common => fltkui}/nstcommon.h | 8 +- source/{common => fltkui}/png.cpp | 0 source/{common => fltkui}/png.h | 0 source/{common => fltkui}/samples.cpp | 40 +- source/{common => fltkui}/samples.h | 0 source/{common => fltkui}/video.cpp | 288 ++-- source/{common => fltkui}/video.h | 8 - source/gtkui/gtkui.cpp | 696 --------- source/gtkui/gtkui.h | 23 - source/gtkui/gtkui_archive.cpp | 182 --- source/gtkui/gtkui_archive.h | 8 - source/gtkui/gtkui_callbacks.cpp | 266 ---- source/gtkui/gtkui_callbacks.h | 41 - source/gtkui/gtkui_cheats.cpp | 619 -------- source/gtkui/gtkui_cheats.h | 17 - source/gtkui/gtkui_config.cpp | 1292 ----------------- source/gtkui/gtkui_config.h | 18 - source/gtkui/gtkui_dialogs.cpp | 258 ---- source/gtkui/gtkui_dialogs.h | 18 - source/gtkui/gtkui_input.cpp | 388 ----- source/gtkui/gtkui_input.h | 99 -- 48 files changed, 2363 insertions(+), 4916 deletions(-) delete mode 100644 source/common/input.cpp delete mode 100644 source/common/input.h rename source/{common => fltkui}/audio.cpp (99%) rename source/{common => fltkui}/audio.h (100%) rename source/{common => fltkui}/cheats.cpp (97%) rename source/{common => fltkui}/cheats.h (100%) rename source/{common => fltkui}/cli.cpp (98%) rename source/{common => fltkui}/cli.h (100%) rename source/{common => fltkui}/config.cpp (98%) rename source/{common => fltkui}/config.h (98%) create mode 100644 source/fltkui/fltkui.cpp create mode 100644 source/fltkui/fltkui.h create mode 100644 source/fltkui/fltkui_archive.cpp create mode 100644 source/fltkui/fltkui_archive.h create mode 100644 source/fltkui/fltkui_config.cpp create mode 100644 source/fltkui/fltkui_config.h rename source/{common => fltkui}/font.h (100%) rename source/{common => fltkui}/homebrew.cpp (100%) rename source/{common => fltkui}/homebrew.h (100%) rename source/{common => fltkui}/ini.cpp (100%) rename source/{common => fltkui}/ini.h (100%) rename source/{common/sdlinput.cpp => fltkui/input.cpp} (51%) rename source/{common/sdlinput.h => fltkui/input.h} (50%) rename source/{common => fltkui}/nstcommon.cpp (97%) rename source/{common => fltkui}/nstcommon.h (92%) rename source/{common => fltkui}/png.cpp (100%) rename source/{common => fltkui}/png.h (100%) rename source/{common => fltkui}/samples.cpp (98%) rename source/{common => fltkui}/samples.h (100%) rename source/{common => fltkui}/video.cpp (81%) rename source/{common => fltkui}/video.h (86%) delete mode 100644 source/gtkui/gtkui.cpp delete mode 100644 source/gtkui/gtkui.h delete mode 100644 source/gtkui/gtkui_archive.cpp delete mode 100644 source/gtkui/gtkui_archive.h delete mode 100644 source/gtkui/gtkui_callbacks.cpp delete mode 100644 source/gtkui/gtkui_callbacks.h delete mode 100644 source/gtkui/gtkui_cheats.cpp delete mode 100644 source/gtkui/gtkui_cheats.h delete mode 100644 source/gtkui/gtkui_config.cpp delete mode 100644 source/gtkui/gtkui_config.h delete mode 100644 source/gtkui/gtkui_dialogs.cpp delete mode 100644 source/gtkui/gtkui_dialogs.h delete mode 100644 source/gtkui/gtkui_input.cpp delete mode 100644 source/gtkui/gtkui_input.h diff --git a/.gitignore b/.gitignore index 3399cec..53c27da 100644 --- a/.gitignore +++ b/.gitignore @@ -25,8 +25,6 @@ configure depcomp install-sh missing -source/common/.deps/ -source/common/.dirstamp source/core/.deps/ source/core/.dirstamp source/core/api/.deps/ @@ -37,10 +35,5 @@ source/core/input/.deps/ source/core/input/.dirstamp source/core/vssystem/.deps/ source/core/vssystem/.dirstamp -source/gtkui/.deps/ -source/sdl/.deps/ -source/sdl/.dirstamp -source/unix/.deps/ -source/unix/.dirstamp -source/unix/gtkui/.deps/ -source/unix/gtkui/.dirstamp +source/fltkui/.deps/ +source/fltkui/.dirstamp diff --git a/Makefile.am b/Makefile.am index fbdfa16..6d8f5e5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,23 +7,19 @@ EXTRA_DIST = doc nestopia_CPPFLAGS = \ -I$(top_srcdir)/source \ - -I$(top_srcdir)/source/common \ - -I$(top_srcdir)/source/gtkui \ - -I$(top_srcdir)/source/sdl \ + -I$(top_srcdir)/source/fltkui \ -DDATADIR=\"$(datadir)/nestopia\" \ -DDATAROOTDIR=\"$(datarootdir)\" \ -DNST_PRAGMA_ONCE \ $(ZLIB_CFLAGS) \ $(LIBARCHIVE_CFLAGS) \ $(SDL2_CFLAGS) \ - $(LIBEPOXY_CFLAGS) \ - $(GTK3_CFLAGS) + $(FLTK_CFLAGS) nestopia_LDADD = \ $(ZLIB_LIBS) \ $(LIBARCHIVE_LIBS) \ $(SDL2_LIBS) \ - $(LIBEPOXY_LIBS) \ - $(GTK3_LIBS) + $(FLTK_LIBS) ################ # Installation # @@ -695,47 +691,37 @@ nestopia_SOURCES = \ source/nes_ntsc/demo_impl.h nestopia_SOURCES += \ - source/common/nstcommon.cpp \ - source/common/nstcommon.h \ - source/common/cheats.cpp \ - source/common/cheats.h \ - source/common/homebrew.cpp \ - source/common/homebrew.h \ - source/common/cli.cpp \ - source/common/cli.h \ - source/common/config.cpp \ - source/common/config.h \ - source/common/video.cpp \ - source/common/video.h \ - source/common/input.cpp \ - source/common/input.h \ - source/common/samples.cpp \ - source/common/samples.h \ - source/common/font.h \ - source/common/ini.cpp \ - source/common/ini.h \ - source/common/png.cpp \ - source/common/png.h \ - source/common/audio.cpp \ - source/common/audio.h \ - source/common/sdlinput.cpp \ - source/common/sdlinput.h + source/fltkui/nstcommon.cpp \ + source/fltkui/nstcommon.h \ + source/fltkui/cheats.cpp \ + source/fltkui/cheats.h \ + source/fltkui/homebrew.cpp \ + source/fltkui/homebrew.h \ + source/fltkui/cli.cpp \ + source/fltkui/cli.h \ + source/fltkui/config.cpp \ + source/fltkui/config.h \ + source/fltkui/video.cpp \ + source/fltkui/video.h \ + source/fltkui/input.cpp \ + source/fltkui/input.h \ + source/fltkui/samples.cpp \ + source/fltkui/samples.h \ + source/fltkui/font.h \ + source/fltkui/ini.cpp \ + source/fltkui/ini.h \ + source/fltkui/png.cpp \ + source/fltkui/png.h \ + source/fltkui/audio.cpp \ + source/fltkui/audio.h nestopia_SOURCES += \ - source/gtkui/gtkui_config.h \ - source/gtkui/gtkui_archive.h \ - source/gtkui/gtkui_cheats.cpp \ - source/gtkui/gtkui_callbacks.h \ - source/gtkui/gtkui_callbacks.cpp \ - source/gtkui/gtkui_dialogs.cpp \ - source/gtkui/gtkui_cheats.h \ - source/gtkui/gtkui_dialogs.h \ - source/gtkui/gtkui_archive.cpp \ - source/gtkui/gtkui.cpp \ - source/gtkui/gtkui.h \ - source/gtkui/gtkui_input.cpp \ - source/gtkui/gtkui_input.h \ - source/gtkui/gtkui_config.cpp + source/fltkui/fltkui_config.h \ + source/fltkui/fltkui_archive.h \ + source/fltkui/fltkui_archive.cpp \ + source/fltkui/fltkui.cpp \ + source/fltkui/fltkui.h \ + source/fltkui/fltkui_config.cpp # install full HTML suite if ENABLE_FULL_HTML diff --git a/configure.ac b/configure.ac index a04a300..a08970a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl Initialise Autoconf AC_PREREQ([2.69]) AC_INIT( [nestopia], - [1.50]) + [1.51.0]) AC_CONFIG_SRCDIR([source]) AC_LANG([C++]) @@ -76,11 +76,11 @@ PKG_CHECK_MODULES([LIBARCHIVE], [libarchive]) dnl SDL2 PKG_CHECK_MODULES([SDL2], [sdl2]) -dnl LibEpoxy -PKG_CHECK_MODULES([LIBEPOXY], [epoxy]) +AC_CHECK_PROG(FLTKCONFIG,fltk-config,[fltk-config],[no]) +test "$FLTKCONFIG" == "no" && AC_MSG_ERROR([Cannot find the fltk-config executable. Is FLTK installed?]) -dnl GTK3 -PKG_CHECK_MODULES([GTK3], [gtk+-3.0]) +AC_SUBST(FLTK_CFLAGS,"$(fltk-config --use-gl --use-images --cxxflags)") +AC_SUBST(FLTK_LIBS,"-lGL $(fltk-config --use-gl --use-images --ldflags)") dnl full HTML suite AC_ARG_ENABLE([doc], diff --git a/source/common/input.cpp b/source/common/input.cpp deleted file mode 100644 index 77fbe15..0000000 --- a/source/common/input.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2016 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include - -#include "nstcommon.h" -#include "config.h" -#include "input.h" -#include "video.h" - -static turbo_t turbostate; -static turbo_t turbotoggle; - -extern Emulator emulator; - -void nst_input_init() { - // Initialize input - char controller[32]; - - for (int i = 0; i < NUMGAMEPADS; i++) { - Input(emulator).AutoSelectController(i); - - switch(Input(emulator).GetConnectedController(i)) { - case Input::UNCONNECTED: - snprintf(controller, sizeof(controller), "%s", "Unconnected"); - break; - case Input::PAD1: - case Input::PAD2: - case Input::PAD3: - case Input::PAD4: - snprintf(controller, sizeof(controller), "%s", "Standard Pad"); - break; - case Input::ZAPPER: - snprintf(controller, sizeof(controller), "%s", "Zapper"); - break; - case Input::PADDLE: - snprintf(controller, sizeof(controller), "%s", "Arkanoid Paddle"); - break; - case Input::POWERPAD: - snprintf(controller, sizeof(controller), "%s", "Power Pad"); - break; - case Input::POWERGLOVE: - snprintf(controller, sizeof(controller), "%s", "Power Glove"); - break; - case Input::MOUSE: - snprintf(controller, sizeof(controller), "%s", "Mouse"); - break; - case Input::ROB: - snprintf(controller, sizeof(controller), "%s", "R.O.B."); - break; - case Input::FAMILYTRAINER: - snprintf(controller, sizeof(controller), "%s", "Family Trainer"); - break; - case Input::FAMILYKEYBOARD: - snprintf(controller, sizeof(controller), "%s", "Family Keyboard"); - break; - case Input::SUBORKEYBOARD: - snprintf(controller, sizeof(controller), "%s", "Subor Keyboard"); - break; - case Input::DOREMIKKOKEYBOARD: - snprintf(controller, sizeof(controller), "%s", "Doremikko Keyboard"); - break; - case Input::HORITRACK: - snprintf(controller, sizeof(controller), "%s", "Hori Track"); - break; - case Input::PACHINKO: - snprintf(controller, sizeof(controller), "%s", "Pachinko"); - break; - case Input::OEKAKIDSTABLET: - snprintf(controller, sizeof(controller), "%s", "Oeka Kids Tablet"); - break; - case Input::KONAMIHYPERSHOT: - snprintf(controller, sizeof(controller), "%s", "Konami Hypershot"); - break; - case Input::BANDAIHYPERSHOT: - snprintf(controller, sizeof(controller), "%s", "Bandai Hypershot"); - break; - case Input::CRAZYCLIMBER: - snprintf(controller, sizeof(controller), "%s", "Crazy Climber"); - break; - case Input::MAHJONG: - snprintf(controller, sizeof(controller), "%s", "Mahjong"); - break; - case Input::EXCITINGBOXING: - snprintf(controller, sizeof(controller), "%s", "Exciting Boxing"); - break; - case Input::TOPRIDER: - snprintf(controller, sizeof(controller), "%s", "Top Rider"); - break; - case Input::POKKUNMOGURAA: - snprintf(controller, sizeof(controller), "%s", "Pokkun Moguraa"); - break; - case Input::PARTYTAP: - snprintf(controller, sizeof(controller), "%s", "PartyTap"); - break; - case Input::TURBOFILE: - snprintf(controller, sizeof(controller), "%s", "Turbo File"); - break; - case Input::BARCODEWORLD: - snprintf(controller, sizeof(controller), "%s", "Barcode World"); - break; - default: - snprintf(controller, sizeof(controller), "%s", "Unknown"); - break; - } - - fprintf(stderr, "Port %d: %s\n", i + 1, controller); - } -} - -void nst_input_inject(Input::Controllers *controllers, nesinput_t input) { - // Insert the input signal into the NES - if(controllers == NULL) { return; } - - if (input.pressed) { - controllers->pad[input.player].buttons |= input.nescode; - - if (input.turboa) { input.player == 0 ? turbostate.p1a = true : turbostate.p2a = true; } - if (input.turbob) { input.player == 0 ? turbostate.p1b = true : turbostate.p2b = true; } - } - else { - controllers->pad[input.player].buttons &= ~input.nescode; - - if (input.turboa) { input.player == 0 ? turbostate.p1a = false : turbostate.p2a = false; } - if (input.turbob) { input.player == 0 ? turbostate.p1b = false : turbostate.p2b = false; } - } -} - -void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y) { - // Insert input signal for Zappers - if(controllers == NULL) { return; } - - double xaspect; - double yaspect; - - if (s) { - // Get X coords - if (conf.video_filter == 1) { // NTSC - xaspect = (double)(Video::Output::WIDTH) / (double)(Video::Output::NTSC_WIDTH / 2); - } - else if (conf.video_tv_aspect) { - xaspect = (double)(Video::Output::WIDTH) / (double)(TV_WIDTH); - } - else { xaspect = 1.0; } - - dimensions_t rendersize = nst_video_get_dimensions_render(); - dimensions_t screensize = nst_video_get_dimensions_screen(); - - // Calculate fullscreen X coords - if (conf.video_fullscreen) { - if (conf.video_stretch_aspect) { - xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(screensize.w); - } - else { - // Remove the same amount of pixels as the black area to the left of the screen - x -= screensize.w / 2.0f - rendersize.w / 2.0f; - xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(rendersize.w); - } - } - controllers->zapper.x = (int)(x * xaspect) / conf.video_scale_factor; - - // Get Y coords - if (conf.video_unmask_overscan) { - controllers->zapper.y = y / conf.video_scale_factor; - } - else { - controllers->zapper.y = (y + OVERSCAN_TOP * conf.video_scale_factor) / conf.video_scale_factor; - } - - // Calculate fullscreen Y coords - if (conf.video_fullscreen) { - yaspect = (double)(conf.video_scale_factor * Video::Output::HEIGHT) / (double)(screensize.h); - controllers->zapper.y = (y * yaspect) / conf.video_scale_factor; - } - - // Offscreen - if (b != 1) { controllers->zapper.x = ~1U; } - - controllers->zapper.fire = true; - } - else { controllers->zapper.fire = false; } -} - -void nst_input_turbo_init() { - // Initialize the turbo button states - turbostate.p1a = turbotoggle.p1a = 0; - turbostate.p1b = turbotoggle.p1b = 0; - turbostate.p2a = turbotoggle.p2a = 0; - turbostate.p2b = turbotoggle.p2b = 0; -} - -void nst_input_turbo_pulse(Input::Controllers *controllers) { - // Pulse the turbo buttons if they're pressed - if (turbostate.p1a) { - turbotoggle.p1a++; - if (turbotoggle.p1a >= conf.timing_turbopulse) { - turbotoggle.p1a = 0; - controllers->pad[0].buttons &= ~Input::Controllers::Pad::A; - } - else { controllers->pad[0].buttons |= Input::Controllers::Pad::A; } - } - - if (turbostate.p1b) { - turbotoggle.p1b++; - if (turbotoggle.p1b >= conf.timing_turbopulse) { - turbotoggle.p1b = 0; - controllers->pad[0].buttons &= ~Input::Controllers::Pad::B; - } - else { controllers->pad[0].buttons |= Input::Controllers::Pad::B; } - } - - if (turbostate.p2a) { - turbotoggle.p2a++; - if (turbotoggle.p2a >= conf.timing_turbopulse) { - turbotoggle.p2a = 0; - controllers->pad[1].buttons &= ~Input::Controllers::Pad::A; - } - else { controllers->pad[1].buttons |= Input::Controllers::Pad::A; } - } - - if (turbostate.p2b) { - turbotoggle.p2b++; - if (turbotoggle.p2b >= conf.timing_turbopulse) { - turbotoggle.p2b = 0; - controllers->pad[1].buttons &= ~Input::Controllers::Pad::B; - } - else { controllers->pad[1].buttons |= Input::Controllers::Pad::B; } - } -} - -int nst_input_zapper_present() { - // Check if a Zapper is presently connected - if (Input(emulator).GetConnectedController(0) == Input::ZAPPER || - Input(emulator).GetConnectedController(1) == Input::ZAPPER) { - return 1; - } - else { return 0; } -} diff --git a/source/common/input.h b/source/common/input.h deleted file mode 100644 index 56fc96c..0000000 --- a/source/common/input.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _INPUT_H_ -#define _INPUT_H_ - -#define NUMGAMEPADS 2 -#define NUMBUTTONS 10 - -#include "core/api/NstApiInput.hpp" - -using namespace Nes::Api; - -typedef struct { - unsigned char player; - unsigned char nescode; - unsigned char pressed; - unsigned char turboa; - unsigned char turbob; -} nesinput_t; - -typedef struct { - int p1a; - int p1b; - int p2a; - int p2b; -} turbo_t; - -void nst_input_init(); - -void nst_input_inject(Input::Controllers *controllers, nesinput_t input); -void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y); - -void nst_input_turbo_init(); -void nst_input_turbo_pulse(Input::Controllers *controllers); - -int nst_input_zapper_present(); - -int input_configure_item(int pnum, int bnum, int type); -#endif diff --git a/source/common/audio.cpp b/source/fltkui/audio.cpp similarity index 99% rename from source/common/audio.cpp rename to source/fltkui/audio.cpp index 30bb085..6f39740 100644 --- a/source/common/audio.cpp +++ b/source/fltkui/audio.cpp @@ -1,23 +1,23 @@ /* * Nestopia UE - * + * * Copyright (C) 2012-2017 R. Danbrook - * + * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include @@ -52,7 +52,7 @@ void audio_set_speed(int speed) { void audio_queue() { while ((bufsamples + bufsize) >= EBUFSIZE) { SDL_Delay(1); } - + SDL_LockAudioDevice(dev); for (int i = 0; i < bufsize; i++) { extbuf[bufend] = intbuf[i]; @@ -90,9 +90,9 @@ void audio_init_sdl() { spec.samples = 512; spec.userdata = 0; spec.callback = audio_cb; - + bufsize = channels * (conf.audio_sample_rate / framerate); - + dev = SDL_OpenAudioDevice(NULL, 0, &spec, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE); if (!dev) { fprintf(stderr, "Error opening audio device.\n"); @@ -100,7 +100,7 @@ void audio_init_sdl() { else { fprintf(stderr, "Audio: SDL - %dHz %d-bit, %d channel(s)\n", spec.freq, 16, spec.channels); } - + SDL_PauseAudioDevice(dev, 1); // Setting to 0 unpauses } @@ -129,15 +129,15 @@ void audio_unpause() { void audio_set_params(Sound::Output *soundoutput) { // Set audio parameters Sound sound(emulator); - + sound.SetSampleBits(16); sound.SetSampleRate(conf.audio_sample_rate); - + sound.SetSpeaker(conf.audio_stereo ? Sound::SPEAKER_STEREO : Sound::SPEAKER_MONO); sound.SetSpeed(Sound::DEFAULT_SPEED); - + audio_adj_volume(); - + soundoutput->samples[0] = intbuf; soundoutput->length[0] = conf.audio_sample_rate / framerate; soundoutput->samples[1] = NULL; @@ -159,6 +159,6 @@ void audio_adj_volume() { sound.SetVolume(Sound::CHANNEL_VRC7, conf.audio_vol_vrc7); sound.SetVolume(Sound::CHANNEL_N163, conf.audio_vol_n163); sound.SetVolume(Sound::CHANNEL_S5B, conf.audio_vol_s5b); - + if (conf.audio_volume == 0) { memset(intbuf, 0, sizeof(intbuf)); } } diff --git a/source/common/audio.h b/source/fltkui/audio.h similarity index 100% rename from source/common/audio.h rename to source/fltkui/audio.h diff --git a/source/common/cheats.cpp b/source/fltkui/cheats.cpp similarity index 97% rename from source/common/cheats.cpp rename to source/fltkui/cheats.cpp index 8200e92..83e9f99 100644 --- a/source/common/cheats.cpp +++ b/source/fltkui/cheats.cpp @@ -1,23 +1,23 @@ /* * Nestopia UE - * + * * Copyright (C) 2012-2018 R. Danbrook - * + * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include @@ -32,35 +32,35 @@ void nst_cheats_init(const char *cheatpath) { // Initialize cheat engine Cheats cheats(emulator); Xml xml; - + cheats.ClearCodes(); - + std::ifstream cheatfile(cheatpath, std::ifstream::in|std::ifstream::binary); - + if (cheatfile.is_open()) { xml.Read(cheatfile); - + if (xml.GetRoot().IsType(L"cheats")) { - + Xml::Node root(xml.GetRoot()); Xml::Node node(root.GetFirstChild()); - + for (int i = 0; i < root.NumChildren(L"cheat"); i++) { - + if (node.GetAttribute(L"enabled").IsValue(L"1")) { - + if (node.GetChild(L"genie")) { // Game Genie nst_cheats_code_gg_add(node.GetChild(L"genie").GetValue()); } - + else if (node.GetChild(L"rocky")) { // Pro Action Rocky nst_cheats_code_par_add(node.GetChild(L"rocky").GetValue()); } - + else if (node.GetChild(L"address")) { // Raw nst_cheats_code_raw_add(node); } - + //fprintf(stderr, "Cheat: %ls\n", node.GetChild(L"description").GetValue()); } node = node.GetNextSibling(); @@ -74,13 +74,13 @@ void nst_cheats_init(const char *cheatpath) { // List the active cheats Cheats cheats(emulator); Cheats::Code code; - + char gg[9]; - + for (int i = 0; i < cheats.NumCodes(); i++) { cheats.GetCode(i, code); cheats.GameGenieEncode(code, gg); - + fprintf(stderr, "Cheat: %s\n", gg); } }*/ @@ -89,10 +89,10 @@ void nst_cheats_code_gg_add(const wchar_t *data) { // Add a Game Genie code Cheats cheats(emulator); Cheats::Code code; - + char gg[9]; wcstombs(gg, data, sizeof(gg)); - + cheats.GameGenieDecode(gg, code); cheats.SetCode(code); } @@ -101,10 +101,10 @@ void nst_cheats_code_par_add(const wchar_t *data) { // Add a Pro Action Rocky code Cheats cheats(emulator); Cheats::Code code; - + char par[9]; wcstombs(par, data, sizeof(par)); - + cheats.ProActionRockyDecode(par, code); cheats.SetCode(code); } @@ -113,9 +113,9 @@ void nst_cheats_code_raw_add(Xml::Node node) { // Add a Raw code Cheats cheats(emulator); Cheats::Code code; - + code.useCompare = false; - + code.address = node.GetChild(L"address").GetUnsignedValue(); if (node.GetChild(L"value")) { code.value = node.GetChild(L"value").GetUnsignedValue(); @@ -132,18 +132,18 @@ void nst_dip_handle(const char *dippath) { // Handle the DIP switch file DipSwitches dipswitches(emulator); Xml xml; - + std::ifstream dipfile(dippath, std::ifstream::in|std::ifstream::binary); - + if (dipfile.is_open()) { xml.Read(dipfile); - + if (xml.GetRoot().IsType(L"dipswitches")) { Xml::Node root(xml.GetRoot()); Xml::Node node(root.GetFirstChild()); - + for (int i = 0; i < root.NumChildren(L"dip"); i++) { - + if (node.GetChild(L"value")) { dipswitches.SetValue(i, node.GetChild(L"value").GetUnsignedValue()); } @@ -154,34 +154,34 @@ void nst_dip_handle(const char *dippath) { } else { Xml::Node root(xml.GetRoot()); - + root = xml.Create(L"dipswitches"); root.AddAttribute(L"version", L"1.0"); - + wchar_t wbuf[32]; char buf[2]; - + int numdips = dipswitches.NumDips(); - + if (numdips > 0) { for (int i = 0; i < numdips; i++) { Xml::Node node(root.AddChild(L"dip")); - + mbstowcs(wbuf, dipswitches.GetDipName(i), sizeof(wbuf)); node.AddChild(L"description", wbuf); - + snprintf(buf, sizeof(buf), "%d", dipswitches.GetValue(i)); mbstowcs(wbuf, buf, sizeof(buf)); node.AddChild(L"value", wbuf); } } - + std::ofstream dipout(dippath, std::ifstream::out|std::ifstream::binary); if (dipout.is_open()) { xml.Write(root, dipout); } - + dipout.close(); } } diff --git a/source/common/cheats.h b/source/fltkui/cheats.h similarity index 100% rename from source/common/cheats.h rename to source/fltkui/cheats.h diff --git a/source/common/cli.cpp b/source/fltkui/cli.cpp similarity index 98% rename from source/common/cli.cpp rename to source/fltkui/cli.cpp index c0b8133..c6edc71 100644 --- a/source/common/cli.cpp +++ b/source/fltkui/cli.cpp @@ -1,23 +1,23 @@ /* * Nestopia UE - * + * * Copyright (C) 2012-2016 R. Danbrook - * + * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include @@ -82,28 +82,28 @@ void cli_handle_command(int argc, char *argv[]) { {"version", no_argument, 0, 'v'}, {0, 0, 0, 0} }; - + int option_index = 0; - + c = getopt_long(argc, argv, "defhl:mnopqrs:tuvw", long_options, &option_index); - + if (c == -1) { break; } - + switch(c) { case 'f': conf.video_fullscreen = true; break; - + case 'w': conf.video_fullscreen = false; break; - + case 'h': cli_show_usage(); exit(0); break; - + case 'l': optint = atoi(optarg); if (optint < 6) { @@ -113,23 +113,23 @@ void cli_handle_command(int argc, char *argv[]) { cli_error("Error: Invalid filter"); } break; - + case 'm': conf.video_unmask_overscan = false; break; - + case 'n': conf.video_unmask_overscan = true; break; - + case 'o': conf.video_stretch_aspect = true; break; - + case 'p': conf.video_stretch_aspect = false; break; - + case 's': optint = atoi(optarg); if (optint < 5 && optint != 0) { @@ -139,28 +139,28 @@ void cli_handle_command(int argc, char *argv[]) { cli_error("Error: Invalid scale factor"); } break; - + case 't': conf.video_tv_aspect = true; break; - + case 'r': conf.video_tv_aspect = false; break; - + case 'u': conf.video_unlimited_sprites = true; break; - + case 'q': conf.video_unlimited_sprites = false; break; - + case 'v': cli_show_version(); exit(0); break; - + default: cli_error("Error: Invalid option"); break; diff --git a/source/common/cli.h b/source/fltkui/cli.h similarity index 100% rename from source/common/cli.h rename to source/fltkui/cli.h diff --git a/source/common/config.cpp b/source/fltkui/config.cpp similarity index 98% rename from source/common/config.cpp rename to source/fltkui/config.cpp index 9c9a616..187ff8b 100644 --- a/source/common/config.cpp +++ b/source/fltkui/config.cpp @@ -1,6 +1,6 @@ /* * Nestopia UE - * + * * Copyright (C) 2012-2016 R. Danbrook * Copyright (C) 2018-2018 Phil Smith * @@ -8,17 +8,17 @@ * 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include @@ -45,10 +45,10 @@ void config_file_read(const char *nstdir) { void config_file_write(const char *nstdir) { // Write the config file - + char confpath[256]; snprintf(confpath, sizeof(confpath), "%snestopia.conf", nstdir); - + FILE *fp = fopen(confpath, "w"); if (fp != NULL) { // Video @@ -87,11 +87,9 @@ void config_file_write(const char *nstdir) { fprintf(fp, "unlimited_sprites=%d\n", conf.video_unlimited_sprites); fprintf(fp, "xbr_pixel_blending=%d\n", conf.video_xbr_pixel_blending); fprintf(fp, "\n"); // End of Section - + // Audio fprintf(fp, "[audio]\n"); - fprintf(fp, "; 0=SDL, 1=libao, 2=jack\n"); - fprintf(fp, "api=%d\n\n", conf.audio_api); fprintf(fp, "; Valid values are 1 and 0.\n"); fprintf(fp, "stereo=%d\n\n", conf.audio_stereo); fprintf(fp, "; Valid values are 11025, 22050, 44100, 48000, and 96000.\n"); @@ -110,7 +108,7 @@ void config_file_write(const char *nstdir) { fprintf(fp, "vol_n163=%d\n", conf.audio_vol_n163); fprintf(fp, "vol_s5b=%d\n", conf.audio_vol_s5b); fprintf(fp, "\n"); // End of Section - + // Timing fprintf(fp, "[timing]\n"); fprintf(fp, "; Base speed for NTSC in Frames per Second.\n"); @@ -120,7 +118,7 @@ void config_file_write(const char *nstdir) { fprintf(fp, "; Pulse turbo buttons every n frames. Minimum value is 2.\n"); fprintf(fp, "turbopulse=%d\n", conf.timing_turbopulse); fprintf(fp, "\n"); // End of Section - + // Misc fprintf(fp, "[misc]\n"); fprintf(fp, "; 0=Auto, 1=NTSC, 2=PAL, 3=Famicom, 4=Dendy\n"); @@ -147,7 +145,7 @@ void config_file_write(const char *nstdir) { } void config_set_default() { - + // Video conf.video_filter = 0; conf.video_scale_factor = 2; @@ -171,9 +169,8 @@ void config_set_default() { conf.video_stretch_aspect = false; conf.video_unlimited_sprites = false; conf.video_xbr_pixel_blending = false; - + // Audio - conf.audio_api = 0; conf.audio_stereo = false; conf.audio_sample_rate = 48000; conf.audio_volume = 85; @@ -188,12 +185,12 @@ void config_set_default() { conf.audio_vol_vrc7 = 85; conf.audio_vol_n163 = 85; conf.audio_vol_s5b = 85; - + // Timing conf.timing_speed = 60; conf.timing_ffspeed = 3; conf.timing_turbopulse = 3; - + // Misc conf.misc_default_system = 0; conf.misc_soft_patching = true; @@ -211,7 +208,7 @@ void config_set_default() { static int config_match(void* user, const char* section, const char* name, const char* value) { // Match values from config file and populate live config settings_t* pconfig = (settings_t*)user; - + // Video if (MATCH("video", "filter")) { pconfig->video_filter = atoi(value); } else if (MATCH("video", "scale_factor")) { pconfig->video_scale_factor = atoi(value); } @@ -235,9 +232,8 @@ static int config_match(void* user, const char* section, const char* name, const else if (MATCH("video", "stretch_aspect")) { pconfig->video_stretch_aspect = atoi(value); } else if (MATCH("video", "unlimited_sprites")) { pconfig->video_unlimited_sprites = atoi(value); } else if (MATCH("video", "xbr_pixel_blending")) { pconfig->video_xbr_pixel_blending = atoi(value); } - + // Audio - else if (MATCH("audio", "api")) { pconfig->audio_api = atoi(value); } else if (MATCH("audio", "stereo")) { pconfig->audio_stereo = atoi(value); } else if (MATCH("audio", "sample_rate")) { pconfig->audio_sample_rate = atoi(value); } else if (MATCH("audio", "volume")) { pconfig->audio_volume = atoi(value); } @@ -252,12 +248,12 @@ static int config_match(void* user, const char* section, const char* name, const else if (MATCH("audio", "vol_vrc7")) { pconfig->audio_vol_vrc7 = atoi(value); } else if (MATCH("audio", "vol_n163")) { pconfig->audio_vol_n163 = atoi(value); } else if (MATCH("audio", "vol_s5b")) { pconfig->audio_vol_s5b = atoi(value); } - + // Timing else if (MATCH("timing", "speed")) { pconfig->timing_speed = atoi(value); } else if (MATCH("timing", "ffspeed")) { pconfig->timing_ffspeed = atoi(value); } else if (MATCH("timing", "turbopulse")) { pconfig->timing_turbopulse = atoi(value); } - + // Misc else if (MATCH("misc", "default_system")) { pconfig->misc_default_system = atoi(value); } else if (MATCH("misc", "soft_patching")) { pconfig->misc_soft_patching = atoi(value); } diff --git a/source/common/config.h b/source/fltkui/config.h similarity index 98% rename from source/common/config.h rename to source/fltkui/config.h index 8f7a1bb..110cf3c 100644 --- a/source/common/config.h +++ b/source/fltkui/config.h @@ -2,7 +2,7 @@ #define _CONFIG_H_ typedef struct { - + // Video int video_filter; int video_scale_factor; @@ -26,9 +26,8 @@ typedef struct { bool video_stretch_aspect; bool video_unlimited_sprites; bool video_xbr_pixel_blending; - + // Audio - int audio_api; bool audio_stereo; int audio_sample_rate; int audio_volume; @@ -43,12 +42,12 @@ typedef struct { int audio_vol_vrc7; int audio_vol_n163; int audio_vol_s5b; - + // Timing int timing_speed; int timing_ffspeed; int timing_turbopulse; - + // Misc int misc_default_system; bool misc_soft_patching; diff --git a/source/fltkui/fltkui.cpp b/source/fltkui/fltkui.cpp new file mode 100644 index 0000000..3b0d835 --- /dev/null +++ b/source/fltkui/fltkui.cpp @@ -0,0 +1,536 @@ +/* + * Nestopia UE + * + * Copyright (C) 2012-2021 R. Danbrook + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nstcommon.h" +#include "cli.h" +#include "config.h" +#include "audio.h" +#include "video.h" +#include "input.h" + +#include "fltkui.h" +#include "fltkui_archive.h" +#include "fltkui_config.h" + +#define MBARHEIGHT 24 + +static NstWindow *nstwin; +static Fl_Menu_Bar *menubar; +static NstGlArea *glarea; +static NstConfWindow *confwin; + +Fl_Color NstGreen = 0x255f6500; +Fl_Color NstPurple = 0x5f578700; +Fl_Color NstRed = 0xb51e2c00; +Fl_Color NstBlueGrey = 0x383c4a00; +Fl_Color NstLightGrey = 0xd3dae300; + +extern Input::Controllers *cNstPads; +extern nstpaths_t nstpaths; + +extern bool (*nst_archive_select)(const char*, char*, size_t); + +static void fltkui_config(Fl_Widget* w, void* userdata) { + confwin->show(); +} + +static void fltkui_rom_open(Fl_Widget* w, void* userdata) { + // Create native chooser + Fl_Native_File_Chooser fc; + fc.title("Select a ROM"); + fc.type(Fl_Native_File_Chooser::BROWSE_FILE); + fc.filter("NES Games\t*.{nes,unf,fds,zip,7z,gz,bz2,xz}"); + + // Show file chooser + switch (fc.show()) { + case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; + case 1: break; // Cancel + default: + if (fc.filename()) { + int loaded = nst_load(fc.filename()); + nstwin->label(nstpaths.gamename); + if (loaded) { nst_play(); } + } + break; + } +} + +static void fltkui_movie_load(Fl_Widget* w, void* userdata) { + // Create native chooser + if (!nst_playing()) { return; } + + Fl_Native_File_Chooser fc; + fc.title("Select a Movie"); + fc.type(Fl_Native_File_Chooser::BROWSE_FILE); + fc.directory((const char*)nstpaths.nstdir); + fc.filter("Nestopia Movies\t*.nsv"); + + // Show file chooser + switch (fc.show()) { + case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; + case 1: break; // Cancel + default: + if (fc.filename()) { + nst_movie_load(fc.filename()); + } + break; + } +} + +static void fltkui_movie_save(Fl_Widget* w, void* userdata) { + // Create native chooser + if (!nst_playing()) { return; } + + Fl_Native_File_Chooser fc; + fc.title("Save Movie"); + fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); + fc.directory((const char*)nstpaths.nstdir); + fc.filter("Nestopia Moviess\t*.nsv"); + fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); + + // Show file chooser + if (fc.show()) { return; } + + nst_movie_save(fc.filename()); +} + +static void fltkui_movie_stop(Fl_Widget* w, void* userdata) { + nst_movie_stop(); +} + +static void fltkui_state_load(Fl_Widget* w, void* userdata) { + // Create native chooser + if (!nst_playing()) { return; } + + Fl_Native_File_Chooser fc; + fc.title("Load State"); + fc.type(Fl_Native_File_Chooser::BROWSE_FILE); + fc.directory((const char*)nstpaths.statepath); + fc.filter("Nestopia States\t*.nst"); + + // Show file chooser + switch (fc.show()) { + case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; + case 1: break; // Cancel + default: + if (fc.filename()) { + nst_state_load(fc.filename()); + } + break; + } +} + +static void fltkui_state_save(Fl_Widget* w, void* userdata) { + // Create native chooser + if (!nst_playing()) { return; } + + Fl_Native_File_Chooser fc; + fc.title("Save State"); + fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); + fc.directory((const char*)nstpaths.statepath); + fc.filter("Nestopia States\t*.nst"); + fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); + + // Show file chooser + if (fc.show()) { return; } + + nst_state_save(fc.filename()); +} + +static void fltkui_screenshot(Fl_Widget* w, void* userdata) { + // Create native chooser + if (!nst_playing()) { return; } + + Fl_Native_File_Chooser fc; + fc.title("Save Screenshot"); + fc.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); + fc.directory((const char*)nstpaths.nstdir); + fc.filter("PNG Screenshots\t*.png"); + fc.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM | Fl_Native_File_Chooser::USE_FILTER_EXT); + + // Show file chooser + if (fc.show()) { return; } + + video_screenshot(fc.filename()); +} + +static void fltkui_palette_open(Fl_Widget* w, void* userdata) { + // Create native chooser + Fl_Native_File_Chooser fc; + fc.title("Select a Palette"); + fc.type(Fl_Native_File_Chooser::BROWSE_FILE); + fc.filter("NES Palettes\t*.pal"); + + // Show file chooser + switch (fc.show()) { + case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break; + case 1: break; // Cancel + default: + if (fc.filename()) { + nst_palette_load(fc.filename()); + nst_palette_save(); + conf.video_palette_mode = 2; + video_init(); + } + break; + } +} + +static void fltkui_state_qload(Fl_Widget* w, void* userdata) { + nst_state_quickload(atoi((const char*)userdata)); +} + +static void fltkui_state_qsave(Fl_Widget* w, void* userdata) { + nst_state_quicksave(atoi((const char*)userdata)); +} + +static void fltkui_pause(Fl_Widget* w, void* userdata) { + if (nst_playing()) { + nst_pause(); + } + else { + nst_play(); + } +} + +static void fltkui_reset(Fl_Widget* w, void* userdata) { + nst_reset(atoi((const char*)userdata)); +} + +void fltkui_resize() { + video_set_dimensions(); + dimensions_t rendersize = nst_video_get_dimensions_render(); + nstwin->size(rendersize.w, rendersize.h + MBARHEIGHT); + menubar->resize(0, 0, nstwin->w(), MBARHEIGHT); + glarea->resize(0, 24, rendersize.w, rendersize.h); + nst_video_set_dimensions_screen(rendersize); + video_init(); +} + +void fltkui_fullscreen(Fl_Widget* w, void* userdata) { + if (!nst_playing()) { return; } + + conf.video_fullscreen ^= 1; + + if (conf.video_fullscreen) { + int x, y, w, h; + Fl::screen_xywh(x, y, w, h); + menubar->hide(); + nstwin->fullscreen(); + dimensions_t scrdim = {w, h}; + nstwin->resize(0, 0, scrdim.w, scrdim.h); + glarea->resize(0, 0, scrdim.w, scrdim.h); + nst_video_set_dimensions_screen(scrdim); + video_init(); + } + else { + video_set_dimensions(); + dimensions_t rendersize = nst_video_get_dimensions_render(); + nstwin->fullscreen_off(); + nstwin->size(rendersize.w, rendersize.h + MBARHEIGHT); + menubar->show(); + menubar->resize(0, 0, nstwin->w(), MBARHEIGHT); + glarea->resize(0, 24, rendersize.w, rendersize.h); + nst_video_set_dimensions_screen(rendersize); + video_init(); + } +} + +static void fltkui_fds_flip(Fl_Widget* w, void* userdata) { + nst_fds_flip(); +} + +static void fltkui_fds_switch(Fl_Widget* w, void* userdata) { + nst_fds_switch(); +} + +static void fltkui_about_close(Fl_Widget* w, void* userdata) { + Fl_Window *about = (Fl_Window*)userdata; + about->hide(); +} + +static void fltkui_about(Fl_Widget* w, void* userdata) { + Fl_Window about(460, 440); + Fl_Box iconbox(166, 16, 128, 128); + + Fl_Box text0(0, 144, 460, 24, "Nestopia UE"); + text0.labelfont(FL_BOLD); + + Fl_Box text1(0, 166, 460, 24, "1.51.0"); + + Fl_Box text2(0, 208, 460, 24, "Cycle-Accurate Nintendo Entertainment System Emulator"); + + Fl_Box text3(0, 256, 460, 24, "FLTK Frontend\n(c) 2012-2021, R. Danbrook\n(c) 2007-2008, R. Belmont"); + text3.labelsize(10); + + Fl_Box text4(0, 320, 460, 24, "Nestopia Emulator\n(c) 2020-2021, Rupert Carmichael\n(c) 2012-2020, Nestopia UE Contributors\n(c) 2003-2008, Martin Freij"); + text4.labelsize(10); + + Fl_Box text5(0, 360, 460, 24, "Icon based on drawing by Trollekop"); + text5.labelsize(10); + + Fl_PNG_Image nsticon("nestopia.png"); + iconbox.image(nsticon); + + Fl_Button close(360, 400, 80, 24, "&Close"); + close.callback(fltkui_about_close, (void*)&about); + + about.set_modal(); + about.show(); + while (about.shown()) { Fl::wait(); } +} + +static void quit_cb(Fl_Widget* w, void* userdata) { + nstwin->hide(); +} + +// this is used to stop Esc from exiting the program: +int handle(int e) { + return (e == FL_SHORTCUT); // eat all keystrokes +} + +int NstWindow::handle(int e) { + switch (e) { case FL_KEYDOWN: case FL_KEYUP: fltkui_input_process_key(e); break; } + return Fl_Double_Window::handle(e); +} + +int NstGlArea::handle(int e) { + if (nst_input_zapper_present()) { + switch (e) { + case FL_ENTER: + cursor(conf.misc_disable_cursor_special ? FL_CURSOR_NONE : FL_CURSOR_CROSS); + break; + case FL_LEAVE: + cursor(FL_CURSOR_DEFAULT); + break; + case FL_PUSH: + nst_input_inject_mouse(cNstPads, Fl::event_button(), 1, Fl::event_x(), Fl::event_y()); + break; + case FL_RELEASE: + nst_input_inject_mouse(cNstPads, Fl::event_button(), 0, Fl::event_x(), Fl::event_y()); + break; + } + } + else if (e == FL_ENTER && conf.misc_disable_cursor) { cursor(FL_CURSOR_NONE); } + else if (e == FL_LEAVE) { cursor(FL_CURSOR_DEFAULT); } + + return Fl_Gl_Window::handle(e); +} + +static Fl_Menu_Item menutable[] = { + {"&File", 0, 0, 0, FL_SUBMENU}, + {"&Open", FL_ALT + 'o', fltkui_rom_open, 0, FL_MENU_DIVIDER}, + {"Load State...", 0, fltkui_state_load, 0, 0}, + {"Save State...", 0, fltkui_state_save, 0, FL_MENU_DIVIDER}, + {"Quick Load", 0, 0, 0, FL_SUBMENU}, + {"Slot 0", 0, fltkui_state_qload, (void*)"0", 0}, + {"Slot 1", 0, fltkui_state_qload, (void*)"1", 0}, + {"Slot 2", 0, fltkui_state_qload, (void*)"2", 0}, + {"Slot 3", 0, fltkui_state_qload, (void*)"3", 0}, + {"Slot 4", 0, fltkui_state_qload, (void*)"4", 0}, + {0}, + {"Quick Save", 0, 0, 0, FL_SUBMENU|FL_MENU_DIVIDER}, + {"Slot 0", 0, fltkui_state_qsave, (void*)"0", 0}, + {"Slot 1", 0, fltkui_state_qsave, (void*)"1", 0}, + {"Slot 2", 0, fltkui_state_qsave, (void*)"2", 0}, + {"Slot 3", 0, fltkui_state_qsave, (void*)"3", 0}, + {"Slot 4", 0, fltkui_state_qsave, (void*)"4", 0}, + {0}, + {"Open Palette...", 0, fltkui_palette_open, 0, FL_MENU_DIVIDER}, + {"Screenshot...", 0, fltkui_screenshot, 0, FL_MENU_DIVIDER}, + {"Load Movie...", 0, fltkui_movie_load, 0, 0}, + {"Record Movie...", 0, fltkui_movie_save, 0, 0}, + {"Stop Movie", 0, fltkui_movie_stop, 0, FL_MENU_DIVIDER}, + {"&Quit", FL_ALT + 'q', quit_cb}, + {0}, // End File + {"&Emulator", 0, 0, 0, FL_SUBMENU}, + {"Pause/Play", 0, fltkui_pause, 0, FL_MENU_DIVIDER}, + {"Reset (Soft)", 0, fltkui_reset, (void*)"0", 0}, + {"Reset (Hard)", 0, fltkui_reset, (void*)"1", FL_MENU_DIVIDER}, + {"Fullscreen", 0, fltkui_fullscreen, 0, FL_MENU_DIVIDER}, + {"Flip Disk", 0, fltkui_fds_flip, 0, 0}, + {"Switch Disk", 0, fltkui_fds_switch, 0, FL_MENU_DIVIDER}, + //{"Cheats...", 0, 0, 0, FL_MENU_DIVIDER}, + {"Configuration...", 0, fltkui_config, 0}, + {0}, // End Emulator + {"&Help", 0, 0, 0, FL_SUBMENU}, + {"About", 0, fltkui_about, 0, 0}, + {0}, // End Help + {0} // End Menu +}; + +void makenstwin(const char *name) { + video_set_dimensions(); + dimensions_t rendersize = nst_video_get_dimensions_render(); + + // Configuration Window + Fl::add_handler(handle); + confwin = new NstConfWindow(400, 400, "Configuration"); + confwin->populate(); + + // Main Window + nstwin = new NstWindow(rendersize.w, rendersize.h + MBARHEIGHT, name); + nstwin->color(FL_BLACK); + nstwin->xclass("nestopia"); + + // Menu Bar + menubar = new Fl_Menu_Bar(0, 0, nstwin->w(), MBARHEIGHT); + menubar->box(FL_FLAT_BOX); + menubar->menu(menutable); + + glarea = new NstGlArea(0, MBARHEIGHT, nstwin->w(), nstwin->h() - MBARHEIGHT); + glarea->color(FL_BLACK); + + nstwin->resizable(glarea); + nstwin->resizable(nstwin); + nstwin->end(); +} + +int main(int argc, char *argv[]) { + // Set up directories + nst_set_dirs(); + + // Set default config options + config_set_default(); + + // Read the config file and override defaults + config_file_read(nstpaths.nstconfdir); + + // Handle command line arguments + cli_handle_command(argc, argv); + + // Set the video dimensions + video_set_dimensions(); + + // Set up callbacks + nst_set_callbacks(); + + // Initialize SDL Audio and Joystick + if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { + fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + // Set archive handler function pointer + nst_archive_select = &fltkui_archive_select; + + // Detect and set up Joysticks + nstsdl_input_joysticks_detect(); + nstsdl_input_conf_defaults(); + nstsdl_input_conf_read(); + + // Initialize and load FDS BIOS and NstDatabase.xml + nst_fds_bios_load(); + nst_db_load(); + + makenstwin(argv[0]); + nstwin->label("Nestopia UE"); + nstwin->show(); + menubar->show(); + glarea->make_current(); + glarea->show(); + + Fl::check(); + + // Load a rom from the command line + if (argc > 1 && argv[argc - 1][0] != '-') { + int loaded = nst_load(argv[argc - 1]); + if (loaded) { nst_play(); } + else { exit(1); } + nstwin->label(nstpaths.gamename); + } + else if (conf.video_fullscreen) { + conf.video_fullscreen = 0; + } + + if (conf.video_fullscreen) { + conf.video_fullscreen = 0; + fltkui_fullscreen(NULL, NULL); + } + + video_init(); + + while (true) { + glarea->redraw(); + + if (nstwin->visible() && !Fl::check()) { + break; + } + else if (!nstwin->shown() && confwin->shown()) { + break; + } + else if (!Fl::wait()) { + break; + } + + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_JOYHATMOTION: + case SDL_JOYAXISMOTION: + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + nstsdl_input_process(cNstPads, event); + break; + default: break; + } + } + + nst_emuloop(); + glarea->redraw(); + } + + // Remove the cartridge and shut down the NES + nst_unload(); + + // Unload the FDS BIOS, NstDatabase.xml, and the custom palette + nst_db_unload(); + nst_fds_bios_unload(); + nst_palette_unload(); + + // Deinitialize audio + audio_deinit(); + + // Deinitialize joysticks + nstsdl_input_joysticks_close(); + + // Write the input config file + nstsdl_input_conf_write(); + + // Write the config file + config_file_write(nstpaths.nstconfdir); + + return 0; +} diff --git a/source/fltkui/fltkui.h b/source/fltkui/fltkui.h new file mode 100644 index 0000000..8dc9552 --- /dev/null +++ b/source/fltkui/fltkui.h @@ -0,0 +1,33 @@ +#ifndef MAIN_H +#define MAIN_H + +class NstWindow : public Fl_Double_Window { +private: + int handle(int e); + +public: + NstWindow(int w, int h, const char* t = 0) : Fl_Double_Window(w, h, t) { } + virtual ~NstWindow() { } +}; + +class NstGlArea : public Fl_Gl_Window { +private: + void draw() { nst_ogl_render(); } + int handle(int e); + +public: + NstGlArea(int x, int y, int w, int h, const char *l = 0) : Fl_Gl_Window(x, y, w, h, l) { + box(FL_DOWN_FRAME); + } +}; + +extern Fl_Color NstGreen; +extern Fl_Color NstPurple; +extern Fl_Color NstRed; +extern Fl_Color NstBlueGrey; +extern Fl_Color NstLightGrey; + +void fltkui_resize(); +void fltkui_fullscreen(Fl_Widget* w, void* userdata); + +#endif diff --git a/source/fltkui/fltkui_archive.cpp b/source/fltkui/fltkui_archive.cpp new file mode 100644 index 0000000..faf4dff --- /dev/null +++ b/source/fltkui/fltkui_archive.cpp @@ -0,0 +1,125 @@ +/* + * Nestopia UE + * + * Copyright (C) 2012-2021 R. Danbrook + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "nstcommon.h" +#include "config.h" + +#include "fltkui_archive.h" + +static Fl_Double_Window *window; +static Fl_Select_Browser *browser; +static char *romfile = NULL; + +static void fltkui_archive_ok(Fl_Widget *w, long) { + window->hide(); +} + +static void fltkui_archive_cancel(Fl_Widget *w, long) { + snprintf(romfile, 256, "%s", ""); + window->hide(); +} + +static void fltkui_archive_setfile(Fl_Widget *w, long) { + int r = ((Fl_Browser*)w)->value(); + if (r) { + snprintf(romfile, 256, "%s", ((Fl_Browser*)w)->text(r)); + if (Fl::event_clicks()) { window->hide(); } + } + else { + snprintf(romfile, 256, "%s", ""); + } +} + +bool fltkui_archive_select(const char *filename, char *reqfile, size_t reqsize) { + // Select a filename to pull out of the archive + struct archive *a; + struct archive_entry *entry; + int r, numarchives = 0; + + a = archive_read_new(); + archive_read_support_filter_all(a); + archive_read_support_format_all(a); + r = archive_read_open_filename(a, filename, 10240); + + // Test if it's actually an archive + if (r != ARCHIVE_OK) { + r = archive_read_free(a); + return false; + } + // If it is an archive, handle it + else { + if (window) { delete window; } + + window = new Fl_Double_Window(420, 260, "Load from Archive"); + browser = new Fl_Select_Browser(0, 0, window->w(), 200, 0); + browser->type(FL_HOLD_BROWSER); + browser->callback(fltkui_archive_setfile, 0); + Fl_Button btncancel(260, 220, 80, 24, "&Cancel"); + btncancel.callback(fltkui_archive_cancel, 0); + Fl_Button btnok(350, 220, 40, 24, "&OK"); + btnok.callback(fltkui_archive_ok, 0); + + romfile = reqfile; + + // Fill the treestore with the filenames + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + const char *currentfile = archive_entry_pathname(entry); + if (nst_archive_checkext(currentfile)) { + browser->add(currentfile); + numarchives++; + snprintf(reqfile, reqsize, "%s", currentfile); + } + archive_read_data_skip(a); + } + + // Free the archive + r = archive_read_free(a); + + // If there are no valid files in the archive, return + if (numarchives == 0) { return false; } + // If there's only one file, don't bring up the selector + else if (numarchives == 1) { return true; } + + browser->select(1); + snprintf(romfile, 256, "%s", browser->text(1)); + + window->resizable(browser); + window->show(); + window->set_modal(); + window->show(); + while (window->shown()) { Fl::wait(); } + + if (strlen(romfile)) { return true; } + } + return false; +} diff --git a/source/fltkui/fltkui_archive.h b/source/fltkui/fltkui_archive.h new file mode 100644 index 0000000..d5666f1 --- /dev/null +++ b/source/fltkui/fltkui_archive.h @@ -0,0 +1,6 @@ +#ifndef _FLTKUI_ARCHIVE_H_ +#define _FLTKUI_ARCHIVE_H_ + +bool fltkui_archive_select(const char *filename, char *reqfile, size_t reqsize); + +#endif diff --git a/source/fltkui/fltkui_config.cpp b/source/fltkui/fltkui_config.cpp new file mode 100644 index 0000000..5bfd466 --- /dev/null +++ b/source/fltkui/fltkui_config.cpp @@ -0,0 +1,666 @@ +/* + * Nestopia UE + * + * Copyright (C) 2012-2021 R. Danbrook + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nstcommon.h" +#include "config.h" +#include "audio.h" +#include "video.h" +#include "input.h" + +#include "fltkui.h" +#include "fltkui_config.h" + +static const char *icfg_labels[10] = { + "Press Key For: Up", + "Press Key For: Down", + "Press Key For: Left", + "Press Key For: Right", + "Press Key For: Select", + "Press Key For: Start", + "Press Key For: A", + "Press Key For: B", + "Press Key For: Turbo A", + "Press Key For: Turbo B" +}; + +NstInputConfWindow *icfg; + +static Fl_Dial *dial_vall, *dial_vsq1, *dial_vsq2, *dial_vtri, *dial_vnoise, *dial_vdpcm, + *dial_vfds, *dial_vmmc5, *dial_vvrc6, *dial_vvrc7, *dial_vn163, *dial_vs5b; + +extern inputsettings_t inputconf; + +static void cb_filter(Fl_Widget *w, long) { + conf.video_filter = ((Fl_Choice*)w)->value(); + fltkui_resize(); +} + +static void cb_scale(Fl_Widget *w, long) { + conf.video_scale_factor = ((Fl_Choice*)w)->value() + 1; + fltkui_resize(); +} + +static void cb_ntscmode(Fl_Widget *w, long) { + conf.video_ntsc_mode = ((Fl_Choice*)w)->value(); + fltkui_resize(); +} + +static void cb_xbrrounding(Fl_Widget *w, long) { + conf.video_xbr_corner_rounding = ((Fl_Choice*)w)->value(); + video_init(); + video_toggle_filterupdate(); +} + +static void cb_palettemode(Fl_Widget *w, long) { + conf.video_palette_mode = ((Fl_Choice*)w)->value(); + video_init(); +} + +static void cb_decoder(Fl_Widget *w, long) { + conf.video_decoder = ((Fl_Choice*)w)->value(); + video_init(); +} + +static void cb_brightness(Fl_Widget *w, long) { + conf.video_brightness = ((Fl_Valuator*)w)->value(); + video_init(); +} + +static void cb_saturation(Fl_Widget *w, long) { + conf.video_saturation = ((Fl_Valuator*)w)->value(); + video_init(); +} + +static void cb_contrast(Fl_Widget *w, long) { + conf.video_contrast = ((Fl_Valuator*)w)->value(); + video_init(); +} + +static void cb_hue(Fl_Widget *w, long) { + conf.video_hue = ((Fl_Valuator*)w)->value(); + video_init(); +} + +static void cb_xbrpixblend(Fl_Widget *w, long) { + conf.video_xbr_pixel_blending = ((Fl_Check_Button*)w)->value(); + video_init(); + video_toggle_filterupdate(); +} + +static void cb_linearfilter(Fl_Widget *w, long) { + conf.video_linear_filter = ((Fl_Check_Button*)w)->value(); + video_init(); +} + +static void cb_tvaspect(Fl_Widget *w, long) { + conf.video_tv_aspect = ((Fl_Check_Button*)w)->value(); + fltkui_resize(); +} + +static void cb_unmask_overscan(Fl_Widget *w, long) { + conf.video_unmask_overscan = ((Fl_Check_Button*)w)->value(); + fltkui_resize(); +} + +static void cb_unlimited_sprites(Fl_Widget *w, long) { + conf.video_unlimited_sprites = ((Fl_Check_Button*)w)->value(); +} + +static void cb_samplerate(Fl_Widget *w, long) { + switch (((Fl_Choice*)w)->value()) { + case 0: conf.audio_sample_rate = 11025; break; + case 1: conf.audio_sample_rate = 22050; break; + case 2: conf.audio_sample_rate = 44100; break; + case 3: conf.audio_sample_rate = 48000; break; + case 4: conf.audio_sample_rate = 96000; break; + default: conf.audio_sample_rate = 48000; break; + } + + if (nst_playing()) { + nst_pause(); + nst_play(); + } +} + +static void cb_dials() { + dial_vall->value(conf.audio_volume); + dial_vsq1->value(conf.audio_vol_sq1); + dial_vsq2->value(conf.audio_vol_sq2); + dial_vtri->value(conf.audio_vol_tri); + dial_vnoise->value(conf.audio_vol_noise); + dial_vdpcm->value(conf.audio_vol_dpcm); + dial_vfds->value(conf.audio_vol_fds); + dial_vmmc5->value(conf.audio_vol_mmc5); + dial_vvrc6->value(conf.audio_vol_vrc6); + dial_vvrc7->value(conf.audio_vol_vrc7); + dial_vn163->value(conf.audio_vol_n163); + dial_vs5b->value(conf.audio_vol_s5b); +} + +static void cb_volume(Fl_Widget *w, long adj) { + Fl_Dial *dial = (Fl_Dial*)w; + + switch (adj) { + case 0: + conf.audio_volume = (int)dial->value(); + conf.audio_vol_sq1 = conf.audio_vol_sq2 = conf.audio_vol_tri = conf.audio_vol_noise = + conf.audio_vol_dpcm = conf.audio_vol_fds = conf.audio_vol_mmc5 = conf.audio_vol_vrc6 = + conf.audio_vol_vrc7 = conf.audio_vol_n163 = conf.audio_vol_s5b = conf.audio_volume; + break; + case 1: conf.audio_vol_sq1 = (int)dial->value(); break; + case 2: conf.audio_vol_sq2 = (int)dial->value(); break; + case 3: conf.audio_vol_tri = (int)dial->value(); break; + case 4: conf.audio_vol_noise = (int)dial->value(); break; + case 5: conf.audio_vol_dpcm = (int)dial->value(); break; + case 6: conf.audio_vol_fds = (int)dial->value(); break; + case 7: conf.audio_vol_mmc5 = (int)dial->value(); break; + case 8: conf.audio_vol_vrc6 = (int)dial->value(); break; + case 9: conf.audio_vol_vrc7 = (int)dial->value(); break; + case 10: conf.audio_vol_n163 = (int)dial->value(); break; + case 11: conf.audio_vol_s5b = (int)dial->value(); break; + } + + audio_adj_volume(); + cb_dials(); + +} + +static void cb_stereo(Fl_Widget *w, long) { + conf.audio_stereo = ((Fl_Check_Button*)w)->value(); + + if (nst_playing()) { + nst_pause(); + nst_play(); + } +} + +int NstInputConfWindow::handle(int e) { + switch (e) { + case FL_KEYUP: + fltkui_input_conf_set(Fl::event_key(), player, btn); + this->hide(); + this->set_non_modal(); + break; + } + + return Fl_Double_Window::handle(e); +} + +static void cb_icfg(Fl_Widget *w, long btn) { + icfg->set_modal(); + icfg->btn = btn; + icfg->text->label(icfg_labels[btn]); + icfg->show(); + + if (icfg->device == 1) { + nstsdl_input_conf_button(icfg->player, btn); + icfg->hide(); + icfg->set_non_modal(); + } +} + +static void cb_player(Fl_Widget *w, long) { + icfg->player = ((Fl_Choice*)w)->value(); +} + +static void cb_idevice(Fl_Widget *w, long) { + icfg->device = ((Fl_Choice*)w)->value(); +} + +static void cb_turbopulse(Fl_Widget *w, long) { + conf.timing_turbopulse = ((Fl_Valuator*)w)->value(); +} + +static void cb_default_system(Fl_Widget *w, long) { + conf.misc_default_system = ((Fl_Choice*)w)->value(); +} + +static void cb_power_state(Fl_Widget *w, long) { + conf.misc_power_state = ((Fl_Choice*)w)->value(); +} + +static void cb_ffspeed(Fl_Widget *w, long) { + conf.timing_ffspeed = ((Fl_Valuator*)w)->value(); +} + +static void cb_soft_patching(Fl_Widget *w, long) { + conf.misc_soft_patching = ((Fl_Check_Button*)w)->value(); +} + +static void cb_genie_distortion(Fl_Widget *w, long) { + conf.misc_genie_distortion = ((Fl_Check_Button*)w)->value(); +} + +static void cb_disable_cursor(Fl_Widget *w, long) { + conf.misc_disable_cursor = ((Fl_Check_Button*)w)->value(); +} + +static void cb_disable_cursor_special(Fl_Widget *w, long) { + conf.misc_disable_cursor_special = ((Fl_Check_Button*)w)->value(); +} + +static void cb_ok(Fl_Widget *w, long) { + w->parent()->hide(); +} + +void NstConfWindow::populate() { + Fl_Tabs *tabs = new Fl_Tabs(10, 5, 380, 360); + + Fl_Group *vtab = new Fl_Group(10, 30, 380, 360, "&Video"); + + Fl_Choice *ch_filter = new Fl_Choice(20, 55, 160, 25, "Filter"); + ch_filter->align(FL_ALIGN_TOP_LEFT); + ch_filter->add("None"); + ch_filter->add("NTSC"); + ch_filter->add("xBR"); + ch_filter->add("HqX"); + ch_filter->add("2XSaI"); + ch_filter->add("ScaleX"); + ch_filter->value(conf.video_filter); + ch_filter->callback(cb_filter); + + Fl_Choice *ch_scale = new Fl_Choice(200, 55, 160, 25, "Scale Factor"); + ch_scale->align(FL_ALIGN_TOP_LEFT); + ch_scale->add("1x"); + ch_scale->add("2x"); + ch_scale->add("3x"); + ch_scale->add("4x"); + ch_scale->add("5x"); + ch_scale->add("6x"); + ch_scale->add("7x"); + ch_scale->add("8x"); + ch_scale->value(conf.video_scale_factor - 1); + ch_scale->callback(cb_scale); + + Fl_Choice *ch_ntscmode = new Fl_Choice(20, 105, 160, 25, "NTSC Mode"); + ch_ntscmode->align(FL_ALIGN_TOP_LEFT); + ch_ntscmode->add("Composite"); + ch_ntscmode->add("S-Video"); + ch_ntscmode->add("RGB"); + ch_ntscmode->add("Monochrome"); + ch_ntscmode->add("Custom"); + ch_ntscmode->value(conf.video_ntsc_mode); + ch_ntscmode->callback(cb_ntscmode); + + Fl_Choice *ch_xbrrounding = new Fl_Choice(200, 105, 160, 25, "xBR Corner Rounding"); + ch_xbrrounding->align(FL_ALIGN_TOP_LEFT); + ch_xbrrounding->add("None"); + ch_xbrrounding->add("Some"); + ch_xbrrounding->add("All"); + ch_xbrrounding->value(conf.video_xbr_corner_rounding); + ch_xbrrounding->callback(cb_xbrrounding); + + Fl_Choice *ch_palettemode = new Fl_Choice(20, 155, 160, 25, "Palette Mode"); + ch_palettemode->align(FL_ALIGN_TOP_LEFT); + ch_palettemode->add("YUV"); + ch_palettemode->add("RGB"); + ch_palettemode->add("Custom"); + ch_palettemode->value(conf.video_palette_mode); + ch_palettemode->callback(cb_palettemode); + + Fl_Choice *ch_decoder = new Fl_Choice(200, 155, 160, 25, "YUV Decoder"); + ch_decoder->align(FL_ALIGN_TOP_LEFT); + ch_decoder->add("Consumer"); + ch_decoder->add("Canonical"); + ch_decoder->add("Alternative"); + ch_decoder->value(conf.video_decoder); + ch_decoder->callback(cb_decoder); + + Fl_Hor_Value_Slider *sld_brightness = new Fl_Hor_Value_Slider(20, 210, 160, 25, "Brightness"); + sld_brightness->align(FL_ALIGN_TOP_LEFT); + sld_brightness->bounds(-100, 100); + sld_brightness->box(FL_FLAT_BOX); + sld_brightness->callback(cb_brightness); + sld_brightness->step(1); + sld_brightness->selection_color(NstGreen); + sld_brightness->type(FL_HOR_NICE_SLIDER); + sld_brightness->value(conf.video_brightness); + + Fl_Hor_Value_Slider *sld_saturation = new Fl_Hor_Value_Slider(20, 250, 160, 25, "Saturation"); + sld_saturation->align(FL_ALIGN_TOP_LEFT); + sld_saturation->bounds(-100, 100); + sld_saturation->box(FL_FLAT_BOX); + sld_saturation->callback(cb_saturation); + sld_saturation->step(1); + sld_saturation->selection_color(NstGreen); + sld_saturation->type(FL_HOR_NICE_SLIDER); + sld_saturation->value(conf.video_saturation); + + Fl_Hor_Value_Slider *sld_contrast = new Fl_Hor_Value_Slider(20, 290, 160, 25, "Contrast"); + sld_contrast->align(FL_ALIGN_TOP_LEFT); + sld_contrast->bounds(-100, 100); + sld_contrast->box(FL_FLAT_BOX); + sld_contrast->callback(cb_contrast); + sld_contrast->step(1); + sld_contrast->selection_color(NstGreen); + sld_contrast->type(FL_HOR_NICE_SLIDER); + sld_contrast->value(conf.video_contrast); + + Fl_Hor_Value_Slider *sld_hue = new Fl_Hor_Value_Slider(20, 330, 160, 25, "Hue"); + sld_hue->align(FL_ALIGN_TOP_LEFT); + sld_hue->bounds(-45, 45); + sld_hue->box(FL_FLAT_BOX); + sld_hue->callback(cb_hue); + sld_hue->step(1); + sld_hue->selection_color(NstGreen); + sld_hue->type(FL_HOR_NICE_SLIDER); + sld_hue->value(conf.video_hue); + + Fl_Check_Button *chk_xbrpixblend = new Fl_Check_Button(200, 210, 160, 25, "xBR Pixel Blending"); + chk_xbrpixblend->value(conf.video_xbr_pixel_blending); + chk_xbrpixblend->callback(cb_xbrpixblend); + + Fl_Check_Button *chk_linearfilter = new Fl_Check_Button(200, 235, 160, 25, "Linear Filter"); + chk_linearfilter->value(conf.video_linear_filter); + chk_linearfilter->callback(cb_linearfilter); + + Fl_Check_Button *chk_tvaspect = new Fl_Check_Button(200, 260, 160, 25, "TV Aspect Ratio"); + chk_tvaspect->value(conf.video_tv_aspect); + chk_tvaspect->callback(cb_tvaspect); + + Fl_Check_Button *chk_unmask_overscan = new Fl_Check_Button(200, 285, 160, 25, "Unmask Overscan"); + chk_unmask_overscan->value(conf.video_unmask_overscan); + chk_unmask_overscan->callback(cb_unmask_overscan); + + Fl_Check_Button *chk_unlimited_sprites = new Fl_Check_Button(200, 310, 160, 25, "Unlimited Sprites"); + chk_unlimited_sprites->value(conf.video_unlimited_sprites); + chk_unlimited_sprites->callback(cb_unlimited_sprites); + + vtab->end(); + + Fl_Group *atab = new Fl_Group(10, 30, 380, 360, "&Audio"); + + Fl_Choice *ch_samplerate = new Fl_Choice(20, 55, 160, 25, "Sample Rate"); + ch_samplerate->align(FL_ALIGN_TOP_LEFT); + ch_samplerate->add("11025Hz"); + ch_samplerate->add("22050Hz"); + ch_samplerate->add("44100Hz"); + ch_samplerate->add("48000Hz"); + ch_samplerate->add("96000Hz"); + switch (conf.audio_sample_rate) { + case 11025: ch_samplerate->value(0); break; + case 22050: ch_samplerate->value(1); break; + case 44100: ch_samplerate->value(2); break; + case 48000: ch_samplerate->value(3); break; + case 96000: ch_samplerate->value(4); break; + default: ch_samplerate->value(3); break; + } + ch_samplerate->callback(cb_samplerate); + + Fl_Check_Button *chk_stereo = new Fl_Check_Button(200, 55, 160, 25, "Stereo"); + chk_stereo->value(conf.audio_stereo); + chk_stereo->callback(cb_stereo); + + dial_vall = new Fl_Dial(20, 100, 100, 100, "All"); + dial_vall->bounds(0, 100); + dial_vall->step(1); + dial_vall->color(NstPurple); + dial_vall->selection_color(NstGreen); + dial_vall->callback(cb_volume, 0); + dial_vall->value(conf.audio_volume); + + dial_vsq1 = new Fl_Dial(130, 115, 40, 40, "SQ1"); + dial_vsq1->bounds(0, 100); + dial_vsq1->step(1); + dial_vsq1->color(NstGreen); + dial_vsq1->selection_color(NstPurple); + dial_vsq1->callback(cb_volume, 1); + dial_vsq1->value(conf.audio_vol_sq1); + + dial_vsq2 = new Fl_Dial(180, 115, 40, 40, "SQ2"); + dial_vsq2->bounds(0, 100); + dial_vsq2->step(1); + dial_vsq2->color(NstGreen); + dial_vsq2->selection_color(NstPurple); + dial_vsq2->callback(cb_volume, 2); + dial_vsq2->value(conf.audio_vol_sq2); + + dial_vtri = new Fl_Dial(230, 115, 40, 40, "TRI"); + dial_vtri->bounds(0, 100); + dial_vtri->step(1); + dial_vtri->color(NstGreen); + dial_vtri->selection_color(NstPurple); + dial_vtri->callback(cb_volume, 3); + dial_vtri->value(conf.audio_vol_tri); + + dial_vnoise = new Fl_Dial(280, 115, 40, 40, "NOISE"); + dial_vnoise->bounds(0, 100); + dial_vnoise->step(1); + dial_vnoise->color(NstGreen); + dial_vnoise->selection_color(NstPurple); + dial_vnoise->callback(cb_volume, 4); + dial_vnoise->value(conf.audio_vol_noise); + + dial_vdpcm = new Fl_Dial(330, 115, 40, 40, "DPCM"); + dial_vdpcm->bounds(0, 100); + dial_vdpcm->step(1); + dial_vdpcm->color(NstGreen); + dial_vdpcm->selection_color(NstPurple); + dial_vdpcm->callback(cb_volume, 5); + dial_vdpcm->value(conf.audio_vol_dpcm); + + dial_vfds = new Fl_Dial(80, 225, 40, 40, "FDS"); + dial_vfds->bounds(0, 100); + dial_vfds->step(1); + dial_vfds->color(NstGreen); + dial_vfds->selection_color(NstPurple); + dial_vfds->callback(cb_volume, 6); + dial_vfds->value(conf.audio_vol_fds); + + dial_vmmc5 = new Fl_Dial(130, 225, 40, 40, "MMC5"); + dial_vmmc5->bounds(0, 100); + dial_vmmc5->step(1); + dial_vmmc5->color(NstGreen); + dial_vmmc5->selection_color(NstPurple); + dial_vmmc5->callback(cb_volume, 7); + dial_vmmc5->value(conf.audio_vol_mmc5); + + dial_vvrc6 = new Fl_Dial(180, 225, 40, 40, "VRC6"); + dial_vvrc6->bounds(0, 100); + dial_vvrc6->step(1); + dial_vvrc6->color(NstGreen); + dial_vvrc6->selection_color(NstPurple); + dial_vvrc6->callback(cb_volume, 8); + dial_vvrc6->value(conf.audio_vol_vrc6); + + dial_vvrc7 = new Fl_Dial(230, 225, 40, 40, "VRC7"); + dial_vvrc7->bounds(0, 100); + dial_vvrc7->step(1); + dial_vvrc7->color(NstGreen); + dial_vvrc7->selection_color(NstPurple); + dial_vvrc7->callback(cb_volume, 9); + dial_vvrc7->value(conf.audio_vol_vrc7); + + dial_vn163 = new Fl_Dial(280, 225, 40, 40, "N163"); + dial_vn163->bounds(0, 100); + dial_vn163->step(1); + dial_vn163->color(NstGreen); + dial_vn163->selection_color(NstPurple); + dial_vn163->callback(cb_volume, 10); + dial_vn163->value(conf.audio_vol_n163); + + dial_vs5b = new Fl_Dial(330, 225, 40, 40, "S5B"); + dial_vs5b->bounds(0, 100); + dial_vs5b->step(1); + dial_vs5b->color(NstGreen); + dial_vs5b->selection_color(NstPurple); + dial_vs5b->callback(cb_volume, 11); + dial_vs5b->value(conf.audio_vol_s5b); + + atab->end(); + + Fl_Group *itab = new Fl_Group(10, 30, 380, 360, "&Input"); + + Fl_Button *btn_icfg_u = new Fl_Button(70, 55, 30, 24, "U"); + btn_icfg_u->callback(cb_icfg, 0); + btn_icfg_u->color(NstBlueGrey); + btn_icfg_u->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_d = new Fl_Button(70, 115, 30, 24, "D"); + btn_icfg_d->callback(cb_icfg, 1); + btn_icfg_d->color(NstBlueGrey); + btn_icfg_d->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_l = new Fl_Button(30, 85, 30, 24, "L"); + btn_icfg_l->callback(cb_icfg, 2); + btn_icfg_l->color(NstBlueGrey); + btn_icfg_l->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_r = new Fl_Button(110, 85, 30, 24, "R"); + btn_icfg_r->callback(cb_icfg, 3); + btn_icfg_r->color(NstBlueGrey); + btn_icfg_r->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_slct = new Fl_Button(150, 85, 60, 24, "Select"); + btn_icfg_slct->callback(cb_icfg, 4); + btn_icfg_slct->color(NstGreen); + btn_icfg_slct->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_strt = new Fl_Button(220, 85, 60, 24, "Start"); + btn_icfg_strt->callback(cb_icfg, 5); + btn_icfg_strt->color(NstGreen); + btn_icfg_strt->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_a = new Fl_Button(330, 100, 30, 24, "A"); + btn_icfg_a->callback(cb_icfg, 6); + btn_icfg_a->color(NstRed); + btn_icfg_a->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_b = new Fl_Button(290, 100, 30, 24, "B"); + btn_icfg_b->callback(cb_icfg, 7); + btn_icfg_b->color(NstRed); + btn_icfg_b->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_ta = new Fl_Button(330, 65, 30, 24, "TA"); + btn_icfg_ta->callback(cb_icfg, 8); + btn_icfg_ta->color(NstRed); + btn_icfg_ta->labelcolor(NstLightGrey); + + Fl_Button *btn_icfg_tb = new Fl_Button(290, 65, 30, 24, "TB"); + btn_icfg_tb->callback(cb_icfg, 9); + btn_icfg_tb->color(NstRed); + btn_icfg_tb->labelcolor(NstLightGrey); + + icfg = new NstInputConfWindow(110, 55, 170, 24, "Input Config"); + icfg->color(NstPurple); + icfg->hide(); + icfg->text = new Fl_Box(0, 0, 0, 24); + icfg->text->align(FL_ALIGN_RIGHT); + icfg->text->labelcolor(NstLightGrey); + icfg->player = icfg->btn = icfg->device = 0; + icfg->end(); + + Fl_Choice *ch_player = new Fl_Choice(20, 180, 160, 25, "Player"); + ch_player->align(FL_ALIGN_TOP_LEFT); + ch_player->add("Player 1"); + ch_player->add("Player 2"); + ch_player->value(0); + ch_player->callback(cb_player); + + Fl_Choice *ch_idevice = new Fl_Choice(20, 230, 160, 25, "Input Device"); + ch_idevice->align(FL_ALIGN_TOP_LEFT); + ch_idevice->add("Keyboard"); + ch_idevice->add("Joystick"); + ch_idevice->value(0); + ch_idevice->callback(cb_idevice); + + Fl_Hor_Value_Slider *sld_turbopulse = new Fl_Hor_Value_Slider(200, 180, 160, 25, "Turbo Pulse"); + sld_turbopulse->align(FL_ALIGN_TOP_LEFT); + sld_turbopulse->bounds(2, 9); + sld_turbopulse->box(FL_FLAT_BOX); + sld_turbopulse->callback(cb_turbopulse); + sld_turbopulse->step(1); + sld_turbopulse->selection_color(NstGreen); + sld_turbopulse->type(FL_HOR_NICE_SLIDER); + sld_turbopulse->value(conf.timing_turbopulse); + + itab->end(); + + Fl_Group *mtab = new Fl_Group(10, 30, 380, 360, "&Misc"); + + Fl_Choice *ch_default_system = new Fl_Choice(20, 55, 160, 25, "Default System"); + ch_default_system->align(FL_ALIGN_TOP_LEFT); + ch_default_system->add("Auto"); + ch_default_system->add("NTSC"); + ch_default_system->add("PAL"); + ch_default_system->add("Famicom"); + ch_default_system->add("Dendy"); + ch_default_system->value(conf.misc_default_system); + ch_default_system->callback(cb_default_system); + + Fl_Choice *ch_power_state = new Fl_Choice(20, 105, 160, 25, "RAM Power-on State"); + ch_power_state->align(FL_ALIGN_TOP_LEFT); + ch_power_state->add("0x00"); + ch_power_state->add("0xFF"); + ch_power_state->add("Random"); + ch_power_state->value(conf.misc_power_state); + ch_power_state->callback(cb_power_state); + + Fl_Hor_Value_Slider *sld_ffspeed = new Fl_Hor_Value_Slider(20, 160, 160, 25, "Fast-Forward Speed"); + sld_ffspeed->align(FL_ALIGN_TOP_LEFT); + sld_ffspeed->bounds(1, 8); + sld_ffspeed->box(FL_FLAT_BOX); + sld_ffspeed->callback(cb_ffspeed); + sld_ffspeed->step(1); + sld_ffspeed->selection_color(NstGreen); + sld_ffspeed->type(FL_HOR_NICE_SLIDER); + sld_ffspeed->value(conf.timing_ffspeed); + + Fl_Check_Button *chk_soft_patching = new Fl_Check_Button(200, 55, 185, 25, "Auto Soft Patching"); + chk_soft_patching->value(conf.misc_soft_patching); + chk_soft_patching->callback(cb_soft_patching); + + Fl_Check_Button *chk_genie_distortion = new Fl_Check_Button(200, 80, 185, 25, "Genie Sound Distortion"); + chk_genie_distortion->value(conf.misc_genie_distortion); + chk_genie_distortion->callback(cb_genie_distortion); + + Fl_Check_Button *chk_disable_cursor = new Fl_Check_Button(200, 105, 185, 25, "Disable Cursor"); + chk_disable_cursor->value(conf.misc_disable_cursor); + chk_disable_cursor->callback(cb_disable_cursor); + + Fl_Check_Button *chk_disable_cursor_special = new Fl_Check_Button(200, 130, 185, 25, "Disable Special Cursor"); + chk_disable_cursor_special->value(conf.misc_disable_cursor_special); + chk_disable_cursor_special->callback(cb_disable_cursor_special); + + mtab->end(); + + tabs->end(); + + Fl_Button *btn_ok = new Fl_Button(350, 370, 40, 24, "&OK"); + btn_ok->callback(cb_ok, 0); + this->end(); +} diff --git a/source/fltkui/fltkui_config.h b/source/fltkui/fltkui_config.h new file mode 100644 index 0000000..6f6e30b --- /dev/null +++ b/source/fltkui/fltkui_config.h @@ -0,0 +1,31 @@ +#ifndef _FLTKUI_CONFIG_H_ +#define _FLTKUI_CONFIG_H_ + +class NstConfWindow : public Fl_Double_Window { +private: + bool icfg_running; + +public: + NstConfWindow(int w, int h, const char* t) : Fl_Double_Window(w, h, t) { } + virtual ~NstConfWindow() { } + + void populate(); +}; + +class NstInputConfWindow : public Fl_Double_Window { +private: + int handle(int e); + +public: + NstInputConfWindow(int x, int y, int w, int h, const char* t) : Fl_Double_Window(x, y, w, h, t) { + box(FL_DOWN_BOX); + } + virtual ~NstInputConfWindow() { } + + Fl_Box *text; + int btn; + int player; + int device; // Keyboard or Joystick +}; + +#endif diff --git a/source/common/font.h b/source/fltkui/font.h similarity index 100% rename from source/common/font.h rename to source/fltkui/font.h diff --git a/source/common/homebrew.cpp b/source/fltkui/homebrew.cpp similarity index 100% rename from source/common/homebrew.cpp rename to source/fltkui/homebrew.cpp diff --git a/source/common/homebrew.h b/source/fltkui/homebrew.h similarity index 100% rename from source/common/homebrew.h rename to source/fltkui/homebrew.h diff --git a/source/common/ini.cpp b/source/fltkui/ini.cpp similarity index 100% rename from source/common/ini.cpp rename to source/fltkui/ini.cpp diff --git a/source/common/ini.h b/source/fltkui/ini.h similarity index 100% rename from source/common/ini.h rename to source/fltkui/ini.h diff --git a/source/common/sdlinput.cpp b/source/fltkui/input.cpp similarity index 51% rename from source/common/sdlinput.cpp rename to source/fltkui/input.cpp index ab27baf..3062704 100644 --- a/source/common/sdlinput.cpp +++ b/source/fltkui/input.cpp @@ -1,42 +1,55 @@ /* * Nestopia UE - * - * Copyright (C) 2012-2018 R. Danbrook - * + * + * Copyright (C) 2012-2016 R. Danbrook + * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ -#include +#include + +#include +#include +#include #include -#include "gtkui/gtkui.h" #include "nstcommon.h" -#include "video.h" +#include "config.h" #include "input.h" - +#include "video.h" #include "ini.h" -#include "sdlinput.h" +#include "fltkui.h" static SDL_Joystick *joystick; gamepad_t player[NUMGAMEPADS]; -static inputsettings_t inputconf; +inputsettings_t inputconf; static char inputconfpath[256]; + +static turbo_t turbostate; +static turbo_t turbotoggle; + +extern Emulator emulator; +extern nstpaths_t nstpaths; + +extern Emulator emulator; +extern Input::Controllers *cNstPads; + extern int drawtext; static unsigned char nescodes[TOTALBUTTONS] = { @@ -62,22 +75,241 @@ static unsigned char nescodes[TOTALBUTTONS] = { Input::Controllers::Pad::B }; -extern Emulator emulator; -extern nstpaths_t nstpaths; +void nst_input_init() { + // Initialize input + char controller[32]; + + for (int i = 0; i < NUMGAMEPADS; i++) { + Input(emulator).AutoSelectController(i); + + switch(Input(emulator).GetConnectedController(i)) { + case Input::UNCONNECTED: + snprintf(controller, sizeof(controller), "%s", "Unconnected"); + break; + case Input::PAD1: + case Input::PAD2: + case Input::PAD3: + case Input::PAD4: + snprintf(controller, sizeof(controller), "%s", "Standard Pad"); + break; + case Input::ZAPPER: + snprintf(controller, sizeof(controller), "%s", "Zapper"); + break; + case Input::PADDLE: + snprintf(controller, sizeof(controller), "%s", "Arkanoid Paddle"); + break; + case Input::POWERPAD: + snprintf(controller, sizeof(controller), "%s", "Power Pad"); + break; + case Input::POWERGLOVE: + snprintf(controller, sizeof(controller), "%s", "Power Glove"); + break; + case Input::MOUSE: + snprintf(controller, sizeof(controller), "%s", "Mouse"); + break; + case Input::ROB: + snprintf(controller, sizeof(controller), "%s", "R.O.B."); + break; + case Input::FAMILYTRAINER: + snprintf(controller, sizeof(controller), "%s", "Family Trainer"); + break; + case Input::FAMILYKEYBOARD: + snprintf(controller, sizeof(controller), "%s", "Family Keyboard"); + break; + case Input::SUBORKEYBOARD: + snprintf(controller, sizeof(controller), "%s", "Subor Keyboard"); + break; + case Input::DOREMIKKOKEYBOARD: + snprintf(controller, sizeof(controller), "%s", "Doremikko Keyboard"); + break; + case Input::HORITRACK: + snprintf(controller, sizeof(controller), "%s", "Hori Track"); + break; + case Input::PACHINKO: + snprintf(controller, sizeof(controller), "%s", "Pachinko"); + break; + case Input::OEKAKIDSTABLET: + snprintf(controller, sizeof(controller), "%s", "Oeka Kids Tablet"); + break; + case Input::KONAMIHYPERSHOT: + snprintf(controller, sizeof(controller), "%s", "Konami Hypershot"); + break; + case Input::BANDAIHYPERSHOT: + snprintf(controller, sizeof(controller), "%s", "Bandai Hypershot"); + break; + case Input::CRAZYCLIMBER: + snprintf(controller, sizeof(controller), "%s", "Crazy Climber"); + break; + case Input::MAHJONG: + snprintf(controller, sizeof(controller), "%s", "Mahjong"); + break; + case Input::EXCITINGBOXING: + snprintf(controller, sizeof(controller), "%s", "Exciting Boxing"); + break; + case Input::TOPRIDER: + snprintf(controller, sizeof(controller), "%s", "Top Rider"); + break; + case Input::POKKUNMOGURAA: + snprintf(controller, sizeof(controller), "%s", "Pokkun Moguraa"); + break; + case Input::PARTYTAP: + snprintf(controller, sizeof(controller), "%s", "PartyTap"); + break; + case Input::TURBOFILE: + snprintf(controller, sizeof(controller), "%s", "Turbo File"); + break; + case Input::BARCODEWORLD: + snprintf(controller, sizeof(controller), "%s", "Barcode World"); + break; + default: + snprintf(controller, sizeof(controller), "%s", "Unknown"); + break; + } + + fprintf(stderr, "Port %d: %s\n", i + 1, controller); + } +} + +void nst_input_inject(Input::Controllers *controllers, nesinput_t input) { + // Insert the input signal into the NES + if(controllers == NULL) { return; } + + if (input.pressed) { + controllers->pad[input.player].buttons |= input.nescode; + + if (input.turboa) { input.player == 0 ? turbostate.p1a = true : turbostate.p2a = true; } + if (input.turbob) { input.player == 0 ? turbostate.p1b = true : turbostate.p2b = true; } + } + else { + controllers->pad[input.player].buttons &= ~input.nescode; + + if (input.turboa) { input.player == 0 ? turbostate.p1a = false : turbostate.p2a = false; } + if (input.turbob) { input.player == 0 ? turbostate.p1b = false : turbostate.p2b = false; } + } +} + +void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y) { + // Insert input signal for Zappers + if(controllers == NULL) { return; } + + double xaspect; + double yaspect; + + if (s) { + // Get X coords + if (conf.video_filter == 1) { // NTSC + xaspect = (double)(Video::Output::WIDTH) / (double)(Video::Output::NTSC_WIDTH / 2); + } + else if (conf.video_tv_aspect) { + xaspect = (double)(Video::Output::WIDTH) / (double)(TV_WIDTH); + } + else { xaspect = 1.0; } + + dimensions_t rendersize = nst_video_get_dimensions_render(); + dimensions_t screensize = nst_video_get_dimensions_screen(); + + // Calculate fullscreen X coords + if (conf.video_fullscreen) { + if (conf.video_stretch_aspect) { + xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(screensize.w); + } + else { + // Remove the same amount of pixels as the black area to the left of the screen + x -= screensize.w / 2.0f - rendersize.w / 2.0f; + xaspect = (double)(conf.video_scale_factor * Video::Output::WIDTH) / (double)(rendersize.w); + } + } + controllers->zapper.x = (int)(x * xaspect) / conf.video_scale_factor; + + // Get Y coords + if (conf.video_unmask_overscan) { + controllers->zapper.y = y / conf.video_scale_factor; + } + else { + controllers->zapper.y = (y + OVERSCAN_TOP * conf.video_scale_factor) / conf.video_scale_factor; + } + + // Calculate fullscreen Y coords + if (conf.video_fullscreen) { + yaspect = (double)(conf.video_scale_factor * Video::Output::HEIGHT) / (double)(screensize.h); + controllers->zapper.y = (y * yaspect) / conf.video_scale_factor; + } + + // Offscreen + if (b != 1) { controllers->zapper.x = ~1U; } + + controllers->zapper.fire = true; + } + else { controllers->zapper.fire = false; } +} + +void nst_input_turbo_init() { + // Initialize the turbo button states + turbostate.p1a = turbotoggle.p1a = 0; + turbostate.p1b = turbotoggle.p1b = 0; + turbostate.p2a = turbotoggle.p2a = 0; + turbostate.p2b = turbotoggle.p2b = 0; +} + +void nst_input_turbo_pulse(Input::Controllers *controllers) { + // Pulse the turbo buttons if they're pressed + if (turbostate.p1a) { + turbotoggle.p1a++; + if (turbotoggle.p1a >= conf.timing_turbopulse) { + turbotoggle.p1a = 0; + controllers->pad[0].buttons &= ~Input::Controllers::Pad::A; + } + else { controllers->pad[0].buttons |= Input::Controllers::Pad::A; } + } + + if (turbostate.p1b) { + turbotoggle.p1b++; + if (turbotoggle.p1b >= conf.timing_turbopulse) { + turbotoggle.p1b = 0; + controllers->pad[0].buttons &= ~Input::Controllers::Pad::B; + } + else { controllers->pad[0].buttons |= Input::Controllers::Pad::B; } + } + + if (turbostate.p2a) { + turbotoggle.p2a++; + if (turbotoggle.p2a >= conf.timing_turbopulse) { + turbotoggle.p2a = 0; + controllers->pad[1].buttons &= ~Input::Controllers::Pad::A; + } + else { controllers->pad[1].buttons |= Input::Controllers::Pad::A; } + } + + if (turbostate.p2b) { + turbotoggle.p2b++; + if (turbotoggle.p2b >= conf.timing_turbopulse) { + turbotoggle.p2b = 0; + controllers->pad[1].buttons &= ~Input::Controllers::Pad::B; + } + else { controllers->pad[1].buttons |= Input::Controllers::Pad::B; } + } +} + +int nst_input_zapper_present() { + // Check if a Zapper is presently connected + if (Input(emulator).GetConnectedController(0) == Input::ZAPPER || + Input(emulator).GetConnectedController(1) == Input::ZAPPER) { + return 1; + } + else { return 0; } +} void nstsdl_input_joysticks_detect() { // Initialize any joysticks fprintf(stderr, "%i joystick(s) found:\n", SDL_NumJoysticks()); - - int i; - - for (i = 0; i < SDL_NumJoysticks(); i++) { + + for (int i = 0; i < SDL_NumJoysticks(); i++) { joystick = SDL_JoystickOpen(i); printf("%s\n", SDL_JoystickName(joystick)); } SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); - + nst_input_turbo_init(); } @@ -94,25 +326,25 @@ int nstsdl_input_checksign(int axisvalue) { void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event event) { // Match NES buttons to joystick input int j; - + nesinput_t input, reverseinput; - + input.nescode = 0x00; input.player = 0; input.pressed = 0; input.turboa = 0; input.turbob = 0; - + // This is for releasing opposing directions reverseinput.nescode = 0x00; reverseinput.player = 0; reverseinput.pressed = 0; - + SDL_Event buttons[TOTALBUTTONS] = { player[0].ju, player[0].jd, player[0].jl, player[0].jr, player[0].jselect, player[0].jstart, player[0].ja, player[0].jb, player[0].jta, player[0].jtb, - + player[1].ju, player[1].jd, player[1].jl, player[1].jr, player[1].jselect, player[1].jstart, player[1].ja, player[1].jb, player[1].jta, player[1].jtb @@ -137,7 +369,7 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even } } input.pressed = event.jbutton.state; - + // Rewind if (event.jbutton.button == rw[0].jbutton.button && event.jbutton.which == rw[0].jbutton.which) { nst_set_rewind(0); } if (event.jbutton.button == rw[1].jbutton.button && event.jbutton.which == rw[1].jbutton.which) { nst_set_rewind(1); } @@ -149,10 +381,10 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even case SDL_JOYHATMOTION: unsigned char hu, hd, hl, hr; hu = hd = hl = hr = 0; - + // Start a loop to check if input matches for (j = 0; j < TOTALBUTTONS; j++) { - + // Read value of each hat direction on current hat if (buttons[j].type == event.type && buttons[j].jhat.which == event.jhat.which @@ -164,9 +396,9 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even else if (buttons[j].jhat.value == SDL_HAT_DOWN) { hd = nescodes[j]; } else if (buttons[j].jhat.value == SDL_HAT_LEFT) { hl = nescodes[j]; } else if (buttons[j].jhat.value == SDL_HAT_RIGHT) { hr = nescodes[j]; } - + input.pressed = 1; - + // Make sure opposing hat positions are turned off switch(event.jhat.value) { case SDL_HAT_UP: @@ -212,7 +444,7 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even // Handle axis input case SDL_JOYAXISMOTION: for (j = 0; j < TOTALBUTTONS; j++) { - + int nvalue = nstsdl_input_checksign(event.jaxis.value); if (buttons[j].jaxis.axis == event.jaxis.axis @@ -221,7 +453,7 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even && buttons[j].jaxis.value == nvalue) { if (j >= NUMBUTTONS) { input.player = reverseinput.player = 1; } - + input.nescode = nescodes[j]; } @@ -229,23 +461,50 @@ void nstsdl_input_match_joystick(Input::Controllers *controllers, SDL_Event even && buttons[j].jaxis.which == event.jaxis.which && buttons[j].jaxis.type == event.jaxis.type && buttons[j].jaxis.value == !nvalue) { - + reverseinput.nescode = nescodes[j]; } if (abs(event.jaxis.value) > DEADZONE) { input.pressed = 1; } } break; - + default: break; } - + nst_input_inject(controllers, reverseinput); nst_input_inject(controllers, input); } void nstsdl_input_conf_defaults() { // Set default input config + + inputconf.qsave1 = FL_F + 5; + inputconf.qsave2 = FL_F + 6; + inputconf.qload1 = FL_F + 7; + inputconf.qload2 = FL_F + 8; + inputconf.screenshot = FL_F + 9; + inputconf.fdsflip = FL_F + 3; + inputconf.fdsswitch = FL_F + 4; + inputconf.insertcoin1 = FL_F + 1; + inputconf.insertcoin2 = FL_F + 2; + inputconf.reset = FL_F + 12; + inputconf.ffspeed = '`'; + inputconf.rwstart = FL_BackSpace; + inputconf.rwstop = '\\'; + inputconf.fullscreen = 'f'; + + player[0].u = FL_Up; + player[0].d = FL_Down; + player[0].l = FL_Left; + player[0].r = FL_Right; + player[0].select = FL_Shift_R; + player[0].start = FL_Enter; + player[0].a = 'z'; + player[0].b = 'a'; + player[0].ta = 'x'; + player[0].tb = 's'; + player[0].ju = nstsdl_input_translate_string("j0h01"); player[0].jd = nstsdl_input_translate_string("j0h04"); player[0].jl = nstsdl_input_translate_string("j0h08"); @@ -256,12 +515,23 @@ void nstsdl_input_conf_defaults() { player[0].jb = nstsdl_input_translate_string("j0b0"); player[0].jta = nstsdl_input_translate_string("j0b2"); player[0].jtb = nstsdl_input_translate_string("j0b3"); - + player[0].rwstart = nstsdl_input_translate_string("j0b4"); player[0].rwstop = nstsdl_input_translate_string("j0b5"); player[0].softreset = nstsdl_input_translate_string("j0b99"); player[0].hardreset = nstsdl_input_translate_string("j0b99"); - + + player[1].u = 'i'; + player[1].d = 'j'; + player[1].l = 'k'; + player[1].r = 'l'; + player[1].select = FL_Shift_L; + player[1].start = FL_Control_L; + player[1].a = 'm'; + player[1].b = 'n'; + player[1].ta = 'b'; + player[1].tb = 'v'; + player[1].ju = nstsdl_input_translate_string("j1h01"); player[1].jd = nstsdl_input_translate_string("j1h04"); player[1].jl = nstsdl_input_translate_string("j1h08"); @@ -274,80 +544,78 @@ void nstsdl_input_conf_defaults() { player[1].jtb = nstsdl_input_translate_string("j1b3"); } -void nstsdl_input_conf_set(SDL_Event event, int type, int pnum, int counter) { +void fltkui_input_conf_set(int kval, int pnum, int bnum) { // Set an input item to what was requested by configuration process - if (type == 0) { // Keyboard - switch(counter) { - case 0: player[pnum].u = event.key.keysym.scancode; break; - case 1: player[pnum].d = event.key.keysym.scancode; break; - case 2: player[pnum].l = event.key.keysym.scancode; break; - case 3: player[pnum].r = event.key.keysym.scancode; break; - case 4: player[pnum].select = event.key.keysym.scancode; break; - case 5: player[pnum].start = event.key.keysym.scancode; break; - case 6: player[pnum].a = event.key.keysym.scancode; break; - case 7: player[pnum].b = event.key.keysym.scancode; break; - case 8: player[pnum].ta = event.key.keysym.scancode; break; - case 9: player[pnum].tb = event.key.keysym.scancode; break; - default: break; - } + switch (bnum) { + case 0: player[pnum].u = kval; break; + case 1: player[pnum].d = kval; break; + case 2: player[pnum].l = kval; break; + case 3: player[pnum].r = kval; break; + case 4: player[pnum].select = kval; break; + case 5: player[pnum].start = kval; break; + case 6: player[pnum].a = kval; break; + case 7: player[pnum].b = kval; break; + case 8: player[pnum].ta = kval; break; + case 9: player[pnum].tb = kval; break; + default: break; } - else if (type == 1) { // Joystick - switch(counter) { - case 0: player[pnum].ju = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 1: player[pnum].jd = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 2: player[pnum].jl = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 3: player[pnum].jr = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 4: player[pnum].jselect = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 5: player[pnum].jstart = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 6: player[pnum].ja = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 7: player[pnum].jb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 8: player[pnum].jta = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - case 9: player[pnum].jtb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; - default: break; - } +} + +void nstsdl_input_conf_set(SDL_Event event, int pnum, int bnum) { + // Set an input item to what was requested by configuration process + switch (bnum) { + case 0: player[pnum].ju = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 1: player[pnum].jd = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 2: player[pnum].jl = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 3: player[pnum].jr = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 4: player[pnum].jselect = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 5: player[pnum].jstart = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 6: player[pnum].ja = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 7: player[pnum].jb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 8: player[pnum].jta = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + case 9: player[pnum].jtb = nstsdl_input_translate_string(nstsdl_input_translate_event(event)); break; + default: break; } } static int nstsdl_input_config_match(void* user, const char* section, const char* name, const char* value) { // Match values from input config file and populate live config inputsettings_t* pconfig = (inputsettings_t*)user; - + // User Interface - if (MATCH("ui", "qsave1")) { pconfig->qsave1 = strdup(value); } - else if (MATCH("ui", "qsave2")) { pconfig->qsave2 = strdup(value); } - else if (MATCH("ui", "qload1")) { pconfig->qload1 = strdup(value); } - else if (MATCH("ui", "qload2")) { pconfig->qload2 = strdup(value); } - - else if (MATCH("ui", "screenshot")) { pconfig->screenshot = strdup(value); } - - else if (MATCH("ui", "fdsflip")) { pconfig->fdsflip = strdup(value); } - else if (MATCH("ui", "fdsswitch")) { pconfig->fdsswitch = strdup(value); } - - else if (MATCH("ui", "insertcoin1")) { pconfig->insertcoin1 = strdup(value); } - else if (MATCH("ui", "insertcoin2")) { pconfig->insertcoin2 = strdup(value); } - - else if (MATCH("ui", "reset")) { pconfig->reset = strdup(value); } - - else if (MATCH("ui", "ffspeed")) { pconfig->ffspeed = strdup(value); } - else if (MATCH("ui", "rwstart")) { pconfig->rwstart = strdup(value); } - else if (MATCH("ui", "rwstop")) { pconfig->rwstop = strdup(value); } - - else if (MATCH("ui", "fullscreen")) { pconfig->fullscreen = strdup(value); } - else if (MATCH("ui", "filter")) { pconfig->filter = strdup(value); } - else if (MATCH("ui", "scalefactor")) { pconfig->scalefactor = strdup(value); } - + if (MATCH("ui", "qsave1")) { pconfig->qsave1 = atoi(value); } + else if (MATCH("ui", "qsave2")) { pconfig->qsave2 = atoi(value); } + else if (MATCH("ui", "qload1")) { pconfig->qload1 = atoi(value); } + else if (MATCH("ui", "qload2")) { pconfig->qload2 = atoi(value); } + + else if (MATCH("ui", "screenshot")) { pconfig->screenshot = atoi(value); } + + else if (MATCH("ui", "fdsflip")) { pconfig->fdsflip = atoi(value); } + else if (MATCH("ui", "fdsswitch")) { pconfig->fdsswitch = atoi(value); } + + else if (MATCH("ui", "insertcoin1")) { pconfig->insertcoin1 = atoi(value); } + else if (MATCH("ui", "insertcoin2")) { pconfig->insertcoin2 = atoi(value); } + + else if (MATCH("ui", "reset")) { pconfig->reset = atoi(value); } + + else if (MATCH("ui", "ffspeed")) { pconfig->ffspeed = atoi(value); } + else if (MATCH("ui", "rwstart")) { pconfig->rwstart = atoi(value); } + else if (MATCH("ui", "rwstop")) { pconfig->rwstop = atoi(value); } + + else if (MATCH("ui", "fullscreen")) { pconfig->fullscreen = atoi(value); } + // Player 1 - else if (MATCH("gamepad1", "kb_u")) { pconfig->kb_p1u = strdup(value); } - else if (MATCH("gamepad1", "kb_d")) { pconfig->kb_p1d = strdup(value); } - else if (MATCH("gamepad1", "kb_l")) { pconfig->kb_p1l = strdup(value); } - else if (MATCH("gamepad1", "kb_r")) { pconfig->kb_p1r = strdup(value); } - else if (MATCH("gamepad1", "kb_select")) { pconfig->kb_p1select = strdup(value); } - else if (MATCH("gamepad1", "kb_start")) { pconfig->kb_p1start = strdup(value); } - else if (MATCH("gamepad1", "kb_a")) { pconfig->kb_p1a = strdup(value); } - else if (MATCH("gamepad1", "kb_b")) { pconfig->kb_p1b = strdup(value); } - else if (MATCH("gamepad1", "kb_ta")) { pconfig->kb_p1ta = strdup(value); } - else if (MATCH("gamepad1", "kb_tb")) { pconfig->kb_p1tb = strdup(value); } - + else if (MATCH("gamepad1", "kb_u")) { pconfig->kb_p1u = atoi(value); } + else if (MATCH("gamepad1", "kb_d")) { pconfig->kb_p1d = atoi(value); } + else if (MATCH("gamepad1", "kb_l")) { pconfig->kb_p1l = atoi(value); } + else if (MATCH("gamepad1", "kb_r")) { pconfig->kb_p1r = atoi(value); } + else if (MATCH("gamepad1", "kb_select")) { pconfig->kb_p1select = atoi(value); } + else if (MATCH("gamepad1", "kb_start")) { pconfig->kb_p1start = atoi(value); } + else if (MATCH("gamepad1", "kb_a")) { pconfig->kb_p1a = atoi(value); } + else if (MATCH("gamepad1", "kb_b")) { pconfig->kb_p1b = atoi(value); } + else if (MATCH("gamepad1", "kb_ta")) { pconfig->kb_p1ta = atoi(value); } + else if (MATCH("gamepad1", "kb_tb")) { pconfig->kb_p1tb = atoi(value); } + else if (MATCH("gamepad1", "js_u")) { pconfig->js_p1u = strdup(value); } else if (MATCH("gamepad1", "js_d")) { pconfig->js_p1d = strdup(value); } else if (MATCH("gamepad1", "js_l")) { pconfig->js_p1l = strdup(value); } @@ -358,7 +626,7 @@ static int nstsdl_input_config_match(void* user, const char* section, const char else if (MATCH("gamepad1", "js_b")) { pconfig->js_p1b = strdup(value); } else if (MATCH("gamepad1", "js_ta")) { pconfig->js_p1ta = strdup(value); } else if (MATCH("gamepad1", "js_tb")) { pconfig->js_p1tb = strdup(value); } - + else if (MATCH("gamepad1", "js_rwstart")) { pconfig->js_rwstart = strdup(value); } else if (MATCH("gamepad1", "js_rwstop")) { pconfig->js_rwstop = strdup(value); } @@ -366,17 +634,17 @@ static int nstsdl_input_config_match(void* user, const char* section, const char else if (MATCH("gamepad1", "js_hardreset")) { pconfig->js_hardreset = strdup(value); } // Player 2 - else if (MATCH("gamepad2", "kb_u")) { pconfig->kb_p2u = strdup(value); } - else if (MATCH("gamepad2", "kb_d")) { pconfig->kb_p2d = strdup(value); } - else if (MATCH("gamepad2", "kb_l")) { pconfig->kb_p2l = strdup(value); } - else if (MATCH("gamepad2", "kb_r")) { pconfig->kb_p2r = strdup(value); } - else if (MATCH("gamepad2", "kb_select")) { pconfig->kb_p2select = strdup(value); } - else if (MATCH("gamepad2", "kb_start")) { pconfig->kb_p2start = strdup(value); } - else if (MATCH("gamepad2", "kb_a")) { pconfig->kb_p2a = strdup(value); } - else if (MATCH("gamepad2", "kb_b")) { pconfig->kb_p2b = strdup(value); } - else if (MATCH("gamepad2", "kb_ta")) { pconfig->kb_p2ta = strdup(value); } - else if (MATCH("gamepad2", "kb_tb")) { pconfig->kb_p2tb = strdup(value); } - + else if (MATCH("gamepad2", "kb_u")) { pconfig->kb_p2u = atoi(value); } + else if (MATCH("gamepad2", "kb_d")) { pconfig->kb_p2d = atoi(value); } + else if (MATCH("gamepad2", "kb_l")) { pconfig->kb_p2l = atoi(value); } + else if (MATCH("gamepad2", "kb_r")) { pconfig->kb_p2r = atoi(value); } + else if (MATCH("gamepad2", "kb_select")) { pconfig->kb_p2select = atoi(value); } + else if (MATCH("gamepad2", "kb_start")) { pconfig->kb_p2start = atoi(value); } + else if (MATCH("gamepad2", "kb_a")) { pconfig->kb_p2a = atoi(value); } + else if (MATCH("gamepad2", "kb_b")) { pconfig->kb_p2b = atoi(value); } + else if (MATCH("gamepad2", "kb_ta")) { pconfig->kb_p2ta = atoi(value); } + else if (MATCH("gamepad2", "kb_tb")) { pconfig->kb_p2tb = atoi(value); } + else if (MATCH("gamepad2", "js_u")) { pconfig->js_p2u = strdup(value); } else if (MATCH("gamepad2", "js_d")) { pconfig->js_p2d = strdup(value); } else if (MATCH("gamepad2", "js_l")) { pconfig->js_p2l = strdup(value); } @@ -387,19 +655,30 @@ static int nstsdl_input_config_match(void* user, const char* section, const char else if (MATCH("gamepad2", "js_b")) { pconfig->js_p2b = strdup(value); } else if (MATCH("gamepad2", "js_ta")) { pconfig->js_p2ta = strdup(value); } else if (MATCH("gamepad2", "js_tb")) { pconfig->js_p2tb = strdup(value); } - + else { return 0; } - return 1; + return 1; } void nstsdl_input_conf_read() { // Read the input config file snprintf(inputconfpath, sizeof(inputconfpath), "%sinput.conf", nstpaths.nstconfdir); - + if (ini_parse(inputconfpath, nstsdl_input_config_match, &inputconf) < 0) { fprintf(stderr, "Failed to load input config file %s: Using defaults.\n", inputconfpath); } else { // Map the input settings from the config file + player[0].u = inputconf.kb_p1u; + player[0].d = inputconf.kb_p1d; + player[0].l = inputconf.kb_p1l; + player[0].r = inputconf.kb_p1r; + player[0].select = inputconf.kb_p1select; + player[0].start = inputconf.kb_p1start; + player[0].a = inputconf.kb_p1a; + player[0].b = inputconf.kb_p1b; + player[0].ta = inputconf.kb_p1ta; + player[0].tb = inputconf.kb_p1tb; + player[0].ju = nstsdl_input_translate_string(inputconf.js_p1u); player[0].jd = nstsdl_input_translate_string(inputconf.js_p1d); player[0].jl = nstsdl_input_translate_string(inputconf.js_p1l); @@ -410,7 +689,7 @@ void nstsdl_input_conf_read() { player[0].jb = nstsdl_input_translate_string(inputconf.js_p1b); player[0].jta = nstsdl_input_translate_string(inputconf.js_p1ta); player[0].jtb = nstsdl_input_translate_string(inputconf.js_p1tb); - + if (inputconf.js_rwstart) { player[0].rwstart = nstsdl_input_translate_string(inputconf.js_rwstart); } if (inputconf.js_rwstop) { player[0].rwstop = nstsdl_input_translate_string(inputconf.js_rwstop); } @@ -418,6 +697,17 @@ void nstsdl_input_conf_read() { if (inputconf.js_hardreset) { player[0].hardreset = nstsdl_input_translate_string(inputconf.js_hardreset); } // Player 2 + player[1].u = inputconf.kb_p2u; + player[1].d = inputconf.kb_p2d; + player[1].l = inputconf.kb_p2l; + player[1].r = inputconf.kb_p2r; + player[1].select = inputconf.kb_p2select; + player[1].start = inputconf.kb_p2start; + player[1].a = inputconf.kb_p2a; + player[1].b = inputconf.kb_p2b; + player[1].ta = inputconf.kb_p2ta; + player[1].tb = inputconf.kb_p2tb; + player[1].ju = nstsdl_input_translate_string(inputconf.js_p2u); player[1].jd = nstsdl_input_translate_string(inputconf.js_p2d); player[1].jl = nstsdl_input_translate_string(inputconf.js_p2l); @@ -435,13 +725,39 @@ void nstsdl_input_conf_write() { // Write out the input configuration file FILE *fp = fopen(inputconfpath, "w"); if (fp != NULL) { - fprintf(fp, "; Nestopia UE SDL Input Configuration File\n\n"); + fprintf(fp, "; Nestopia UE Input Configuration File\n\n"); fprintf(fp, "; Possible values for joystick input:\n; j[joystick number][a|b|h][button/hat/axis number][1/0 = +/- (axes only)]\n"); fprintf(fp, "; Example: j0b3 = joystick 0, button 3. j1a11 = joystick 1, axis 1 +\n\n"); - fprintf(fp, "; Press Ctrl or Shift + [player number] to configure input in-game.\n; Ctrl for Keyboard, Shift for Joystick.\n"); - fprintf(fp, "; Example: Shift + 1 for Joystick input for Player 1\n\n"); - + + fprintf(fp, "[ui]\n"); + fprintf(fp, "qsave1=%d\n", inputconf.qsave1); + fprintf(fp, "qsave2=%d\n", inputconf.qsave2); + fprintf(fp, "qload1=%d\n", inputconf.qload1); + fprintf(fp, "qload2=%d\n", inputconf.qload2); + fprintf(fp, "screenshot=%d\n", inputconf.screenshot); + fprintf(fp, "fdsflip=%d\n", inputconf.fdsflip); + fprintf(fp, "fdsswitch=%d\n", inputconf.fdsswitch); + fprintf(fp, "insertcoin1=%d\n", inputconf.insertcoin1); + fprintf(fp, "insertcoin2=%d\n", inputconf.insertcoin2); + fprintf(fp, "reset=%d\n", inputconf.reset); + fprintf(fp, "ffspeed=%d\n", inputconf.ffspeed); + fprintf(fp, "rwstart=%d\n", inputconf.rwstart); + fprintf(fp, "rwstop=%d\n", inputconf.rwstop); + fprintf(fp, "fullscreen=%d\n", inputconf.fullscreen); + fprintf(fp, "\n"); // End of Section + fprintf(fp, "[gamepad1]\n"); + fprintf(fp, "kb_u=%d\n", player[0].u); + fprintf(fp, "kb_d=%d\n", player[0].d); + fprintf(fp, "kb_l=%d\n", player[0].l); + fprintf(fp, "kb_r=%d\n", player[0].r); + fprintf(fp, "kb_select=%d\n", player[0].select); + fprintf(fp, "kb_start=%d\n", player[0].start); + fprintf(fp, "kb_a=%d\n", player[0].a); + fprintf(fp, "kb_b=%d\n", player[0].b); + fprintf(fp, "kb_ta=%d\n", player[0].ta); + fprintf(fp, "kb_tb=%d\n", player[0].tb); + fprintf(fp, "js_u=%s\n", nstsdl_input_translate_event(player[0].ju)); fprintf(fp, "js_d=%s\n", nstsdl_input_translate_event(player[0].jd)); fprintf(fp, "js_l=%s\n", nstsdl_input_translate_event(player[0].jl)); @@ -452,14 +768,25 @@ void nstsdl_input_conf_write() { fprintf(fp, "js_b=%s\n", nstsdl_input_translate_event(player[0].jb)); fprintf(fp, "js_ta=%s\n", nstsdl_input_translate_event(player[0].jta)); fprintf(fp, "js_tb=%s\n", nstsdl_input_translate_event(player[0].jtb)); - + fprintf(fp, "js_rwstart=%s\n", nstsdl_input_translate_event(player[0].rwstart)); fprintf(fp, "js_rwstop=%s\n", nstsdl_input_translate_event(player[0].rwstop)); fprintf(fp, "js_softreset=%s\n", nstsdl_input_translate_event(player[0].softreset)); fprintf(fp, "js_hardreset=%s\n", nstsdl_input_translate_event(player[0].hardreset)); fprintf(fp, "\n"); // End of Section - + fprintf(fp, "[gamepad2]\n"); + fprintf(fp, "kb_u=%d\n", player[1].u); + fprintf(fp, "kb_d=%d\n", player[1].d); + fprintf(fp, "kb_l=%d\n", player[1].l); + fprintf(fp, "kb_r=%d\n", player[1].r); + fprintf(fp, "kb_select=%d\n", player[1].select); + fprintf(fp, "kb_start=%d\n", player[1].start); + fprintf(fp, "kb_a=%d\n", player[1].a); + fprintf(fp, "kb_b=%d\n", player[1].b); + fprintf(fp, "kb_ta=%d\n", player[1].ta); + fprintf(fp, "kb_tb=%d\n", player[1].tb); + fprintf(fp, "js_u=%s\n", nstsdl_input_translate_event(player[1].ju)); fprintf(fp, "js_d=%s\n", nstsdl_input_translate_event(player[1].jd)); fprintf(fp, "js_l=%s\n", nstsdl_input_translate_event(player[1].jl)); @@ -470,8 +797,7 @@ void nstsdl_input_conf_write() { fprintf(fp, "js_b=%s\n", nstsdl_input_translate_event(player[1].jb)); fprintf(fp, "js_ta=%s\n", nstsdl_input_translate_event(player[1].jta)); fprintf(fp, "js_tb=%s\n", nstsdl_input_translate_event(player[1].jtb)); - fprintf(fp, "\n"); // End of Section - + fclose(fp); } } @@ -492,16 +818,16 @@ void nstsdl_input_process(Input::Controllers *controllers, SDL_Event event) { char* nstsdl_input_translate_event(SDL_Event event) { // Translate an SDL_Event to an inputcode static char inputcode[6]; - + switch(event.type) { case SDL_JOYAXISMOTION: sprintf(inputcode, "j%da%d%d", event.jaxis.which, event.jaxis.axis, nstsdl_input_checksign(event.jaxis.value)); break; - + case SDL_JOYHATMOTION: sprintf(inputcode, "j%dh%d%d", event.jhat.which, event.jhat.hat, event.jhat.value); break; - + case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: sprintf(inputcode, "j%db%d", event.jbutton.which, event.jbutton.button); @@ -513,7 +839,7 @@ char* nstsdl_input_translate_event(SDL_Event event) { SDL_Event nstsdl_input_translate_string(const char *string) { // Translate an inputcode to an SDL_Event SDL_Event event; - + int type, axis, value; int which = 0, whichdigits = 0; @@ -530,7 +856,7 @@ SDL_Event nstsdl_input_translate_string(const char *string) { for (int i = 1; i <= whichdigits; i++) { which += (string[i] - '0') * (pow (10, (whichdigits - i))); } - + if ((unsigned char)string[whichdigits + 1] == 0x61) { // Axis axis = string[whichdigits + 2] - '0'; value = string[whichdigits + 3] - '0'; @@ -547,7 +873,7 @@ SDL_Event nstsdl_input_translate_string(const char *string) { event.type = SDL_JOYBUTTONDOWN; event.jbutton.which = which; event.jbutton.button = value; - + } else if ((unsigned char)string[whichdigits + 1] == 0x68) { // Hat axis = string[whichdigits + 2] - '0'; @@ -560,7 +886,7 @@ SDL_Event nstsdl_input_translate_string(const char *string) { else { fprintf(stderr, "Malformed inputcode: %s\n", string); } - + return event; } @@ -568,10 +894,10 @@ void nstsdl_input_conf_button(int pnum, int bnum) { // Configure Inputs for single Joystick Buttons SDL_Event event, eventbuf; int axis = 0, axisnoise = 0, confrunning = 1; - + + if (SDL_NumJoysticks() == 0) { return; } + while (confrunning) { - while (gtk_events_pending()) { gtk_main_iteration(); } - while (SDL_PollEvent(&event)) { if (event.type == SDL_JOYAXISMOTION) { if (abs(event.jaxis.value) >= DEADZONE) { @@ -580,21 +906,66 @@ void nstsdl_input_conf_button(int pnum, int bnum) { axis = event.jaxis.axis; } else if (abs(event.jaxis.value) < DEADZONE && axisnoise && event.jaxis.axis == axis) { - nstsdl_input_conf_set(eventbuf, 1, pnum, bnum); + nstsdl_input_conf_set(eventbuf, pnum, bnum); axisnoise = 0; confrunning = 0; } } else if (event.type == SDL_JOYHATMOTION) { if (event.jhat.value != SDL_HAT_CENTERED) { - nstsdl_input_conf_set(event, 1, pnum, bnum); + nstsdl_input_conf_set(event, pnum, bnum); confrunning = 0; } } else if (event.type == SDL_JOYBUTTONDOWN) { - nstsdl_input_conf_set(event, 1, pnum, bnum); + nstsdl_input_conf_set(event, pnum, bnum); confrunning = 0; } } + SDL_Delay(1); } } + +void fltkui_input_process_key(int e) { + nesinput_t input; + + input.nescode = input.player = input.pressed = input.turboa = input.turbob = 0; + + if (e == FL_KEYDOWN) { + input.pressed = 1; + if (Fl::event_key() == '`') nst_timing_set_ffspeed(); + else if (Fl::event_key() == inputconf.qsave1) nst_state_quicksave(0); + else if (Fl::event_key() == inputconf.qsave2) nst_state_quicksave(1); + else if (Fl::event_key() == inputconf.qload1) nst_state_quickload(0); + else if (Fl::event_key() == inputconf.qload2) nst_state_quickload(1); + else if (Fl::event_key() == inputconf.screenshot) { video_screenshot(NULL); } + else if (Fl::event_key() == inputconf.fdsflip) { nst_fds_flip(); } + else if (Fl::event_key() == inputconf.fdsswitch) { nst_fds_switch(); } + else if (Fl::event_key() == inputconf.insertcoin1) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_1; } + else if (Fl::event_key() == inputconf.insertcoin2) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_2; } + else if (Fl::event_key() == inputconf.reset) { nst_reset(0); } + else if (Fl::event_key() == inputconf.rwstart) { nst_set_rewind(0); } + else if (Fl::event_key() == inputconf.rwstop) { nst_set_rewind(1); } + else if (Fl::event_key() == ' ') { cNstPads->pad[1].mic = 0x04; } + } + else { + if (Fl::event_key() == inputconf.ffspeed) nst_timing_set_default(); + else if (Fl::event_key() == inputconf.fullscreen) fltkui_fullscreen(NULL, NULL); + else if (Fl::event_key() == ' ') { cNstPads->pad[1].mic = 0x00; } + } + + for (int i = 0; i < NUMGAMEPADS; i++) { + if (Fl::event_key() == player[i].u) { input.player = i; input.nescode = Input::Controllers::Pad::UP; } + else if (Fl::event_key() == player[i].d) { input.player = i; input.nescode = Input::Controllers::Pad::DOWN; } + else if (Fl::event_key() == player[i].l) { input.player = i; input.nescode = Input::Controllers::Pad::LEFT; } + else if (Fl::event_key() == player[i].r) { input.player = i; input.nescode = Input::Controllers::Pad::RIGHT; } + else if (Fl::event_key() == player[i].select) { input.player = i; input.nescode = Input::Controllers::Pad::SELECT; } + else if (Fl::event_key() == player[i].start) { input.player = i; input.nescode = Input::Controllers::Pad::START; } + else if (Fl::event_key() == player[i].a) { input.player = i; input.nescode = Input::Controllers::Pad::A; } + else if (Fl::event_key() == player[i].b) { input.player = i; input.nescode = Input::Controllers::Pad::B; } + else if (Fl::event_key() == player[i].ta) { input.player = i; input.turboa = 1; input.nescode = Input::Controllers::Pad::A; } + else if (Fl::event_key() == player[i].tb) { input.player = i; input.turbob = 1; input.nescode = Input::Controllers::Pad::B; } + } + + nst_input_inject(cNstPads, input); +} diff --git a/source/common/sdlinput.h b/source/fltkui/input.h similarity index 50% rename from source/common/sdlinput.h rename to source/fltkui/input.h index a1d7868..43ddb7f 100644 --- a/source/common/sdlinput.h +++ b/source/fltkui/input.h @@ -1,23 +1,25 @@ -#ifndef _SDLINPUT_H_ -#define _SDLINPUT_H_ +#ifndef _INPUT_H_ +#define _INPUT_H_ +#define NUMGAMEPADS 2 +#define NUMBUTTONS 10 #define TOTALBUTTONS (NUMGAMEPADS*NUMBUTTONS) #define DEADZONE (32768/3) #include "core/api/NstApiInput.hpp" typedef struct { - SDL_Scancode u; - SDL_Scancode d; - SDL_Scancode l; - SDL_Scancode r; - SDL_Scancode select; - SDL_Scancode start; - SDL_Scancode a; - SDL_Scancode b; - SDL_Scancode ta; - SDL_Scancode tb; - + int u; + int d; + int l; + int r; + int select; + int start; + int a; + int b; + int ta; + int tb; + SDL_Event ju; SDL_Event jd; SDL_Event jl; @@ -36,41 +38,39 @@ typedef struct { typedef struct { // User Interface - char *qsave1; - char *qsave2; - char *qload1; - char *qload2; - - char *screenshot; - - char *fdsflip; - char *fdsswitch; - - char *insertcoin1; - char *insertcoin2; - - char *reset; - - char *ffspeed; - char *rwstart; - char *rwstop; - - char *fullscreen; - char *filter; - char *scalefactor; - + int qsave1; + int qsave2; + int qload1; + int qload2; + + int screenshot; + + int fdsflip; + int fdsswitch; + + int insertcoin1; + int insertcoin2; + + int reset; + + int ffspeed; + int rwstart; + int rwstop; + + int fullscreen; + // Player 1 - char *kb_p1u; - char *kb_p1d; - char *kb_p1l; - char *kb_p1r; - char *kb_p1select; - char *kb_p1start; - char *kb_p1a; - char *kb_p1b; - char *kb_p1ta; - char *kb_p1tb; - + int kb_p1u; + int kb_p1d; + int kb_p1l; + int kb_p1r; + int kb_p1select; + int kb_p1start; + int kb_p1a; + int kb_p1b; + int kb_p1ta; + int kb_p1tb; + char *js_p1u; char *js_p1d; char *js_p1l; @@ -81,7 +81,7 @@ typedef struct { char *js_p1b; char *js_p1ta; char *js_p1tb; - + char *js_rwstart; char *js_rwstop; @@ -89,17 +89,17 @@ typedef struct { char *js_hardreset; // Player 2 - char *kb_p2u; - char *kb_p2d; - char *kb_p2l; - char *kb_p2r; - char *kb_p2select; - char *kb_p2start; - char *kb_p2a; - char *kb_p2b; - char *kb_p2ta; - char *kb_p2tb; - + int kb_p2u; + int kb_p2d; + int kb_p2l; + int kb_p2r; + int kb_p2select; + int kb_p2start; + int kb_p2a; + int kb_p2b; + int kb_p2ta; + int kb_p2tb; + char *js_p2u; char *js_p2d; char *js_p2l; @@ -112,11 +112,39 @@ typedef struct { char *js_p2tb; } inputsettings_t; +using namespace Nes::Api; + +typedef struct { + unsigned char player; + unsigned char nescode; + unsigned char pressed; + unsigned char turboa; + unsigned char turbob; +} nesinput_t; + +typedef struct { + int p1a; + int p1b; + int p2a; + int p2b; +} turbo_t; + +void nst_input_init(); + +void nst_input_inject(Input::Controllers *controllers, nesinput_t input); +void nst_input_inject_mouse(Input::Controllers *controllers, int b, int s, int x, int y); + +void nst_input_turbo_init(); +void nst_input_turbo_pulse(Input::Controllers *controllers); + +int nst_input_zapper_present(); + +int input_configure_item(int pnum, int bnum, int type); void nstsdl_input_conf(int type, int pnum); void nstsdl_input_conf_button(int pnum, int bnum); void nstsdl_input_conf_defaults(); -void nstsdl_input_conf_set(SDL_Event event, int type, int pnum, int counter); +void nstsdl_input_conf_set(SDL_Event event, int pnum, int bnum); void nstsdl_input_conf_read(); void nstsdl_input_conf_write(); @@ -131,4 +159,6 @@ void nstsdl_input_process(Input::Controllers *controllers, SDL_Event event); char* nstsdl_input_translate_event(SDL_Event event); SDL_Event nstsdl_input_translate_string(const char *string); +void fltkui_input_conf_set(int kval, int pnum, int bnum); +void fltkui_input_process_key(int e); #endif diff --git a/source/common/nstcommon.cpp b/source/fltkui/nstcommon.cpp similarity index 97% rename from source/common/nstcommon.cpp rename to source/fltkui/nstcommon.cpp index 0afdc78..ab72dde 100644 --- a/source/common/nstcommon.cpp +++ b/source/fltkui/nstcommon.cpp @@ -1,25 +1,25 @@ /* * Nestopia UE - * + * * Copyright (C) 2007-2008 R. Belmont - * Copyright (C) 2012-2018 R. Danbrook + * Copyright (C) 2012-2021 R. Danbrook * Copyright (C) 2018-2018 Phil Smith * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include @@ -37,6 +37,8 @@ #include #include +#include + // Nst Common #include "nstcommon.h" #include "config.h" @@ -73,7 +75,7 @@ bool (*nst_archive_select)(const char*, char*, size_t); static bool NST_CALLBACK nst_cb_videolock(void* userData, Video::Output& video) { video.pitch = video_lock_screen(video.pixels); - return true; // true=lock success, false=lock failed (Nestopia will carry on but skip video) + return true; } static void NST_CALLBACK nst_cb_videounlock(void* userData, Video::Output& video) { @@ -115,7 +117,7 @@ static void NST_CALLBACK nst_cb_file(void *userData, User::File& file) { unsigned char *compbuffer; int compsize, compoffset; char *filename; - + switch (file.GetAction()) { case User::File::LOAD_ROM: // Nothing here for now @@ -132,13 +134,13 @@ static void NST_CALLBACK nst_cb_file(void *userData, User::File& file) { case User::File::LOAD_EEPROM: // used by some Bandai games, can be treated the same as battery files case User::File::LOAD_TAPE: // for loading Famicom cassette tapes case User::File::LOAD_TURBOFILE: // for loading turbofile data - { + { std::ifstream batteryFile(nstpaths.savename, std::ifstream::in|std::ifstream::binary); - + if (batteryFile.is_open()) { file.SetContent(batteryFile); } break; } - + case User::File::SAVE_BATTERY: // save battery data to a file case User::File::SAVE_EEPROM: // can be treated the same as battery files case User::File::SAVE_TAPE: // for saving Famicom cassette tapes @@ -160,7 +162,7 @@ static void NST_CALLBACK nst_cb_file(void *userData, User::File& file) { char fdsname[512]; snprintf(fdsname, sizeof(fdsname), "%s.ups", nstpaths.fdssave); - + std::ifstream batteryFile( fdsname, std::ifstream::in|std::ifstream::binary ); // no ups, look for ips @@ -232,12 +234,12 @@ bool nst_archive_select_file(const char *filename, char *reqfile, size_t reqsize struct archive *a; struct archive_entry *entry; int r, numarchives = 0; - + a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, filename, 10240); - + // Test if it's actually an archive if (r != ARCHIVE_OK) { r = archive_read_free(a); @@ -257,7 +259,7 @@ bool nst_archive_select_file(const char *filename, char *reqfile, size_t reqsize } // Free the archive r = archive_read_free(a); - + // If there are no valid files in the archive, return if (numarchives == 0) { return false; } else { return true; } @@ -271,18 +273,18 @@ bool nst_archive_open(const char *filename, char **rom, int *romsize, const char struct archive_entry *entry; int r; int64_t entrysize; - + a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, filename, 10240); - + // Test if it's actually an archive if (r != ARCHIVE_OK) { r = archive_read_free(a); return false; } - + // Scan through the archive for files while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { char *rombuf; @@ -327,28 +329,28 @@ void nst_db_load() { // Try to open the database file snprintf(dbpath, sizeof(dbpath), "%sNstDatabase.xml", nstpaths.nstdir); nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary); - + if (nstdb->is_open()) { database.Load(*nstdb); database.Enable(true); return; } - + // If it fails, try looking in the data directory - snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", DATADIR); + snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", "."); nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary); - + if (nstdb->is_open()) { database.Load(*nstdb); database.Enable(true); return; } - + // If that fails, try looking in the working directory char *pwd = getenv("PWD"); snprintf(dbpath, sizeof(dbpath), "%s/NstDatabase.xml", pwd); nstdb = new std::ifstream(dbpath, std::ifstream::in|std::ifstream::binary); - + if (nstdb->is_open()) { database.Load(*nstdb); database.Enable(true); @@ -368,19 +370,19 @@ void nst_db_unload() { void nst_dipswitch() { // Print DIP switch information and call handler DipSwitches dipswitches(emulator); - + int numdips = dipswitches.NumDips(); - + if (numdips > 0) { for (int i = 0; i < numdips; i++) { fprintf(stderr, "%d: %s\n", i, dipswitches.GetDipName(i)); int numvalues = dipswitches.NumValues(i); - + for (int j = 0; j < numvalues; j++) { fprintf(stderr, " %d: %s\n", j, dipswitches.GetValueName(i, j)); } } - + char dippath[512]; snprintf(dippath, sizeof(dippath), "%s%s.dip", nstpaths.savedir, nstpaths.gamename); nst_dip_handle(dippath); @@ -391,7 +393,7 @@ void nst_fds_bios_load() { // Load the Famicom Disk System BIOS Nes::Api::Fds fds(emulator); char biospath[512]; - + if (fdsbios) { return; } snprintf(biospath, sizeof(biospath), "%sdisksys.rom", nstpaths.nstdir); @@ -418,7 +420,7 @@ void nst_fds_info() { const char* disk; const char* side; char textbuf[24]; - + fds.GetCurrentDisk() == 0 ? disk = "1" : disk = "2"; fds.GetCurrentDiskSide() == 0 ? side = "A" : side = "B"; @@ -440,9 +442,9 @@ void nst_fds_flip() { void nst_fds_switch() { // Switches the FDS disk in multi-disk games Fds fds(emulator); - + int currentdisk = fds.GetCurrentDisk(); - + // If it's a multi-disk game, eject and insert the other disk if (fds.GetNumDisks() > 1) { fds.EjectDisk(); @@ -451,11 +453,11 @@ void nst_fds_switch() { } } -void nst_movie_save(char *filename) { +void nst_movie_save(const char *filename) { // Save/Record a movie Movie movie(emulator); - - movierecfile = new std::fstream(filename, std::ifstream::out|std::ifstream::binary); + + movierecfile = new std::fstream(filename, std::ifstream::out|std::ifstream::binary); if (movierecfile->is_open()) { movie.Record((std::iostream&)*movierecfile, Nes::Api::Movie::CLEAN); @@ -466,11 +468,11 @@ void nst_movie_save(char *filename) { } } -void nst_movie_load(char *filename) { +void nst_movie_load(const char *filename) { // Load and play a movie Movie movie(emulator); - - moviefile = new std::ifstream(filename, std::ifstream::in|std::ifstream::binary); + + moviefile = new std::ifstream(filename, std::ifstream::in|std::ifstream::binary); if (moviefile->is_open()) { movie.Play(*moviefile); @@ -484,7 +486,7 @@ void nst_movie_load(char *filename) { void nst_movie_stop() { // Stop any movie that is playing or recording Movie movie(emulator); - + if (movie.IsPlaying() || movie.IsRecording()) { movie.Stop(); movierecfile = NULL; @@ -534,18 +536,18 @@ bool nst_playing() { return playing; } void nst_palette_load(const char *filename) { // Load a custom palette - + FILE *file; long filesize; // File size in bytes size_t result; - + char custgamepalpath[512]; snprintf(custgamepalpath, sizeof(custgamepalpath), "%s%s%s", nstpaths.nstdir, nstpaths.gamename, ".pal"); - + // Try the game-specific palette first file = fopen(custgamepalpath, "rb"); if (!file) { file = fopen(filename, "rb"); } - + // Then try the global custom palette if (!file) { if (conf.video_palette_mode == 2) { @@ -554,17 +556,17 @@ void nst_palette_load(const char *filename) { } return; } - + fseek(file, 0, SEEK_END); filesize = ftell(file); fseek(file, 0, SEEK_SET); - + if (custompalette) { free(custompalette); } custompalette = malloc(filesize * sizeof(uint8_t)); custpalsize = filesize * sizeof(uint8_t); - + result = fread(custompalette, sizeof(uint8_t), filesize, file); - + fclose(file); } @@ -572,14 +574,14 @@ void nst_palette_save() { // Save a custom palette FILE *file; void *custpalout; - + file = fopen(nstpaths.palettepath, "wb"); if (!file) { return; } - + custpalout = malloc(custpalsize); - + memcpy(custpalout, custompalette, custpalsize); - + fwrite(custpalout, custpalsize, sizeof(uint8_t), file); fclose(file); free(custpalout); @@ -602,30 +604,30 @@ bool nst_find_patch(char *patchname, unsigned int patchname_length, const char * // since copying into same string as the argument we don't want any overlap memmove(filedir, dirname(filedir), sizeof(filedir)); filedir[sizeof(filedir) - 1] = '\0'; - + if (!conf.misc_soft_patching) { return 0; } - + snprintf(patchname, patchname_length, "%s/%s.ips", filedir, nstpaths.gamename); - + if ((file = fopen(patchname, "rb")) != NULL) { fclose(file); return 1; } else { snprintf(patchname, patchname_length, "%s/%s.ups", filedir, nstpaths.gamename); if ((file = fopen(patchname, "rb")) != NULL) { fclose(file); return 1; } } - + return 0; } void nst_set_callbacks() { // Set up the callbacks void *userData = (void*)0xDEADC0DE; - + Video::Output::lockCallback.Set(nst_cb_videolock, userData); Video::Output::unlockCallback.Set(nst_cb_videounlock, userData); - + Sound::Output::lockCallback.Set(nst_cb_soundlock, userData); Sound::Output::unlockCallback.Set(nst_cb_soundunlock, userData); - + User::fileIoCallback.Set(nst_cb_file, userData); User::logCallback.Set(nst_cb_log, userData); User::eventCallback.Set(nst_cb_event, userData); @@ -640,11 +642,11 @@ void nst_set_dirs() { else { snprintf(nstpaths.nstconfdir, sizeof(nstpaths.nstconfdir), "%s/.config/nestopia/", getenv("HOME")); } - + if (mkdir(nstpaths.nstconfdir, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", nstpaths.nstconfdir, errno); } - + // create data directory if it doesn't exist if (getenv("XDG_DATA_HOME")) { snprintf(nstpaths.nstdir, sizeof(nstpaths.nstdir), "%s/nestopia/", getenv("XDG_DATA_HOME")); @@ -652,15 +654,15 @@ void nst_set_dirs() { else { snprintf(nstpaths.nstdir, sizeof(nstpaths.nstdir), "%s/.local/share/nestopia/", getenv("HOME")); } - + if (mkdir(nstpaths.nstdir, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", nstpaths.nstdir, errno); } - + // create save and state directories if they don't exist char dirstr[256]; snprintf(dirstr, sizeof(dirstr), "%ssave", nstpaths.nstdir); - + if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } @@ -669,22 +671,22 @@ void nst_set_dirs() { if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } - + // create cheats directory if it doesn't exist snprintf(dirstr, sizeof(dirstr), "%scheats", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } - + // create screenshots directory if it doesn't exist snprintf(dirstr, sizeof(dirstr), "%sscreenshots", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { fprintf(stderr, "Failed to create %s: %d\n", dirstr, errno); } - + // Construct the custom palette path snprintf(nstpaths.palettepath, sizeof(nstpaths.palettepath), "%s%s", nstpaths.nstdir, "custom.pal"); - + // Construct samples directory if it doesn't exist snprintf(dirstr, sizeof(dirstr), "%ssamples", nstpaths.nstdir); if (mkdir(dirstr, 0755) && errno != EEXIST) { @@ -693,13 +695,13 @@ void nst_set_dirs() { } void nst_set_paths(const char *filename) { - + // Set up the save directory snprintf(nstpaths.savedir, sizeof(nstpaths.savedir), "%ssave/", nstpaths.nstdir); - + // Copy the full file path to the savename variable snprintf(nstpaths.savename, sizeof(nstpaths.savename), "%s", filename); - + // strip the . and extention off the filename for saving for (int i = strlen(nstpaths.savename)-1; i > 0; i--) { if (nstpaths.savename[i] == '.') { @@ -707,22 +709,22 @@ void nst_set_paths(const char *filename) { break; } } - + // Set up the sample directory snprintf(nstpaths.sampdir, sizeof(nstpaths.sampdir), "%ssamples/", nstpaths.nstdir); - + // Get the name of the game minus file path and extension snprintf(nstpaths.gamename, sizeof(nstpaths.gamename), "%s", basename(nstpaths.savename)); - + // Construct save path snprintf(nstpaths.savename, sizeof(nstpaths.savename), "%s%s%s", nstpaths.savedir, nstpaths.gamename, ".sav"); // Construct path for FDS save patches snprintf(nstpaths.fdssave, sizeof(nstpaths.fdssave), "%s%s", nstpaths.savedir, nstpaths.gamename); - + // Construct the save state path snprintf(nstpaths.statepath, sizeof(nstpaths.statepath), "%sstate/%s", nstpaths.nstdir, nstpaths.gamename); - + // Construct the cheat path snprintf(nstpaths.cheatpath, sizeof(nstpaths.cheatpath), "%scheats/%s.xml", nstpaths.nstdir, nstpaths.gamename); } @@ -731,7 +733,7 @@ void nst_set_region() { // Set the region Machine machine(emulator); Cartridge::Database database(emulator); - + /*if (database.IsLoaded()) { std::ifstream dbfile(filename, std::ios::in|std::ios::binary); Cartridge::Profile profile; @@ -739,7 +741,7 @@ void nst_set_region() { dbentry = database.FindEntry(profile.hash, nst_default_system()); printf("Mapper: %d\n", dbentry.GetMapper()); }*/ - + switch (conf.misc_default_system) { case 0: machine.SetMode(machine.GetDesiredMode()); break; // Auto case 1: machine.SetMode(Machine::NTSC); break; // NTSC @@ -758,23 +760,23 @@ void nst_set_rewind(int direction) { } } -void nst_state_save(char *filename) { +void nst_state_save(const char *filename) { // Save a state by filename Machine machine(emulator); - + std::ofstream statefile(filename, std::ifstream::out|std::ifstream::binary); - + if (statefile.is_open()) { machine.SaveState(statefile, Nes::Api::Machine::NO_COMPRESSION); } fprintf(stderr, "State Saved: %s\n", filename); nst_video_print("State Saved", 8, 212, 2, true); } -void nst_state_load(char *filename) { +void nst_state_load(const char *filename) { // Load a state by filename Machine machine(emulator); - + std::ifstream statefile(filename, std::ifstream::in|std::ifstream::binary); - + if (statefile.is_open()) { machine.LoadState(statefile); } fprintf(stderr, "State Loaded: %s\n", filename); nst_video_print("State Loaded", 8, 212, 2, true); @@ -782,6 +784,7 @@ void nst_state_load(char *filename) { void nst_state_quicksave(int slot) { // Quick Save State + if (!loaded) { return; } char slotpath[520]; snprintf(slotpath, sizeof(slotpath), "%s_%d.nst", nstpaths.statepath, slot); nst_state_save(slotpath); @@ -790,16 +793,17 @@ void nst_state_quicksave(int slot) { void nst_state_quickload(int slot) { // Quick Load State + if (!loaded) { return; } char slotpath[520]; snprintf(slotpath, sizeof(slotpath), "%s_%d.nst", nstpaths.statepath, slot); - + struct stat qloadstat; if (stat(slotpath, &qloadstat) == -1) { fprintf(stderr, "No State to Load\n"); nst_video_print("No State to Load", 8, 212, 2, true); return; } - + nst_state_load(slotpath); } @@ -827,7 +831,7 @@ void nst_reset(bool hardreset) { Fds fds(emulator); machine.SetRamPowerState(conf.misc_power_state); machine.Reset(hardreset); - + // Set the FDS disk to defaults fds.EjectDisk(); fds.InsertDisk(0, 0); @@ -838,11 +842,11 @@ void nst_emuloop() { if (NES_SUCCEEDED(Rewinder(emulator).Enable(true))) { Rewinder(emulator).EnableSound(true); } - + if (playing) { // Pulse the turbo buttons nst_input_turbo_pulse(cNstPads); - + // Execute frames for (int i = 0; i < nst_timing_runframes(); i++) { emulator.Execute(cNstVideo, cNstSound, cNstPads); @@ -853,7 +857,7 @@ void nst_emuloop() { void nst_unload() { // Remove the cartridge and shut down the NES Machine machine(emulator); - + // Power down the NES machine.Power(false); @@ -867,14 +871,14 @@ void nst_pause() { audio_pause(); audio_deinit(); } - + playing = false; } void nst_play() { // Play the game if (playing) { return; } - + video_init(); audio_init(); nst_input_init(); @@ -884,16 +888,16 @@ void nst_play() { cNstVideo = new Video::Output; cNstSound = new Sound::Output; cNstPads = new Input::Controllers; - + audio_set_params(cNstSound); audio_unpause(); - + if (nst_nsf()) { Nsf nsf(emulator); nsf.PlaySong(); video_disp_nsf(); } - + playing = true; } @@ -906,33 +910,33 @@ int nst_load(const char *filename) { char *rom; int romsize; char patchname[512]; - + // Pause play before pulling out a cartridge if (playing) { nst_pause(); } - + // Pull out any inserted cartridges if (loaded) { nst_unload(); } nst_video_print_time("", false); - + // Check if the file is an archive and select the file within char reqfile[256]; // Requested file inside the archive if (nst_archive_select(filename, reqfile, sizeof(reqfile))) { // Extract the contents nst_archive_open(filename, &rom, &romsize, reqfile); - + // Convert the malloc'd char* to an istream std::string rombuf(rom, romsize); std::istringstream file(rombuf); free(rom); - + result = machine.Load(file, nst_default_system()); } else { // Otherwise just load the file std::ifstream file(filename, std::ios::in|std::ios::binary); - + // Set the file paths nst_set_paths(filename); - + if (nst_find_patch(patchname, sizeof(patchname), filename)) { // Load with a patch if there is one std::ifstream pfile(patchname, std::ios::in|std::ios::binary); Machine::Patch patch(pfile, false); @@ -940,7 +944,7 @@ int nst_load(const char *filename) { } else { result = machine.Load(file, nst_default_system()); } } - + if (NES_FAILED(result)) { char errorstring[32]; switch (result) { @@ -968,39 +972,39 @@ int nst_load(const char *filename) { snprintf(errorstring, sizeof(errorstring), "Error: %d", result); break; } - + fprintf(stderr, "%s\n", errorstring); - + return 0; } - + // Deal with any DIP Switches nst_dipswitch(); - + // Set the region nst_set_region(); - + if (machine.Is(Machine::DISK)) { Fds fds(emulator); fds.InsertDisk(0, 0); nst_fds_info(); } - + // Check if this is an NSF if (nst_nsf()) { nsf.StopSong(); } - + // Check if sound distortion should be enabled sound.SetGenie(conf.misc_genie_distortion); - + // Load the custom palette nst_palette_load(nstpaths.palettepath); - + // Set the RAM's power state machine.SetRamPowerState(conf.misc_power_state); - + // Power on machine.Power(true); - + loaded = 1; return loaded; } diff --git a/source/common/nstcommon.h b/source/fltkui/nstcommon.h similarity index 92% rename from source/common/nstcommon.h rename to source/fltkui/nstcommon.h index a0ca673..12185d3 100644 --- a/source/common/nstcommon.h +++ b/source/fltkui/nstcommon.h @@ -53,8 +53,8 @@ void nst_fds_flip(); void nst_fds_switch(); // Movies -void nst_movie_save(char *filename); -void nst_movie_load(char *filename); +void nst_movie_save(const char *filename); +void nst_movie_load(const char *filename); void nst_movie_stop(); // NSF @@ -87,8 +87,8 @@ void nst_set_region(); void nst_set_rewind(int direction); // States -void nst_state_save(char *filename); -void nst_state_load(char *filename); +void nst_state_save(const char *filename); +void nst_state_load(const char *filename); void nst_state_quicksave(int isvst); void nst_state_quickload(int isvst); diff --git a/source/common/png.cpp b/source/fltkui/png.cpp similarity index 100% rename from source/common/png.cpp rename to source/fltkui/png.cpp diff --git a/source/common/png.h b/source/fltkui/png.h similarity index 100% rename from source/common/png.h rename to source/fltkui/png.h diff --git a/source/common/samples.cpp b/source/fltkui/samples.cpp similarity index 98% rename from source/common/samples.cpp rename to source/fltkui/samples.cpp index f2ac386..e601372 100644 --- a/source/common/samples.cpp +++ b/source/fltkui/samples.cpp @@ -1,23 +1,23 @@ /* * Nestopia UE - * + * * Copyright (C) 2012-2018 R. Danbrook - * + * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include @@ -25,10 +25,8 @@ #include #include -#ifndef _MINGW #include #include -#endif #include "nstcommon.h" #include "samples.h" @@ -42,22 +40,22 @@ int nst_sample_load_file(const char* filepath) { FILE *file; long filesize; // File size in bytes size_t result; - + file = fopen(filepath, "rb"); - + if (!file) { return 0; } - + fseek(file, 0, SEEK_END); filesize = ftell(file); fseek(file, 0, SEEK_SET); - + wavfile = (uint8_t*)malloc(filesize * sizeof(uint8_t)); - + if (wavfile == NULL) { return 0; } - + result = fread(wavfile, sizeof(uint8_t), filesize, file); if (result != filesize) { return 0; } - + fclose(file); return 1; } @@ -68,18 +66,18 @@ int nst_sample_load_archive(const char* filename, const char* reqfile) { struct archive_entry *entry; int r; int64_t entrysize; - + a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, filename, 10240); - + // Test if it's actually an archive if (r != ARCHIVE_OK) { r = archive_read_free(a); return 0; } - + // Scan through the archive for files while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { const char *currentfile = archive_entry_pathname(entry); @@ -108,7 +106,7 @@ int nst_sample_unload_file() { void nst_sample_setcontent(User::File& file) { // Parse the .WAV header and load the sample into the emulator - + // Check to see if it has a valid header uint8_t fmt[4] = { 0x66, 0x6d, 0x74, 0x20}; uint8_t subchunk2id[4] = { 0x64, 0x61, 0x74, 0x61}; @@ -116,7 +114,7 @@ void nst_sample_setcontent(User::File& file) { if (memcmp(&wavfile[0x08], "WAVE", 4) != 0) { return; } if (memcmp(&wavfile[0x0c], &fmt, 4) != 0) { return; } if (memcmp(&wavfile[0x24], &subchunk2id, 4) != 0) { return; } - + // Load the sample into the emulator uint8_t *dataptr = &wavfile[0x2c]; uint32_t datasize = wavfile[0x2b] << 24 | wavfile[0x2a] << 16 | wavfile[0x29] << 8 | wavfile[0x28]; @@ -131,10 +129,10 @@ void nst_sample_load_samples(User::File& file, const char* sampgame) { // Load samples for the specific game char reqfile[16]; char samppath[576]; - + // Requested sample .wav file snprintf(reqfile, sizeof(reqfile), "%02d.wav", file.GetId()); - + // Check if there's a MAME-style zip archive snprintf(samppath, sizeof(samppath), "%s%s.zip", nstpaths.sampdir, sampgame); if (nst_sample_load_archive(samppath, reqfile)) { diff --git a/source/common/samples.h b/source/fltkui/samples.h similarity index 100% rename from source/common/samples.h rename to source/fltkui/samples.h diff --git a/source/common/video.cpp b/source/fltkui/video.cpp similarity index 81% rename from source/common/video.cpp rename to source/fltkui/video.cpp index afb1112..b4cc0e0 100644 --- a/source/common/video.cpp +++ b/source/fltkui/video.cpp @@ -1,28 +1,29 @@ /* * Nestopia UE - * + * * Copyright (C) 2007-2008 R. Belmont - * Copyright (C) 2012-2020 R. Danbrook - * + * Copyright (C) 2012-2021 R. Danbrook + * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * + * */ #include #include +#include #include #include "core/api/NstApiEmulator.hpp" @@ -30,6 +31,8 @@ #include "core/api/NstApiVideo.hpp" #include "core/api/NstApiNsf.hpp" +#include + #include "nstcommon.h" #include "video.h" #include "config.h" @@ -53,114 +56,41 @@ extern void *custompalette; extern nstpaths_t nstpaths; extern Emulator emulator; -// Shader sources -const GLchar* vshader_src = - "#version 150 core\n" - "in vec2 position;" - "in vec2 texcoord;" - "out vec2 outcoord;" - "void main() {" - " outcoord = texcoord;" - " gl_Position = vec4(position, 0.0, 1.0);" - "}"; - -const GLchar* fshader_src = - "#version 150 core\n" - "in vec2 outcoord;" - "out vec4 fragcolor;" - "uniform sampler2D nestex;" - "void main() {" - " fragcolor = texture(nestex, outcoord);" - "}"; - -GLuint vao; -GLuint vbo; -GLuint vshader; -GLuint fshader; -GLuint gl_shader_prog = 0; GLuint gl_texture_id = 0; void nst_ogl_init() { // Initialize OpenGL - - float vertices[] = { - -1.0f, -1.0f, // Vertex 1 (X, Y) - -1.0f, 1.0f, // Vertex 2 (X, Y) - 1.0f, -1.0f, // Vertex 3 (X, Y) - 1.0f, 1.0f, // Vertex 4 (X, Y) - 0.0, 1.0, // Texture 1 (X, Y) - 0.0, 0.0, // Texture 2 (X, Y) - 1.0, 1.0, // Texture 3 (X, Y) - 1.0, 0.0 // Texture 4 (X, Y) - }; - - GLint status; - - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - vshader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vshader, 1, &vshader_src, NULL); - glCompileShader(vshader); - - glGetShaderiv(vshader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { fprintf(stderr, "Failed to compile vertex shader\n"); } - - fshader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fshader, 1, &fshader_src, NULL); - glCompileShader(fshader); - - glGetShaderiv(fshader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { fprintf(stderr, "Failed to compile fragment shader\n"); } - - GLuint gl_shader_prog = glCreateProgram(); - glAttachShader(gl_shader_prog, vshader); - glAttachShader(gl_shader_prog, fshader); - - glLinkProgram(gl_shader_prog); - - glValidateProgram(gl_shader_prog); - glGetProgramiv(gl_shader_prog, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { fprintf(stderr, "Failed to link shader program\n"); } - - glUseProgram(gl_shader_prog); - - GLint posAttrib = glGetAttribLocation(gl_shader_prog, "position"); - glEnableVertexAttribArray(posAttrib); - glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); - - GLint texAttrib = glGetAttribLocation(gl_shader_prog, "texcoord"); - glEnableVertexAttribArray(texAttrib); - glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, (void*)(8 * sizeof(GLfloat))); - + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &gl_texture_id); - glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, gl_texture_id); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, conf.video_linear_filter ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - conf.video_fullscreen ? + + conf.video_fullscreen ? glViewport(screensize.w / 2.0f - rendersize.w / 2.0f, 0, rendersize.w, rendersize.h) : glViewport(0, 0, rendersize.w, rendersize.h); - - glUniform1i(glGetUniformLocation(gl_shader_prog, "nestex"), 0); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_3D_EXT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, rendersize.w * conf.video_scale_factor, rendersize.h * conf.video_scale_factor, 0.0, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); } void nst_ogl_deinit() { // Deinitialize OpenGL - if (gl_texture_id) { glDeleteTextures(1, &gl_texture_id); } - if (gl_shader_prog) { glDeleteProgram(gl_shader_prog); } - if (vshader) { glDeleteShader(vshader); } - if (fshader) { glDeleteShader(fshader); } - if (vao) { glDeleteVertexArrays(1, &vao); } - if (vbo) { glDeleteBuffers(1, &vbo); } + if (gl_texture_id) { + glDeleteTextures(1, &gl_texture_id); + } } void nst_ogl_render() { @@ -174,36 +104,42 @@ void nst_ogl_render() { GL_BGRA, GL_UNSIGNED_BYTE, videobuf + overscan_offset); - + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glBegin(GL_QUADS); + glTexCoord2f(1.0f, 1.0f); + glVertex2f(rendersize.w * conf.video_scale_factor, rendersize.h * conf.video_scale_factor); + + glTexCoord2f(1.0f, 0.0f); + glVertex2f(rendersize.w * conf.video_scale_factor, 0.0); + + glTexCoord2f(0.0f, 0.0f); + glVertex2f(0.0, 0.0); + + glTexCoord2f(0.0f, 1.0f); + glVertex2f(0, rendersize.h * conf.video_scale_factor); + glEnd(); } void nst_video_refresh() { // Refresh the video settings nst_ogl_deinit(); - + nst_ogl_init(); } void video_init() { // Initialize video nst_ogl_deinit(); - + video_set_dimensions(); video_set_filter(); - - nst_ogl_init(); - - if (nst_nsf()) { video_clear_buffer(); video_disp_nsf(); } -} -void video_toggle_filter() { - conf.video_filter++; - if (conf.video_filter > 5) { conf.video_filter = 0; } - video_init(); - nst_video_refresh(); + nst_ogl_init(); + + if (nst_nsf()) { video_clear_buffer(); video_disp_nsf(); } } void video_toggle_filterupdate() { @@ -212,20 +148,13 @@ void video_toggle_filterupdate() { video.ClearFilterUpdateFlag(); } -void video_toggle_scalefactor() { - // Toggle video scale factor - conf.video_scale_factor++; - if (conf.video_scale_factor > 8) { conf.video_scale_factor = 1; } - //video_init(); -} - void video_set_filter() { // Set the filter Video video(emulator); int scalefactor = conf.video_scale_factor; if (conf.video_scale_factor > 4) { scalefactor = 4; } if ((conf.video_scale_factor > 3) && (conf.video_filter == 5)) { scalefactor = 3; } - + switch(conf.video_filter) { case 0: // None filter = Video::RenderState::FILTER_NONE; @@ -268,7 +197,7 @@ void video_set_filter() { break; } break; - + case 4: // 2xSaI filter = Video::RenderState::FILTER_2XSAI; break; @@ -288,52 +217,52 @@ void video_set_filter() { break; break; } - + // Set the sprite limit: false = enable sprite limit, true = disable sprite limit video.EnableUnlimSprites(conf.video_unlimited_sprites ? true : false); - + // Set Palette options switch (conf.video_palette_mode) { case 0: // YUV video.GetPalette().SetMode(Video::Palette::MODE_YUV); break; - + case 1: // RGB video.GetPalette().SetMode(Video::Palette::MODE_RGB); break; - + case 2: // Custom video.GetPalette().SetMode(Video::Palette::MODE_CUSTOM); video.GetPalette().SetCustom((const unsigned char (*)[3])custompalette, Video::Palette::EXT_PALETTE); break; - + default: break; } - + // Set YUV Decoder/Picture options if (video.GetPalette().GetMode() == Video::Palette::MODE_YUV) { switch (conf.video_decoder) { case 0: // Consumer video.SetDecoder(Video::DECODER_CONSUMER); break; - + case 1: // Canonical video.SetDecoder(Video::DECODER_CANONICAL); break; - + case 2: // Alternative (Canonical with yellow boost) video.SetDecoder(Video::DECODER_ALTERNATIVE); break; - + default: break; } } - + video.SetBrightness(conf.video_brightness); video.SetSaturation(conf.video_saturation); video.SetContrast(conf.video_contrast); video.SetHue(conf.video_hue); - + // Set NTSC options if (conf.video_filter == 1) { switch (conf.video_ntsc_mode) { @@ -345,7 +274,7 @@ void video_set_filter() { video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_COMP); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_COMP); break; - + case 1: // S-Video video.SetSaturation(Video::DEFAULT_SATURATION_SVIDEO); video.SetSharpness(Video::DEFAULT_SHARPNESS_SVIDEO); @@ -354,7 +283,7 @@ void video_set_filter() { video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_SVIDEO); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_SVIDEO); break; - + case 2: // RGB video.SetSaturation(Video::DEFAULT_SATURATION_RGB); video.SetSharpness(Video::DEFAULT_SHARPNESS_RGB); @@ -363,7 +292,7 @@ void video_set_filter() { video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_RGB); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_RGB); break; - + case 3: // Monochrome video.SetSaturation(Video::DEFAULT_SATURATION_MONO); video.SetSharpness(Video::DEFAULT_SHARPNESS_MONO); @@ -372,7 +301,7 @@ void video_set_filter() { video.SetColorArtifacts(Video::DEFAULT_COLOR_ARTIFACTS_MONO); video.SetColorFringing(Video::DEFAULT_COLOR_FRINGING_MONO); break; - + case 4: // Custom video.SetSaturation(conf.video_saturation); video.SetSharpness(conf.video_ntsc_sharpness); @@ -381,23 +310,23 @@ void video_set_filter() { video.SetColorArtifacts(conf.video_ntsc_artifacts); video.SetColorFringing(conf.video_ntsc_fringing); break; - + default: break; } } - + // Set xBR options if (conf.video_filter == 2) { video.SetCornerRounding(conf.video_xbr_corner_rounding); video.SetBlend(conf.video_xbr_pixel_blending); } - + // Set up the render state parameters renderstate.filter = filter; renderstate.width = basesize.w; renderstate.height = basesize.h; renderstate.bits.count = 32; - + int e = 1; // Check Endianness if ((int)*((unsigned char *)&e) == 1) { // Little Endian renderstate.bits.mask.r = 0x00ff0000; @@ -409,7 +338,7 @@ void video_set_filter() { renderstate.bits.mask.g = 0xff000000; renderstate.bits.mask.b = 0x00ff0000; } - + if (NES_FAILED(video.SetRenderState(renderstate))) { fprintf(stderr, "Nestopia core rejected render state\n"); exit(1); @@ -437,7 +366,7 @@ void video_set_dimensions() { if ((conf.video_scale_factor > 3) && (conf.video_filter == 5)) { scalefactor = 3; } int wscalefactor = conf.video_scale_factor; int tvwidth = nst_pal() ? PAL_TV_WIDTH : TV_WIDTH; - + switch(conf.video_filter) { case 0: // None basesize.w = Video::Output::WIDTH; @@ -467,7 +396,7 @@ void video_set_dimensions() { overscan_offset = basesize.w * OVERSCAN_TOP * scalefactor; overscan_height = basesize.h - (OVERSCAN_TOP + OVERSCAN_BOTTOM) * scalefactor; break; - + case 4: // 2xSaI basesize.w = Video::Output::WIDTH * 2; basesize.h = Video::Output::HEIGHT * 2; @@ -482,9 +411,13 @@ void video_set_dimensions() { rendersize.h -= (OVERSCAN_TOP + OVERSCAN_BOTTOM) * scalefactor; } else { overscan_offset = 0; overscan_height = basesize.h; } - + // Calculate the aspect from the height because it's smaller - float aspect = (float)screensize.h / (float)rendersize.h; + if (conf.video_fullscreen) { + float aspect = (float)screensize.h / (float)rendersize.h; + rendersize.w *= aspect; + rendersize.h *= aspect; + } } long video_lock_screen(void*& ptr) { @@ -493,15 +426,14 @@ long video_lock_screen(void*& ptr) { } void video_unlock_screen(void*) { - int xscale = renderstate.width / Video::Output::WIDTH;; int yscale = renderstate.height / Video::Output::HEIGHT; - + if (osdtext.drawtext) { nst_video_text_draw(osdtext.textbuf, osdtext.xpos * xscale, osdtext.ypos * yscale, osdtext.bg); osdtext.drawtext--; } - + if (osdtext.drawtime) { nst_video_text_draw(osdtext.timebuf, 208 * xscale, 218 * yscale, false); } @@ -513,7 +445,7 @@ void video_screenshot_flip(unsigned char *pixels, int width, int height, int byt unsigned char *row = (unsigned char*)malloc(rowsize); unsigned char *low = pixels; unsigned char *high = &pixels[(height - 1) * rowsize]; - + for (; low < high; low += rowsize, high -= rowsize) { memcpy(row, low, rowsize); memcpy(low, high, rowsize); @@ -526,16 +458,16 @@ void video_screenshot(const char* filename) { // Take a screenshot in .png format unsigned char *pixels; pixels = (unsigned char*)malloc(sizeof(unsigned char) * rendersize.w * rendersize.h * 4); - + // Read the pixels and flip them vertically glReadPixels(0, 0, rendersize.w, rendersize.h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); video_screenshot_flip(pixels, rendersize.w, rendersize.h, 4); - + if (filename == NULL) { // Set the filename char sshotpath[512]; snprintf(sshotpath, sizeof(sshotpath), "%sscreenshots/%s-%ld-%d.png", nstpaths.nstdir, nstpaths.gamename, time(NULL), rand() % 899 + 100); - + // Save the file lodepng_encode32_file(sshotpath, (const unsigned char*)pixels, rendersize.w, rendersize.h); fprintf(stderr, "Screenshot: %s\n", sshotpath); @@ -543,7 +475,7 @@ void video_screenshot(const char* filename) { else { lodepng_encode32_file(filename, (const unsigned char*)pixels, rendersize.w, rendersize.h); } - + free(pixels); } @@ -555,50 +487,18 @@ void video_clear_buffer() { void video_disp_nsf() { // Display NSF text Nsf nsf(emulator); - + int xscale = renderstate.width / Video::Output::WIDTH;; int yscale = renderstate.height / Video::Output::HEIGHT;; - + nst_video_text_draw(nsf.GetName(), 4 * xscale, 16 * yscale, false); nst_video_text_draw(nsf.GetArtist(), 4 * xscale, 28 * yscale, false); nst_video_text_draw(nsf.GetCopyright(), 4 * xscale, 40 * yscale, false); - + char currentsong[10]; snprintf(currentsong, sizeof(currentsong), "%d / %d", nsf.GetCurrentSong() +1, nsf.GetNumSongs()); nst_video_text_draw(currentsong, 4 * xscale, 52 * yscale, false); - - nst_ogl_render(); -} -void nst_video_disp_inputconf(int type, int pnum, int bnum) { - - int xscale = renderstate.width / Video::Output::WIDTH;; - int yscale = renderstate.height / Video::Output::HEIGHT;; - - char textbuf[32]; - char buttontext[8]; - - if (type == 0) { snprintf(textbuf, sizeof(textbuf), "Player %d Keyboard Configuration", pnum + 1); } - else { snprintf(textbuf, sizeof(textbuf), "Player %d Joystick Configuration", pnum + 1); } - - switch (bnum) { - case 0: snprintf(buttontext, sizeof(buttontext), "Up"); break; - case 1: snprintf(buttontext, sizeof(buttontext), "Down"); break; - case 2: snprintf(buttontext, sizeof(buttontext), "Left"); break; - case 3: snprintf(buttontext, sizeof(buttontext), "Right"); break; - case 4: snprintf(buttontext, sizeof(buttontext), "Select"); break; - case 5: snprintf(buttontext, sizeof(buttontext), "Start"); break; - case 6: snprintf(buttontext, sizeof(buttontext), "A"); break; - case 7: snprintf(buttontext, sizeof(buttontext), "B"); break; - case 8: snprintf(buttontext, sizeof(buttontext), "Turbo A"); break; - case 9: snprintf(buttontext, sizeof(buttontext), "Turbo B"); break; - } - - video_clear_buffer(); - - nst_video_text_draw(textbuf, 4 * xscale, 64 * yscale, false); - nst_video_text_draw(buttontext, 112 * xscale, 128 * yscale, false); - nst_ogl_render(); } @@ -621,13 +521,13 @@ void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg) { uint32_t b = 0x00000000; // Black uint32_t g = 0x00358570; // Nestopia UE Green uint32_t d = 0x00255f65; // Nestopia UE Dark Green - + int numchars = strlen(text); - + int letterypos; int letterxpos; int letternum = 0; - + if (bg) { // Draw background borders for (int i = 0; i < numchars * 8; i++) { // Rows above and below videobuf[(xpos + i) + ((ypos - 1) * renderstate.width)] = g; @@ -638,7 +538,7 @@ void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg) { videobuf[(xpos + (numchars * 8)) + ((ypos + i) * renderstate.width)] = g; } } - + for (int tpos = 0; tpos < (8 * numchars); tpos+=8) { nst_video_text_match(text, &letterxpos, &letterypos, letternum); for (int row = 0; row < 8; row++) { // Draw Rows @@ -647,11 +547,11 @@ void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg) { case '.': videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = w; break; - + case '+': videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = g; break; - + default: if (bg) { videobuf[xpos + ((ypos + row) * renderstate.width) + (col + tpos)] = d; } break; diff --git a/source/common/video.h b/source/fltkui/video.h similarity index 86% rename from source/common/video.h rename to source/fltkui/video.h index 53822b4..01a7227 100644 --- a/source/common/video.h +++ b/source/fltkui/video.h @@ -10,11 +10,6 @@ #define VIDBUF_MAXSIZE 31457280 -#include -#ifdef _APPLE -#include -#endif - typedef struct { int w; int h; @@ -35,9 +30,7 @@ void nst_ogl_deinit(); void nst_ogl_render(); void video_init(); -void video_toggle_filter(); void video_toggle_filterupdate(); -void video_toggle_scalefactor(); void video_set_filter(); dimensions_t nst_video_get_dimensions_render(); @@ -50,7 +43,6 @@ void video_unlock_screen(void*); void video_screenshot(const char* filename); void video_clear_buffer(); void video_disp_nsf(); -void nst_video_disp_inputconf(int type, int pnum, int bnum); void nst_video_print(const char *text, int xpos, int ypos, int seconds, bool bg); void nst_video_print_time(const char *timebuf, bool drawtime); void nst_video_text_draw(const char *text, int xpos, int ypos, bool bg); diff --git a/source/gtkui/gtkui.cpp b/source/gtkui/gtkui.cpp deleted file mode 100644 index fe70e10..0000000 --- a/source/gtkui/gtkui.cpp +++ /dev/null @@ -1,696 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2018 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include -#include -#include - -#include - -#include "nstcommon.h" -#include "cli.h" -#include "config.h" -#include "audio.h" -#include "video.h" -#include "input.h" - -#include "sdlinput.h" - -#include "gtkui.h" -#include "gtkui_archive.h" -#include "gtkui_callbacks.h" -#include "gtkui_config.h" -#include "gtkui_cheats.h" -#include "gtkui_dialogs.h" -#include "gtkui_input.h" - -GtkWidget *gtkwindow; -static GtkWidget *menubar; -static GtkWidget *drawingarea; - -static GThread *emuthread; - -char iconpath[512]; -char padpath[512]; - -extern bool (*nst_archive_select)(const char*, char*, size_t); - -extern Input::Controllers *cNstPads; -extern nstpaths_t nstpaths; -int nst_quit = 1; - -gpointer gtkui_emuloop(gpointer data) { - while(!nst_quit) { nst_emuloop(); } - g_thread_exit(emuthread); - return NULL; -} - -void gtkui_emuloop_start() { - nst_quit = 0; - emuthread = g_thread_new("emuloop", gtkui_emuloop, NULL); -} - -void gtkui_emuloop_stop() { - nst_quit = true; -} - -void gtkui_quit() { - gtkui_emuloop_stop(); - gtk_main_quit(); -} - -static void gtkui_glarea_realize(GtkGLArea *glarea) { - gtk_gl_area_make_current(glarea); - gtk_gl_area_set_has_depth_buffer(glarea, FALSE); - nst_ogl_init(); -} - -static void gtkui_swapbuffers() { - gtk_widget_queue_draw(drawingarea); - gtk_widget_queue_draw(menubar); // Needed on some builds of GTK3 - nst_ogl_render(); - nst_emuloop(); - - // Move this later FIXME - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_JOYHATMOTION: - case SDL_JOYAXISMOTION: - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: - nstsdl_input_process(cNstPads, event); - break; - default: break; - } - } -} - -void gtkui_state_quickload(GtkWidget *widget, gpointer userdata) { - // Wrapper function to quickload states - nst_state_quickload(GPOINTER_TO_INT(userdata)); -} - -void gtkui_state_quicksave(GtkWidget *widget, gpointer userdata) { - // Wrapper function to quicksave states - nst_state_quicksave(GPOINTER_TO_INT(userdata)); -} - -void gtkui_open_recent(GtkWidget *widget, gpointer userdata) { - // Open a recently used item - gchar *uri = gtk_recent_chooser_get_current_uri((GtkRecentChooser*)widget); - nst_load(g_filename_from_uri(uri, NULL, NULL)); - gtkui_set_title(nstpaths.gamename); - gtkui_play(); -} - -dimensions_t gtkui_video_get_dimensions() { - // Return the dimensions of the current screen - dimensions_t scrsize; - dimensions_t rendsize = nst_video_get_dimensions_render(); - GdkDisplay *display = gdk_display_get_default(); - GdkWindow *gdkwindow = gtk_widget_get_window(GTK_WIDGET(gtkwindow)); - GdkMonitor *monitor = gdk_display_get_monitor_at_window(display, gdkwindow); - GdkRectangle geom; - gdk_monitor_get_geometry(monitor, &geom); - scrsize.w = geom.width; - scrsize.h = geom.height; - float ratio = (float)scrsize.h / (float)rendsize.h; - scrsize.w = (int)(rendsize.w * ratio); - return scrsize; -} - -void gtkui_create() { - // Create the GTK Window - - gtkui_image_paths(); - GdkPixbuf *icon = gdk_pixbuf_new_from_file(iconpath, NULL); - - char title[24]; - snprintf(title, sizeof(title), "Nestopia UE"); - - gtkwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_icon(GTK_WINDOW(gtkwindow), icon); - gtk_window_set_title(GTK_WINDOW(gtkwindow), title); - gtk_window_set_resizable(GTK_WINDOW(gtkwindow), FALSE); - - GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add(GTK_CONTAINER(gtkwindow), box); - - // Define the menubar and menus - menubar = gtk_menu_bar_new(); - - // Define the File menu - GtkWidget *filemenu = gtk_menu_new(); - GtkWidget *file = gtk_menu_item_new_with_label("File"); - GtkWidget *open = gtk_menu_item_new_with_label("Open..."); - GtkWidget *recent = gtk_menu_item_new_with_label("Open Recent"); - GtkWidget *sep_open = gtk_separator_menu_item_new(); - GtkWidget *stateload = gtk_menu_item_new_with_label("Load State..."); - GtkWidget *statesave = gtk_menu_item_new_with_label("Save State..."); - - GtkWidget *quickload = gtk_menu_item_new_with_label("Quick Load"); - GtkWidget *qloadmenu = gtk_menu_new(); - GtkWidget *qload0 = gtk_menu_item_new_with_label("0"); - GtkWidget *qload1 = gtk_menu_item_new_with_label("1"); - GtkWidget *qload2 = gtk_menu_item_new_with_label("2"); - GtkWidget *qload3 = gtk_menu_item_new_with_label("3"); - GtkWidget *qload4 = gtk_menu_item_new_with_label("4"); - - GtkWidget *quicksave = gtk_menu_item_new_with_label("Quick Save"); - GtkWidget *qsavemenu = gtk_menu_new(); - GtkWidget *qsave0 = gtk_menu_item_new_with_label("0"); - GtkWidget *qsave1 = gtk_menu_item_new_with_label("1"); - GtkWidget *qsave2 = gtk_menu_item_new_with_label("2"); - GtkWidget *qsave3 = gtk_menu_item_new_with_label("3"); - GtkWidget *qsave4 = gtk_menu_item_new_with_label("4"); - - GtkWidget *sep_state = gtk_separator_menu_item_new(); - GtkWidget *palette = gtk_menu_item_new_with_label("Open Palette..."); - GtkWidget *sep_palette = gtk_separator_menu_item_new(); - GtkWidget *screenshot = gtk_menu_item_new_with_label("Screenshot..."); - GtkWidget *sep_screenshot = gtk_separator_menu_item_new(); - GtkWidget *movieload = gtk_menu_item_new_with_label("Load Movie..."); - GtkWidget *moviesave = gtk_menu_item_new_with_label("Record Movie..."); - GtkWidget *moviestop = gtk_menu_item_new_with_label("Stop Movie"); - GtkWidget *sep_movie = gtk_separator_menu_item_new(); - GtkWidget *quit = gtk_menu_item_new_with_label("Quit"); - - // Set up the recently used items - GtkWidget *recent_items = gtk_recent_chooser_menu_new(); - GtkRecentFilter *recent_filter = gtk_recent_filter_new(); - gtk_recent_filter_add_pattern(recent_filter, "*.nes"); - gtk_recent_filter_add_pattern(recent_filter, "*.fds"); - gtk_recent_filter_add_pattern(recent_filter, "*.unf"); - gtk_recent_filter_add_pattern(recent_filter, "*.unif"); - gtk_recent_filter_add_pattern(recent_filter, "*.nsf"); - gtk_recent_filter_add_pattern(recent_filter, "*.zip"); - gtk_recent_filter_add_pattern(recent_filter, "*.7z"); - gtk_recent_filter_add_pattern(recent_filter, "*.txz"); - gtk_recent_filter_add_pattern(recent_filter, "*.tar.xz"); - gtk_recent_filter_add_pattern(recent_filter, "*.xz"); - gtk_recent_filter_add_pattern(recent_filter, "*.tgz"); - gtk_recent_filter_add_pattern(recent_filter, "*.tar.gz"); - gtk_recent_filter_add_pattern(recent_filter, "*.gz"); - gtk_recent_filter_add_pattern(recent_filter, "*.tbz"); - gtk_recent_filter_add_pattern(recent_filter, "*.tar.bz2"); - gtk_recent_filter_add_pattern(recent_filter, "*.bz2"); - gtk_recent_chooser_add_filter(GTK_RECENT_CHOOSER(recent_items), recent_filter); - - // Populate the File menu - gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), recent); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), recent_items); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_open); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), stateload); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), statesave); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quickload); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(quickload), qloadmenu); - gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload0); - gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload1); - gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload2); - gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload3); - gtk_menu_shell_append(GTK_MENU_SHELL(qloadmenu), qload4); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quicksave); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(quicksave), qsavemenu); - gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave0); - gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave1); - gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave2); - gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave3); - gtk_menu_shell_append(GTK_MENU_SHELL(qsavemenu), qsave4); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_state); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), palette); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_palette); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), screenshot); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_screenshot); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), movieload); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), moviesave); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), moviestop); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep_movie); - gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit); - - // Define the Emulator menu - GtkWidget *emulatormenu = gtk_menu_new(); - GtkWidget *emu = gtk_menu_item_new_with_label("Emulator"); - GtkWidget *cont = gtk_menu_item_new_with_label("Continue"); - GtkWidget *pause = gtk_menu_item_new_with_label("Pause"); - GtkWidget *sep_pause = gtk_separator_menu_item_new(); - GtkWidget *resetsoft = gtk_menu_item_new_with_label("Reset (Soft)"); - GtkWidget *resethard = gtk_menu_item_new_with_label("Reset (Hard)"); - GtkWidget *sep_reset = gtk_separator_menu_item_new(); - GtkWidget *fullscreen = gtk_menu_item_new_with_label("Fullscreen"); - GtkWidget *sep_fullscreen = gtk_separator_menu_item_new(); - GtkWidget *diskflip = gtk_menu_item_new_with_label("Flip FDS Disk"); - GtkWidget *diskswitch = gtk_menu_item_new_with_label("Switch FDS Disk"); - GtkWidget *sep_disk = gtk_separator_menu_item_new(); - GtkWidget *cheats = gtk_menu_item_new_with_label("Cheats..."); - GtkWidget *sep_cheats = gtk_separator_menu_item_new(); - GtkWidget *configuration = gtk_menu_item_new_with_label("Configuration..."); - - // Populate the Emulator menu - gtk_menu_item_set_submenu(GTK_MENU_ITEM(emu), emulatormenu); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), cont); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), pause); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_pause); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), resetsoft); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), resethard); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_reset); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), fullscreen); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_fullscreen); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), diskflip); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), diskswitch); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_disk); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), cheats); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), sep_cheats); - gtk_menu_shell_append(GTK_MENU_SHELL(emulatormenu), configuration); - - // Define the Help menu - GtkWidget *helpmenu = gtk_menu_new(); - GtkWidget *help = gtk_menu_item_new_with_label("Help"); - GtkWidget *about = gtk_menu_item_new_with_label("About"); - - // Populate the Help menu - gtk_menu_item_set_submenu(GTK_MENU_ITEM(help), helpmenu); - gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu), about); - - // Put the menus into the menubar - gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file); - gtk_menu_shell_append(GTK_MENU_SHELL(menubar), emu); - gtk_menu_shell_append(GTK_MENU_SHELL(menubar), help); - - // Create the DrawingArea/OpenGL context - drawingarea = gtk_gl_area_new(); - g_signal_connect(G_OBJECT(drawingarea), "realize", G_CALLBACK(gtkui_glarea_realize), NULL); - g_signal_connect(G_OBJECT(drawingarea), "render", gtkui_swapbuffers, NULL); - - g_object_set_data(G_OBJECT(gtkwindow), "area", drawingarea); - - // Set the Drawing Area to be the size of the game output - dimensions_t rendersize = nst_video_get_dimensions_render(); - gtk_widget_set_size_request(drawingarea, rendersize.w, rendersize.h); - - // Pack the box with the menubar, drawingarea, and statusbar - gtk_box_pack_start(GTK_BOX(box), menubar, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box), drawingarea, TRUE, TRUE, 0); - - // Make it dark if there's a dark theme - GtkSettings *gtksettings = gtk_settings_get_default(); - g_object_set(G_OBJECT(gtksettings), "gtk-application-prefer-dark-theme", TRUE, nullptr); - - // Set up the Drag and Drop target - GtkTargetEntry target_entry[1]; - - target_entry[0].target = (gchar*)"text/uri-list"; - target_entry[0].flags = 0; - target_entry[0].info = 0; - - gtk_drag_dest_set(drawingarea, (GtkDestDefaults)(GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP), - target_entry, sizeof(target_entry) / sizeof(GtkTargetEntry), (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY)); - - // Connect the signals - g_signal_connect(G_OBJECT(drawingarea), "drag-data-received", - G_CALLBACK(gtkui_drag_data), NULL); - - g_signal_connect(G_OBJECT(gtkwindow), "delete_event", - G_CALLBACK(gtkui_quit), NULL); - - // File menu - g_signal_connect(G_OBJECT(open), "activate", - G_CALLBACK(gtkui_file_open), NULL); - - g_signal_connect(G_OBJECT(recent_items), "item-activated", - G_CALLBACK(gtkui_open_recent), NULL); - - g_signal_connect(G_OBJECT(stateload), "activate", - G_CALLBACK(gtkui_state_load), NULL); - - g_signal_connect(G_OBJECT(statesave), "activate", - G_CALLBACK(gtkui_state_save), NULL); - - g_signal_connect(G_OBJECT(qload0), "activate", - G_CALLBACK(gtkui_state_quickload), gpointer(0)); - - g_signal_connect(G_OBJECT(qload1), "activate", - G_CALLBACK(gtkui_state_quickload), gpointer(1)); - - g_signal_connect(G_OBJECT(qload2), "activate", - G_CALLBACK(gtkui_state_quickload), gpointer(2)); - - g_signal_connect(G_OBJECT(qload3), "activate", - G_CALLBACK(gtkui_state_quickload), gpointer(3)); - - g_signal_connect(G_OBJECT(qload4), "activate", - G_CALLBACK(gtkui_state_quickload), gpointer(4)); - - g_signal_connect(G_OBJECT(qsave0), "activate", - G_CALLBACK(gtkui_state_quicksave), gpointer(0)); - - g_signal_connect(G_OBJECT(qsave1), "activate", - G_CALLBACK(gtkui_state_quicksave), gpointer(1)); - - g_signal_connect(G_OBJECT(qsave2), "activate", - G_CALLBACK(gtkui_state_quicksave), gpointer(2)); - - g_signal_connect(G_OBJECT(qsave3), "activate", - G_CALLBACK(gtkui_state_quicksave), gpointer(3)); - - g_signal_connect(G_OBJECT(qsave4), "activate", - G_CALLBACK(gtkui_state_quicksave), gpointer(4)); - - g_signal_connect(G_OBJECT(screenshot), "activate", - G_CALLBACK(gtkui_screenshot_save), NULL); - - g_signal_connect(G_OBJECT(palette), "activate", - G_CALLBACK(gtkui_palette_load), NULL); - - g_signal_connect(G_OBJECT(moviesave), "activate", - G_CALLBACK(gtkui_movie_save), NULL); - - g_signal_connect(G_OBJECT(movieload), "activate", - G_CALLBACK(gtkui_movie_load), NULL); - - g_signal_connect(G_OBJECT(moviestop), "activate", - G_CALLBACK(gtkui_movie_stop), NULL); - - g_signal_connect(G_OBJECT(quit), "activate", - G_CALLBACK(gtkui_quit), NULL); - - // Emulator menu - g_signal_connect(G_OBJECT(cont), "activate", - G_CALLBACK(gtkui_play), NULL); - - g_signal_connect(G_OBJECT(pause), "activate", - G_CALLBACK(gtkui_pause), NULL); - - g_signal_connect(G_OBJECT(resetsoft), "activate", - G_CALLBACK(gtkui_cb_reset), gpointer(0)); - - g_signal_connect(G_OBJECT(resethard), "activate", - G_CALLBACK(gtkui_cb_reset), gpointer(1)); - - g_signal_connect(G_OBJECT(fullscreen), "activate", - G_CALLBACK(gtkui_video_toggle_fullscreen), NULL); - - g_signal_connect(G_OBJECT(diskflip), "activate", - G_CALLBACK(nst_fds_flip), NULL); - - g_signal_connect(G_OBJECT(diskswitch), "activate", - G_CALLBACK(nst_fds_switch), NULL); - - g_signal_connect(G_OBJECT(cheats), "activate", - G_CALLBACK(gtkui_cheats), NULL); - - g_signal_connect(G_OBJECT(configuration), "activate", - G_CALLBACK(gtkui_config), NULL); - - // Help menu - g_signal_connect(G_OBJECT(about), "activate", - G_CALLBACK(gtkui_about), NULL); - - // Mouse input events - gtk_widget_add_events(GTK_WIDGET(drawingarea), GDK_BUTTON_PRESS_MASK); - gtk_widget_add_events(GTK_WIDGET(drawingarea), GDK_BUTTON_RELEASE_MASK); - - gtk_widget_show_all(gtkwindow); - - nst_video_set_dimensions_screen(gtkui_video_get_dimensions()); -} - -void gtkui_signals_init() { - // Key translation - if (nst_nsf()) { - g_signal_connect(G_OBJECT(gtkwindow), "key-press-event", - G_CALLBACK(gtkui_input_process_key_nsf), NULL); - - g_signal_connect(G_OBJECT(gtkwindow), "key-release-event", - G_CALLBACK(gtkui_input_process_key_nsf), NULL); - } - else { - g_signal_connect(G_OBJECT(gtkwindow), "key-press-event", - G_CALLBACK(gtkui_input_process_key), NULL); - - g_signal_connect(G_OBJECT(gtkwindow), "key-release-event", - G_CALLBACK(gtkui_input_process_key), NULL); - } - // Mouse translation - g_signal_connect(G_OBJECT(drawingarea), "button-press-event", - G_CALLBACK(gtkui_input_process_mouse), NULL); - - g_signal_connect(G_OBJECT(drawingarea), "button-release-event", - G_CALLBACK(gtkui_input_process_mouse), NULL); -} - -void gtkui_signals_deinit() { - // Key translation - g_signal_connect(G_OBJECT(gtkwindow), "key-press-event", - gtkui_input_null, NULL); - - g_signal_connect(G_OBJECT(gtkwindow), "key-release-event", - gtkui_input_null, NULL); - - // Mouse translation - g_signal_connect(G_OBJECT(drawingarea), "button-press-event", - gtkui_input_null, NULL); - - g_signal_connect(G_OBJECT(drawingarea), "button-release-event", - gtkui_input_null, NULL); -} - -void gtkui_resize() { - // Resize the GTK window - if (gtkwindow) { - dimensions_t rendersize; - if (conf.video_fullscreen) { rendersize = gtkui_video_get_dimensions(); } - else { rendersize = nst_video_get_dimensions_render(); } - gtk_widget_set_size_request(drawingarea, rendersize.w, rendersize.h); - } -} - -void gtkui_set_title(const char *title) { - gtk_window_set_title(GTK_WINDOW(gtkwindow), title); -} - -void gtkui_video_toggle_fullscreen() { - conf.video_fullscreen ^= 1; - - if (conf.video_fullscreen) { - gtk_widget_hide(menubar); - gtk_window_fullscreen(GTK_WINDOW(gtkwindow)); - if (nst_input_zapper_present()) { - gtkui_cursor_set(conf.misc_disable_cursor_special ? 0 : 2); - } - else {gtkui_cursor_set(0); } - } - else { - gtk_window_unfullscreen(GTK_WINDOW(gtkwindow)); - gtk_widget_show(menubar); - if (nst_input_zapper_present()) { - gtkui_cursor_set(conf.misc_disable_cursor_special ? 0 : 2); - } - else {gtkui_cursor_set(1); } - } - nst_video_set_dimensions_screen(gtkui_video_get_dimensions()); - - gtkui_resize(); - video_init(); -} - -void gtkui_video_toggle_filter() { - video_toggle_filter(); - gtkui_resize(); - video_init(); -} - -void gtkui_video_toggle_scale() { - video_toggle_scalefactor(); - gtkui_resize(); - video_init(); -} - -GtkWidget *gtkui_about() { - // Pull up the About dialog - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size(iconpath, 192, 192, NULL); - GtkWidget *aboutdialog = gtk_about_dialog_new(); - gtk_window_set_transient_for(GTK_WINDOW(aboutdialog), GTK_WINDOW(gtkwindow)); - - gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(aboutdialog), pixbuf); - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(aboutdialog), "Nestopia UE"); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(aboutdialog), "vx.xx"); - gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(aboutdialog), "Cycle-Accurate Nintendo Entertainment System Emulator"); - gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(aboutdialog), "http://0ldsk00l.ca/nestopia/"); - gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(aboutdialog), "GTK Frontend\n(c) 2012-2021, R. Danbrook\n(c) 2007-2008, R. Belmont\n\nNestopia Emulator\n(c) 2020-2021, Rupert Carmichael\n(c) 2012-2020, Nestopia UE Contributors\n(c) 2003-2008, Martin Freij\n\nIcon based on art from Trollekop"); - gtk_dialog_run(GTK_DIALOG(aboutdialog)); - gtk_widget_destroy(aboutdialog); - - return aboutdialog; -} - -void gtkui_image_paths() { - // Set paths to SVG icons/images - snprintf(iconpath, sizeof(iconpath), "%s/icons/hicolor/scalable/apps/nestopia.svg", DATAROOTDIR); - snprintf(padpath, sizeof(padpath), "%s/icons/hicolor/scalable/apps/nespad.svg", DATAROOTDIR); - - // Load the SVG from local source dir if make install hasn't been done - struct stat svgstat; - if (stat(iconpath, &svgstat) == -1) { - snprintf(iconpath, sizeof(iconpath), "icons/svg/nestopia.svg"); - } - if (stat(padpath, &svgstat) == -1) { - snprintf(padpath, sizeof(padpath), "icons/svg/nespad.svg"); - } -} - -void gtkui_message(const char* message) { - GtkWidget *messagewindow = gtk_message_dialog_new( - GTK_WINDOW(gtkwindow), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_INFO, - GTK_BUTTONS_OK, - "%s", message); - gtk_dialog_run(GTK_DIALOG(messagewindow)); - gtk_widget_destroy(messagewindow); -} - -void gtkui_cursor_set(int curtype) { - // Set the cursor - GdkCursor *cursor; - GdkDisplay *display = gdk_display_get_default(); - - switch (curtype) { - case 0: cursor = gdk_cursor_new_from_name(display, "none"); break; - case 1: cursor = gdk_cursor_new_from_name(display, "default"); break; - case 2: cursor = gdk_cursor_new_from_name(display, "crosshair"); break; - default: cursor = gdk_cursor_new_from_name(display, "default"); break; - } - - GdkWindow *gdkwindow = gtk_widget_get_window(GTK_WIDGET(drawingarea)); - gdk_window_set_cursor(gdkwindow, cursor); - gdk_display_flush(display); - g_object_unref(cursor); -} - -void gtkui_play() { - gtkui_signals_init(); - nst_play(); - - if (nst_input_zapper_present()) { - gtkui_cursor_set(conf.misc_disable_cursor_special ? 0 : 2); - } - else { - gtkui_cursor_set(conf.misc_disable_cursor ? 0 : 1); - } -} - -void gtkui_pause() { - gtkui_signals_deinit(); - nst_pause(); -} - -int main(int argc, char *argv[]) { - - // Set up directories - nst_set_dirs(); - - // Set default config options - config_set_default(); - - // Read the config file and override defaults - config_file_read(nstpaths.nstconfdir); - - // Handle command line arguments - cli_handle_command(argc, argv); - - // Set default input keys - gtkui_input_set_default(); - - // Read the input config file and override defaults - gtkui_input_config_read(); - - // Set the video dimensions - video_set_dimensions(); - - // Set up callbacks - nst_set_callbacks(); - - // Initialize SDL Audio and Joystick - if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { - fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); - return 1; - } - - // Set archive handler function pointer - nst_archive_select = >kui_archive_select; - - // Detect and set up Joysticks - nstsdl_input_joysticks_detect(); - nstsdl_input_conf_defaults(); - nstsdl_input_conf_read(); - - // Initialize and load FDS BIOS and NstDatabase.xml - nst_fds_bios_load(); - nst_db_load(); - - // Initialize the GTK GUI - gtk_init(&argc, &argv); - gtkui_create(); - - // Load a rom from the command line - if (argc > 1 && argv[argc - 1][0] != '-') { - nst_load(argv[argc - 1]); - if (conf.video_fullscreen) { - conf.video_fullscreen = 0; - gtkui_video_toggle_fullscreen(); - } - gtkui_play(); - gtkui_set_title(nstpaths.gamename); - } - else if (conf.video_fullscreen) { conf.video_fullscreen = 0; } - - // Start GTK main loop - gtk_main(); - - // Remove the cartridge and shut down the NES - nst_unload(); - - // Unload the FDS BIOS, NstDatabase.xml, and the custom palette - nst_db_unload(); - nst_fds_bios_unload(); - nst_palette_unload(); - - // Deinitialize audio - audio_deinit(); - - // Deinitialize joysticks - nstsdl_input_joysticks_close(); - - // Write the input config file - nstsdl_input_conf_write(); - - // Write the input config file - gtkui_input_config_write(); - - // Write the config file - config_file_write(nstpaths.nstconfdir); - - return 0; -} diff --git a/source/gtkui/gtkui.h b/source/gtkui/gtkui.h deleted file mode 100644 index 02d3c15..0000000 --- a/source/gtkui/gtkui.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _GTKUI_H_ -#define _GTKUI_H_ - -#include - -void gtkui_emuloop_start(); -void gtkui_emuloop_stop(); -void gtkui_create(); -void gtkui_resize(); -void gtkui_set_title(const char *title); -GtkWidget *gtkui_about(); -void gtkui_image_paths(); -void gtkui_message(const char* message); -void gtkui_cursor_set(int curtype); -void gtkui_video_toggle_fullscreen(); -void gtkui_video_toggle_filter(); -void gtkui_video_toggle_scale(); -void gtkui_signals_init(); -void gtkui_signals_deinit(); -void gtkui_play(); -void gtkui_pause(); - -#endif diff --git a/source/gtkui/gtkui_archive.cpp b/source/gtkui/gtkui_archive.cpp deleted file mode 100644 index be602f6..0000000 --- a/source/gtkui/gtkui_archive.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2016 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include -#include -#include - -#include "nstcommon.h" -#include "config.h" - -#include "gtkui.h" -#include "gtkui_archive.h" - -static bool windowopen, cancelled; - -static GtkWidget *archivewindow; - -bool gtkui_archive_select(const char *filename, char *reqfile, size_t reqsize) { - // Select a filename to pull out of the archive - struct archive *a; - struct archive_entry *entry; - int r, numarchives = 0; - - cancelled = false; - - a = archive_read_new(); - archive_read_support_filter_all(a); - archive_read_support_format_all(a); - r = archive_read_open_filename(a, filename, 10240); - - // Test if it's actually an archive - if (r != ARCHIVE_OK) { - r = archive_read_free(a); - return false; - } - // If it is an archive, handle it - else { - // Set up the archive window - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreeSelection *selection; - - archivewindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(archivewindow), "Choose File from Archive"); - gtk_window_set_modal(GTK_WINDOW(archivewindow), TRUE); - - GtkWidget *archivebox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add(GTK_CONTAINER(archivewindow), archivebox); - gtk_widget_show(archivebox); - - GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL); - gtk_box_pack_start(GTK_BOX(archivebox), scrolledwindow, TRUE, TRUE, 0); - gtk_widget_set_size_request(scrolledwindow, 340, 340); - gtk_widget_show(scrolledwindow); - - GtkWidget *buttonbox = gtk_widget_new(GTK_TYPE_BOX, "halign", GTK_ALIGN_END, NULL); - gtk_box_pack_start(GTK_BOX(archivebox), buttonbox, FALSE, TRUE, 0); - gtk_widget_show(buttonbox); - - GtkWidget *treeview = gtk_tree_view_new(); - gtk_container_add(GTK_CONTAINER(scrolledwindow), treeview); - gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW (treeview), FALSE); - gtk_widget_show(treeview); - - GtkTreeStore *treestore = gtk_tree_store_new(1, G_TYPE_STRING); - - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore)); - - // Fill the treestore with the filenames - while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { - const char *currentfile = archive_entry_pathname(entry); - if (nst_archive_checkext(currentfile)) { - gtk_tree_store_append(treestore, &iter, NULL); - gtk_tree_store_set(treestore, &iter, 0, currentfile, -1); - numarchives++; - snprintf(reqfile, reqsize, "%s", currentfile); - } - archive_read_data_skip(a); - } - // Free the archive - r = archive_read_free(a); - - // If there are no valid files in the archive, return - if (numarchives == 0) { return false; } - // If there's only one file, don't bring up the selector - else if (numarchives == 1) { return true; } - - GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); - - GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes( - "NES file", - renderer, - "text", 0, - nullptr); - - gtk_tree_view_append_column(GTK_TREE_VIEW (treeview), column); - - GtkWidget *cancelbutton = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "Cancel", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(buttonbox), cancelbutton, FALSE, FALSE, 0); - gtk_widget_show(cancelbutton); - - GtkWidget *okbutton = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "OK", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(buttonbox), okbutton, FALSE, FALSE, 0); - gtk_widget_show(okbutton); - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - - g_signal_connect(G_OBJECT(okbutton), "clicked", - G_CALLBACK(gtkui_archive_ok), NULL); - - g_signal_connect(G_OBJECT(cancelbutton), "clicked", - G_CALLBACK(gtkui_archive_cancel), NULL); - - g_signal_connect(G_OBJECT(treeview), "row-activated", - G_CALLBACK(gtkui_archive_ok), NULL); - - g_signal_connect(G_OBJECT(archivewindow), "destroy", - G_CALLBACK(gtkui_archive_cancel), NULL); - - gtk_widget_show(archivewindow); - - // Freeze the rest of the program until a selection is made - windowopen = true; - while (windowopen) { - gtk_main_iteration_do(TRUE); - if (cancelled) { return false; } - } - - gchar *reqbuf; - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - gtk_tree_selection_get_selected(selection, &model, &iter); - gtk_tree_model_get(model, &iter, 0, &reqbuf, -1); - - gtk_widget_destroy(archivewindow); - - snprintf(reqfile, reqsize, "%s", reqbuf); - return true; - } - return false; -} - -void gtkui_archive_ok() { - windowopen = false; -} - -void gtkui_archive_cancel() { - cancelled = true; - gtk_widget_destroy(archivewindow); -} diff --git a/source/gtkui/gtkui_archive.h b/source/gtkui/gtkui_archive.h deleted file mode 100644 index c47078c..0000000 --- a/source/gtkui/gtkui_archive.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _GTKUI_ARCHIVE_H_ -#define _GTKUI_ARCHIVE_H_ - -bool gtkui_archive_select(const char *filename, char *reqfile, size_t reqsize); -void gtkui_archive_ok(); -void gtkui_archive_cancel(); - -#endif diff --git a/source/gtkui/gtkui_callbacks.cpp b/source/gtkui/gtkui_callbacks.cpp deleted file mode 100644 index bcc5509..0000000 --- a/source/gtkui/gtkui_callbacks.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2017 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include - -#include "nstcommon.h" -#include "config.h" -#include "video.h" -#include "input.h" - -#include "gtkui.h" -#include "gtkui_callbacks.h" - -extern bool kbactivate, confrunning; -extern int nst_quit; - -//// Menu //// - -void gtkui_cb_reset(GtkWidget *reset, int hard) { - // Reset the NES from the GUI - nst_reset(hard); -} - -void gtkui_cb_nothing() { - // Do nothing -} - -void gtkui_cb_video_refresh() { - // Refresh the Video output after changes - if (nst_playing()) { video_init(); } - gtkui_resize(); -} - -// Video // - -void gtkui_cb_video_filter(GtkComboBox *combobox, gpointer userdata) { - // Change the video filter - conf.video_filter = gtk_combo_box_get_active(combobox); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_scale(GtkComboBox *combobox, gpointer userdata) { - // Change the scale factor - conf.video_scale_factor = gtk_combo_box_get_active(combobox) + 1; - - // The scalex filter only allows 3x scale and crashes otherwise - if (conf.video_filter == 5 && conf.video_scale_factor == 4) { - conf.video_scale_factor = 3; - } - - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_ntscmode(GtkComboBox *combobox, gpointer userdata) { - // Change the NTSC Mode - conf.video_ntsc_mode = gtk_combo_box_get_active(combobox); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_xbrrounding(GtkComboBox *combobox, gpointer userdata) { - // Set xBR corner rounding parameters - conf.video_xbr_corner_rounding = gtk_combo_box_get_active(combobox); - gtkui_cb_video_refresh(); - video_toggle_filterupdate(); -} - -void gtkui_cb_video_xbrpixblend(GtkToggleButton *togglebutton, gpointer userdata) { - // Set xBR pixel blending parameters - conf.video_xbr_pixel_blending = gtk_toggle_button_get_active(togglebutton); - gtkui_cb_video_refresh(); - video_toggle_filterupdate(); -} - -void gtkui_cb_video_linear_filter(GtkToggleButton *togglebutton, gpointer userdata) { - // Set linear filter - conf.video_linear_filter = gtk_toggle_button_get_active(togglebutton); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_tv_aspect(GtkToggleButton *togglebutton, gpointer userdata) { - // Set TV aspect ratio - conf.video_tv_aspect = gtk_toggle_button_get_active(togglebutton); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_unmask_overscan(GtkToggleButton *togglebutton, gpointer userdata) { - // Set overscan mask - conf.video_unmask_overscan = gtk_toggle_button_get_active(togglebutton); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_stretch_aspect(GtkToggleButton *togglebutton, gpointer userdata) { - // Set aspect ratio stretching/preservation - conf.video_stretch_aspect = gtk_toggle_button_get_active(togglebutton); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_unlimited_sprites(GtkToggleButton *togglebutton, gpointer userdata) { - // Set sprite limit - conf.video_unlimited_sprites = gtk_toggle_button_get_active(togglebutton); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_palette(GtkComboBox *combobox, gpointer userdata) { - // Change the video palette - conf.video_palette_mode = gtk_combo_box_get_active(combobox); - gtkui_cb_video_refresh(); - // this doesn't work unless there's a restart - fix -} - -void gtkui_cb_video_decoder(GtkComboBox *combobox, gpointer userdata) { - // Change the YUV Decoder - conf.video_decoder = gtk_combo_box_get_active(combobox); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_brightness(GtkRange *range, gpointer userdata) { - // Change video brightness - conf.video_brightness = (int)gtk_range_get_value(range); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_saturation(GtkRange *range, gpointer userdata) { - // Change video saturation - conf.video_saturation = (int)gtk_range_get_value(range); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_contrast(GtkRange *range, gpointer userdata) { - // Change video contrast - conf.video_contrast = (int)gtk_range_get_value(range); - gtkui_cb_video_refresh(); -} - -void gtkui_cb_video_hue(GtkRange *range, gpointer userdata) { - // Change video hue - conf.video_hue = (int)gtk_range_get_value(range); - gtkui_cb_video_refresh(); -} - -// Audio // - -void gtkui_cb_audio_samplerate(GtkComboBox *combobox, gpointer userdata) { - // Change the Sample Rate - switch (gtk_combo_box_get_active(combobox)) { - case 0: - conf.audio_sample_rate = 11025; - break; - case 1: - conf.audio_sample_rate = 22050; - break; - case 2: - conf.audio_sample_rate = 44100; - break; - case 3: - conf.audio_sample_rate = 48000; - break; - case 4: - conf.audio_sample_rate = 96000; - break; - default: - conf.audio_sample_rate = 44100; - break; - } - - if (nst_playing()) { - nst_pause(); - nst_play(); - } -} - -void gtkui_cb_audio_stereo(GtkToggleButton *togglebutton, gpointer userdata) { - // Toggle Stereo - conf.audio_stereo = gtk_toggle_button_get_active(togglebutton); - - if (nst_playing()) { - nst_pause(); - nst_play(); - } -} - -//// Input //// - -void gtkui_cb_input_turbopulse(GtkRange *range, gpointer userdata) { - // Change turbo pulse - conf.timing_turbopulse = (int)gtk_range_get_value(range); -} - -//// Misc //// - -void gtkui_cb_misc_default_system(GtkComboBox *combobox, gpointer userdata) { - // Select the default system - conf.misc_default_system = gtk_combo_box_get_active(combobox); -} - -void gtkui_cb_misc_power_state(GtkComboBox *combobox, gpointer userdata) { - // Select the default system - conf.misc_power_state = gtk_combo_box_get_active(combobox); -} - -void gtkui_cb_timing_ffspeed(GtkRange *range, gpointer userdata) { - // Set Fast-Forward Speed - conf.timing_ffspeed = (int)gtk_range_get_value(range); -} - -void gtkui_cb_misc_soft_patching(GtkToggleButton *togglebutton, gpointer userdata) { - // Enable or Disable automatic soft patching - conf.misc_soft_patching = gtk_toggle_button_get_active(togglebutton); -} - -void gtkui_cb_misc_genie_distortion(GtkToggleButton *togglebutton, gpointer userdata) { - // Enable or Disable Game Genie Sound Distortion - conf.misc_genie_distortion = gtk_toggle_button_get_active(togglebutton); -} - -void gtkui_cb_misc_disable_cursor(GtkToggleButton *togglebutton, gpointer userdata) { - // Enable or Disable the Cursor - conf.misc_disable_cursor = gtk_toggle_button_get_active(togglebutton); - if (!nst_quit) { gtkui_play(); } -} - -void gtkui_cb_misc_disable_cursor_special(GtkToggleButton *togglebutton, gpointer userdata) { - // Enable or Disable Special Cursors - conf.misc_disable_cursor_special = gtk_toggle_button_get_active(togglebutton); - if (!nst_quit) { gtkui_play(); } -} - -void gtkui_cb_misc_config_pause(GtkToggleButton *togglebutton, gpointer userdata) { - // Pause GUI when configuration window is open - conf.misc_config_pause = gtk_toggle_button_get_active(togglebutton); -} - -void gtkui_drag_data(GtkWidget *widget, GdkDragContext *dragcontext, gint x, gint y, GtkSelectionData *seldata, guint info, guint time, gpointer data) { - // Handle the Drag and Drop - if ((widget == NULL) || (dragcontext == NULL) || (seldata == NULL)) { return; } - - if (info == 0) { - gchar *fileuri = (gchar*)gtk_selection_data_get_data(seldata); - gchar *filename = g_filename_from_uri(fileuri, NULL, NULL); - - // Dirty hack. g_filename_from_uri adds a \r\n to the string - size_t ln = strlen(filename) - 2; - if (filename[ln] == '\r') { filename[ln] = '\0'; } - - nst_load(filename); - } -} diff --git a/source/gtkui/gtkui_callbacks.h b/source/gtkui/gtkui_callbacks.h deleted file mode 100644 index 1f8b478..0000000 --- a/source/gtkui/gtkui_callbacks.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _GTKUI_CALLBACKS_H_ -#define _GTKUI_CALLBACKS_H_ - -void gtkui_cb_reset(GtkWidget *reset, int hard); -void gtkui_cb_nothing(); -void gtkui_cb_video_refresh(); - -void gtkui_cb_video_filter(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_video_scale(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_video_ntscmode(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_video_xbrrounding(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_video_xbrpixblend(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_video_linear_filter(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_video_tv_aspect(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_video_unmask_overscan(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_video_stretch_aspect(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_video_unlimited_sprites(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_video_palette(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_video_decoder(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_video_brightness(GtkRange *range, gpointer userdata); -void gtkui_cb_video_saturation(GtkRange *range, gpointer userdata); -void gtkui_cb_video_contrast(GtkRange *range, gpointer userdata); -void gtkui_cb_video_hue(GtkRange *range, gpointer userdata); - -void gtkui_cb_audio_samplerate(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_audio_stereo(GtkToggleButton *togglebutton, gpointer userdata); - -void gtkui_cb_input_turbopulse(GtkRange *range, gpointer userdata); - -void gtkui_cb_misc_default_system(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_misc_power_state(GtkComboBox *combobox, gpointer userdata); -void gtkui_cb_timing_ffspeed(GtkRange *range, gpointer userdata); -void gtkui_cb_misc_soft_patching(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_misc_genie_distortion(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_misc_disable_cursor(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_misc_disable_cursor_special(GtkToggleButton *togglebutton, gpointer userdata); -void gtkui_cb_misc_config_pause(GtkToggleButton *togglebutton, gpointer userdata); - -void gtkui_drag_data(GtkWidget *widget, GdkDragContext *dragcontext, gint x, gint y, GtkSelectionData *seldata, guint info, guint time, gpointer data); - -#endif diff --git a/source/gtkui/gtkui_cheats.cpp b/source/gtkui/gtkui_cheats.cpp deleted file mode 100644 index 221ca8e..0000000 --- a/source/gtkui/gtkui_cheats.cpp +++ /dev/null @@ -1,619 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2016 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include -#include - -#include - -#include "nstcommon.h" -#include "config.h" -#include "cheats.h" - -#include "gtkui.h" -#include "gtkui_callbacks.h" -#include "gtkui_cheats.h" -#include "gtkui_dialogs.h" - -extern nstpaths_t nstpaths; -extern Emulator emulator; - -GtkWidget *cheatwindow; -GtkTreeStore *treestore; -GtkWidget *treeview; -GtkWidget *descedit, *ggedit, *paredit; -GtkWidget *infobar, *infolabel; - -Xml savexml; -Xml::Node saveroot; - -GtkWidget *gtkui_cheats() { - // Create the Cheats window - - if (cheatwindow) { return NULL; } - - cheatwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW (cheatwindow), "Cheat Manager"); - - GtkWidget *cheatbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add(GTK_CONTAINER(cheatwindow), cheatbox); - - GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL); - gtk_box_pack_start(GTK_BOX(cheatbox), scrolledwindow, TRUE, TRUE, 0); - gtk_widget_set_size_request(scrolledwindow, 512, 256); - - treeview = gtk_tree_view_new(); - gtk_container_add(GTK_CONTAINER (scrolledwindow), treeview); - - infobar = gtk_info_bar_new(); - infolabel = gtk_widget_new(GTK_TYPE_LABEL,"label", "", NULL); - gtk_box_pack_start(GTK_BOX(cheatbox), infobar, TRUE, TRUE, 0); - - GtkWidget *content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(infobar)); - gtk_box_pack_start(GTK_BOX(content_area), infolabel, TRUE, TRUE, 0); - - GtkWidget *opensavebox = gtk_widget_new(GTK_TYPE_BOX, "halign", GTK_ALIGN_END, NULL); - gtk_box_pack_start(GTK_BOX(cheatbox), opensavebox, FALSE, FALSE, 0); - - GtkWidget *cheatopen = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "Open", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(opensavebox), cheatopen, FALSE, FALSE, 0); - - GtkWidget *cheatclear = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "Clear", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(opensavebox), cheatclear, FALSE, FALSE, 0); - - GtkWidget *cheatremove = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "Remove", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(opensavebox), cheatremove, FALSE, FALSE, 0); - - GtkWidget *descbox = gtk_widget_new( - GTK_TYPE_BOX, - "halign", GTK_ALIGN_END, - NULL); - gtk_box_pack_start(GTK_BOX(cheatbox), descbox, FALSE, FALSE, 0); - - GtkWidget *desclabel = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Description:", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-left", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(descbox), desclabel, FALSE, FALSE, 0); - - descedit = gtk_widget_new( - GTK_TYPE_ENTRY, - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(descbox), descedit, TRUE, TRUE, 0); - - GtkWidget *ggbox = gtk_widget_new( - GTK_TYPE_BOX, - "halign", GTK_ALIGN_END, - NULL); - gtk_box_pack_start(GTK_BOX(cheatbox), ggbox, FALSE, FALSE, 0); - - GtkWidget *gglabel = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Game Genie:", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-left", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(ggbox), gglabel, FALSE, FALSE, 0); - - ggedit = gtk_widget_new( - GTK_TYPE_ENTRY, - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(ggbox), ggedit, TRUE, TRUE, 0); - - GtkWidget *genieadd = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "Add", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(ggbox), genieadd, FALSE, FALSE, 0); - - GtkWidget *parbox = gtk_widget_new( - GTK_TYPE_BOX, - "halign", GTK_ALIGN_END, - NULL); - gtk_box_pack_start(GTK_BOX(cheatbox), parbox, FALSE, FALSE, 0); - - GtkWidget *parlabel = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Pro Action Rocky:", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-left", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(parbox), parlabel, FALSE, FALSE, 0); - - paredit = gtk_widget_new( - GTK_TYPE_ENTRY, - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(parbox), paredit, FALSE, FALSE, 0); - - GtkWidget *paradd = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "Add", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(parbox), paradd, FALSE, FALSE, 0); - - GtkWidget *cheatok = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "OK", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - gtk_box_pack_start(GTK_BOX(cheatbox), cheatok, FALSE, FALSE, 0); - - gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), FALSE); - - treestore = gtk_tree_store_new(5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore)); - - GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); - GtkCellRenderer *checkbox = gtk_cell_renderer_toggle_new(); - - GtkTreeViewColumn *column[5]; - // create the display columns - column[0] = gtk_tree_view_column_new_with_attributes("Enable", checkbox, "active", 0, nullptr); - column[1] = gtk_tree_view_column_new_with_attributes("Game Genie", renderer, "text", 1, nullptr); - column[2] = gtk_tree_view_column_new_with_attributes("PAR", renderer, "text", 2, nullptr); - column[3] = gtk_tree_view_column_new_with_attributes("Raw", renderer, "text", 3, nullptr); - column[4] = gtk_tree_view_column_new_with_attributes("Description", renderer, "text", 4, nullptr); - - // add the display column and renderer to the tree view - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[0]); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[1]); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[2]); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[3]); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column[4]); - - gtkui_cheats_fill_tree(nstpaths.cheatpath); - - /*g_signal_connect(G_OBJECT(checkbox), "toggled", - G_CALLBACK(gtkui_cheats_check), NULL);*/ - - g_signal_connect(G_OBJECT(treeview), "row-activated", - G_CALLBACK(gtkui_cheats_toggle), NULL); - - g_signal_connect(G_OBJECT(cheatopen), "clicked", - G_CALLBACK(gtkui_cheats_load), NULL); - - g_signal_connect(G_OBJECT(cheatclear), "clicked", - G_CALLBACK(gtkui_cheats_clear), NULL); - - g_signal_connect(G_OBJECT(cheatremove), "clicked", - G_CALLBACK(gtkui_cheats_remove), NULL); - - g_signal_connect(G_OBJECT(genieadd), "clicked", - G_CALLBACK(gtkui_cheats_gg_add), NULL); - - g_signal_connect(G_OBJECT(paradd), "clicked", - G_CALLBACK(gtkui_cheats_par_add), NULL); - - g_signal_connect(G_OBJECT(cheatok), "clicked", - G_CALLBACK(gtkui_cheats_ok), NULL); - - g_signal_connect(G_OBJECT(cheatwindow), "destroy", - G_CALLBACK(gtkui_cheats_ok), NULL); - - gtk_widget_show_all(cheatwindow); - gtk_widget_hide(infobar); - - return cheatwindow; -} - -void gtkui_cheats_check(GtkWidget *widget, gchar *element, gpointer userdata) { - // This function doesn't work. Fix later. - GtkTreeIter iter; - - bool value; - - // Read the value of the checkbox - value = gtk_cell_renderer_toggle_get_active((GtkCellRendererToggle*)widget); - - // Flip the value and set it - value ^= 1; - gtk_cell_renderer_toggle_set_active((GtkCellRendererToggle*)widget, value); -} - -void gtkui_cheats_toggle(GtkWidget *widget, gpointer userdata) { - // Toggle a cheat on or off - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreeSelection *selection; - - bool value; - - // Get the selected item - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); - gtk_tree_selection_get_selected(selection, &model, &iter); - - // Read the value of the checkbox - gtk_tree_model_get(model, &iter, 0, &value, -1); - - // Flip the value and set it - value ^= 1; - gtk_tree_store_set(treestore, &iter, 0, value, -1); - - //Re-initialize the cheats - Cheats cheats(emulator); - cheats.ClearCodes(); - - gtk_tree_model_foreach(GTK_TREE_MODEL(model), gtkui_cheats_scan_list, NULL); -} - -void gtkui_cheats_fill_tree(char *filename) { - // Fill the cheat list - Xml xml; - - GtkTreeIter iter; - - bool enabled = false; - - char codebuf[9]; - char descbuf[512]; - - gtkui_cheats_clear(); - - std::ifstream cheatfile(filename, std::ifstream::in|std::ifstream::binary); - - if (cheatfile.is_open()) { - xml.Read(cheatfile); - - if (xml.GetRoot().IsType(L"cheats")) { - - Xml::Node root(xml.GetRoot()); - Xml::Node node(root.GetFirstChild()); - - for (int i = 0; i < root.NumChildren(L"cheat"); i++) { - - wcstombs(descbuf, node.GetChild(L"description").GetValue(), sizeof(descbuf)); - - // Check if the cheat is enabled - node.GetAttribute(L"enabled").IsValue(L"1") ? enabled = true : enabled = false; - - // Add the cheats to the list - if (node.GetChild(L"genie")) { // Game Genie - wcstombs(codebuf, node.GetChild(L"genie").GetValue(), sizeof(codebuf)); - gtk_tree_store_append(treestore, &iter, NULL); - gtk_tree_store_set(treestore, &iter, - 0, enabled, - 1, codebuf, - 4, descbuf, - -1); - if (enabled) { nst_cheats_code_gg_add(node.GetChild(L"genie").GetValue()); } - } - - else if (node.GetChild(L"rocky")) { // Pro Action Rocky - wcstombs(codebuf, node.GetChild(L"rocky").GetValue(), sizeof(codebuf)); - gtk_tree_store_append(treestore, &iter, NULL); - gtk_tree_store_set(treestore, &iter, - 0, enabled, - 2, codebuf, - 4, descbuf, - -1); - if (enabled) { nst_cheats_code_par_add(node.GetChild(L"rocky").GetValue()); } - } - - else if (node.GetChild(L"address")) { // Raw - char rawbuf[11]; - snprintf(rawbuf, sizeof(rawbuf), - "%04lu %02lu %02lu", - node.GetChild(L"address").GetUnsignedValue(), - node.GetChild(L"value").GetUnsignedValue(), - node.GetChild(L"compare").GetUnsignedValue()); - - gtk_tree_store_append(treestore, &iter, NULL); - gtk_tree_store_set(treestore, &iter, - 0, enabled, - 3, rawbuf, - 4, descbuf, - -1); - if (enabled) { nst_cheats_code_raw_add(node); } - } - - node = node.GetNextSibling(); - } - } - cheatfile.close(); - } -} - -void gtkui_cheats_save() { - // Save the cheat list - std::ofstream cheatfile(nstpaths.cheatpath, std::ifstream::out|std::ifstream::binary); - - if (cheatfile.is_open()) { - - GtkTreeModel *model; - model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); - - saveroot = (savexml.GetRoot()); - - saveroot = savexml.Create( L"cheats" ); - saveroot.AddAttribute( L"version", L"1.0" ); - - gtk_tree_model_foreach(GTK_TREE_MODEL(model), gtkui_cheats_write_list, NULL); - - savexml.Write(saveroot, cheatfile); - cheatfile.close(); - } - else { return; } -} - -void gtkui_cheats_gg_add(GtkWidget *widget, gpointer userdata) { - // Add a Game Genie code to the list - GtkTreeIter iter; - - Cheats cheats(emulator); - Cheats::Code code; - - char codebuf[9]; - char descbuf[512]; - - snprintf(codebuf, sizeof(codebuf), "%.8s", gtk_entry_get_text(GTK_ENTRY(ggedit))); - snprintf(descbuf, sizeof(descbuf), "%s", gtk_entry_get_text(GTK_ENTRY(descedit))); - - if (cheats.GameGenieDecode(codebuf, code) == Nes::RESULT_OK) { - gtk_tree_store_append(treestore, &iter, NULL); - gtk_tree_store_set(treestore, &iter, - 0, true, - 1, codebuf, - 4, descbuf, - -1); - gtk_entry_set_text(GTK_ENTRY(descedit), ""); - gtk_entry_set_text(GTK_ENTRY(ggedit), ""); - gtk_entry_set_text(GTK_ENTRY(paredit), ""); - gtk_widget_hide(infobar); - gtk_label_set_text(GTK_LABEL(infolabel), ""); - cheats.SetCode(code); - } - else { - gtk_info_bar_set_message_type(GTK_INFO_BAR(infobar), GTK_MESSAGE_ERROR); - gtk_label_set_text(GTK_LABEL(infolabel), "Error: Invalid Game Genie code"); - gtk_widget_show(infobar); - } -} - -void gtkui_cheats_par_add(GtkWidget *widget, gpointer userdata) { - // Add a Pro Action Rocky code to the list - GtkTreeIter iter; - - Cheats cheats(emulator); - Cheats::Code code; - - char codebuf[9]; - char descbuf[512]; - - snprintf(codebuf, sizeof(codebuf), "%.8s", gtk_entry_get_text(GTK_ENTRY(paredit))); - snprintf(descbuf, sizeof(descbuf), "%s", gtk_entry_get_text(GTK_ENTRY(descedit))); - - if (cheats.ProActionRockyDecode(codebuf, code) == Nes::RESULT_OK) { - gtk_tree_store_append(treestore, &iter, NULL); - gtk_tree_store_set(treestore, &iter, - 0, true, - 1, codebuf, - 4, descbuf, - -1); - gtk_entry_set_text(GTK_ENTRY(descedit), ""); - gtk_entry_set_text(GTK_ENTRY(ggedit), ""); - gtk_entry_set_text(GTK_ENTRY(paredit), ""); - gtk_widget_hide(infobar); - gtk_label_set_text(GTK_LABEL(infolabel), ""); - cheats.SetCode(code); - } - else { - gtk_info_bar_set_message_type(GTK_INFO_BAR(infobar), GTK_MESSAGE_ERROR); - gtk_label_set_text(GTK_LABEL(infolabel), "Error: Invalid PAR code"); - gtk_widget_show(infobar); - } -} - -void gtkui_cheats_remove(GtkWidget *widget, gpointer userdata) { - // Remove a cheat from the list - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreeSelection *selection; - - // Get the selected item - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - gtk_tree_selection_get_selected(selection, &model, &iter); - - // Remove the cheat - if (gtk_tree_store_iter_is_valid(treestore, &iter)) { - gtk_tree_store_remove(treestore, &iter); - } - - //Re-initialize the cheats - Cheats cheats(emulator); - cheats.ClearCodes(); - - gtk_tree_model_foreach(GTK_TREE_MODEL(model), gtkui_cheats_scan_list, NULL); -} - -void gtkui_cheats_ok() { - // Save the cheats and close the window - gtkui_cheats_save(); - gtk_widget_destroy(cheatwindow); - cheatwindow = NULL; -} - -void gtkui_cheats_clear() { - // Clear the list - gtk_tree_store_clear(treestore); - Cheats cheats(emulator); - cheats.ClearCodes(); -} - -gboolean gtkui_cheats_scan_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata) { - // Scan through the list of cheats - Cheats cheats(emulator); - Cheats::Code code; - - bool enabled; - gchar *ggcode, *parcode, *rawcode, *description; - - gtk_tree_model_get(model, iter, 0, &enabled, 1, &ggcode, 2, &parcode, 3, &rawcode, 4, &description, -1); - - if (enabled) { - if (ggcode) { - cheats.GameGenieDecode(ggcode, code); - cheats.SetCode(code); - } - else if (parcode) { - cheats.ProActionRockyDecode(parcode, code); - cheats.SetCode(code); - } - else if (rawcode) { - code.useCompare = false; - - int addr, value, compare; - char buf[5]; - - snprintf(buf, sizeof(buf), "%c%c%c%c", rawcode[0], rawcode[1], rawcode[2], rawcode[3]); - sscanf(buf, "%x", &addr); - - snprintf(buf, sizeof(buf), "%c%c", rawcode[5], rawcode[6]); - sscanf(buf, "%x", &value); - - snprintf(buf, sizeof(buf), "%c%c", rawcode[8], rawcode[9]); - sscanf(buf, "%x", &compare); - - code.address = addr; - code.value = value; - code.compare = compare; - - if (compare) { code.useCompare = true; } - - cheats.SetCode(code); - } - } - - g_free(ggcode); - g_free(parcode); - g_free(rawcode); - g_free(description); - - return false; -} - -gboolean gtkui_cheats_write_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata) { - // Write entries to the cheat file - bool enabled; - gchar *ggcode, *parcode, *rawcode, *description; - - char buf[9]; - wchar_t wbuf[9]; - - gtk_tree_model_get(model, iter, 0, &enabled, 1, &ggcode, 2, &parcode, 3, &rawcode, 4, &description, -1); - - Xml::Node node(saveroot.AddChild(L"cheat")); - node.AddAttribute(L"enabled", enabled ? L"1" : L"0"); - - if (ggcode) { - snprintf(buf, sizeof(buf), "%s", ggcode); - mbstowcs(wbuf, buf, 9); - node.AddChild(L"genie", wbuf); - } - if (parcode) { - snprintf(buf, sizeof(buf), "%s", parcode); - mbstowcs(wbuf, buf, 9); - node.AddChild(L"rocky", wbuf); - } - if (rawcode) { - snprintf(buf, sizeof(buf), "0x%c%c%c%c", rawcode[0], rawcode[1], rawcode[2], rawcode[3]); - mbstowcs(wbuf, buf, 9); - node.AddChild(L"address", wbuf); - - snprintf(buf, sizeof(buf), "0x%c%c", rawcode[5], rawcode[6]); - mbstowcs(wbuf, buf, 9); - node.AddChild(L"value", wbuf); - - snprintf(buf, sizeof(buf), "0x%c%c", rawcode[8], rawcode[9]); - mbstowcs(wbuf, buf, 9); - node.AddChild(L"compare", wbuf); - } - if (description) { - char descbuf[512]; - wchar_t wdescbuf[512]; - - snprintf(descbuf, sizeof(descbuf), "%s", description); - mbstowcs(wdescbuf, descbuf, 512); - node.AddChild(L"description", wdescbuf); - } - - g_free(ggcode); - g_free(parcode); - g_free(rawcode); - g_free(description); - - return false; -} diff --git a/source/gtkui/gtkui_cheats.h b/source/gtkui/gtkui_cheats.h deleted file mode 100644 index b8f0707..0000000 --- a/source/gtkui/gtkui_cheats.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _GTKUI_CHEATS_H_ -#define _GTKUI_CHEATS_H_ - -GtkWidget *gtkui_cheats(); -void gtkui_cheats_check(GtkWidget *widget, gchar *element, gpointer userdata); -void gtkui_cheats_toggle(GtkWidget *widget, gpointer userdata); -void gtkui_cheats_fill_tree(char *filename); -void gtkui_cheats_save(); -void gtkui_cheats_gg_add(GtkWidget *widget, gpointer userdata); -void gtkui_cheats_par_add(GtkWidget *widget, gpointer userdata); -void gtkui_cheats_remove(GtkWidget *widget, gpointer userdata); -void gtkui_cheats_ok(); -void gtkui_cheats_clear(); -gboolean gtkui_cheats_scan_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata); -gboolean gtkui_cheats_write_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata); - -#endif diff --git a/source/gtkui/gtkui_config.cpp b/source/gtkui/gtkui_config.cpp deleted file mode 100644 index ebfb703..0000000 --- a/source/gtkui/gtkui_config.cpp +++ /dev/null @@ -1,1292 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2016 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include -#include -#include - -#include "nstcommon.h" -#include "config.h" -#include "audio.h" -#include "input.h" - -#include "sdlinput.h" - -#include "gtkui.h" -#include "gtkui_callbacks.h" -#include "gtkui_config.h" -#include "gtkui_input.h" - -extern gamepad_t player[NUMGAMEPADS]; -extern gpad_t pad[NUMGAMEPADS]; -extern char padpath[512]; -bool confrunning; - -GtkWidget *configwindow; -GtkWidget *notebook; -gint tabnum = 0; - -// Audio -GtkWidget *scale_audio_volume[NUMCHANNELS]; -GtkAdjustment *adj_audio_volume[NUMCHANNELS]; - -// Input -GtkWidget *combo_input_player; -GtkWidget *combo_input_type; -GtkWidget *inputconfbutton; -GtkWidget *entry_input[NUMBUTTONS]; - -GtkTreeStore *treestore_input; - -GtkWidget *gtkui_config() { - // Create the Configuration window - - if (configwindow) { return NULL; } - if (conf.misc_config_pause) { if (nst_playing()) { nst_pause(); } } - - configwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(configwindow), "Configuration"); - - GtkWidget *box_upper = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *box_lower = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - notebook = gtk_notebook_new(); - - gtk_container_add(GTK_CONTAINER(configwindow), box_upper); - - // Video // - GtkWidget *box_video = gtk_widget_new( - GTK_TYPE_BOX, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "margin-top", MARGIN_TB, - "margin-bottom", MARGIN_TB, - NULL); - GtkWidget *box_video_l = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkWidget *box_video_r = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - - // Filter - GtkWidget *box_video_filter = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_video_filter = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Filter:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - GtkWidget *combo_video_filter = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_filter), "None"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_filter), "NTSC"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_filter), "xBR"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_filter), "HqX"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_filter), "2xSaI"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_filter), "ScaleX"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_video_filter), conf.video_filter); - - gtk_box_pack_start(GTK_BOX(box_video_filter), label_video_filter, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_filter), combo_video_filter, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_l), box_video_filter, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_video_filter), "changed", - G_CALLBACK(gtkui_cb_video_filter), NULL); - - // Scale Factor - GtkWidget *box_video_scale = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_video_scale = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Scale Factor:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - GtkWidget *combo_video_scale = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "1x"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "2x"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "3x"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "4x"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "5x"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "6x"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "7x"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_scale), "8x"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_video_scale), conf.video_scale_factor - 1); - - gtk_box_pack_start(GTK_BOX(box_video_scale), label_video_scale, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_scale), combo_video_scale, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_l), box_video_scale, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_video_scale), "changed", - G_CALLBACK(gtkui_cb_video_scale), NULL); - - // NTSC Mode - GtkWidget *box_video_ntscmode = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_video_ntscmode = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "NTSC Mode:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - GtkWidget *combo_video_ntscmode = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_ntscmode), "Composite"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_ntscmode), "S-Video"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_ntscmode), "RGB"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_ntscmode), "Monochrome"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_ntscmode), "Custom"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_video_ntscmode), conf.video_ntsc_mode); - - gtk_box_pack_start(GTK_BOX(box_video_ntscmode), label_video_ntscmode, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_ntscmode), combo_video_ntscmode, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_l), box_video_ntscmode, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_video_ntscmode), "changed", - G_CALLBACK(gtkui_cb_video_ntscmode), NULL); - - // xBR Corner Rounding - GtkWidget *box_video_xbrrounding = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_video_xbrrounding = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "xBR Corner Rounding:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - GtkWidget *combo_video_xbrrounding = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_xbrrounding), "None"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_xbrrounding), "Some"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_xbrrounding), "All"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_video_xbrrounding), conf.video_xbr_corner_rounding); - - gtk_box_pack_start(GTK_BOX(box_video_xbrrounding), label_video_xbrrounding, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_xbrrounding), combo_video_xbrrounding, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_l), box_video_xbrrounding, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_video_xbrrounding), "changed", - G_CALLBACK(gtkui_cb_video_xbrrounding), NULL); - - // xBR Pixel Blending - GtkWidget *check_video_xbrpixblend = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "xBR Pixel Blending", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_video_xbrpixblend), conf.video_xbr_pixel_blending); - - gtk_box_pack_start(GTK_BOX(box_video_l), check_video_xbrpixblend, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_video_xbrpixblend), "toggled", - G_CALLBACK(gtkui_cb_video_xbrpixblend), NULL); - - // Linear Filter - GtkWidget *check_video_linear_filter = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Linear Filter", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_video_linear_filter), conf.video_linear_filter); - - gtk_box_pack_start(GTK_BOX(box_video_l), check_video_linear_filter, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_video_linear_filter), "toggled", - G_CALLBACK(gtkui_cb_video_linear_filter), NULL); - - // TV Aspect - GtkWidget *check_video_tv_aspect = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "TV Aspect Ratio", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_video_tv_aspect), conf.video_tv_aspect); - - gtk_box_pack_start(GTK_BOX(box_video_l), check_video_tv_aspect, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_video_tv_aspect), "toggled", - G_CALLBACK(gtkui_cb_video_tv_aspect), NULL); - - // Mask Overscan - GtkWidget *check_video_unmask_overscan = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Unmask Overscan", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_video_unmask_overscan), conf.video_unmask_overscan); - - gtk_box_pack_start(GTK_BOX(box_video_l), check_video_unmask_overscan, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_video_unmask_overscan), "toggled", - G_CALLBACK(gtkui_cb_video_unmask_overscan), NULL); - - // Stretch Aspect - /*GtkWidget *check_video_stretch_aspect = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Stretch Aspect Ratio", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_video_stretch_aspect), conf.video_stretch_aspect); - - gtk_box_pack_start(GTK_BOX(box_video_l), check_video_stretch_aspect, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_video_stretch_aspect), "toggled", - G_CALLBACK(gtkui_cb_video_stretch_aspect), NULL);*/ - - // Unlimited Sprites - GtkWidget *check_video_unlimited_sprites = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Unlimited Sprites", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_video_unlimited_sprites), conf.video_unlimited_sprites); - - gtk_box_pack_start(GTK_BOX(box_video_l), check_video_unlimited_sprites, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_video_unlimited_sprites), "toggled", - G_CALLBACK(gtkui_cb_video_unlimited_sprites), NULL); - - // Palette Mode - GtkWidget *box_video_palette = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_video_palette = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Palette Mode:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - NULL); - GtkWidget *combo_video_palette = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_palette), "YUV"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_palette), "RGB"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_palette), "Custom"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_video_palette), conf.video_palette_mode); - - gtk_box_pack_start(GTK_BOX(box_video_palette), label_video_palette, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_palette), combo_video_palette, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_r), box_video_palette, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_video_palette), "changed", - G_CALLBACK(gtkui_cb_video_palette), NULL); - - // YUV Decoder - GtkWidget *box_video_decoder = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_video_decoder = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "YUV Decoder:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - NULL); - GtkWidget *combo_video_decoder = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_decoder), "Consumer"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_decoder), "Canonical"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_video_decoder), "Alternative"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_video_decoder), conf.video_decoder); - - gtk_box_pack_start(GTK_BOX(box_video_decoder), label_video_decoder, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_decoder), combo_video_decoder, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video_r), box_video_decoder, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_video_decoder), "changed", - G_CALLBACK(gtkui_cb_video_decoder), NULL); - - // Brightness - GtkAdjustment *adj_video_brightness = gtk_adjustment_new(conf.video_brightness, -100, 100, 1, 5, 0); - GtkWidget *frame_video_brightness = gtk_frame_new("Brightness"); - GtkWidget *scale_video_brightness = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - "margin-right", MARGIN_LR, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "adjustment", adj_video_brightness, - "width-request", 201, - "height-request", 32, - "digits", 0, - NULL); - gtk_container_add(GTK_CONTAINER(frame_video_brightness), scale_video_brightness); - gtk_box_pack_start(GTK_BOX(box_video_r), frame_video_brightness, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(scale_video_brightness), "value-changed", - G_CALLBACK(gtkui_cb_video_brightness), NULL); - - // Saturation - GtkAdjustment *adj_video_saturation = gtk_adjustment_new(conf.video_saturation, -100, 100, 1, 5, 0); - GtkWidget *frame_video_saturation = gtk_frame_new("Saturation"); - GtkWidget *scale_video_saturation = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - "margin-right", MARGIN_LR, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "adjustment", adj_video_saturation, - "width-request", 201, - "height-request", 32, - "digits", 0, - NULL); - gtk_container_add(GTK_CONTAINER(frame_video_saturation), scale_video_saturation); - gtk_box_pack_start(GTK_BOX(box_video_r), frame_video_saturation, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(scale_video_saturation), "value-changed", - G_CALLBACK(gtkui_cb_video_saturation), NULL); - - // Contrast - GtkAdjustment *adj_video_contrast = gtk_adjustment_new(conf.video_contrast, -100, 100, 1, 5, 0); - GtkWidget *frame_video_contrast = gtk_frame_new("Contrast"); - GtkWidget *scale_video_contrast = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - "margin-right", MARGIN_LR, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "adjustment", adj_video_contrast, - "width-request", 201, - "height-request", 32, - "digits", 0, - NULL); - gtk_container_add(GTK_CONTAINER(frame_video_contrast), scale_video_contrast); - gtk_box_pack_start(GTK_BOX(box_video_r), frame_video_contrast, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(scale_video_contrast), "value-changed", - G_CALLBACK(gtkui_cb_video_contrast), NULL); - - // Hue - GtkAdjustment *adj_video_hue = gtk_adjustment_new(conf.video_hue, -45, 45, 1, 5, 0); - GtkWidget *frame_video_hue = gtk_frame_new("Hue"); - GtkWidget *scale_video_hue = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - "margin-right", MARGIN_LR, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "adjustment", adj_video_hue, - "width-request", 91, - "height-request", 32, - "digits", 0, - NULL); - gtk_container_add(GTK_CONTAINER(frame_video_hue), scale_video_hue); - gtk_box_pack_start(GTK_BOX(box_video_r), frame_video_hue, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(scale_video_hue), "value-changed", - G_CALLBACK(gtkui_cb_video_hue), NULL); - - gtk_box_pack_start(GTK_BOX(box_video), box_video_l, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_video), box_video_r, FALSE, FALSE, MARGIN_LR); - - // Audio // - GtkWidget *box_audio = gtk_widget_new( - GTK_TYPE_BOX, - "orientation", GTK_ORIENTATION_VERTICAL, - "margin-top", MARGIN_TB, - "margin-bottom", MARGIN_TB, - NULL); - - // Sample Rate - GtkWidget *box_audio_samplerate = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_audio_samplerate = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Sample Rate:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - GtkWidget *combo_audio_samplerate = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_audio_samplerate), "11025Hz"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_audio_samplerate), "22050Hz"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_audio_samplerate), "44100Hz"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_audio_samplerate), "48000Hz"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_audio_samplerate), "96000Hz"); - - switch (conf.audio_sample_rate) { - case 11025: - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_audio_samplerate), 0); - break; - case 22050: - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_audio_samplerate), 1); - break; - case 44100: - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_audio_samplerate), 2); - break; - case 48000: - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_audio_samplerate), 3); - break; - case 96000: - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_audio_samplerate), 4); - break; - default: - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_audio_samplerate), 2); - break; - } - - gtk_box_pack_start(GTK_BOX(box_audio_samplerate), label_audio_samplerate, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_audio_samplerate), combo_audio_samplerate, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_audio), box_audio_samplerate, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_audio_samplerate), "changed", - G_CALLBACK(gtkui_cb_audio_samplerate), NULL); - - // Stereo - GtkWidget *check_audio_stereo = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Stereo", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_audio_stereo), conf.audio_stereo); - - gtk_box_pack_start(GTK_BOX(box_audio), check_audio_stereo, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_audio_stereo), "toggled", - G_CALLBACK(gtkui_cb_audio_stereo), NULL); - - // Volume - GtkWidget *label_audio_volume[NUMCHANNELS]; - - // The Grid - GtkWidget *grid_audio_volume = gtk_widget_new( - GTK_TYPE_GRID, - "column-homogeneous", TRUE, - "column-spacing", MARGIN_LR, - "row-spacing", MARGIN_TB, - "margin", MARGIN_TB, - NULL); - - // Master - label_audio_volume[0] = gtk_widget_new(GTK_TYPE_LABEL, "label", "Master", NULL); - adj_audio_volume[0] = gtk_adjustment_new(conf.audio_volume, 0, 100, 1, 5, 0); - scale_audio_volume[0] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[0], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[0], 0, 0, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[0], 0, 1, 1, 1); - - g_signal_connect(G_OBJECT(scale_audio_volume[0]), "value-changed", - G_CALLBACK(gtkui_audio_volume_master), NULL); - - // Square1 - label_audio_volume[1] = gtk_widget_new(GTK_TYPE_LABEL, "label", "Square1", NULL); - adj_audio_volume[1] = gtk_adjustment_new(conf.audio_vol_sq1, 0, 100, 1, 5, 0); - scale_audio_volume[1] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[1], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[1], 1, 0, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[1], 1, 1, 1, 1); - - // Square2 - label_audio_volume[2] = gtk_widget_new(GTK_TYPE_LABEL, "label", "Square2", NULL); - adj_audio_volume[2] = gtk_adjustment_new(conf.audio_vol_sq2, 0, 100, 1, 5, 0); - scale_audio_volume[2] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[2], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[2], 2, 0, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[2], 2, 1, 1, 1); - - // Triangle - label_audio_volume[3] = gtk_widget_new(GTK_TYPE_LABEL, "label", "Triangle", NULL); - adj_audio_volume[3] = gtk_adjustment_new(conf.audio_vol_tri, 0, 100, 1, 5, 0); - scale_audio_volume[3] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[3], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[3], 3, 0, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[3], 3, 1, 1, 1); - - // Noise - label_audio_volume[4] = gtk_widget_new(GTK_TYPE_LABEL, "label", "Noise", NULL); - adj_audio_volume[4] = gtk_adjustment_new(conf.audio_vol_noise, 0, 100, 1, 5, 0); - scale_audio_volume[4] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[4], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[4], 4, 0, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[4], 4, 1, 1, 1); - - // Noise - label_audio_volume[5] = gtk_widget_new(GTK_TYPE_LABEL, "label", "DPCM", NULL); - adj_audio_volume[5] = gtk_adjustment_new(conf.audio_vol_dpcm, 0, 100, 1, 5, 0); - scale_audio_volume[5] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[5], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[5], 5, 0, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[5], 5, 1, 1, 1); - - // FDS - label_audio_volume[6] = gtk_widget_new(GTK_TYPE_LABEL, "label", "FDS", NULL); - adj_audio_volume[6] = gtk_adjustment_new(conf.audio_vol_fds, 0, 100, 1, 5, 0); - scale_audio_volume[6] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[6], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[6], 0, 2, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[6], 0, 3, 1, 1); - - // MMC5 - label_audio_volume[7] = gtk_widget_new(GTK_TYPE_LABEL, "label", "MMC5", NULL); - adj_audio_volume[7] = gtk_adjustment_new(conf.audio_vol_mmc5, 0, 100, 1, 5, 0); - scale_audio_volume[7] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[7], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[7], 1, 2, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[7], 1, 3, 1, 1); - - // VRC6 - label_audio_volume[8] = gtk_widget_new(GTK_TYPE_LABEL, "label", "VRC6", NULL); - adj_audio_volume[8] = gtk_adjustment_new(conf.audio_vol_vrc6, 0, 100, 1, 5, 0); - scale_audio_volume[8] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[8], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[8], 2, 2, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[8], 2, 3, 1, 1); - - // VRC7 - label_audio_volume[9] = gtk_widget_new(GTK_TYPE_LABEL, "label", "VRC7", NULL); - adj_audio_volume[9] = gtk_adjustment_new(conf.audio_vol_vrc7, 0, 100, 1, 5, 0); - scale_audio_volume[9] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[9], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[9], 3, 2, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[9], 3, 3, 1, 1); - - // N163 - label_audio_volume[10] = gtk_widget_new(GTK_TYPE_LABEL, "label", "N163", NULL); - adj_audio_volume[10] = gtk_adjustment_new(conf.audio_vol_n163, 0, 100, 1, 5, 0); - scale_audio_volume[10] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[10], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[10], 4, 2, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[10], 4, 3, 1, 1); - - // S5B - label_audio_volume[11] = gtk_widget_new(GTK_TYPE_LABEL, "label", "S5B", NULL); - adj_audio_volume[11] = gtk_adjustment_new(conf.audio_vol_s5b, 0, 100, 1, 5, 0); - scale_audio_volume[11] = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_CENTER, - "orientation", GTK_ORIENTATION_VERTICAL, - "adjustment", adj_audio_volume[11], - "width-request", 32, - "height-request", 100, - "inverted", TRUE, - "digits", 0, - NULL); - - gtk_grid_attach(GTK_GRID(grid_audio_volume), label_audio_volume[11], 5, 2, 1, 1); - gtk_grid_attach(GTK_GRID(grid_audio_volume), scale_audio_volume[11], 5, 3, 1, 1); - - // Set the callbacks for every control but master - for (int i = 1; i < NUMCHANNELS; i++) { - g_signal_connect(G_OBJECT(scale_audio_volume[i]), "value-changed", - G_CALLBACK(gtkui_audio_volume), NULL); - } - - // Pack the grid into the box - gtk_box_pack_start(GTK_BOX(box_audio), grid_audio_volume, FALSE, FALSE, 0); - - // Input // - GtkWidget *box_input = gtk_widget_new( - GTK_TYPE_BOX, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "margin-top", MARGIN_TB, - "margin-bottom", MARGIN_TB, - NULL); - - // NES Controller - GtkWidget *box_input_l = gtk_widget_new(GTK_TYPE_BOX, "halign", GTK_ALIGN_START, "orientation", GTK_ORIENTATION_VERTICAL, NULL); - GtkWidget *nespad = gtk_widget_new( - GTK_TYPE_IMAGE, - "halign", GTK_ALIGN_CENTER, - "expand", FALSE, - "file", padpath, - "margin", MARGIN_TB, - NULL); - gtk_box_pack_start(GTK_BOX(box_input_l), nespad, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_input), box_input_l, FALSE, FALSE, 0); - - // Turbo Pulse - GtkAdjustment *adj_input_turbopulse = gtk_adjustment_new(conf.timing_turbopulse, 2, 9, 1, 5, 0); - GtkWidget *box_input_turbopulse = gtk_widget_new( - GTK_TYPE_BOX, - "halign", GTK_ALIGN_END, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "margin-bottom", MARGIN_TB, - "margin-right", MARGIN_LR, - NULL); - GtkWidget *label_input_turbopulse = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Turbo Pulse", - "halign", GTK_ALIGN_START, - "margin-top", MARGIN_TB, - "margin-right", MARGIN_LR, - NULL); - GtkWidget *scale_input_turbopulse = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_START, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "adjustment", adj_input_turbopulse, - "width-request", 60, - "height-request", 32, - "digits", 0, - NULL); - gtk_box_pack_start(GTK_BOX(box_input_turbopulse), label_input_turbopulse, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_input_turbopulse), scale_input_turbopulse, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_input_l), box_input_turbopulse, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(scale_input_turbopulse), "value-changed", - G_CALLBACK(gtkui_cb_input_turbopulse), NULL); - - // Options Box - GtkWidget *box_input_r = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_box_pack_start(GTK_BOX(box_input), box_input_r, FALSE, FALSE, 0); - - // Player Select - combo_input_player = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_END, - "margin-top", MARGIN_TB, - "margin-bottom", MARGIN_TB, - "margin-right", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (combo_input_player), "Player 1"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (combo_input_player), "Player 2"); - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_input_player), 0); - gtk_box_pack_start(GTK_BOX(box_input_l), combo_input_player, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_input_player), "changed", - G_CALLBACK(gtkui_config_input_refresh), NULL); - - // Device Type Select - combo_input_type = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_END, - "margin-top", MARGIN_TB, - "margin-bottom", MARGIN_TB, - "margin-right", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (combo_input_type), "Keyboard"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT (combo_input_type), "Joystick"); - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_input_type), 0); - gtk_box_pack_start(GTK_BOX(box_input_l), combo_input_type, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_input_type), "changed", - G_CALLBACK(gtkui_config_input_refresh), NULL); - - // The Treeview - GtkWidget *treeview = gtk_widget_new(GTK_TYPE_TREE_VIEW, - "margin-top", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW (treeview), FALSE); - gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeview), FALSE); - - treestore_input = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - - gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(treestore_input)); - - GtkTreeIter iter; - GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); - - GtkTreeViewColumn *columns[2]; - columns[0] = gtk_tree_view_column_new_with_attributes( - "Button", renderer, "text", 0, nullptr); - - columns[1] = gtk_tree_view_column_new_with_attributes( - "Mapping", renderer, "text", 1, nullptr); - gtk_tree_view_column_set_expand(columns[1], TRUE); - - gtk_tree_view_append_column(GTK_TREE_VIEW (treeview), columns[0]); - gtk_tree_view_append_column(GTK_TREE_VIEW (treeview), columns[1]); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Up", 1, gdk_keyval_name(pad[0].u), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Down", 1, gdk_keyval_name(pad[0].d), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Left", 1, gdk_keyval_name(pad[0].l), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Right", 1, gdk_keyval_name(pad[0].r), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Select", 1, gdk_keyval_name(pad[0].select), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Start", 1, gdk_keyval_name(pad[0].start), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "A", 1, gdk_keyval_name(pad[0].a), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "B", 1, gdk_keyval_name(pad[0].b), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Turbo A", 1, gdk_keyval_name(pad[0].ta), -1); - - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Turbo B", 1, gdk_keyval_name(pad[0].tb), -1); - - gtk_box_pack_start(GTK_BOX(box_input_r), treeview, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(treeview), "row-activated", - G_CALLBACK(gtkui_config_input_activate), NULL); - - // The Input Defaults button - GtkWidget *inputdefaults = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "Defaults", - "halign", GTK_ALIGN_START, - "margin-top", MARGIN_TB * 2, - "margin-left", MARGIN_LR, - NULL); - gtk_box_pack_start(GTK_BOX(box_input_r), inputdefaults, FALSE, FALSE, 0); - - // Connect the button to a callback - g_signal_connect(G_OBJECT(inputdefaults), "clicked", - G_CALLBACK(gtkui_config_input_defaults), NULL); - - // Misc // - GtkWidget *box_misc = gtk_widget_new( - GTK_TYPE_BOX, - "orientation", GTK_ORIENTATION_VERTICAL, - "margin-top", MARGIN_TB, - "margin-bottom", MARGIN_TB, - NULL); - - // Default System - GtkWidget *box_misc_default_system = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_misc_default_system = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Default System:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - GtkWidget *combo_misc_default_system = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_default_system), "Auto"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_default_system), "NTSC"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_default_system), "PAL"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_default_system), "Famicom"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_default_system), "Dendy"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_misc_default_system), conf.misc_default_system); - - gtk_box_pack_start(GTK_BOX(box_misc_default_system), label_misc_default_system, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_misc_default_system), combo_misc_default_system, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_misc), box_misc_default_system, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_misc_default_system), "changed", - G_CALLBACK(gtkui_cb_misc_default_system), NULL); - - // RAM Power-on State - GtkWidget *box_misc_power_state = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_misc_power_state = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "RAM Power-on State:", - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - GtkWidget *combo_misc_power_state = gtk_widget_new( - GTK_TYPE_COMBO_BOX_TEXT, - "halign", GTK_ALIGN_START, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - NULL); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_power_state), "0x00"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_power_state), "0xFF"); - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_misc_power_state), "Random"); - - gtk_combo_box_set_active(GTK_COMBO_BOX(combo_misc_power_state), conf.misc_power_state); - - gtk_box_pack_start(GTK_BOX(box_misc_power_state), label_misc_power_state, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_misc_power_state), combo_misc_power_state, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_misc), box_misc_power_state, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(combo_misc_power_state), "changed", - G_CALLBACK(gtkui_cb_misc_power_state), NULL); - - // Alternate Speed - GtkAdjustment *adj_timing_ffspeed = gtk_adjustment_new(conf.timing_ffspeed, 1, 8, 1, 5, 0); - GtkWidget *box_timing_ffspeed = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - GtkWidget *label_timing_ffspeed = gtk_widget_new( - GTK_TYPE_LABEL, - "label", "Fast-Forward Speed", - "halign", GTK_ALIGN_START, - "margin-top", MARGIN_TB, - "margin-bottom", MARGIN_TB, - "margin-left", MARGIN_LR, - "margin-right", MARGIN_LR, - NULL); - GtkWidget *scale_timing_ffspeed = gtk_widget_new( - GTK_TYPE_SCALE, - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - "orientation", GTK_ORIENTATION_HORIZONTAL, - "adjustment", adj_timing_ffspeed, - "width-request", 64, - "height-request", 32, - "digits", 0, - NULL); - gtk_box_pack_start(GTK_BOX(box_timing_ffspeed), label_timing_ffspeed, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_timing_ffspeed), scale_timing_ffspeed, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_misc), box_timing_ffspeed, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(scale_timing_ffspeed), "value-changed", - G_CALLBACK(gtkui_cb_timing_ffspeed), NULL); - - // Soft Patching - GtkWidget *check_misc_soft_patching = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Automatic Soft Patching", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_misc_soft_patching), conf.misc_soft_patching); - - gtk_box_pack_start(GTK_BOX(box_misc), check_misc_soft_patching, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_misc_soft_patching), "toggled", - G_CALLBACK(gtkui_cb_misc_soft_patching), NULL); - - // Game Genie Sound Distortion - GtkWidget *check_misc_genie_distortion = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Game Genie Sound Distortion", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_misc_genie_distortion), conf.misc_genie_distortion); - - gtk_box_pack_start(GTK_BOX(box_misc), check_misc_genie_distortion, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_misc_genie_distortion), "toggled", - G_CALLBACK(gtkui_cb_misc_genie_distortion), NULL); - - // Disable Cursor - GtkWidget *check_misc_disable_cursor = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Disable Cursor", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_misc_disable_cursor), conf.misc_disable_cursor); - - gtk_box_pack_start(GTK_BOX(box_misc), check_misc_disable_cursor, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_misc_disable_cursor), "toggled", - G_CALLBACK(gtkui_cb_misc_disable_cursor), NULL); - - // Disable Special Cursor - GtkWidget *check_misc_disable_cursor_special = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Disable Special Cursor", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_misc_disable_cursor_special), conf.misc_disable_cursor_special); - - gtk_box_pack_start(GTK_BOX(box_misc), check_misc_disable_cursor_special, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_misc_disable_cursor_special), "toggled", - G_CALLBACK(gtkui_cb_misc_disable_cursor_special), NULL); - - // Pause While Configuration Open - GtkWidget *check_misc_config_pause = gtk_widget_new( - GTK_TYPE_CHECK_BUTTON, - "label", "Pause While Configuration Open", - "halign", GTK_ALIGN_START, - "margin-left", MARGIN_LR, - NULL); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_misc_config_pause), conf.misc_config_pause); - - gtk_box_pack_start(GTK_BOX(box_misc), check_misc_config_pause, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(check_misc_config_pause), "toggled", - G_CALLBACK(gtkui_cb_misc_config_pause), NULL); - - // Structuring the notebook - GtkWidget *label_video = gtk_label_new("Video"); - GtkWidget *label_audio = gtk_label_new("Audio"); - GtkWidget *label_input = gtk_label_new("Input"); - GtkWidget *label_misc = gtk_label_new("Misc"); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box_video, label_video); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box_audio, label_audio); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box_input, label_input); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box_misc, label_misc); - - // The OK button - GtkWidget *okbutton = gtk_widget_new( - GTK_TYPE_BUTTON, - "label", "OK", - "halign", GTK_ALIGN_END, - "margin-top", 8, - "margin-bottom", 8, - "margin-right", 8, - NULL); - - // Connect the OK button to a callback - g_signal_connect(G_OBJECT(okbutton), "clicked", - G_CALLBACK(gtkui_config_ok), NULL); - - // Structuring the window - gtk_box_pack_start(GTK_BOX(box_upper), notebook, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(box_upper), box_lower, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(box_lower), okbutton, FALSE, FALSE, 0); - - g_signal_connect(G_OBJECT(configwindow), "destroy", - G_CALLBACK(gtkui_config_ok), NULL); - - gtk_widget_show_all(configwindow); - - gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), tabnum); - - return configwindow; -} - -void gtkui_config_ok() { - if (confrunning) { confrunning = false; } - tabnum = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)); - gtk_widget_destroy(configwindow); - configwindow = NULL; - nst_play(); -} - -void gtkui_audio_volume() { - // Set the audio volume on specific channels - conf.audio_vol_sq1 = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[1]); - conf.audio_vol_sq2 = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[2]); - conf.audio_vol_tri = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[3]); - conf.audio_vol_noise = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[4]); - conf.audio_vol_dpcm = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[5]); - conf.audio_vol_fds = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[6]); - conf.audio_vol_mmc5 = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[7]); - conf.audio_vol_vrc6 = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[8]); - conf.audio_vol_vrc7 = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[9]); - conf.audio_vol_n163 = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[10]); - conf.audio_vol_s5b = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[11]); - audio_adj_volume(); -} - -void gtkui_audio_volume_master() { - // Set the audio volume on all channels - conf.audio_volume = (int)gtk_range_get_value((GtkRange*)scale_audio_volume[0]); - - for (int i = 1; i < NUMCHANNELS; i++) { - gtk_adjustment_set_value(adj_audio_volume[i], gtk_range_get_value((GtkRange*)scale_audio_volume[0])); - } - - gtkui_audio_volume(); -} - -void gtkui_config_input_activate(GtkWidget *widget, GtkTreePath *path, gpointer userdata) { - // React to a button configuration request - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreeSelection *selection; - - int pnum = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_input_player)); - int type = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_input_type)); - - // Get the selected item - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); - gtk_tree_selection_get_selected(selection, &model, &iter); - - path = gtk_tree_model_get_path(model, &iter); - int bnum = gtk_tree_path_get_indices(path)[0]; - - // Replace the text with the current key - gtk_tree_store_set(treestore_input, &iter, 1, "Set Key...", -1); - - // Set the key - if (type == 0) { // Keyboard - gtkui_input_config_key(pnum, bnum); - } - else { // Joystick - gtkui_input_config_js(pnum, bnum); - } - - // Replace the text with the new key - if (type == 0) { // Keyboard - switch (bnum) { - case 0: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].u), -1); - break; - case 1: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].d), -1); - break; - case 2: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].l), -1); - break; - case 3: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].r), -1); - break; - case 4: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].select), -1); - break; - case 5: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].start), -1); - break; - case 6: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].a), -1); - break; - case 7: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].b), -1); - break; - case 8: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].ta), -1); - break; - case 9: - gtk_tree_store_set(treestore_input, &iter, 1, gdk_keyval_name(pad[pnum].tb), -1); - break; - default: break; - } - } - else { // Joystick - switch (bnum) { - case 0: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].ju), -1); - break; - case 1: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jd), -1); - break; - case 2: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jl), -1); - break; - case 3: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jr), -1); - break; - case 4: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jselect), -1); - break; - case 5: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jstart), -1); - break; - case 6: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].ja), -1); - break; - case 7: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jb), -1); - break; - case 8: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jta), -1); - break; - case 9: - gtk_tree_store_set(treestore_input, &iter, 1, nstsdl_input_translate_event(player[pnum].jtb), -1); - break; - default: break; - } - } -} - -void gtkui_config_input_refresh() { - // Refresh the input fields - int pnum = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_input_player)); - int type = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_input_type)); - gtkui_config_input_fields(type, pnum); -} - -void gtkui_config_input_fields(int type, int pnum) { - // Set the text in the input fields based on the current settings - GtkTreeIter iter; - - gtk_tree_store_clear(treestore_input); - - if (type == 0) { - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Up", 1, gdk_keyval_name(pad[pnum].u), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Down", 1, gdk_keyval_name(pad[pnum].d), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Left", 1, gdk_keyval_name(pad[pnum].l), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Right", 1, gdk_keyval_name(pad[pnum].r), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Select", 1, gdk_keyval_name(pad[pnum].select), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Start", 1, gdk_keyval_name(pad[pnum].start), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "A", 1, gdk_keyval_name(pad[pnum].a), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "B", 1, gdk_keyval_name(pad[pnum].b), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Turbo A", 1, gdk_keyval_name(pad[pnum].ta), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Turbo B", 1, gdk_keyval_name(pad[pnum].tb), -1); - } - if (type == 1) { - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Up", 1, nstsdl_input_translate_event(player[pnum].ju), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Down", 1, nstsdl_input_translate_event(player[pnum].jd), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Left", 1, nstsdl_input_translate_event(player[pnum].jl), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Right", 1, nstsdl_input_translate_event(player[pnum].jr), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Select", 1, nstsdl_input_translate_event(player[pnum].jselect), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Start", 1, nstsdl_input_translate_event(player[pnum].jstart), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "A", 1, nstsdl_input_translate_event(player[pnum].ja), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "B", 1, nstsdl_input_translate_event(player[pnum].jb), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Turbo A", 1, nstsdl_input_translate_event(player[pnum].jta), -1); - gtk_tree_store_append(treestore_input, &iter, NULL); - gtk_tree_store_set(treestore_input, &iter, 0, "Turbo B", 1, nstsdl_input_translate_event(player[pnum].jtb), -1); - } -} - -void gtkui_config_input_defaults() { - // Restore input defaults - gtkui_input_set_default(); - gtkui_config_input_refresh(); -} diff --git a/source/gtkui/gtkui_config.h b/source/gtkui/gtkui_config.h deleted file mode 100644 index 04b2342..0000000 --- a/source/gtkui/gtkui_config.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _GTKUI_CONFIG_H_ -#define _GTKUI_CONFIG_H_ - -#define MARGIN_TB 5 -#define MARGIN_LR 10 - -#define NUMCHANNELS 12 - -GtkWidget *gtkui_config(); -void gtkui_config_ok(); -void gtkui_audio_volume(); -void gtkui_audio_volume_master(); -void gtkui_config_input_activate(GtkWidget *widget, GtkTreePath *path, gpointer userdata); -void gtkui_config_input_refresh(); -void gtkui_config_input_fields(int type, int pnum); -void gtkui_config_input_defaults(); - -#endif diff --git a/source/gtkui/gtkui_dialogs.cpp b/source/gtkui/gtkui_dialogs.cpp deleted file mode 100644 index 14256dd..0000000 --- a/source/gtkui/gtkui_dialogs.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2016 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include - -#include "nstcommon.h" -#include "video.h" -#include "config.h" - -#include "gtkui.h" -#include "gtkui_cheats.h" - -extern nstpaths_t nstpaths; -extern GtkWidget *gtkwindow; - -void gtkui_file_open() { - // Open a file using a GTK dialog - GtkWidget *dialog = gtk_file_chooser_dialog_new( - "Select a ROM", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_OPEN, - "Cancel", GTK_RESPONSE_CANCEL, - "Open", GTK_RESPONSE_ACCEPT, - nullptr); - - if(conf.misc_last_folder != NULL) - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), conf.misc_last_folder); - - GtkFileFilter *filter = gtk_file_filter_new(); - - gtk_file_filter_set_name(filter, "NES ROMs and Archives"); - gtk_file_filter_add_pattern(filter, "*.nes"); - gtk_file_filter_add_pattern(filter, "*.fds"); - gtk_file_filter_add_pattern(filter, "*.unf"); - gtk_file_filter_add_pattern(filter, "*.unif"); - gtk_file_filter_add_pattern(filter, "*.nsf"); - gtk_file_filter_add_pattern(filter, "*.zip"); - gtk_file_filter_add_pattern(filter, "*.7z"); - gtk_file_filter_add_pattern(filter, "*.txz"); - gtk_file_filter_add_pattern(filter, "*.tar.xz"); - gtk_file_filter_add_pattern(filter, "*.xz"); - gtk_file_filter_add_pattern(filter, "*.tgz"); - gtk_file_filter_add_pattern(filter, "*.tar.gz"); - gtk_file_filter_add_pattern(filter, "*.gz"); - gtk_file_filter_add_pattern(filter, "*.tbz"); - gtk_file_filter_add_pattern(filter, "*.tar.bz2"); - gtk_file_filter_add_pattern(filter, "*.bz2"); - - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename; - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - - if(conf.misc_last_folder != NULL) - free(conf.misc_last_folder); - - conf.misc_last_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog)); - gtk_widget_destroy(dialog); - nst_load(filename); - gtkui_set_title(nstpaths.gamename); - gtkui_play(); - g_free(filename); - } - else { gtk_widget_destroy(dialog); } -} - -void gtkui_state_save() { - // Save a state from the GUI - GtkWidget *dialog = gtk_file_chooser_dialog_new("Save State (.nst)", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_SAVE, - "Cancel", GTK_RESPONSE_CANCEL, - "Save", GTK_RESPONSE_ACCEPT, - nullptr); - - char statepath[512]; - snprintf(statepath, sizeof(statepath), "%s.nst", nstpaths.statepath); - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), statepath); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.statepath); - - if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - nst_state_save(filename); - g_free(filename); - } - - gtk_widget_destroy(dialog); -} - -void gtkui_state_load() { - // Load a state from the GUI - GtkWidget *dialog = gtk_file_chooser_dialog_new("Load State (.nst)", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_OPEN, - "Cancel", GTK_RESPONSE_CANCEL, - "Open", GTK_RESPONSE_ACCEPT, - nullptr); - - GtkFileFilter *filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, "Nestopia Save States"); - gtk_file_filter_add_pattern(filter, "*.nst"); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.statepath); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - nst_state_load(filename); - g_free(filename); - } - - gtk_widget_destroy(dialog); -} - -void gtkui_screenshot_save() { - // Save a screenshot from the GUI - GtkWidget *dialog = gtk_file_chooser_dialog_new("Save screenshot (.png)", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_SAVE, - "Cancel", GTK_RESPONSE_CANCEL, - "Save", GTK_RESPONSE_ACCEPT, - nullptr); - - char sshotpath[512]; - char sshotfile[768]; - snprintf(sshotpath, sizeof(sshotpath), "%sscreenshots/", nstpaths.nstdir); - snprintf(sshotfile, sizeof(sshotfile), "%s%s.png", sshotpath, nstpaths.gamename); - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), sshotfile); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), sshotpath); - - if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - video_screenshot(filename); - g_free(filename); - } - - gtk_widget_destroy(dialog); -} - -void gtkui_movie_save() { - // Save a movie from the GUI - GtkWidget *dialog = gtk_file_chooser_dialog_new("Save movie (.nsv)", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_SAVE, - "Cancel", GTK_RESPONSE_CANCEL, - "Save", GTK_RESPONSE_ACCEPT, - nullptr); - - char moviepath[512]; - snprintf(moviepath, sizeof(moviepath), "%s%s.nsv", nstpaths.nstdir, nstpaths.gamename); - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), moviepath); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.nstdir); - - if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - nst_movie_save(filename); - g_free(filename); - } - - gtk_widget_destroy(dialog); -} - -void gtkui_movie_load() { - // Load a movie from the GUI - GtkWidget *dialog = gtk_file_chooser_dialog_new("Load movie (.nsv)", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_OPEN, - "Cancel", GTK_RESPONSE_CANCEL, - "Open", GTK_RESPONSE_ACCEPT, - nullptr); - - GtkFileFilter *filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, "Nestopia movies"); - gtk_file_filter_add_pattern(filter, "*.nsv"); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.nstdir); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - nst_movie_load(filename); - g_free(filename); - } - - gtk_widget_destroy(dialog); -} - -void gtkui_movie_stop() { - nst_movie_stop(); -} - -void gtkui_cheats_load() { - // Load cheats from the GUI - GtkWidget *dialog = gtk_file_chooser_dialog_new("Load cheats (.xml)", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_OPEN, - "Cancel", GTK_RESPONSE_CANCEL, - "Open", GTK_RESPONSE_ACCEPT, - nullptr); - - GtkFileFilter *filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, "Nestopia cheats"); - gtk_file_filter_add_pattern(filter, "*.xml"); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), nstpaths.nstdir); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - gtkui_cheats_fill_tree(filename); - g_free(filename); - } - - gtk_widget_destroy(dialog); -} - -void gtkui_palette_load() { - // Load a palette from the GUI - GtkWidget *dialog = gtk_file_chooser_dialog_new("Load palette (.pal)", - GTK_WINDOW(gtkwindow), - GTK_FILE_CHOOSER_ACTION_OPEN, - "Cancel", GTK_RESPONSE_CANCEL, - "Open", GTK_RESPONSE_ACCEPT, - nullptr); - - GtkFileFilter *filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, "NES Palettes"); - gtk_file_filter_add_pattern(filter, "*.pal"); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - nst_palette_load(filename); - nst_palette_save(); - g_free(filename); - conf.video_palette_mode = 2; - video_init(); - } - - gtk_widget_destroy(dialog); -} diff --git a/source/gtkui/gtkui_dialogs.h b/source/gtkui/gtkui_dialogs.h deleted file mode 100644 index 5f0c2f5..0000000 --- a/source/gtkui/gtkui_dialogs.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _GTKUI_DIALOGS_H_ -#define _GTKUI_DIALOGS_H_ - -void gtkui_file_open(); -void gtkui_state_save(); -void gtkui_state_load(); - -void gtkui_screenshot_save(); - -void gtkui_movie_save(); -void gtkui_movie_load(); -void gtkui_movie_stop(); - -void gtkui_cheats_load(); - -void gtkui_palette_load(); - -#endif diff --git a/source/gtkui/gtkui_input.cpp b/source/gtkui/gtkui_input.cpp deleted file mode 100644 index d2ddba5..0000000 --- a/source/gtkui/gtkui_input.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Nestopia UE - * - * Copyright (C) 2012-2017 R. Danbrook - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include "nstcommon.h" -#include "input.h" -#include "video.h" -#include "audio.h" -#include "ini.h" - -#include "sdlinput.h" - -#include "gtkui.h" -#include "gtkui_input.h" - -static ginputsettings_t inputconf; -static gkeys_t ui; -gpad_t pad[NUMGAMEPADS]; - -static char inputconfpath[256]; -static bool confrunning = false; -static guint keyval = 0; - -extern GtkWidget *configwindow; -extern nstpaths_t nstpaths; -extern Input::Controllers *cNstPads; - -static int gtkui_input_config_match(void* user, const char* section, const char* name, const char* value) { - // Match values from input config file and populate live config - ginputsettings_t* pconfig = (ginputsettings_t*)user; - - // User Interface - if (MATCH("ui", "qsave1")) { pconfig->qsave1 = strdup(value); } - else if (MATCH("ui", "qsave2")) { pconfig->qsave2 = strdup(value); } - else if (MATCH("ui", "qload1")) { pconfig->qload1 = strdup(value); } - else if (MATCH("ui", "qload2")) { pconfig->qload2 = strdup(value); } - else if (MATCH("ui", "screenshot")) { pconfig->screenshot = strdup(value); } - else if (MATCH("ui", "fdsflip")) { pconfig->fdsflip = strdup(value); } - else if (MATCH("ui", "fdsswitch")) { pconfig->fdsswitch = strdup(value); } - else if (MATCH("ui", "insertcoin1")) { pconfig->insertcoin1 = strdup(value); } - else if (MATCH("ui", "insertcoin2")) { pconfig->insertcoin2 = strdup(value); } - else if (MATCH("ui", "reset")) { pconfig->reset = strdup(value); } - else if (MATCH("ui", "ffspeed")) { pconfig->ffspeed = strdup(value); } - else if (MATCH("ui", "rwstart")) { pconfig->rwstart = strdup(value); } - else if (MATCH("ui", "rwstop")) { pconfig->rwstop = strdup(value); } - else if (MATCH("ui", "fullscreen")) { pconfig->fullscreen = strdup(value); } - else if (MATCH("ui", "filter")) { pconfig->filter = strdup(value); } - else if (MATCH("ui", "scalefactor")) { pconfig->scalefactor = strdup(value); } - - // Player 1 - else if (MATCH("gamepad1", "kb_u")) { pconfig->kb_p1u = strdup(value); } - else if (MATCH("gamepad1", "kb_d")) { pconfig->kb_p1d = strdup(value); } - else if (MATCH("gamepad1", "kb_l")) { pconfig->kb_p1l = strdup(value); } - else if (MATCH("gamepad1", "kb_r")) { pconfig->kb_p1r = strdup(value); } - else if (MATCH("gamepad1", "kb_select")) { pconfig->kb_p1select = strdup(value); } - else if (MATCH("gamepad1", "kb_start")) { pconfig->kb_p1start = strdup(value); } - else if (MATCH("gamepad1", "kb_a")) { pconfig->kb_p1a = strdup(value); } - else if (MATCH("gamepad1", "kb_b")) { pconfig->kb_p1b = strdup(value); } - else if (MATCH("gamepad1", "kb_ta")) { pconfig->kb_p1ta = strdup(value); } - else if (MATCH("gamepad1", "kb_tb")) { pconfig->kb_p1tb = strdup(value); } - - // Player 2 - else if (MATCH("gamepad2", "kb_u")) { pconfig->kb_p2u = strdup(value); } - else if (MATCH("gamepad2", "kb_d")) { pconfig->kb_p2d = strdup(value); } - else if (MATCH("gamepad2", "kb_l")) { pconfig->kb_p2l = strdup(value); } - else if (MATCH("gamepad2", "kb_r")) { pconfig->kb_p2r = strdup(value); } - else if (MATCH("gamepad2", "kb_select")) { pconfig->kb_p2select = strdup(value); } - else if (MATCH("gamepad2", "kb_start")) { pconfig->kb_p2start = strdup(value); } - else if (MATCH("gamepad2", "kb_a")) { pconfig->kb_p2a = strdup(value); } - else if (MATCH("gamepad2", "kb_b")) { pconfig->kb_p2b = strdup(value); } - else if (MATCH("gamepad2", "kb_ta")) { pconfig->kb_p2ta = strdup(value); } - else if (MATCH("gamepad2", "kb_tb")) { pconfig->kb_p2tb = strdup(value); } - - else { return 0; } - return 1; -} - -void gtkui_input_set_default() { - // Set the default input for GTK - - // Gamepads - pad[0].u = GDK_KEY_Up; - pad[0].d = GDK_KEY_Down; - pad[0].l = GDK_KEY_Left; - pad[0].r = GDK_KEY_Right; - pad[0].select = GDK_KEY_Shift_R; - pad[0].start = GDK_KEY_Return; - pad[0].a = GDK_KEY_z; - pad[0].b = GDK_KEY_a; - pad[0].ta = GDK_KEY_x; - pad[0].tb = GDK_KEY_s; - - pad[1].u = GDK_KEY_i; - pad[1].d = GDK_KEY_k; - pad[1].l = GDK_KEY_j; - pad[1].r = GDK_KEY_l; - pad[1].select = GDK_KEY_Shift_L; - pad[1].start = GDK_KEY_Control_L; - pad[1].a = GDK_KEY_m; - pad[1].b = GDK_KEY_n; - pad[1].ta = GDK_KEY_b; - pad[1].tb = GDK_KEY_v; - - // User Interface - ui.qsave1 = GDK_KEY_F5; - ui.qsave2 = GDK_KEY_F6; - ui.qload1 = GDK_KEY_F7; - ui.qload2 = GDK_KEY_F8; - ui.screenshot = GDK_KEY_F9; - ui.fdsflip = GDK_KEY_F3; - ui.fdsswitch = GDK_KEY_F4; - ui.insertcoin1 = GDK_KEY_F1; - ui.insertcoin2 = GDK_KEY_F2; - ui.reset = GDK_KEY_F12; - ui.ffspeed = GDK_KEY_grave; - ui.rwstart = GDK_KEY_BackSpace; - ui.rwstop = GDK_KEY_backslash; - ui.fullscreen = GDK_KEY_f; - ui.filter = GDK_KEY_t; - ui.scalefactor = GDK_KEY_g; -} - -void gtkui_input_config_read() { - // Read the input config file - snprintf(inputconfpath, sizeof(inputconfpath), "%sgtkinput.conf", nstpaths.nstconfdir); - if (ini_parse(inputconfpath, gtkui_input_config_match, &inputconf) < 0) { - fprintf(stderr, "Failed to load input config file %s: Using defaults.\n", inputconfpath); - } - else { - // Map the input settings from the config file - - // User Interface - ui.qsave1 = gdk_keyval_from_name(inputconf.qsave1); - ui.qsave2 = gdk_keyval_from_name(inputconf.qsave2); - ui.qload1 = gdk_keyval_from_name(inputconf.qload1); - ui.qload2 = gdk_keyval_from_name(inputconf.qload2); - ui.screenshot = gdk_keyval_from_name(inputconf.screenshot); - ui.fdsflip = gdk_keyval_from_name(inputconf.fdsflip); - ui.fdsswitch = gdk_keyval_from_name(inputconf.fdsswitch); - ui.insertcoin1 = gdk_keyval_from_name(inputconf.insertcoin1); - ui.insertcoin2 = gdk_keyval_from_name(inputconf.insertcoin2); - ui.reset = gdk_keyval_from_name(inputconf.reset); - ui.ffspeed = gdk_keyval_from_name(inputconf.ffspeed); - ui.rwstart = gdk_keyval_from_name(inputconf.rwstart); - ui.rwstop = gdk_keyval_from_name(inputconf.rwstop); - ui.fullscreen = gdk_keyval_from_name(inputconf.fullscreen); - ui.filter = gdk_keyval_from_name(inputconf.filter); - ui.scalefactor = gdk_keyval_from_name(inputconf.scalefactor); - - // Player 1 - pad[0].u = gdk_keyval_from_name(inputconf.kb_p1u); - pad[0].d = gdk_keyval_from_name(inputconf.kb_p1d); - pad[0].l = gdk_keyval_from_name(inputconf.kb_p1l); - pad[0].r = gdk_keyval_from_name(inputconf.kb_p1r); - pad[0].select = gdk_keyval_from_name(inputconf.kb_p1select); - pad[0].start = gdk_keyval_from_name(inputconf.kb_p1start); - pad[0].a = gdk_keyval_from_name(inputconf.kb_p1a); - pad[0].b = gdk_keyval_from_name(inputconf.kb_p1b); - pad[0].ta = gdk_keyval_from_name(inputconf.kb_p1ta); - pad[0].tb = gdk_keyval_from_name(inputconf.kb_p1tb); - - // Player 2 - pad[1].u = gdk_keyval_from_name(inputconf.kb_p2u); - pad[1].d = gdk_keyval_from_name(inputconf.kb_p2d); - pad[1].l = gdk_keyval_from_name(inputconf.kb_p2l); - pad[1].r = gdk_keyval_from_name(inputconf.kb_p2r); - pad[1].select = gdk_keyval_from_name(inputconf.kb_p2select); - pad[1].start = gdk_keyval_from_name(inputconf.kb_p2start); - pad[1].a = gdk_keyval_from_name(inputconf.kb_p2a); - pad[1].b = gdk_keyval_from_name(inputconf.kb_p2b); - pad[1].ta = gdk_keyval_from_name(inputconf.kb_p2ta); - pad[1].tb = gdk_keyval_from_name(inputconf.kb_p2tb); - } -} - -void gtkui_input_config_write() { - // Write out the input configuration file - - FILE *fp = fopen(inputconfpath, "w"); - if (fp != NULL) { - fprintf(fp, "; Nestopia UE GTK Input Configuration File\n\n"); - fprintf(fp, "; Values for keyboard input are these values with the GDK_KEY_ prefix removed:\n; https://git.gnome.org/browse/gtk+/plain/gdk/gdkkeysyms.h\n\n"); - - fprintf(fp, "[ui]\n"); - fprintf(fp, "qsave1=%s\n", gdk_keyval_name(ui.qsave1)); - fprintf(fp, "qsave2=%s\n", gdk_keyval_name(ui.qsave2)); - fprintf(fp, "qload1=%s\n", gdk_keyval_name(ui.qload1)); - fprintf(fp, "qload2=%s\n", gdk_keyval_name(ui.qload2)); - fprintf(fp, "screenshot=%s\n", gdk_keyval_name(ui.screenshot)); - fprintf(fp, "fdsflip=%s\n", gdk_keyval_name(ui.fdsflip)); - fprintf(fp, "fdsswitch=%s\n", gdk_keyval_name(ui.fdsswitch)); - fprintf(fp, "insertcoin1=%s\n", gdk_keyval_name(ui.insertcoin1)); - fprintf(fp, "insertcoin2=%s\n", gdk_keyval_name(ui.insertcoin2)); - fprintf(fp, "reset=%s\n", gdk_keyval_name(ui.reset)); - fprintf(fp, "ffspeed=%s\n", gdk_keyval_name(ui.ffspeed)); - fprintf(fp, "rwstart=%s\n", gdk_keyval_name(ui.rwstart)); - fprintf(fp, "rwstop=%s\n", gdk_keyval_name(ui.rwstop)); - fprintf(fp, "fullscreen=%s\n", gdk_keyval_name(ui.fullscreen)); - fprintf(fp, "filter=%s\n", gdk_keyval_name(ui.filter)); - fprintf(fp, "scalefactor=%s\n", gdk_keyval_name(ui.scalefactor)); - fprintf(fp, "\n"); // End of Section - - fprintf(fp, "[gamepad1]\n"); - fprintf(fp, "kb_u=%s\n", gdk_keyval_name(pad[0].u)); - fprintf(fp, "kb_d=%s\n", gdk_keyval_name(pad[0].d)); - fprintf(fp, "kb_l=%s\n", gdk_keyval_name(pad[0].l)); - fprintf(fp, "kb_r=%s\n", gdk_keyval_name(pad[0].r)); - fprintf(fp, "kb_select=%s\n", gdk_keyval_name(pad[0].select)); - fprintf(fp, "kb_start=%s\n", gdk_keyval_name(pad[0].start)); - fprintf(fp, "kb_a=%s\n", gdk_keyval_name(pad[0].a)); - fprintf(fp, "kb_b=%s\n", gdk_keyval_name(pad[0].b)); - fprintf(fp, "kb_ta=%s\n", gdk_keyval_name(pad[0].ta)); - fprintf(fp, "kb_tb=%s\n", gdk_keyval_name(pad[0].tb)); - fprintf(fp, "\n"); // End of Section - - fprintf(fp, "[gamepad2]\n"); - fprintf(fp, "kb_u=%s\n", gdk_keyval_name(pad[1].u)); - fprintf(fp, "kb_d=%s\n", gdk_keyval_name(pad[1].d)); - fprintf(fp, "kb_l=%s\n", gdk_keyval_name(pad[1].l)); - fprintf(fp, "kb_r=%s\n", gdk_keyval_name(pad[1].r)); - fprintf(fp, "kb_select=%s\n", gdk_keyval_name(pad[1].select)); - fprintf(fp, "kb_start=%s\n", gdk_keyval_name(pad[1].start)); - fprintf(fp, "kb_a=%s\n", gdk_keyval_name(pad[1].a)); - fprintf(fp, "kb_b=%s\n", gdk_keyval_name(pad[1].b)); - fprintf(fp, "kb_ta=%s\n", gdk_keyval_name(pad[1].ta)); - fprintf(fp, "kb_tb=%s\n", gdk_keyval_name(pad[1].tb)); - - fclose(fp); - } -} - -void gtkui_input_config_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata) { - keyval = event->keyval; - if (keyval == GDK_KEY_Escape || keyval == GDK_KEY_space) { keyval = 0; } - confrunning = false; -} - -void gtkui_input_config_signals_init() { - // Key translation - g_signal_connect(G_OBJECT(configwindow), "key-press-event", - G_CALLBACK(gtkui_input_config_process_key), NULL); - - g_signal_connect(G_OBJECT(configwindow), "key-release-event", - G_CALLBACK(gtkui_input_config_process_key), NULL); -} - -void gtkui_input_config_signals_deinit() { - // Key translation - g_signal_connect(G_OBJECT(configwindow), "key-press-event", - gtkui_input_null, NULL); - - g_signal_connect(G_OBJECT(configwindow), "key-release-event", - gtkui_input_null, NULL); -} - -void gtkui_input_config_key(int pnum, int bnum) { - // Connect signals - gtkui_input_config_signals_init(); - - // Wait for input - confrunning = true; - while (confrunning) { gtk_main_iteration(); } - - // Set the keyval for the input item - if (keyval != 0) { - switch (bnum) { - case 0: pad[pnum].u = keyval; break; - case 1: pad[pnum].d = keyval; break; - case 2: pad[pnum].l = keyval; break; - case 3: pad[pnum].r = keyval; break; - case 4: pad[pnum].select = keyval; break; - case 5: pad[pnum].start = keyval; break; - case 6: pad[pnum].a = keyval; break; - case 7: pad[pnum].b = keyval; break; - case 8: pad[pnum].ta = keyval; break; - case 9: pad[pnum].tb = keyval; break; - default: break; - } - } - - // Disconnect signals - gtkui_input_config_signals_deinit(); -} - -void gtkui_input_config_js(int pnum, int bnum) { - // Wait for input - nstsdl_input_conf_button(pnum, bnum); -} - -void gtkui_input_null() {} - -int gtkui_input_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata) { - // Process input from GDK events - - nesinput_t input; - - input.nescode = input.player = input.pressed = input.turboa = input.turbob = 0; - - for (int i = 0; i < NUMGAMEPADS; i++) { - if (event->keyval == pad[i].u) { input.player = i; input.nescode = Input::Controllers::Pad::UP; } - else if (event->keyval == pad[i].d) { input.player = i; input.nescode = Input::Controllers::Pad::DOWN; } - else if (event->keyval == pad[i].l) { input.player = i; input.nescode = Input::Controllers::Pad::LEFT; } - else if (event->keyval == pad[i].r) { input.player = i; input.nescode = Input::Controllers::Pad::RIGHT; } - else if (event->keyval == pad[i].select) { input.player = i; input.nescode = Input::Controllers::Pad::SELECT; } - else if (event->keyval == pad[i].start) { input.player = i; input.nescode = Input::Controllers::Pad::START; } - else if (event->keyval == pad[i].a) { input.player = i; input.nescode = Input::Controllers::Pad::A; } - else if (event->keyval == pad[i].b) { input.player = i; input.nescode = Input::Controllers::Pad::B; } - else if (event->keyval == pad[i].ta) { input.player = i; input.turboa = 1; input.nescode = Input::Controllers::Pad::A; } - else if (event->keyval == pad[i].tb) { input.player = i; input.turbob = 1; input.nescode = Input::Controllers::Pad::B; } - } - - switch(event->type) { - case GDK_KEY_PRESS: - //printf("Keyval: %x\n", event->keyval); - //printf("Keyval: %s\n", gdk_keyval_name(event->keyval)); - input.pressed = 1; - if (event->keyval == ui.qsave1) { nst_state_quicksave(0); } - else if (event->keyval == ui.qsave2) { nst_state_quicksave(1); } - else if (event->keyval == ui.qload1) { nst_state_quickload(0); } - else if (event->keyval == ui.qload2) { nst_state_quickload(1); } - else if (event->keyval == ui.screenshot) { video_screenshot(NULL); } - else if (event->keyval == ui.fdsflip) { nst_fds_flip(); } - else if (event->keyval == ui.fdsswitch) { nst_fds_switch(); } - else if (event->keyval == ui.insertcoin1) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_1; } - else if (event->keyval == ui.insertcoin2) { cNstPads->vsSystem.insertCoin |= Input::Controllers::VsSystem::COIN_2; } - else if (event->keyval == ui.reset) { nst_reset(0); } - else if (event->keyval == ui.ffspeed) { nst_timing_set_ffspeed(); } - else if (event->keyval == ui.rwstart) { nst_set_rewind(0); } - else if (event->keyval == ui.rwstop) { nst_set_rewind(1); } - else if (event->keyval == ui.filter) { gtkui_video_toggle_filter(); } - else if (event->keyval == ui.scalefactor) { gtkui_video_toggle_scale(); } - else if (event->keyval == gdk_keyval_from_name("space")) { cNstPads->pad[1].mic = 0x04; } - break; - case GDK_KEY_RELEASE: - input.pressed = 0; - if (event->keyval == ui.ffspeed) { nst_timing_set_default(); } - else if (event->keyval == ui.fullscreen) { gtkui_video_toggle_fullscreen(); } - else if (event->keyval == gdk_keyval_from_name("space")) { cNstPads->pad[1].mic = 0x00; } - break; - default: break; - } - - nst_input_inject(cNstPads, input); - - return TRUE; -} - -int gtkui_input_process_key_nsf(GtkWidget *widget, GdkEventKey *event, gpointer userdata) { - if (event->type == GDK_KEY_RELEASE) { - if (event->keyval == GDK_KEY_Up) { nst_nsf_play(); } - if (event->keyval == GDK_KEY_Down) { nst_nsf_stop(); } - if (event->keyval == GDK_KEY_Left) { nst_nsf_prev(); } - if (event->keyval == GDK_KEY_Right) { nst_nsf_next(); } - } - return TRUE; -} - -int gtkui_input_process_mouse(GtkWidget *widget, GdkEventButton *event, gpointer userdata) { - switch(event->type) { - case GDK_BUTTON_PRESS: - nst_input_inject_mouse(cNstPads, event->button, 1, (int)event->x, (int)event->y); - break; - - case GDK_BUTTON_RELEASE: - nst_input_inject_mouse(cNstPads, event->button, 0, (int)event->x, (int)event->y); - break; - default: break; - } - return TRUE; -} diff --git a/source/gtkui/gtkui_input.h b/source/gtkui/gtkui_input.h deleted file mode 100644 index 774d76b..0000000 --- a/source/gtkui/gtkui_input.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef _GTKUI_INPUT_H_ -#define _GTKUI_INPUT_H_ - -typedef struct { - guint u; - guint d; - guint l; - guint r; - guint select; - guint start; - guint a; - guint b; - guint ta; - guint tb; -} gpad_t; - -typedef struct { - guint qsave1; - guint qsave2; - guint qload1; - guint qload2; - guint screenshot; - guint fdsflip; - guint fdsswitch; - guint insertcoin1; - guint insertcoin2; - guint reset; - guint ffspeed; - guint rwstart; - guint rwstop; - guint fullscreen; - guint filter; - guint scalefactor; -} gkeys_t; - -typedef struct { - // User Interface - char *qsave1; - char *qsave2; - char *qload1; - char *qload2; - - char *screenshot; - - char *fdsflip; - char *fdsswitch; - - char *insertcoin1; - char *insertcoin2; - - char *reset; - - char *ffspeed; - char *rwstart; - char *rwstop; - - char *fullscreen; - char *filter; - char *scalefactor; - - // Player 1 - char *kb_p1u; - char *kb_p1d; - char *kb_p1l; - char *kb_p1r; - char *kb_p1select; - char *kb_p1start; - char *kb_p1a; - char *kb_p1b; - char *kb_p1ta; - char *kb_p1tb; - - // Player 2 - char *kb_p2u; - char *kb_p2d; - char *kb_p2l; - char *kb_p2r; - char *kb_p2select; - char *kb_p2start; - char *kb_p2a; - char *kb_p2b; - char *kb_p2ta; - char *kb_p2tb; -} ginputsettings_t; - -void gtkui_input_set_default(); -void gtkui_input_config_read(); -void gtkui_input_config_write(); -void gtkui_input_config_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata); -void gtkui_input_config_signals_init(); -void gtkui_input_config_signals_deinit(); -void gtkui_input_config_key(int pnum, int bnum); -void gtkui_input_config_js(int pnum, int bnum); -void gtkui_input_null(); -int gtkui_input_process_key(GtkWidget *widget, GdkEventKey *event, gpointer userdata); -int gtkui_input_process_key_nsf(GtkWidget *widget, GdkEventKey *event, gpointer userdata); -int gtkui_input_process_mouse(GtkWidget *widget, GdkEventButton *event, gpointer userdata); - -#endif