2010-09-25 17:46:12 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
#include <gdk/gdkx.h>
|
|
|
|
|
|
|
|
#include "gtk_s9x.h"
|
|
|
|
#include "gtk_control.h"
|
|
|
|
#include "gtk_sound.h"
|
|
|
|
#include "gtk_display.h"
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
#include "gtk_netplay.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define IDLE_FUNC_PRIORITY (G_PRIORITY_DEFAULT_IDLE)
|
|
|
|
|
|
|
|
void S9xPostRomInit (void);
|
|
|
|
void S9xSyncSpeedFinish (void);
|
2010-09-26 11:19:15 +02:00
|
|
|
static void S9xCheckPointerTimer (void);
|
2010-09-25 17:46:12 +02:00
|
|
|
static gboolean S9xIdleFunc (gpointer data);
|
|
|
|
static gboolean S9xScreenSaverCheckFunc (gpointer data);
|
|
|
|
|
|
|
|
Snes9xWindow *top_level;
|
|
|
|
Snes9xConfig *gui_config;
|
|
|
|
static struct timeval next_frame_time = { 0, 0 };
|
|
|
|
static struct timeval now;
|
|
|
|
static int needs_fullscreening = FALSE;
|
|
|
|
int syncing;
|
|
|
|
guint idle_func_id;
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xTerm (int signal)
|
|
|
|
{
|
|
|
|
S9xExit ();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
struct sigaction sig_callback;
|
|
|
|
|
|
|
|
g_thread_init (NULL);
|
|
|
|
gdk_threads_init ();
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
bindtextdomain (GETTEXT_PACKAGE, SNES9XLOCALEDIR);
|
|
|
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
|
|
|
textdomain (GETTEXT_PACKAGE);
|
|
|
|
|
|
|
|
ZeroMemory (&Settings, sizeof (Settings));
|
|
|
|
|
|
|
|
/* Allow original config file for backend settings */
|
|
|
|
S9xLoadConfigFiles (argv, argc);
|
|
|
|
|
|
|
|
/* Perform our config here */
|
|
|
|
gui_config = new Snes9xConfig ();
|
|
|
|
|
|
|
|
S9xInitInputDevices ();
|
|
|
|
|
|
|
|
gui_config->load_config_file ();
|
|
|
|
|
|
|
|
char *rom_filename = S9xParseArgs (argv, argc);
|
|
|
|
|
|
|
|
S9xReportControllers ();
|
|
|
|
|
|
|
|
if (!Memory.Init () || !S9xInitAPU ())
|
|
|
|
exit (3);
|
|
|
|
|
|
|
|
g_set_application_name ("Snes9x");
|
|
|
|
|
|
|
|
top_level = new Snes9xWindow (gui_config);
|
2010-09-26 11:19:15 +02:00
|
|
|
|
|
|
|
/* If we're going to fullscreen, do it before showing window to avoid flicker. */
|
|
|
|
if ((gui_config->full_screen_on_open && rom_filename) || (gui_config->fullscreen))
|
|
|
|
gtk_window_fullscreen (top_level->get_window ());
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
top_level->show ();
|
|
|
|
|
|
|
|
S9xInitDisplay (argc, argv);
|
|
|
|
|
|
|
|
Memory.PostRomInitFunc = S9xPostRomInit;
|
|
|
|
|
|
|
|
S9xPortSoundInit ();
|
|
|
|
|
|
|
|
gui_config->reconfigure ();
|
|
|
|
top_level->update_accels ();
|
|
|
|
|
|
|
|
Settings.Paused = TRUE;
|
|
|
|
syncing = 0;
|
|
|
|
idle_func_id = g_idle_add_full (IDLE_FUNC_PRIORITY,
|
|
|
|
S9xIdleFunc,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
g_timeout_add (10000, S9xScreenSaverCheckFunc, NULL);
|
|
|
|
|
|
|
|
S9xNoROMLoaded ();
|
|
|
|
|
|
|
|
if (rom_filename)
|
|
|
|
{
|
2010-09-26 11:19:15 +02:00
|
|
|
if (S9xOpenROM (rom_filename) && gui_config->full_screen_on_open)
|
|
|
|
gtk_window_unfullscreen (top_level->get_window());
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
memset (&sig_callback, 0, sizeof (struct sigaction));
|
|
|
|
sig_callback.sa_handler = S9xTerm;
|
|
|
|
|
|
|
|
sigaction (15 /* SIGTERM */, &sig_callback, NULL);
|
|
|
|
sigaction (3 /* SIGQUIT */, &sig_callback, NULL);
|
|
|
|
sigaction (2 /* SIGINT */, &sig_callback, NULL);
|
|
|
|
|
|
|
|
if (gui_config->fullscreen)
|
|
|
|
{
|
|
|
|
gui_config->fullscreen = 0;
|
|
|
|
needs_fullscreening = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_JOYSTICK
|
|
|
|
gui_config->flush_joysticks ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
gdk_threads_lock ();
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
S9xOpenROM (const char *rom_filename)
|
|
|
|
{
|
|
|
|
uint32 flags;
|
|
|
|
bool8 loaded;
|
|
|
|
|
|
|
|
if (gui_config->rom_loaded)
|
|
|
|
{
|
|
|
|
S9xAutoSaveSRAM ();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
S9xNetplayDisconnect ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
flags = CPU.Flags;
|
|
|
|
|
|
|
|
loaded = FALSE;
|
|
|
|
|
|
|
|
if (Settings.Multi)
|
|
|
|
loaded = Memory.LoadMultiCart (Settings.CartAName, Settings.CartBName);
|
|
|
|
else if (rom_filename)
|
|
|
|
loaded = Memory.LoadROM (rom_filename);
|
|
|
|
|
|
|
|
Settings.StopEmulation = !loaded;
|
|
|
|
|
|
|
|
if (!loaded && rom_filename)
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
|
|
|
|
_splitpath (rom_filename, drive, dir, name, ext);
|
|
|
|
_makepath (fname, drive, dir, name, ext);
|
|
|
|
|
|
|
|
strcpy (fname, S9xGetDirectory (ROM_DIR));
|
|
|
|
strcat (fname, SLASH_STR);
|
|
|
|
strcat (fname, name);
|
|
|
|
|
|
|
|
if (ext [0])
|
|
|
|
{
|
|
|
|
strcat (fname, ".");
|
|
|
|
strcat (fname, ext);
|
|
|
|
}
|
|
|
|
|
|
|
|
_splitpath (fname, drive, dir, name, ext);
|
|
|
|
_makepath (fname, drive, dir, name, ext);
|
|
|
|
|
|
|
|
if ((Settings.StopEmulation = !Memory.LoadROM (fname)))
|
|
|
|
{
|
|
|
|
fprintf (stderr, _("Error opening: %s\n"), rom_filename);
|
|
|
|
|
|
|
|
loaded = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
loaded = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loaded)
|
|
|
|
{
|
|
|
|
Memory.LoadSRAM (S9xGetFilename (".srm", SRAM_DIR));
|
|
|
|
S9xLoadCheatFile (S9xGetFilename (".cht", CHEAT_DIR));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
S9xReset ();
|
|
|
|
|
|
|
|
CPU.Flags = flags;
|
|
|
|
Settings.Paused = 1;
|
|
|
|
|
|
|
|
S9xNoROMLoaded ();
|
|
|
|
top_level->refresh ();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CPU.Flags = flags;
|
|
|
|
|
|
|
|
S9xROMLoaded ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xROMLoaded (void)
|
|
|
|
{
|
|
|
|
gui_config->rom_loaded = TRUE;
|
|
|
|
top_level->configure_widgets ();
|
|
|
|
|
|
|
|
top_level->last_width = top_level->last_height = SIZE_FLAG_DIRTY;
|
|
|
|
|
|
|
|
if (gui_config->full_screen_on_open)
|
|
|
|
{
|
|
|
|
Settings.Paused = FALSE;
|
|
|
|
top_level->enter_fullscreen_mode ();
|
|
|
|
}
|
|
|
|
|
|
|
|
S9xSoundStart ();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xNoROMLoaded (void)
|
|
|
|
{
|
|
|
|
S9xSoundStop ();
|
|
|
|
gui_config->rom_loaded = FALSE;
|
|
|
|
S9xDisplayRefresh (-1, -1);
|
|
|
|
top_level->configure_widgets ();
|
|
|
|
top_level->update_statusbar ();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
static inline void check_messages (void)
|
|
|
|
{
|
|
|
|
static unsigned int current_timeout = 0;
|
|
|
|
|
|
|
|
if (GFX.InfoStringTimeout > current_timeout)
|
|
|
|
{
|
|
|
|
top_level->show_status_message (GFX.InfoString);
|
|
|
|
}
|
|
|
|
|
|
|
|
current_timeout = GFX.InfoStringTimeout;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
S9xPauseFunc (gpointer data)
|
|
|
|
{
|
|
|
|
S9xProcessEvents (TRUE);
|
|
|
|
|
|
|
|
if (!gui_config->rom_loaded)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
if (!S9xNetplayPush ())
|
|
|
|
{
|
|
|
|
S9xNetplayPop ();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!Settings.Paused) /* Coming out of pause */
|
|
|
|
{
|
|
|
|
#ifdef USE_JOYSTICK
|
|
|
|
/* Clear joystick queues */
|
|
|
|
gui_config->flush_joysticks ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
S9xSetSoundMute (FALSE);
|
|
|
|
S9xSoundStart ();
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
if (Settings.NetPlay && NetPlay.Connected)
|
|
|
|
{
|
|
|
|
S9xNPSendPause (FALSE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Resume high-performance callback */
|
|
|
|
idle_func_id = g_idle_add_full (IDLE_FUNC_PRIORITY,
|
|
|
|
S9xIdleFunc,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
top_level->update_statusbar ();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
S9xIdleFunc (gpointer data)
|
|
|
|
{
|
|
|
|
if (needs_fullscreening)
|
|
|
|
{
|
|
|
|
top_level->enter_fullscreen_mode();
|
|
|
|
needs_fullscreening = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Settings.Paused)
|
|
|
|
{
|
|
|
|
S9xSetSoundMute (gui_config->mute_sound);
|
|
|
|
S9xSoundStop ();
|
|
|
|
|
|
|
|
#ifdef USE_JOYSTICK
|
|
|
|
gui_config->flush_joysticks ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
if (Settings.NetPlay && NetPlay.Connected)
|
|
|
|
{
|
|
|
|
S9xNPSendPause (TRUE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Move to a timer-based function to use less CPU */
|
|
|
|
g_timeout_add (100, S9xPauseFunc, NULL);
|
|
|
|
top_level->update_statusbar ();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (syncing)
|
|
|
|
S9xSyncSpeedFinish ();
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
S9xCheckPointerTimer ();
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
S9xProcessEvents (TRUE);
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
if (!S9xNetplayPush ())
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
S9xMainLoop ();
|
|
|
|
S9xMixSound ();
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
S9xNetplayPop ();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
S9xScreenSaverCheckFunc (gpointer data)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!Settings.Paused &&
|
|
|
|
(gui_config->screensaver_needs_reset ||
|
|
|
|
gui_config->prevent_screensaver))
|
|
|
|
top_level->reset_screensaver ();
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Snes9x core hooks */
|
|
|
|
void
|
|
|
|
S9xMessage (int type, int number, const char *message)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
fprintf (stderr, "%s\n", message);
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Varies from ParseArgs because this one is for the OS port to handle */
|
|
|
|
void
|
|
|
|
S9xParseArg (char **argv, int &i, int argc)
|
|
|
|
{
|
|
|
|
if (!strcasecmp (argv[i], "-filter"))
|
|
|
|
{
|
|
|
|
if ((++i) < argc)
|
|
|
|
{
|
|
|
|
if (!strcasecmp (argv[i], "none"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_NONE;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp (argv[i], "supereagle"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_SUPEREAGLE;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp (argv[i], "2xsai"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_2XSAI;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp (argv[i], "super2xsai"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_SUPER2XSAI;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
#ifdef USE_HQ2X
|
2010-09-25 17:46:12 +02:00
|
|
|
else if (!strcasecmp (argv[i], "hq2x"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_HQ2X;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp (argv[i], "hq3x"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_HQ3X;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp (argv[i], "hq4x"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_HQ4X;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
#endif /* USE_HQ2X */
|
2010-09-25 17:46:12 +02:00
|
|
|
else if (!strcasecmp (argv[i], "epx"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_EPX;
|
|
|
|
}
|
|
|
|
else if (!strcasecmp (argv[i], "ntsc"))
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_NTSC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gui_config->scale_method = FILTER_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!strcasecmp (argv[i], "-mutesound"))
|
|
|
|
{
|
|
|
|
gui_config->mute_sound = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef TIMER_DIFF
|
|
|
|
#define TIMER_DIFF(a, b) ((((a).tv_sec - (b).tv_sec) * 1000000) + (a).tv_usec - (b).tv_usec)
|
|
|
|
/* Finishes syncing by using more accurate system sleep functions*/
|
|
|
|
void
|
|
|
|
S9xSyncSpeedFinish (void)
|
|
|
|
{
|
|
|
|
if (!syncing)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gettimeofday (&now, NULL);
|
|
|
|
|
|
|
|
if (Settings.SoundSync)
|
|
|
|
{
|
|
|
|
while (!S9xSyncSound ())
|
|
|
|
{
|
|
|
|
usleep (100);
|
|
|
|
|
|
|
|
gettimeofday (&next_frame_time, NULL);
|
|
|
|
|
|
|
|
/* If we can't sync sound within a second, we're probably deadlocked */
|
|
|
|
if (TIMER_DIFF (next_frame_time, now) > 1000000)
|
|
|
|
{
|
|
|
|
/* Flush out our sample buffer and give up. */
|
|
|
|
S9xClearSamples ();
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
next_frame_time = now;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TIMER_DIFF (next_frame_time, now) < -500000)
|
|
|
|
{
|
|
|
|
next_frame_time = now;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (timercmp (&next_frame_time, &now, >))
|
|
|
|
{
|
|
|
|
int time_left = TIMER_DIFF (next_frame_time, now);
|
|
|
|
|
|
|
|
if (time_left > 500000)
|
|
|
|
{
|
|
|
|
next_frame_time = now;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
usleep (time_left);
|
|
|
|
|
|
|
|
gettimeofday (&now, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
next_frame_time.tv_usec += Settings.FrameTime;
|
|
|
|
|
|
|
|
if (next_frame_time.tv_usec >= 1000000)
|
|
|
|
{
|
|
|
|
next_frame_time.tv_sec += next_frame_time.tv_usec / 1000000;
|
|
|
|
next_frame_time.tv_usec %= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
syncing = 0;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SyncSpeed Handles delays between frames, similar to unix.cpp version,
|
|
|
|
* cleaned up for clarity, adjusted for GUI event loop */
|
|
|
|
void
|
|
|
|
S9xSyncSpeed (void)
|
|
|
|
{
|
|
|
|
unsigned int limit;
|
|
|
|
int lag;
|
|
|
|
|
|
|
|
#ifdef NETPLAY_SUPPORT
|
|
|
|
if (S9xNetplaySyncSpeed ())
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (Settings.HighSpeedSeek > 0)
|
|
|
|
{
|
|
|
|
Settings.HighSpeedSeek--;
|
|
|
|
IPPU.RenderThisFrame = FALSE;
|
|
|
|
IPPU.SkippedFrames = 0;
|
|
|
|
|
|
|
|
gettimeofday (&now, NULL);
|
|
|
|
next_frame_time = now;
|
|
|
|
|
|
|
|
syncing = 0;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (Settings.TurboMode)
|
|
|
|
{
|
|
|
|
if ((++IPPU.FrameSkip >= Settings.TurboSkipFrames)
|
|
|
|
&& !Settings.HighSpeedSeek)
|
|
|
|
{
|
|
|
|
IPPU.FrameSkip = 0;
|
|
|
|
IPPU.SkippedFrames = 0;
|
|
|
|
IPPU.RenderThisFrame = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IPPU.SkippedFrames++;
|
|
|
|
IPPU.RenderThisFrame = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gettimeofday (&now, NULL);
|
|
|
|
|
|
|
|
if (next_frame_time.tv_sec == 0)
|
|
|
|
{
|
|
|
|
next_frame_time = now;
|
|
|
|
++next_frame_time.tv_usec;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Settings.SkipFrames == AUTO_FRAMERATE && !Settings.SoundSync)
|
|
|
|
{
|
|
|
|
lag = TIMER_DIFF (now, next_frame_time);
|
|
|
|
|
|
|
|
/* We compensate for the frame time by a frame in case it's just a CPU
|
|
|
|
* discrepancy. We can recover lost time in the next frame anyway. */
|
|
|
|
if (lag > (int) (Settings.FrameTime))
|
|
|
|
{
|
|
|
|
if (lag > (int) Settings.FrameTime * 10)
|
|
|
|
{
|
|
|
|
/* Running way too slowly */
|
|
|
|
next_frame_time = now;
|
|
|
|
IPPU.RenderThisFrame = 1;
|
|
|
|
IPPU.SkippedFrames = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IPPU.RenderThisFrame = 0;
|
|
|
|
IPPU.SkippedFrames++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IPPU.RenderThisFrame = 1;
|
|
|
|
IPPU.SkippedFrames = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
limit = Settings.SoundSync ? 1 : Settings.SkipFrames + 1;
|
|
|
|
|
|
|
|
IPPU.SkippedFrames++;
|
|
|
|
IPPU.RenderThisFrame = 0;
|
|
|
|
|
|
|
|
if (IPPU.SkippedFrames >= limit)
|
|
|
|
{
|
|
|
|
IPPU.RenderThisFrame = 1;
|
|
|
|
IPPU.SkippedFrames = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
syncing = 1;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
static void
|
|
|
|
S9xCheckPointerTimer (void)
|
|
|
|
{
|
|
|
|
if (!gui_config->pointer_is_visible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gettimeofday (&now, NULL);
|
|
|
|
|
|
|
|
if (TIMER_DIFF (now, gui_config->pointer_timestamp) > 1000000)
|
|
|
|
{
|
|
|
|
top_level->hide_mouse_cursor ();
|
|
|
|
gui_config->pointer_is_visible = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
/* Final exit point, issues exit (0) */
|
|
|
|
void
|
|
|
|
S9xExit (void)
|
|
|
|
{
|
|
|
|
gui_config->save_config_file ();
|
|
|
|
|
|
|
|
top_level->leave_fullscreen_mode ();
|
|
|
|
|
|
|
|
S9xPortSoundDeinit ();
|
|
|
|
|
|
|
|
Settings.StopEmulation = TRUE;
|
|
|
|
|
|
|
|
if (gui_config->rom_loaded)
|
|
|
|
{
|
|
|
|
S9xAutoSaveSRAM ();
|
|
|
|
}
|
|
|
|
|
|
|
|
S9xDeinitAPU ();
|
|
|
|
|
|
|
|
S9xDeinitInputDevices ();
|
|
|
|
S9xDeinitDisplay ();
|
|
|
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
|
|
|
delete top_level;
|
|
|
|
delete gui_config;
|
|
|
|
|
|
|
|
exit (0);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xPostRomInit (void)
|
|
|
|
{
|
|
|
|
//First plug in both, they'll change later as needed
|
|
|
|
S9xSetController (0, CTL_JOYPAD, 0, 0, 0, 0);
|
|
|
|
S9xSetController (1, CTL_JOYPAD, 1, 0, 0, 0);
|
|
|
|
top_level->set_menu_item_selected ("joypad1");
|
|
|
|
top_level->set_menu_item_selected ("joypad2");
|
|
|
|
|
|
|
|
if (!strncmp ((const char *) Memory.NSRTHeader + 24, "NSRT", 4))
|
|
|
|
{
|
|
|
|
switch (Memory.NSRTHeader[29])
|
|
|
|
{
|
|
|
|
case 0: //Everything goes
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x10: //Mouse in Port 0
|
|
|
|
S9xSetController (0, CTL_MOUSE, 0, 0, 0, 0);
|
|
|
|
top_level->set_menu_item_selected ("mouse1");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x01: //Mouse in Port 1
|
|
|
|
S9xSetController (1, CTL_MOUSE, 1, 0, 0, 0);
|
|
|
|
top_level->set_menu_item_selected ("mouse2");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x03: //Super Scope in Port 1
|
|
|
|
S9xSetController (1, CTL_SUPERSCOPE, 0, 0, 0, 0);
|
|
|
|
top_level->set_menu_item_selected ("superscope1");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x06: //Multitap in Port 1
|
|
|
|
S9xSetController (1, CTL_MP5, 1, 2, 3, 4);
|
|
|
|
top_level->set_menu_item_selected ("multitap1");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x66: //Multitap in Ports 0 and 1
|
|
|
|
S9xSetController (0, CTL_MP5, 0, 1, 2, 3);
|
|
|
|
S9xSetController (1, CTL_MP5, 4, 5, 6, 7);
|
|
|
|
top_level->set_menu_item_selected ("multitap1");
|
|
|
|
top_level->set_menu_item_selected ("multitap2");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x08: //Multitap in Port 1, Mouse in new Port 1
|
|
|
|
S9xSetController (1, CTL_MOUSE, 1, 0, 0, 0);
|
|
|
|
//There should be a toggle here for putting in Multitap instead
|
|
|
|
top_level->set_menu_item_selected ("mouse2");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x04: //Pad or Super Scope in Port 1
|
|
|
|
S9xSetController (1, CTL_SUPERSCOPE, 0, 0, 0, 0);
|
|
|
|
top_level->set_menu_item_selected ("superscope2");
|
|
|
|
//There should be a toggle here for putting in a pad instead
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x05: //Justifier - Must ask user...
|
|
|
|
S9xSetController (1, CTL_JUSTIFIER, 1, 0, 0, 0);
|
|
|
|
//There should be a toggle here for how many justifiers
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x20: //Pad or Mouse in Port 0
|
|
|
|
S9xSetController (0, CTL_MOUSE, 0, 0, 0, 0);
|
|
|
|
//There should be a toggle here for putting in a pad instead
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x22: //Pad or Mouse in Port 0 & 1
|
|
|
|
S9xSetController (0, CTL_MOUSE, 0, 0, 0, 0);
|
|
|
|
S9xSetController (1, CTL_MOUSE, 1, 0, 0, 0);
|
|
|
|
//There should be a toggles here for putting in pads instead
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x24: //Pad or Mouse in Port 0, Pad or Super Scope in Port 1
|
|
|
|
//There should be a toggles here for what to put in, I'm leaving it at gamepad for now
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x27: //Pad or Mouse in Port 0, Pad or Mouse or Super Scope in Port 1
|
|
|
|
//There should be a toggles here for what to put in, I'm leaving it at gamepad for now
|
|
|
|
break;
|
|
|
|
|
|
|
|
//Not Supported yet
|
|
|
|
case 0x99: break; //Lasabirdie
|
|
|
|
case 0x0A: break; //Barcode Battler
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
S9xStringInput(const char *message)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xExtraUsage (void)
|
|
|
|
{
|
|
|
|
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 epx ntsc\n"
|
|
|
|
"\n"
|
|
|
|
"-mutesound Disables sound output.\n");
|
|
|
|
return;
|
|
|
|
}
|