mirror of
https://github.com/ShadauxCat/CATSFC.git
synced 2025-04-02 10:41:47 -04:00
1411 lines
31 KiB
C++
1411 lines
31 KiB
C++
//entry.c
|
|
#include <stdio.h>
|
|
|
|
#include "ds2_types.h"
|
|
#include "ds2_cpu.h"
|
|
#include "ds2_timer.h"
|
|
#include "ds2io.h"
|
|
#include "fs_api.h"
|
|
|
|
#include "snes9x.h"
|
|
#include "soundux.h"
|
|
#include "memmap.h"
|
|
#include "apu.h"
|
|
#include "cheats.h"
|
|
#include "snapshot.h"
|
|
#include "display.h"
|
|
#include "gfx.h"
|
|
#include "cpuexec.h"
|
|
#include "spc7110.h"
|
|
|
|
#include "draw.h"
|
|
#include "gui.h"
|
|
#include "entry.h"
|
|
#include "ds2sound.h"
|
|
|
|
void S9xProcessSound (unsigned int);
|
|
|
|
char *rom_filename = NULL;
|
|
char *SDD1_pack = NULL;
|
|
|
|
static u8 Buf[MAX_BUFFER_SIZE];
|
|
|
|
#define FIXED_POINT 0x10000
|
|
#define FIXED_POINT_SHIFT 16
|
|
#define FIXED_POINT_REMAINDER 0xffff
|
|
|
|
void S9xMessage (int /*type*/, int /*number*/, const char *message)
|
|
{
|
|
#if 1
|
|
#define MAX_MESSAGE_LEN (36 * 3)
|
|
|
|
static char buffer [MAX_MESSAGE_LEN + 1];
|
|
|
|
printf ("%s\n", message);
|
|
strncpy (buffer, message, MAX_MESSAGE_LEN);
|
|
buffer [MAX_MESSAGE_LEN] = 0;
|
|
S9xSetInfoString (buffer);
|
|
#endif
|
|
}
|
|
|
|
void S9xExtraUsage ()
|
|
{
|
|
/*empty*/
|
|
}
|
|
|
|
/*
|
|
* Release display device
|
|
*/
|
|
void S9xDeinitDisplay (void)
|
|
{
|
|
if(GFX.Screen) free(GFX.Screen);
|
|
if(GFX.SubScreen) free(GFX.SubScreen);
|
|
if(GFX.ZBuffer) free(GFX.ZBuffer);
|
|
if(GFX.SubZBuffer) free(GFX.SubZBuffer);
|
|
}
|
|
|
|
void S9xInitDisplay (int, char **)
|
|
{
|
|
int h = IMAGE_HEIGHT;
|
|
|
|
GFX.Pitch = IMAGE_WIDTH * 2;
|
|
GFX.Screen = (unsigned char*) malloc (GFX.Pitch * h);
|
|
GFX.SubScreen = (unsigned char*) malloc (GFX.Pitch * h);
|
|
GFX.ZBuffer = (unsigned char*) malloc ((GFX.Pitch >> 1) * h);
|
|
GFX.SubZBuffer =(unsigned char*) malloc ((GFX.Pitch >> 1) * h);
|
|
GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
|
|
}
|
|
|
|
void S9xParseArg (char **argv, int &i, int argc)
|
|
{
|
|
}
|
|
|
|
void S9xParseDisplayArg (char **argv, int &ind, int)
|
|
{
|
|
}
|
|
|
|
void S9xExit ()
|
|
{
|
|
ds2_setCPUclocklevel(13); // Crank it up to exit quickly
|
|
if(Settings.SPC7110)
|
|
(*CleanUp7110)();
|
|
|
|
S9xSetSoundMute (TRUE);
|
|
S9xDeinitDisplay ();
|
|
Memory.SaveSRAM (S9xGetFilename (".srm"));
|
|
// S9xSaveCheatFile (S9xGetFilename (".chb")); // cheat binary file
|
|
// Do this when loading a cheat file!
|
|
Memory.Deinit ();
|
|
S9xDeinitAPU ();
|
|
|
|
#ifdef _NETPLAY_SUPPORT
|
|
if (Settings.NetPlay)
|
|
S9xNetPlayDisconnect ();
|
|
#endif
|
|
|
|
exit(0);
|
|
}
|
|
|
|
const char *S9xBasename (const char *f)
|
|
{
|
|
const char *p;
|
|
if ((p = strrchr (f, '/')) != NULL || (p = strrchr (f, '\\')) != NULL)
|
|
return (p + 1);
|
|
|
|
return (f);
|
|
}
|
|
|
|
bool8 S9xInitUpdate ()
|
|
{
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
extern void NDSSFCDrawFrameAntialiased();
|
|
|
|
|
|
bool8 S9xDeinitUpdate (int Width, int Height, bool8 /*sixteen_bit*/)
|
|
{
|
|
switch(game_config.graphic)
|
|
{
|
|
//Up
|
|
case 1:
|
|
memcpy(up_screen_addr, GFX.Screen+256*32*2, 256*192*2);
|
|
break;
|
|
|
|
//Down
|
|
case 2:
|
|
memcpy(up_screen_addr, GFX.Screen, 256*192*2);
|
|
break;
|
|
|
|
//Both
|
|
case 3:
|
|
memcpy(up_screen_addr, GFX.Screen+256*16*2, 256*192*2);
|
|
break;
|
|
|
|
case 4:
|
|
NDSSFCDrawFrameAntialiased ();
|
|
break;
|
|
|
|
|
|
default:
|
|
{
|
|
unsigned char *src, *dst;
|
|
unsigned int m;
|
|
|
|
src = GFX.Screen;
|
|
dst = (unsigned char*)up_screen_addr;
|
|
for(m = 0; m < 32; m++)
|
|
{
|
|
memcpy(dst, src, 256*6*2);
|
|
dst += 256*6*2;
|
|
src += 256*7*2;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
ds2_flipScreen(UP_SCREEN, UP_SCREEN_UPDATE_METHOD);
|
|
// A problem with update method 1 (wait, double buffer) means that, after
|
|
// about 15 minutes of play time, the screen starts to half-redraw every
|
|
// frame. With update method 0, this is mitigated. (Method 2 is too slow.)
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
void _makepath (char *path, const char *, const char *dir,
|
|
const char *fname, const char *ext)
|
|
{
|
|
if (dir && *dir)
|
|
{
|
|
strcpy (path, dir);
|
|
strcat (path, "/");
|
|
}
|
|
else
|
|
*path = 0;
|
|
strcat (path, fname);
|
|
if (ext && *ext)
|
|
{
|
|
strcat (path, ".");
|
|
strcat (path, ext);
|
|
}
|
|
}
|
|
|
|
void _splitpath (const char *path, char *drive, char *dir, char *fname,
|
|
char *ext)
|
|
{
|
|
*drive = 0;
|
|
|
|
char *slash = strrchr (path, '/');
|
|
if (!slash)
|
|
slash = strrchr (path, '\\');
|
|
|
|
char *dot = strrchr (path, '.');
|
|
|
|
if (dot && slash && dot < slash)
|
|
dot = NULL;
|
|
|
|
if (!slash)
|
|
{
|
|
strcpy (dir, "");
|
|
strcpy (fname, path);
|
|
if (dot)
|
|
{
|
|
*(fname + (dot - path)) = 0;
|
|
strcpy (ext, dot + 1);
|
|
}
|
|
else
|
|
strcpy (ext, "");
|
|
}
|
|
else
|
|
{
|
|
strcpy (dir, path);
|
|
*(dir + (slash - path)) = 0;
|
|
strcpy (fname, slash + 1);
|
|
if (dot)
|
|
{
|
|
*(fname + (dot - slash) - 1) = 0;
|
|
strcpy (ext, dot + 1);
|
|
}
|
|
else
|
|
strcpy (ext, "");
|
|
}
|
|
}
|
|
|
|
void S9xProcessEvents (bool8 block)
|
|
{
|
|
|
|
}
|
|
|
|
void OutOfMemory ()
|
|
{
|
|
}
|
|
|
|
|
|
const char *S9xGetROMDirectory ()
|
|
{
|
|
return ((const char*)g_default_rom_dir);
|
|
}
|
|
|
|
|
|
const char *S9xGetSnapshotDirectory ()
|
|
{
|
|
return ((const char*)DEFAULT_RTS_DIR);
|
|
}
|
|
|
|
const char *S9xGetFilename (const char *ex)
|
|
{
|
|
static char filename [PATH_MAX + 1];
|
|
char drive [_MAX_DRIVE + 1];
|
|
char dir [_MAX_DIR + 1];
|
|
char fname [_MAX_FNAME + 1];
|
|
char ext [_MAX_EXT + 1];
|
|
|
|
_splitpath (Memory.ROMFilename, drive, dir, fname, ext);
|
|
strcpy (filename, S9xGetSnapshotDirectory ());
|
|
strcat (filename, SLASH_STR);
|
|
strcat (filename, fname);
|
|
strcat (filename, ex);
|
|
|
|
return (filename);
|
|
}
|
|
|
|
const char *S9xGetFilenameInc (const char *e)
|
|
{
|
|
return e;
|
|
#if 0
|
|
static char filename [_MAX_PATH + 1];
|
|
char drive [_MAX_DRIVE + 1];
|
|
char dir [_MAX_DIR + 1];
|
|
char fname [_MAX_FNAME + 1];
|
|
char ext [_MAX_EXT + 1];
|
|
char *ptr;
|
|
struct stat buf;
|
|
|
|
if (strlen (S9xGetSnapshotDirectory()))
|
|
{
|
|
_splitpath (Memory.ROMFilename, drive, dir, fname, ext);
|
|
strcpy (filename, S9xGetSnapshotDirectory());
|
|
strcat (filename, "/");
|
|
strcat (filename, fname);
|
|
ptr = filename + strlen (filename);
|
|
strcat (filename, "00/");
|
|
strcat (filename, e);
|
|
}
|
|
else
|
|
{
|
|
_splitpath (Memory.ROMFilename, drive, dir, fname, ext);
|
|
strcat (fname, "00/");
|
|
_makepath (filename, drive, dir, fname, e);
|
|
ptr = strstr (filename, "00/");
|
|
}
|
|
|
|
do
|
|
{
|
|
if (++*(ptr + 2) > '9')
|
|
{
|
|
*(ptr + 2) = '0';
|
|
if (++*(ptr + 1) > '9')
|
|
{
|
|
*(ptr + 1) = '0';
|
|
if (++*ptr > '9')
|
|
break;
|
|
}
|
|
}
|
|
} while( stat(filename, &buf) == 0 );
|
|
|
|
return (filename);
|
|
#endif
|
|
}
|
|
|
|
void S9xInitInputDevices ()
|
|
{
|
|
#ifdef JOYSTICK_SUPPORT
|
|
InitJoysticks ();
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void game_disableAudio()
|
|
{
|
|
if( game_enable_audio == 1)
|
|
{
|
|
S9xSetSoundMute (FALSE);
|
|
}
|
|
else
|
|
{
|
|
S9xSetSoundMute (TRUE);
|
|
}
|
|
}
|
|
|
|
void game_set_frameskip()
|
|
{
|
|
if( game_config.frameskip_value == 0)
|
|
{
|
|
Settings.SkipFrames = AUTO_FRAMERATE;
|
|
}
|
|
else
|
|
{
|
|
Settings.SkipFrames = game_config.frameskip_value - 1 /* 1 -> 0 and so on */;
|
|
}
|
|
}
|
|
|
|
void game_set_fluidity()
|
|
{
|
|
if( game_config.SoundSync == 1)
|
|
{
|
|
Settings.SoundSync = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Settings.SoundSync = FALSE;
|
|
}
|
|
}
|
|
|
|
void init_sfc_setting(void)
|
|
{
|
|
ZeroMemory (&Settings, sizeof (Settings));
|
|
#ifdef JOYSTICK_SUPPORT
|
|
Settings.JoystickEnabled = TRUE;
|
|
#else
|
|
Settings.JoystickEnabled = FALSE;
|
|
#endif
|
|
|
|
Settings.SoundPlaybackRate = SNES9X_SRATE_ID; // -> ds2sound.h for defs
|
|
#ifndef FOREVER_STEREO
|
|
Settings.Stereo = TRUE;
|
|
#endif
|
|
Settings.SoundBufferSize = DS2_BUFFER_SIZE;
|
|
Settings.CyclesPercentage = 100;
|
|
Settings.DisableSoundEcho = FALSE;
|
|
//sound settings
|
|
Settings.APUEnabled = Settings.NextAPUEnabled = TRUE;
|
|
Settings.FixFrequency = 1;
|
|
|
|
|
|
Settings.H_Max = SNES_CYCLES_PER_SCANLINE;
|
|
Settings.SkipFrames = AUTO_FRAMERATE;
|
|
Settings.ShutdownMaster = TRUE;
|
|
Settings.FrameTimePAL = 20000;
|
|
Settings.FrameTimeNTSC = 16667;
|
|
Settings.DisableSampleCaching = FALSE;
|
|
Settings.DisableMasterVolume = FALSE;
|
|
Settings.Mouse = TRUE;
|
|
Settings.SuperScope = TRUE;
|
|
Settings.MultiPlayer5 = TRUE;
|
|
Settings.ControllerOption = SNES_JOYPAD;
|
|
|
|
Settings.Transparency = TRUE;
|
|
#ifndef FOREVER_16_BIT
|
|
Settings.SixteenBit = TRUE;
|
|
#endif
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
Settings.SixteenBitSound = TRUE;
|
|
#endif
|
|
|
|
Settings.SupportHiRes = FALSE;
|
|
Settings.ThreadSound = FALSE;
|
|
Settings.SoundSync = TRUE;
|
|
Settings.AutoSaveDelay = 0;
|
|
#ifdef _NETPLAY_SUPPORT
|
|
Settings.NetPlay = FALSE;
|
|
Settings.ServerName [0] = 0;
|
|
Settings.Port = NP_DEFAULT_PORT;
|
|
#endif
|
|
Settings.ApplyCheats = TRUE;
|
|
Settings.TurboMode = FALSE;
|
|
Settings.TurboSkipFrames = 10;
|
|
Settings.StretchScreenshots = 1;
|
|
|
|
Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX;
|
|
}
|
|
|
|
void S9xAutoSaveSRAM ()
|
|
{
|
|
Memory.SaveSRAM (S9xGetFilename (".srm"));
|
|
}
|
|
|
|
int game_load_state(char* file)
|
|
{
|
|
int flag;
|
|
|
|
flag = 0;
|
|
if(S9xUnfreezeGame(file) == FALSE)
|
|
flag = -1;
|
|
|
|
return flag;
|
|
}
|
|
|
|
int game_save_state(char* file)
|
|
{
|
|
int flag;
|
|
|
|
flag = 0;
|
|
if(S9xFreezeGame(file) == FALSE)
|
|
flag = -1;
|
|
|
|
S9xAutoSaveSRAM ();
|
|
|
|
return flag;
|
|
}
|
|
|
|
void game_restart(void)
|
|
{
|
|
CPU.Flags = 0;
|
|
S9xReset ();
|
|
}
|
|
|
|
int load_gamepak(char* file)
|
|
{
|
|
CPU.Flags = 0;
|
|
// mdelay(50); // Delete this delay
|
|
if (!Memory.LoadROM (file))
|
|
return -1;
|
|
S9xReset ();
|
|
|
|
Settings.FrameTime = (Settings.PAL ? Settings.FrameTimePAL : Settings.FrameTimeNTSC);
|
|
|
|
Memory.LoadSRAM (S9xGetFilename (".srm"));
|
|
// mdelay(50); // Delete this delay
|
|
S9xLoadCheatFile (S9xGetFilename (".chb")); // cheat binary file, as opposed to text
|
|
|
|
#ifdef _NETPLAY_SUPPORT
|
|
if (strlen (Settings.ServerName) == 0)
|
|
{
|
|
char *server = getenv ("S9XSERVER");
|
|
if (server)
|
|
{
|
|
strncpy (Settings.ServerName, server, 127);
|
|
Settings.ServerName [127] = 0;
|
|
}
|
|
}
|
|
char *port = getenv ("S9XPORT");
|
|
if (Settings.Port >= 0 && port)
|
|
Settings.Port = atoi (port);
|
|
else if (Settings.Port < 0)
|
|
Settings.Port = -Settings.Port;
|
|
|
|
if (Settings.NetPlay)
|
|
{
|
|
int player;
|
|
|
|
if (!S9xNetPlayConnectToServer (Settings.ServerName, Settings.Port,
|
|
Memory.ROMName, player))
|
|
{
|
|
fprintf (stderr, "Failed to connected to Snes9x netplay"
|
|
" server \"%s\" on port %d.\n",
|
|
Settings.ServerName, Settings.Port);
|
|
S9xExit ();
|
|
}
|
|
fprintf (stderr, "Connected to \"%s\" on port %d as"
|
|
" player #%d playing \"%s\"\n",
|
|
Settings.ServerName, Settings.Port, player, Memory.ROMName);
|
|
}
|
|
|
|
#endif
|
|
/*
|
|
if (snapshot_filename)
|
|
{
|
|
int Flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG);
|
|
if (!S9xLoadSnapshot (snapshot_filename))
|
|
exit (1);
|
|
CPU.Flags |= Flags;
|
|
}
|
|
*/
|
|
|
|
// mdelay(50); // Delete this delay
|
|
|
|
return 0;
|
|
}
|
|
|
|
extern "C" int sfc_main (int argc, char **argv);
|
|
|
|
int sfc_main (int argc, char **argv)
|
|
{
|
|
//Initialize GUI
|
|
gui_init(0);
|
|
|
|
init_sfc_setting();
|
|
|
|
if (!Memory.Init () || !S9xInitAPU())
|
|
OutOfMemory ();
|
|
|
|
S9xInitDisplay (argc, argv);
|
|
if (!S9xGraphicsInit())
|
|
OutOfMemory ();
|
|
|
|
S9xInitSound (Settings.SoundPlaybackRate,
|
|
#ifndef FOREVER_STEREO
|
|
Settings.Stereo,
|
|
#else
|
|
TRUE,
|
|
#endif
|
|
Settings.SoundBufferSize);
|
|
#ifdef GFX_MULTI_FORMAT
|
|
// S9xSetRenderPixelFormat (RGB565);
|
|
S9xSetRenderPixelFormat (BGR555);
|
|
#endif
|
|
|
|
#ifdef JOYSTICK_SUPPORT
|
|
uint32 JoypadSkip = 0;
|
|
#endif
|
|
|
|
Settings.Paused = 1;
|
|
bool8 FirstInvocation = TRUE;
|
|
|
|
while (1)
|
|
{
|
|
if (!Settings.Paused
|
|
#ifdef DEBUGGER
|
|
|| (CPU.Flags & (DEBUG_MODE_FLAG | SINGLE_STEP_FLAG)
|
|
#endif
|
|
)
|
|
S9xMainLoop ();
|
|
|
|
|
|
#ifdef DEBUGGER
|
|
if (CPU.Flags & DEBUG_MODE_FLAG)
|
|
{
|
|
S9xDoDebug ();
|
|
}
|
|
else
|
|
#endif
|
|
if (Settings.Paused)
|
|
{
|
|
S9xSetSoundMute (TRUE);
|
|
unsigned short screen[256*192];
|
|
|
|
copy_screen((void*)screen, up_screen_addr, 0, 0, 256, 192);
|
|
menu(screen, FirstInvocation);
|
|
FirstInvocation = FALSE;
|
|
game_disableAudio();
|
|
Settings.Paused = 0;
|
|
}
|
|
|
|
#ifdef JOYSTICK_SUPPORT
|
|
//if (Settings.JoystickEnabled && (JoypadSkip++ & 1) == 0)
|
|
if (Settings.JoystickEnabled)
|
|
ReadJoysticks ();
|
|
#endif
|
|
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static unsigned int sync_last= 0;
|
|
static unsigned int sync_next = 0;
|
|
static unsigned int auto_equivalent_skip = 0;
|
|
|
|
static unsigned int skip_rate= 0;
|
|
|
|
void S9xSyncSpeed ()
|
|
{
|
|
uint32 syncnow;
|
|
int32 syncdif;
|
|
|
|
#if 0
|
|
if (Settings.SoundSync == 2)
|
|
{
|
|
IPPU.RenderThisFrame = TRUE;
|
|
IPPU.SkippedFrames = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
syncnow = getSysTime();
|
|
|
|
if (game_fast_forward || temporary_fast_forward /* hotkey is held */)
|
|
{
|
|
sync_last = syncnow;
|
|
sync_next = syncnow;
|
|
|
|
if(++skip_rate < Settings.TurboSkipFrames)
|
|
IPPU.RenderThisFrame = false;
|
|
else
|
|
{
|
|
skip_rate = 0;
|
|
IPPU.RenderThisFrame = true;
|
|
}
|
|
}
|
|
else if (Settings.SkipFrames == AUTO_FRAMERATE /* && !game_fast_forward && !temporary_fast_forward */)
|
|
{
|
|
// frame_time is in getSysTime units: 42.667 microseconds.
|
|
int32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
|
|
if (sync_last > syncnow) // Overflow occurred! (every 50 hrs)
|
|
{
|
|
// Render this frame regardless, set the
|
|
// sync_next, and get the hell out.
|
|
IPPU.RenderThisFrame = TRUE;
|
|
sync_last = syncnow;
|
|
sync_next = syncnow + frame_time;
|
|
return;
|
|
}
|
|
sync_last = syncnow;
|
|
// If this is positive, we have syncdif*42.66 microseconds to
|
|
// spare.
|
|
// If this is negative, we're late by syncdif*42.66
|
|
// microseconds.
|
|
syncdif = sync_next - syncnow;
|
|
if (syncdif < 0 && syncdif >= -(frame_time / 2))
|
|
{
|
|
// We're late, but by less than half a frame. Draw it
|
|
// anyway. If the next frame is too late, it'll be
|
|
// skipped.
|
|
skip_rate = 0;
|
|
IPPU.RenderThisFrame = true;
|
|
sync_next += frame_time;
|
|
}
|
|
else if(syncdif < 0)
|
|
{
|
|
/*
|
|
* If we're consistently late, delay up to 8 frames.
|
|
*
|
|
* That really helps with certain games, such as
|
|
* Super Mario RPG and Yoshi's Island.
|
|
*/
|
|
if(++skip_rate < 10)
|
|
{
|
|
if(syncdif >= -11719 /* not more than 500.0 ms late */)
|
|
{
|
|
IPPU.RenderThisFrame = FALSE;
|
|
sync_next += frame_time;
|
|
}
|
|
else
|
|
{ //lag more than 0.5s, maybe paused
|
|
IPPU.RenderThisFrame = TRUE;
|
|
sync_next = syncnow + frame_time;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
skip_rate = 0;
|
|
IPPU.RenderThisFrame = TRUE;
|
|
sync_next = syncnow + frame_time;
|
|
}
|
|
}
|
|
else // Early
|
|
{
|
|
skip_rate = 0;
|
|
if (syncdif > 0)
|
|
{
|
|
do {
|
|
S9xProcessSound (0);
|
|
syncdif = sync_next - getSysTime();
|
|
} while (syncdif > 0);
|
|
}
|
|
|
|
IPPU.RenderThisFrame = TRUE;
|
|
sync_next += frame_time;
|
|
}
|
|
#if 0
|
|
if(++framenum >= 60)
|
|
{
|
|
syncdif = syncnow - sync_last;
|
|
sync_last = syncnow;
|
|
framenum = 0;
|
|
//printf("T %d %d\n", syncdif*42667/1000, realframe);
|
|
realframe = 0;
|
|
}
|
|
#endif
|
|
}
|
|
else /* if (Settings.SkipFrames != AUTO_FRAMERATE && !game_fast_forward && !temporary_fast_forward) */
|
|
{
|
|
// frame_time is in getSysTime units: 42.667 microseconds.
|
|
uint32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */;
|
|
sync_last = syncnow;
|
|
if (++skip_rate > Settings.SkipFrames)
|
|
{
|
|
skip_rate = 0;
|
|
IPPU.RenderThisFrame = TRUE;
|
|
// Are we early?
|
|
syncdif = sync_next - syncnow;
|
|
if (syncdif > 0)
|
|
{
|
|
do {
|
|
S9xProcessSound (0);
|
|
syncdif = sync_next - getSysTime();
|
|
} while (syncdif > 0);
|
|
// After that little delay, what time is it?
|
|
syncnow = getSysTime();
|
|
}
|
|
sync_next = syncnow + frame_time * (Settings.SkipFrames + 1);
|
|
}
|
|
else
|
|
{
|
|
IPPU.RenderThisFrame = FALSE;
|
|
}
|
|
}
|
|
|
|
#ifdef __sgi
|
|
/* BS: saves on CPU usage */
|
|
sginap(1);
|
|
#endif
|
|
|
|
#if 0
|
|
/* Check events */
|
|
|
|
static struct timeval next1 = {0, 0};
|
|
struct timeval now;
|
|
|
|
CHECK_SOUND();
|
|
// S9xProcessEvents(FALSE);
|
|
|
|
while (gettimeofday (&now, NULL) < 0) ;
|
|
|
|
/* If there is no known "next" frame, initialize it now */
|
|
if (next1.tv_sec == 0) { next1 = now; ++next1.tv_usec; }
|
|
|
|
/* If we're on AUTO_FRAMERATE, we'll display frames always
|
|
* only if there's excess time.
|
|
* Otherwise we'll display the defined amount of frames.
|
|
*/
|
|
unsigned limit = Settings.SkipFrames == AUTO_FRAMERATE
|
|
? (timercmp(&next1, &now, <) ? 10 : 1)
|
|
: Settings.SkipFrames;
|
|
|
|
IPPU.RenderThisFrame = ++IPPU.SkippedFrames >= limit;
|
|
if(IPPU.RenderThisFrame)
|
|
{
|
|
IPPU.SkippedFrames = 0;
|
|
}
|
|
else
|
|
{
|
|
/* If we were behind the schedule, check how much it is */
|
|
if(timercmp(&next1, &now, <))
|
|
{
|
|
unsigned lag =
|
|
(now.tv_sec - next1.tv_sec) * 1000000
|
|
+ now.tv_usec - next1.tv_usec;
|
|
if(lag >= 1000000)
|
|
{
|
|
/* More than a second behind means probably
|
|
* pause. The next line prevents the magic
|
|
* fast-forward effect.
|
|
*/
|
|
next1 = now;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Delay until we're completed this frame */
|
|
|
|
/* Can't use setitimer because the sound code already could
|
|
* be using it. We don't actually need it either.
|
|
*/
|
|
|
|
while(timercmp(&next1, &now, >))
|
|
{
|
|
/* If we're ahead of time, sleep a while */
|
|
unsigned timeleft =
|
|
(next1.tv_sec - now.tv_sec) * 1000000
|
|
+ next1.tv_usec - now.tv_usec;
|
|
//fprintf(stderr, "<%u>", timeleft);
|
|
usleep(timeleft);
|
|
|
|
CHECK_SOUND();
|
|
// S9xProcessEvents(FALSE);
|
|
|
|
while (gettimeofday (&now, NULL) < 0) ;
|
|
/* Continue with a while-loop because usleep()
|
|
* could be interrupted by a signal
|
|
*/
|
|
}
|
|
|
|
/* Calculate the timestamp of the next frame. */
|
|
next1.tv_usec += Settings.FrameTime;
|
|
if (next1.tv_usec >= 1000000)
|
|
{
|
|
next1.tv_sec += next1.tv_usec / 1000000;
|
|
next1.tv_usec %= 1000000;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool8 S9xOpenSoundDevice (int mode, bool8 stereo, int buffer_size)
|
|
{
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
so.sixteen_bit = TRUE;
|
|
#endif
|
|
#ifndef FOREVER_STEREO
|
|
so.stereo = stereo;
|
|
#endif
|
|
so.playback_rate = SND_SAMPLE_RATE;
|
|
S9xSetPlaybackRate (so.playback_rate);
|
|
|
|
if (buffer_size == 0)
|
|
buffer_size = DS2_BUFFER_SIZE;
|
|
|
|
if (buffer_size > MAX_BUFFER_SIZE / 4)
|
|
buffer_size = MAX_BUFFER_SIZE / 4;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
if (so.sixteen_bit)
|
|
#endif
|
|
buffer_size *= 2;
|
|
#ifndef FOREVER_STEREO
|
|
if (so.stereo)
|
|
#endif
|
|
buffer_size *= 2;
|
|
|
|
so.buffer_size = buffer_size;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
void S9xGenerateSound ()
|
|
{
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
int bytes_so_far = so.sixteen_bit ? (so.samples_mixed_so_far << 1) :
|
|
so.samples_mixed_so_far;
|
|
#else
|
|
int bytes_so_far = so.samples_mixed_so_far << 1;
|
|
#endif
|
|
|
|
if (bytes_so_far >= so.buffer_size)
|
|
return;
|
|
|
|
so.err_counter += so.err_rate;
|
|
if (so.err_counter >= FIXED_POINT)
|
|
{
|
|
// Write this many samples overall
|
|
int samples_to_write = so.err_counter >> FIXED_POINT_SHIFT;
|
|
#ifndef FOREVER_STEREO
|
|
if (so.stereo)
|
|
#endif
|
|
samples_to_write <<= 1;
|
|
int byte_offset = (bytes_so_far + so.play_position) & SOUND_BUFFER_SIZE_MASK;
|
|
|
|
so.err_counter &= FIXED_POINT_REMAINDER;
|
|
|
|
do
|
|
{
|
|
int bytes_this_run = samples_to_write;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
if (so.sixteen_bit)
|
|
#endif
|
|
bytes_this_run <<= 1;
|
|
|
|
if (byte_offset + bytes_this_run > SOUND_BUFFER_SIZE)
|
|
{
|
|
bytes_this_run = SOUND_BUFFER_SIZE - byte_offset;
|
|
}
|
|
|
|
if (bytes_so_far + bytes_this_run > so.buffer_size)
|
|
{
|
|
bytes_this_run = so.buffer_size - bytes_so_far;
|
|
if (bytes_this_run == 0)
|
|
break;
|
|
}
|
|
|
|
int samples_this_run = bytes_this_run;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
if (so.sixteen_bit)
|
|
#endif
|
|
samples_this_run >>= 1;
|
|
|
|
S9xMixSamples (Buf + byte_offset, samples_this_run);
|
|
so.samples_mixed_so_far += samples_this_run;
|
|
samples_to_write -= samples_this_run;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
bytes_so_far += so.sixteen_bit ? (samples_this_run << 1) :
|
|
samples_this_run;
|
|
#else
|
|
bytes_so_far += samples_this_run << 1;
|
|
#endif
|
|
byte_offset = (byte_offset + bytes_this_run) & SOUND_BUFFER_SIZE_MASK;
|
|
} while (samples_to_write > 0);
|
|
}
|
|
}
|
|
|
|
#define SOUND_EMISSION_INTERVAL ((unsigned int) ((((unsigned long long) DS2_BUFFER_SIZE * 1000000) / SND_SAMPLE_RATE) * 3 / 128))
|
|
unsigned int LastSoundEmissionTime = 0;
|
|
|
|
void S9xProcessSound (unsigned int)
|
|
{
|
|
if (so.mute_sound || !game_enable_audio)
|
|
return;
|
|
|
|
if(ds2_checkAudiobuff() > AUDIO_BUFFER_COUNT * 3/4)
|
|
{
|
|
LastSoundEmissionTime++;
|
|
return;
|
|
}
|
|
|
|
unsigned short *audiobuff;
|
|
|
|
unsigned int Now = getSysTime();
|
|
if (Now - LastSoundEmissionTime >= SOUND_EMISSION_INTERVAL)
|
|
{
|
|
if (Now - LastSoundEmissionTime >= 11719 /* 500 milliseconds */)
|
|
{
|
|
LastSoundEmissionTime = Now;
|
|
// We were probably paused. Restart sending sound with an
|
|
// empty buffer.
|
|
do {
|
|
audiobuff = (unsigned short*)ds2_getAudiobuff();
|
|
} while (audiobuff == NULL); //There are audio queue in sending or wait to send
|
|
|
|
memset(audiobuff, 0, DS2_BUFFER_SIZE
|
|
#ifndef FOREVER_STEREO
|
|
<< (so.stereo ? 1 : 0)
|
|
#else
|
|
<< 1
|
|
#endif
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
<< (so.sixteen_bit ? 1 : 0)
|
|
#else
|
|
<< 1
|
|
#endif
|
|
);
|
|
|
|
ds2_updateAudio();
|
|
// And then the real audio. (fall through)
|
|
}
|
|
else
|
|
{
|
|
LastSoundEmissionTime += SOUND_EMISSION_INTERVAL;
|
|
}
|
|
/* Number of samples to generate now */
|
|
int sample_count = so.buffer_size;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
if (so.sixteen_bit)
|
|
{
|
|
#endif
|
|
/* to prevent running out of buffer space,
|
|
* create less samples
|
|
*/
|
|
sample_count >>= 1;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
}
|
|
#endif
|
|
|
|
do {
|
|
audiobuff = (unsigned short*)ds2_getAudiobuff();
|
|
} while (audiobuff == NULL); //There are audio queue in sending or wait to send
|
|
|
|
/* If we need more audio samples */
|
|
if (so.samples_mixed_so_far < sample_count)
|
|
{
|
|
/* Where to put the samples to */
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
unsigned byte_offset = (so.play_position +
|
|
(so.sixteen_bit ? (so.samples_mixed_so_far << 1) : so.samples_mixed_so_far)) & SOUND_BUFFER_SIZE_MASK;
|
|
#else
|
|
unsigned byte_offset = (so.play_position +
|
|
(so.samples_mixed_so_far << 1)) & SOUND_BUFFER_SIZE_MASK;
|
|
#endif
|
|
|
|
if (Settings.SoundSync == 2)
|
|
{
|
|
/*memset (Buf + (byte_offset & SOUND_BUFFER_SIZE_MASK), 0,
|
|
sample_count - so.samples_mixed_so_far);*/
|
|
}
|
|
else
|
|
{
|
|
/* Mix the missing samples */
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
int bytes_so_far = so.sixteen_bit ? (so.samples_mixed_so_far << 1) :
|
|
so.samples_mixed_so_far;
|
|
#else
|
|
int bytes_so_far = so.samples_mixed_so_far << 1;
|
|
#endif
|
|
|
|
uint32 samples_to_write = sample_count - so.samples_mixed_so_far;
|
|
do
|
|
{
|
|
int bytes_this_run = samples_to_write;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
if (so.sixteen_bit)
|
|
#endif
|
|
bytes_this_run <<= 1;
|
|
|
|
if (byte_offset + bytes_this_run > SOUND_BUFFER_SIZE)
|
|
{
|
|
bytes_this_run = SOUND_BUFFER_SIZE - byte_offset;
|
|
}
|
|
|
|
if (bytes_so_far + bytes_this_run > so.buffer_size)
|
|
{
|
|
bytes_this_run = so.buffer_size - bytes_so_far;
|
|
if (bytes_this_run == 0)
|
|
break;
|
|
}
|
|
|
|
int samples_this_run = bytes_this_run;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
if (so.sixteen_bit)
|
|
#endif
|
|
samples_this_run >>= 1;
|
|
|
|
S9xMixSamples (Buf + byte_offset, samples_this_run);
|
|
so.samples_mixed_so_far += samples_this_run;
|
|
samples_to_write -= samples_this_run;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
bytes_so_far += so.sixteen_bit ? (samples_this_run << 1) :
|
|
samples_this_run;
|
|
#else
|
|
bytes_so_far += samples_this_run << 1;
|
|
#endif
|
|
byte_offset = (byte_offset + bytes_this_run) & SOUND_BUFFER_SIZE_MASK;
|
|
} while (samples_to_write > 0);
|
|
}
|
|
}
|
|
|
|
// if (!so.mute_sound)
|
|
{
|
|
unsigned bytes_to_write = sample_count;
|
|
#ifndef FOREVER_16_BIT_SOUND
|
|
if(so.sixteen_bit)
|
|
#endif
|
|
bytes_to_write <<= 1;
|
|
|
|
unsigned byte_offset = so.play_position;
|
|
so.play_position = (so.play_position + bytes_to_write) & SOUND_BUFFER_SIZE_MASK; /* wrap to beginning */
|
|
|
|
unsigned short *dst_pt = audiobuff;
|
|
unsigned short *dst_pt1 = dst_pt + DS2_BUFFER_SIZE;
|
|
|
|
/* Feed the samples to the soundcard until nothing is left */
|
|
for(;;)
|
|
{
|
|
int I = bytes_to_write;
|
|
if (byte_offset + I > SOUND_BUFFER_SIZE)
|
|
{
|
|
I = SOUND_BUFFER_SIZE - byte_offset;
|
|
}
|
|
if(I == 0) break;
|
|
|
|
// memcpy(dst_pt, (char *) Buf + byte_offset, I);
|
|
// dst_pt += I;
|
|
|
|
unsigned short *src_pt= (unsigned short*)(Buf + byte_offset);
|
|
for(int m= 0; m < I/4; m++)
|
|
{
|
|
*dst_pt++= *src_pt++;//(*src_pt++) <<1;
|
|
*dst_pt1++= *src_pt++;//(*src_pt++) <<1;
|
|
}
|
|
|
|
bytes_to_write -= I;
|
|
byte_offset = (byte_offset + I) & SOUND_BUFFER_SIZE_MASK; /* wrap */
|
|
}
|
|
|
|
ds2_updateAudio();
|
|
|
|
/* All data sent. */
|
|
}
|
|
|
|
so.samples_mixed_so_far -= sample_count;
|
|
}
|
|
}
|
|
|
|
/*
|
|
const unsigned int keymap[12] = {
|
|
0x80, //KEY_A
|
|
0x8000, //KEY_B
|
|
0x2000, //KEY_SELECT
|
|
0x1000, //KEY_START
|
|
0x100, //KEY_RIGHT
|
|
0x200, //KEY_LEFT
|
|
0x800, //KEY_UP
|
|
0x400, //KEY_DOWN
|
|
0x10, //KEY_R
|
|
0x20, //KEY_L
|
|
0x40, //KEY_X
|
|
0x4000 //KEY_Y
|
|
};
|
|
*/
|
|
|
|
static bool8 SoundToggleWasHeld = FALSE;
|
|
|
|
unsigned int S9xReadJoypad (int which1)
|
|
{
|
|
struct key_buf inputdata;
|
|
|
|
ds2_getrawInput(&inputdata);
|
|
|
|
if (inputdata.key & KEY_LID)
|
|
{
|
|
ds2_setCPUclocklevel(0);
|
|
ds2_setSupend();
|
|
do {
|
|
ds2_getrawInput(&inputdata);
|
|
mdelay(1);
|
|
} while (inputdata.key & KEY_LID);
|
|
ds2_wakeup();
|
|
// Before starting to emulate again, turn off the lower
|
|
// screen's backlight.
|
|
mdelay(100); // needed to avoid ds2_setBacklight crashing
|
|
ds2_setBacklight(2);
|
|
set_cpu_clock(clock_speed_number);
|
|
}
|
|
|
|
u32 HotkeyReturnToMenu = game_config.HotkeyReturnToMenu != 0 ? game_config.HotkeyReturnToMenu : emu_config.HotkeyReturnToMenu;
|
|
u32 HotkeyTemporaryFastForward = game_config.HotkeyTemporaryFastForward != 0 ? game_config.HotkeyTemporaryFastForward : emu_config.HotkeyTemporaryFastForward;
|
|
u32 HotkeyToggleSound = game_config.HotkeyToggleSound != 0 ? game_config.HotkeyToggleSound : emu_config.HotkeyToggleSound;
|
|
|
|
if(inputdata.key & KEY_TOUCH ||
|
|
(HotkeyReturnToMenu && ((inputdata.key & HotkeyReturnToMenu) == HotkeyReturnToMenu))
|
|
) //Active menu
|
|
Settings.Paused = 1;
|
|
|
|
temporary_fast_forward =
|
|
(HotkeyTemporaryFastForward && ((inputdata.key & HotkeyTemporaryFastForward) == HotkeyTemporaryFastForward))
|
|
;
|
|
|
|
bool8 SoundToggleIsHeld =
|
|
(HotkeyToggleSound && ((inputdata.key & HotkeyToggleSound) == HotkeyToggleSound))
|
|
;
|
|
|
|
if (SoundToggleIsHeld && !SoundToggleWasHeld)
|
|
{
|
|
game_enable_audio = !game_enable_audio;
|
|
game_disableAudio();
|
|
}
|
|
|
|
SoundToggleWasHeld = SoundToggleIsHeld;
|
|
|
|
if(which1 < 1)
|
|
{
|
|
unsigned int key;
|
|
|
|
// DS -> SNES
|
|
key = (inputdata.key & KEY_A ) << 7; // 0x0001 -> 0x0080
|
|
key |= (inputdata.key & KEY_B ) << 14; // 0x0002 -> 0x8000
|
|
key |= (inputdata.key & KEY_SELECT) << 11; // 0x0004 -> 0x2000
|
|
key |= (inputdata.key & KEY_START ) << 9; // 0x0008 -> 0x1000
|
|
key |= (inputdata.key & KEY_UP ) << 5; // 0x0040 -> 0x0800
|
|
// 0x0010 -> 0x0100; 0x0020 -> 0x0200
|
|
// 0x0030 -> 0x0300
|
|
key |= (inputdata.key & (KEY_RIGHT | KEY_LEFT)) << 4;
|
|
// 0x0100 -> 0x0010; 0x0200 -> 0x0020; 0x0400 -> 0x0040
|
|
// 0x0700 -> 0x0070
|
|
key |= (inputdata.key & (KEY_R | KEY_L | KEY_X)) >> 4;
|
|
// 0x0080 -> 0x0400; 0x0800 -> 0x4000
|
|
// 0x0880 -> 0x4400
|
|
key |= (inputdata.key & (KEY_DOWN | KEY_Y)) << 3;
|
|
/*
|
|
for(i= 0; i < 12; i++) //remap key
|
|
{
|
|
key |= (inputdata.key & (1<<i)) ? keymap[i] : 0;
|
|
}
|
|
*/
|
|
|
|
return (key | 0x80000000);
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static int S9xCompareSDD1IndexEntries (const void *p1, const void *p2)
|
|
{
|
|
return (*(uint32 *) p1 - *(uint32 *) p2);
|
|
}
|
|
|
|
void S9xLoadSDD1Data ()
|
|
{
|
|
char filename [_MAX_PATH + 1];
|
|
char index [_MAX_PATH + 1];
|
|
char data [_MAX_PATH + 1];
|
|
char patch [_MAX_PATH + 1];
|
|
|
|
Memory.FreeSDD1Data ();
|
|
|
|
strcpy (filename, S9xGetSnapshotDirectory ());
|
|
|
|
Settings.SDD1Pack=FALSE;
|
|
if (strncmp (Memory.ROMName, "Star Ocean", 10) == 0){
|
|
if(SDD1_pack) strcpy (filename, SDD1_pack);
|
|
#ifdef SDD1_DECOMP
|
|
else Settings.SDD1Pack=TRUE;
|
|
#else
|
|
strcat (filename, "/socnsdd1");
|
|
#endif
|
|
} else if(strncmp(Memory.ROMName, "STREET FIGHTER ALPHA2", 21)==0){
|
|
if(SDD1_pack) strcpy (filename, SDD1_pack);
|
|
#ifdef SDD1_DECOMP
|
|
else Settings.SDD1Pack=TRUE;
|
|
#else
|
|
strcat (filename, "/sfa2sdd1");
|
|
#endif
|
|
} else {
|
|
if(SDD1_pack) strcpy (filename, SDD1_pack);
|
|
#ifdef SDD1_DECOMP
|
|
else Settings.SDD1Pack=TRUE;
|
|
#else
|
|
S9xMessage(S9X_WARNING, S9X_ROM_INFO, "WARNING: No default SDD1 pack for this ROM");
|
|
#endif
|
|
}
|
|
|
|
if(Settings.SDD1Pack) return;
|
|
|
|
DIR *dir = opendir (filename);
|
|
|
|
index [0] = 0;
|
|
data [0] = 0;
|
|
patch [0] = 0;
|
|
|
|
if (dir)
|
|
{
|
|
// struct dirent *d;
|
|
dirent *d;
|
|
|
|
while ((d = readdir (dir)))
|
|
{
|
|
if (strcasecmp (d->d_name, "SDD1GFX.IDX") == 0)
|
|
{
|
|
strcpy (index, filename);
|
|
strcat (index, "/");
|
|
strcat (index, d->d_name);
|
|
}
|
|
else
|
|
if (strcasecmp (d->d_name, "SDD1GFX.DAT") == 0)
|
|
{
|
|
strcpy (data, filename);
|
|
strcat (data, "/");
|
|
strcat (data, d->d_name);
|
|
}
|
|
if (strcasecmp (d->d_name, "SDD1GFX.PAT") == 0)
|
|
{
|
|
strcpy (patch, filename);
|
|
strcat (patch, "/");
|
|
strcat (patch, d->d_name);
|
|
}
|
|
}
|
|
closedir (dir);
|
|
|
|
if (strlen (index) && strlen (data))
|
|
{
|
|
FILE *fs = fopen (index, "rb");
|
|
int len = 0;
|
|
|
|
if (fs)
|
|
{
|
|
// Index is stored as a sequence of entries, each entry being
|
|
// 12 bytes consisting of:
|
|
// 4 byte key: (24bit address & 0xfffff * 16) | translated block
|
|
// 4 byte ROM offset
|
|
// 4 byte length
|
|
fseek (fs, 0, SEEK_END);
|
|
len = ftell (fs);
|
|
//rewind (fs);
|
|
fseek (fs, 0, SEEK_SET);
|
|
Memory.SDD1Index = (uint8 *) malloc (len);
|
|
fread (Memory.SDD1Index, 1, len, fs);
|
|
fclose (fs);
|
|
Memory.SDD1Entries = len / 12;
|
|
|
|
if (!(fs = fopen (data, "rb")))
|
|
{
|
|
free ((char *) Memory.SDD1Index);
|
|
Memory.SDD1Index = NULL;
|
|
Memory.SDD1Entries = 0;
|
|
}
|
|
else
|
|
{
|
|
fseek (fs, 0, SEEK_END);
|
|
len = ftell (fs);
|
|
//rewind (fs);
|
|
fseek (fs, 0, SEEK_SET);
|
|
Memory.SDD1Data = (uint8 *) malloc (len);
|
|
fread (Memory.SDD1Data, 1, len, fs);
|
|
fclose (fs);
|
|
|
|
if (strlen (patch) > 0 &&
|
|
(fs = fopen (patch, "rb")))
|
|
{
|
|
fclose (fs);
|
|
}
|
|
#ifdef MSB_FIRST
|
|
// Swap the byte order of the 32-bit value triplets on
|
|
// MSBFirst machines.
|
|
uint8 *ptr = Memory.SDD1Index;
|
|
for (int i = 0; i < Memory.SDD1Entries; i++, ptr += 12)
|
|
{
|
|
SWAP_DWORD ((*(uint32 *) (ptr + 0)));
|
|
SWAP_DWORD ((*(uint32 *) (ptr + 4)));
|
|
SWAP_DWORD ((*(uint32 *) (ptr + 8)));
|
|
}
|
|
#endif
|
|
qsort (Memory.SDD1Index, Memory.SDD1Entries, 12,
|
|
S9xCompareSDD1IndexEntries);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr, "Decompressed data pack not found in '%s'.\n",
|
|
filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool8 S9xReadMousePosition (int which1, int &x, int &y, uint32 &buttons)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
bool8 S9xReadSuperScopePosition (int &x, int &y, uint32 &buttons)
|
|
{
|
|
return (TRUE);
|
|
}
|
|
|
|
bool JustifierOffscreen()
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
void JustifierButtons(uint32& justifiers)
|
|
{
|
|
}
|
|
|
|
START_EXTERN_C
|
|
char* osd_GetPackDir()
|
|
{
|
|
static char filename[_MAX_PATH];
|
|
memset(filename, 0, _MAX_PATH);
|
|
|
|
if(strlen(S9xGetSnapshotDirectory())!=0)
|
|
strcpy (filename, S9xGetSnapshotDirectory());
|
|
else
|
|
{
|
|
char dir [_MAX_DIR + 1];
|
|
char drive [_MAX_DRIVE + 1];
|
|
char name [_MAX_FNAME + 1];
|
|
char ext [_MAX_EXT + 1];
|
|
_splitpath(Memory.ROMFilename, drive, dir, name, ext);
|
|
_makepath(filename, drive, dir, NULL, NULL);
|
|
}
|
|
|
|
if(!strncmp((char*)&Memory.ROM [0xffc0], "SUPER POWER LEAG 4 ", 21))
|
|
{
|
|
if (getenv("SPL4PACK"))
|
|
return getenv("SPL4PACK");
|
|
else
|
|
strcat(filename, "/SPL4-SP7");
|
|
}
|
|
else if(!strncmp((char*)&Memory.ROM [0xffc0], "MOMOTETSU HAPPY ",21))
|
|
{
|
|
if (getenv("MDHPACK"))
|
|
return getenv("MDHPACK");
|
|
else
|
|
strcat(filename, "/SMHT-SP7");
|
|
}
|
|
else if(!strncmp((char*)&Memory.ROM [0xffc0], "HU TENGAI MAKYO ZERO ", 21))
|
|
{
|
|
if (getenv("FEOEZPACK"))
|
|
return getenv("FEOEZPACK");
|
|
else
|
|
strcat(filename, "/FEOEZSP7");
|
|
}
|
|
else if(!strncmp((char*)&Memory.ROM [0xffc0], "JUMP TENGAIMAKYO ZERO",21))
|
|
{
|
|
if (getenv("SJNSPACK"))
|
|
return getenv("SJNSPACK");
|
|
else
|
|
strcat(filename, "/SJUMPSP7");
|
|
} else strcat(filename, "/MISC-SP7");
|
|
return filename;
|
|
}
|
|
END_EXTERN_C
|
|
|
|
|