2018-11-16 00:42:29 +01:00
|
|
|
/*****************************************************************************\
|
|
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
This file is licensed under the Snes9x License.
|
|
|
|
For further information, consult the LICENSE file in the root directory.
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <signal.h>
|
2020-07-05 00:53:38 +02:00
|
|
|
#include "giomm/application.h"
|
|
|
|
#include "glibmm/main.h"
|
|
|
|
#include "gtk_compat.h"
|
2019-11-09 00:05:36 +01:00
|
|
|
#include "gtk_config.h"
|
2010-09-25 17:46:12 +02:00
|
|
|
#include "gtk_s9x.h"
|
|
|
|
#include "gtk_control.h"
|
|
|
|
#include "gtk_sound.h"
|
|
|
|
#include "gtk_display.h"
|
2018-12-02 02:58:13 +01:00
|
|
|
#include "gtk_netplay.h"
|
2014-06-27 10:36:36 +02:00
|
|
|
#include "statemanager.h"
|
2019-11-09 00:05:36 +01:00
|
|
|
#include "background_particles.h"
|
2020-07-05 00:53:38 +02:00
|
|
|
#include "snes9x.h"
|
|
|
|
#include "display.h"
|
|
|
|
#include "apu/apu.h"
|
|
|
|
#include "netplay.h"
|
|
|
|
#include "movie.h"
|
|
|
|
#include "controls.h"
|
|
|
|
#include "snapshot.h"
|
|
|
|
#include "gfx.h"
|
|
|
|
#include "memmap.h"
|
|
|
|
#include "ppu.h"
|
|
|
|
|
|
|
|
static void S9xThrottle(int);
|
|
|
|
static void S9xCheckPointerTimer();
|
|
|
|
static bool S9xIdleFunc();
|
|
|
|
static bool S9xPauseFunc();
|
|
|
|
static bool S9xScreenSaverCheckFunc();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
Snes9xWindow *top_level;
|
|
|
|
Snes9xConfig *gui_config;
|
|
|
|
StateManager state_manager;
|
2020-07-05 00:53:38 +02:00
|
|
|
gint64 frame_clock = -1;
|
|
|
|
gint64 pointer_timestamp = -1;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
Background::Particles particles(Background::Particles::Snow);
|
2019-11-09 00:05:36 +01:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
static void S9xTerm(int signal)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xExit();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
int main(int argc, char *argv[])
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
struct sigaction sig_callback;
|
2020-08-09 21:28:20 +02:00
|
|
|
auto app = Gtk::Application::create("com.snes9x.gtk", Gio::APPLICATION_NON_UNIQUE);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
bindtextdomain(GETTEXT_PACKAGE, SNES9XLOCALEDIR);
|
|
|
|
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
|
|
|
|
textdomain(GETTEXT_PACKAGE);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
memset(&Settings, 0, sizeof(Settings));
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
// Original config fills out values this port doesn't.
|
|
|
|
S9xLoadConfigFiles(argv, argc);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
gui_config = new Snes9xConfig();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xInitInputDevices();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
gui_config->load_config_file();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
char *rom_filename = S9xParseArgs(argv, argc);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
auto settings = Gtk::Settings::get_default();
|
|
|
|
settings->set_property("gtk-menu-images", gui_config->enable_icons);
|
|
|
|
settings->set_property("gtk-button-images", gui_config->enable_icons);
|
2019-03-20 17:54:16 +01:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xReportControllers();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (!Memory.Init() || !S9xInitAPU())
|
|
|
|
exit(3);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level = new Snes9xWindow(gui_config);
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
// Setting fullscreen before showing the window avoids some flicker.
|
2010-09-26 11:19:15 +02:00
|
|
|
if ((gui_config->full_screen_on_open && rom_filename) || (gui_config->fullscreen))
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->window->fullscreen();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->show();
|
2020-11-04 19:41:55 +01:00
|
|
|
|
2020-11-04 19:10:30 +01:00
|
|
|
S9xInitDisplay(argc, argv);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-11-04 19:41:55 +01:00
|
|
|
S9xPortSoundInit();
|
|
|
|
|
2018-10-03 23:58:40 +02:00
|
|
|
for (int port = 0; port < 2; port++)
|
|
|
|
{
|
|
|
|
enum controllers type;
|
|
|
|
int8 id;
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xGetController(port, &type, &id, &id, &id, &id);
|
2018-10-03 23:58:40 +02:00
|
|
|
std::string device_type;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case CTL_MP5:
|
|
|
|
device_type = "multitap";
|
|
|
|
break;
|
|
|
|
case CTL_MOUSE:
|
|
|
|
device_type = "mouse";
|
|
|
|
break;
|
|
|
|
case CTL_SUPERSCOPE:
|
|
|
|
device_type = "superscope";
|
|
|
|
break;
|
2018-12-12 23:44:47 +01:00
|
|
|
case CTL_JOYPAD:
|
2018-10-03 23:58:40 +02:00
|
|
|
device_type = "joypad";
|
2018-12-12 23:44:47 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
device_type = "nothingpluggedin";
|
2018-10-03 23:58:40 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
device_type += std::to_string(port + 1);
|
|
|
|
top_level->set_menu_item_selected(device_type.c_str());
|
2018-10-03 23:58:40 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
gui_config->rebind_keys();
|
|
|
|
top_level->update_accelerators();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
Settings.Paused = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
Glib::signal_timeout().connect(sigc::ptr_fun(S9xPauseFunc), 100);
|
|
|
|
Glib::signal_timeout().connect(sigc::ptr_fun(S9xScreenSaverCheckFunc), 10000);
|
|
|
|
|
|
|
|
S9xNoROMLoaded();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (rom_filename)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
if (S9xOpenROM(rom_filename) && gui_config->full_screen_on_open)
|
|
|
|
top_level->window->unfullscreen();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
memset(&sig_callback, 0, sizeof(struct sigaction));
|
2010-09-25 17:46:12 +02:00
|
|
|
sig_callback.sa_handler = S9xTerm;
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
sigaction(15, &sig_callback, NULL); // SIGTERM
|
|
|
|
sigaction(3, &sig_callback, NULL); // SIGQUIT
|
|
|
|
sigaction(2, &sig_callback, NULL); // SIGINT
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
// Perform the complete fullscreen process, including mode sets, which
|
|
|
|
// didn't happen in the earlier Gtk call.
|
2010-09-25 17:46:12 +02:00
|
|
|
if (gui_config->fullscreen)
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->enter_fullscreen_mode();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
gui_config->flush_joysticks();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-05-14 18:20:12 +02:00
|
|
|
if (rom_filename && *Settings.InitialSnapshotFilename)
|
2017-12-17 01:13:07 +01:00
|
|
|
S9xUnfreezeGame(Settings.InitialSnapshotFilename);
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
app->run(*top_level->window.get());
|
2010-09-25 17:46:12 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
int S9xOpenROM(const char *rom_filename)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
uint32 flags;
|
2020-07-05 00:53:38 +02:00
|
|
|
bool loaded;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (gui_config->rom_loaded)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xAutoSaveSRAM();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xNetplayDisconnect();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
flags = CPU.Flags;
|
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
loaded = false;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (Settings.Multi)
|
2020-07-05 00:53:38 +02:00
|
|
|
loaded = Memory.LoadMultiCart(Settings.CartAName, Settings.CartBName);
|
2010-09-25 17:46:12 +02:00
|
|
|
else if (rom_filename)
|
2020-07-05 00:53:38 +02:00
|
|
|
loaded = Memory.LoadROM(rom_filename);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
Settings.StopEmulation = !loaded;
|
|
|
|
|
|
|
|
if (!loaded && rom_filename)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
char dir[_MAX_DIR + 1];
|
|
|
|
char drive[_MAX_DRIVE + 1];
|
|
|
|
char name[_MAX_FNAME + 1];
|
|
|
|
char ext[_MAX_EXT + 1];
|
|
|
|
char fname[_MAX_PATH + 1];
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
_splitpath(rom_filename, drive, dir, name, ext);
|
|
|
|
_makepath(fname, drive, dir, name, ext);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
strcpy(fname, S9xGetDirectory(ROM_DIR));
|
|
|
|
strcat(fname, SLASH_STR);
|
|
|
|
strcat(fname, name);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (ext[0])
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
strcat(fname, ".");
|
|
|
|
strcat(fname, ext);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
_splitpath(fname, drive, dir, name, ext);
|
|
|
|
_makepath(fname, drive, dir, name, ext);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if ((Settings.StopEmulation = !Memory.LoadROM(fname)))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
fprintf(stderr, _("Error opening: %s\n"), rom_filename);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
loaded = false;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
else
|
2018-12-28 23:32:32 +01:00
|
|
|
loaded = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (loaded)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
Memory.LoadSRAM(S9xGetFilename(".srm", SRAM_DIR));
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CPU.Flags = flags;
|
2018-12-28 23:32:32 +01:00
|
|
|
Settings.Paused = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xNoROMLoaded();
|
|
|
|
top_level->refresh();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CPU.Flags = flags;
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (state_manager.init(gui_config->rewind_buffer_size * 1024 * 1024))
|
2014-06-27 10:36:36 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
printf("Using rewind buffer of %uMB\n", gui_config->rewind_buffer_size);
|
2014-06-27 10:36:36 +02:00
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xROMLoaded();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void S9xROMLoaded()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-12-28 23:32:32 +01:00
|
|
|
gui_config->rom_loaded = true;
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->configure_widgets();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (gui_config->full_screen_on_open)
|
|
|
|
{
|
2018-12-28 23:32:32 +01:00
|
|
|
Settings.Paused = false;
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->enter_fullscreen_mode();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xSoundStart();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void S9xNoROMLoaded()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xSoundStop();
|
2018-12-28 23:32:32 +01:00
|
|
|
gui_config->rom_loaded = false;
|
2020-07-01 00:28:10 +02:00
|
|
|
S9xDisplayRefresh(-1, -1);
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->configure_widgets();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
static bool S9xPauseFunc()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xProcessEvents(true);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (!S9xNetplayPush())
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xNetplayPop();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!Settings.Paused) /* Coming out of pause */
|
|
|
|
{
|
|
|
|
/* Clear joystick queues */
|
2020-07-05 00:53:38 +02:00
|
|
|
gui_config->flush_joysticks();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xSoundStart();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (Settings.NetPlay && NetPlay.Connected)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xNPSendPause(false);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Resume high-performance callback */
|
2020-07-05 00:53:38 +02:00
|
|
|
Glib::signal_idle().connect(sigc::ptr_fun(S9xIdleFunc));
|
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
return false;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2019-11-09 00:05:36 +01:00
|
|
|
if (!gui_config->rom_loaded)
|
|
|
|
{
|
|
|
|
if (gui_config->splash_image >= SPLASH_IMAGE_STARFIELD)
|
|
|
|
{
|
|
|
|
if (gui_config->splash_image == SPLASH_IMAGE_STARFIELD)
|
|
|
|
particles.setmode(Background::Particles::Stars);
|
|
|
|
else
|
|
|
|
particles.setmode(Background::Particles::Snow);
|
|
|
|
|
|
|
|
S9xThrottle(THROTTLE_TIMER);
|
|
|
|
particles.advance();
|
|
|
|
particles.copyto(GFX.Screen, GFX.Pitch);
|
|
|
|
S9xDeinitUpdate(256, 224);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
Glib::signal_timeout().connect(sigc::ptr_fun(S9xPauseFunc), 8);
|
2019-11-09 00:05:36 +01:00
|
|
|
|
|
|
|
return false;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
static bool S9xIdleFunc()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2019-11-09 00:05:36 +01:00
|
|
|
if (Settings.Paused && gui_config->rom_loaded)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xSoundStop();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
gui_config->flush_joysticks();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (Settings.NetPlay && NetPlay.Connected)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xNPSendPause(true);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Move to a timer-based function to use less CPU */
|
2020-07-05 00:53:38 +02:00
|
|
|
Glib::signal_timeout().connect(sigc::ptr_fun(S9xPauseFunc), 8);
|
2018-12-28 23:32:32 +01:00
|
|
|
return false;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xCheckPointerTimer();
|
2019-03-02 23:10:00 +01:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xProcessEvents(true);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (!S9xDisplayDriverIsReady())
|
2019-04-02 00:10:12 +02:00
|
|
|
{
|
|
|
|
usleep(100);
|
2018-12-28 23:32:32 +01:00
|
|
|
return true;
|
2019-04-02 00:10:12 +02:00
|
|
|
}
|
2018-12-04 01:21:09 +01:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xThrottle(Settings.SkipFrames);
|
2018-12-04 01:21:09 +01:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (!S9xNetplayPush())
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
if (Settings.Rewinding)
|
2018-12-02 02:58:13 +01:00
|
|
|
{
|
|
|
|
uint16 joypads[8];
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
joypads[i] = MovieGetJoypad(i);
|
2018-06-17 00:31:41 +02:00
|
|
|
|
2018-12-02 02:58:13 +01:00
|
|
|
Settings.Rewinding = state_manager.pop();
|
2018-06-17 00:31:41 +02:00
|
|
|
|
2018-12-02 02:58:13 +01:00
|
|
|
for (int i = 0; i < 8; i++)
|
2020-07-05 00:53:38 +02:00
|
|
|
MovieSetJoypad(i, joypads[i]);
|
2018-12-02 02:58:13 +01:00
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (IPPU.TotalEmulatedFrames % gui_config->rewind_granularity == 0)
|
2018-12-02 02:58:13 +01:00
|
|
|
state_manager.push();
|
2016-10-09 04:15:45 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if ((Settings.TurboMode || Settings.Rewinding) && gui_config->mute_sound_turbo)
|
|
|
|
Settings.Mute |= 0x80;
|
|
|
|
else
|
|
|
|
Settings.Mute &= ~0x80;
|
2016-08-02 17:31:05 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xMainLoop();
|
2016-08-02 17:31:05 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xNetplayPop();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
return true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
static bool S9xScreenSaverCheckFunc()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
if (!Settings.Paused &&
|
|
|
|
(gui_config->screensaver_needs_reset ||
|
|
|
|
gui_config->prevent_screensaver))
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->reset_screensaver();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
return true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Snes9x core hooks */
|
2020-07-05 00:53:38 +02:00
|
|
|
void S9xMessage(int type, int number, const char *message)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-12-12 23:15:56 +01:00
|
|
|
switch (number)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
case S9X_MOVIE_INFO:
|
|
|
|
S9xSetInfoString(message);
|
2018-12-12 23:15:56 +01:00
|
|
|
break;
|
2020-07-05 00:53:38 +02:00
|
|
|
default:
|
2018-12-12 23:15:56 +01:00
|
|
|
break;
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Varies from ParseArgs because this one is for the OS port to handle */
|
2020-07-05 00:53:38 +02:00
|
|
|
void S9xParseArg(char **argv, int &i, int argc)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
if (!strcasecmp(argv[i], "-filter"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
if ((++i) < argc)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
if (!strcasecmp(argv[i], "none"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_NONE;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "supereagle"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_SUPEREAGLE;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "2xsai"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_2XSAI;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "super2xsai"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_SUPER2XSAI;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
#ifdef USE_HQ2X
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "hq2x"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_HQ2X;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "hq3x"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_HQ3X;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "hq4x"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_HQ4X;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
#endif /* USE_HQ2X */
|
2015-01-28 15:24:35 +01:00
|
|
|
#ifdef USE_XBRZ
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "2xbrz"))
|
2015-01-28 15:24:35 +01:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_2XBRZ;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "3xbrz"))
|
2015-01-28 15:24:35 +01:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_3XBRZ;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "4xbrz"))
|
2015-01-28 15:24:35 +01:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_4XBRZ;
|
|
|
|
}
|
|
|
|
#endif /* USE_XBRZ */
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "epx"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_EPX;
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "ntsc"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_NTSC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-05 00:53:38 +02:00
|
|
|
else if (!strcasecmp(argv[i], "-mutesound"))
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-12-28 23:32:32 +01:00
|
|
|
gui_config->mute_sound = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
static void S9xThrottle(int method)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-10-28 22:55:33 +01:00
|
|
|
gint64 now;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (S9xNetplaySyncSpeed())
|
2010-09-25 17:46:12 +02:00
|
|
|
return;
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
now = g_get_monotonic_time();
|
2018-10-28 22:55:33 +01:00
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
if (Settings.HighSpeedSeek > 0)
|
|
|
|
{
|
|
|
|
Settings.HighSpeedSeek--;
|
2018-12-28 23:32:32 +01:00
|
|
|
IPPU.RenderThisFrame = false;
|
2010-09-25 17:46:12 +02:00
|
|
|
IPPU.SkippedFrames = 0;
|
2018-10-28 22:55:33 +01:00
|
|
|
frame_clock = now;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
if (Settings.TurboMode)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-10-28 22:55:33 +01:00
|
|
|
IPPU.FrameSkip++;
|
2020-07-05 00:53:38 +02:00
|
|
|
if ((IPPU.FrameSkip >= Settings.TurboSkipFrames) && !Settings.HighSpeedSeek)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
IPPU.FrameSkip = 0;
|
|
|
|
IPPU.SkippedFrames = 0;
|
2018-12-28 23:32:32 +01:00
|
|
|
IPPU.RenderThisFrame = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IPPU.SkippedFrames++;
|
2018-12-28 23:32:32 +01:00
|
|
|
IPPU.RenderThisFrame = false;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
frame_clock = now;
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
IPPU.RenderThisFrame = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
if (now - frame_clock > 500000)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-10-28 22:55:33 +01:00
|
|
|
frame_clock = now;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2019-11-09 00:05:36 +01:00
|
|
|
if (method == THROTTLE_SOUND_SYNC ||
|
|
|
|
method == THROTTLE_NONE)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-10-28 22:55:33 +01:00
|
|
|
frame_clock = now;
|
|
|
|
IPPU.SkippedFrames = 0;
|
|
|
|
}
|
|
|
|
else // THROTTLE_TIMER or THROTTLE_TIMER_FRAMESKIP
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2019-11-09 00:05:36 +01:00
|
|
|
if (method == THROTTLE_TIMER_FRAMESKIP)
|
2018-10-28 22:55:33 +01:00
|
|
|
{
|
|
|
|
if (now - frame_clock > Settings.FrameTime)
|
|
|
|
{
|
|
|
|
IPPU.SkippedFrames++;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
if (IPPU.SkippedFrames < 8)
|
|
|
|
{
|
2018-12-28 23:32:32 +01:00
|
|
|
IPPU.RenderThisFrame = false;
|
2018-10-28 22:55:33 +01:00
|
|
|
frame_clock += Settings.FrameTime;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
frame_clock = now - Settings.FrameTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
while (now - frame_clock < Settings.FrameTime)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
usleep(100);
|
|
|
|
now = g_get_monotonic_time();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
frame_clock += Settings.FrameTime;
|
|
|
|
IPPU.FrameSkip = 0;
|
|
|
|
IPPU.SkippedFrames = 0;
|
|
|
|
}
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void S9xSyncSpeed()
|
2018-10-28 22:55:33 +01:00
|
|
|
{
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
static void S9xCheckPointerTimer()
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
if (!gui_config->pointer_is_visible)
|
|
|
|
return;
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
if (g_get_monotonic_time() - gui_config->pointer_timestamp > 1000000)
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->hide_mouse_cursor();
|
2018-12-28 23:32:32 +01:00
|
|
|
gui_config->pointer_is_visible = false;
|
2010-09-26 11:19:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
/* Final exit point, issues exit (0) */
|
2020-07-05 00:53:38 +02:00
|
|
|
void S9xExit()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
gui_config->save_config_file();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
top_level->leave_fullscreen_mode();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xPortSoundDeinit();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-12-28 23:32:32 +01:00
|
|
|
Settings.StopEmulation = true;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (gui_config->rom_loaded)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xAutoSaveSRAM();
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xDeinitAPU();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
S9xDeinitInputDevices();
|
|
|
|
S9xDeinitDisplay();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
delete top_level;
|
|
|
|
delete gui_config;
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
exit(0);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2018-10-28 22:55:33 +01:00
|
|
|
const char *S9xStringInput(const char *message)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void S9xExtraUsage()
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
printf("GTK port options:\n"
|
|
|
|
"-filter [option] Use a filter to scale the image.\n"
|
|
|
|
" [option] is one of: none supereagle 2xsai\n"
|
|
|
|
" super2xsai hq2x hq3x hq4x 2xbrz 3xbrz 4xbrz epx ntsc\n"
|
|
|
|
"\n"
|
|
|
|
"-mutesound Disables sound output.\n");
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|