Updated X11 and SDL ports to make use of the new DEVELOPER_SUPPORT

stuff.  These are availble only if DEVELOPER_SUPPORT as been defined.

The keys are as follows:

Alt+s:    Save the current properties to your home directory named as
          "Cartridge.Name".pro, with all spaces in the filename
          converted to underscore.

Alt+f:    Toggle between NTSC and PAL modes, and update the palette
          accordingly.

PageUp / PageDown:  Increase / decrease the "Display.YStart" variable.

Alt+PageUp / Alt+PageDown:  Increase / decrease the "Display.Height" variable.

Home / End:  Increase / decrease the "Display.XStart" variable.

Alt+Home / Alt+End:  Increase / decrease the "Display.Width" variable.


Also, cleaned up the code a bit wrt C functions.  Got rid of all sprintf
C-style functions, and used C++ style sstream instead.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@125 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2002-11-10 19:18:35 +00:00
parent a12078de97
commit 4d149d7885
2 changed files with 301 additions and 136 deletions

View File

@ -13,14 +13,15 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: mainSDL.cxx,v 1.31 2002-10-12 15:24:49 stephena Exp $ // $Id: mainSDL.cxx,v 1.32 2002-11-10 19:18:35 stephena Exp $
//============================================================================ //============================================================================
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <sstream>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
@ -57,7 +58,7 @@
// function prototypes // function prototypes
static bool setupDisplay(); static bool setupDisplay();
static bool setupJoystick(); static bool setupJoystick();
static bool createScreen(int width, int height); static bool createScreen();
static void recalculate8BitPalette(); static void recalculate8BitPalette();
static void setupPalette(); static void setupPalette();
static void cleanup(); static void cleanup();
@ -274,17 +275,12 @@ bool setupDisplay()
} }
// Set the window title and icon // Set the window title and icon
char name[512]; ostringstream name;
sprintf(name, "Stella: \"%s\"", name << "Stella: \"" << theConsole->properties().get("Cartridge.Name") << "\"";
theConsole->properties().get("Cartridge.Name").c_str()); SDL_WM_SetCaption(name.str().c_str(), "stella");
SDL_WM_SetCaption(name, "stella");
// Figure out the desired size of the window
int width = settings->theWidth * settings->theWindowSize * 2;
int height = settings->theHeight * settings->theWindowSize;
// Create the screen // Create the screen
if(!createScreen(width, height)) if(!createScreen())
return false; return false;
setupPalette(); setupPalette();
@ -350,8 +346,11 @@ bool setupJoystick()
It updates the global screen variable. When this happens, the It updates the global screen variable. When this happens, the
8-bit palette needs to be recalculated. 8-bit palette needs to be recalculated.
*/ */
bool createScreen(int w, int h) bool createScreen()
{ {
int w = settings->theWidth * settings->theWindowSize * 2;
int h = settings->theHeight * settings->theWindowSize;
screen = SDL_SetVideoMode(w, h, 0, sdlflags); screen = SDL_SetVideoMode(w, h, 0, sdlflags);
if(screen == NULL) if(screen == NULL)
{ {
@ -363,6 +362,8 @@ bool createScreen(int w, int h)
if(bpp == 8) if(bpp == 8)
recalculate8BitPalette(); recalculate8BitPalette();
theRedrawEntireFrameIndicator = true;
return true; return true;
} }
@ -404,6 +405,8 @@ void recalculate8BitPalette()
palette[i] = SDL_MapRGB(format, r, g, b); palette[i] = SDL_MapRGB(format, r, g, b);
} }
theRedrawEntireFrameIndicator = true;
} }
@ -449,6 +452,8 @@ void setupPalette()
break; break;
} }
} }
theRedrawEntireFrameIndicator = true;
} }
@ -464,39 +469,45 @@ void doQuit()
/** /**
This routine is called when the user wants to resize the window. This routine is called when the user wants to resize the window.
A '1' argument indicates that the window should increase in size, while '0' A '1' argument indicates that the window should increase in size, while '0'
indicates that the windows should decrease in size. indicates that the windows should decrease in size. A '-1' indicates that
the window should be sized according to the current properties.
Can't resize in fullscreen mode. Will only resize up to the maximum size Can't resize in fullscreen mode. Will only resize up to the maximum size
of the screen. of the screen.
*/ */
void resizeWindow(int mode) void resizeWindow(int mode)
{ {
// reset size to that given in properties
// this is a special case of allowing a resize while in fullscreen mode
if(mode == -1)
{
settings->theWidth = theConsole->mediaSource().width();
settings->theHeight = theConsole->mediaSource().height();
settings->theMaxWindowSize = maxWindowSizeForScreen();
}
else if(mode == 1) // increase size
{
if(isFullscreen) if(isFullscreen)
return; return;
if(mode == 1) // increase size
{
if(settings->theWindowSize == settings->theMaxWindowSize) if(settings->theWindowSize == settings->theMaxWindowSize)
settings->theWindowSize = 1; settings->theWindowSize = 1;
else else
settings->theWindowSize++; settings->theWindowSize++;
} }
else // decrease size else if(mode == 0) // decrease size
{ {
if(isFullscreen)
return;
if(settings->theWindowSize == 1) if(settings->theWindowSize == 1)
settings->theWindowSize = settings->theMaxWindowSize; settings->theWindowSize = settings->theMaxWindowSize;
else else
settings->theWindowSize--; settings->theWindowSize--;
} }
// Figure out the desired size of the window if(!createScreen())
int width = settings->theWidth * settings->theWindowSize * 2;
int height = settings->theHeight * settings->theWindowSize;
if(!createScreen(width, height))
return; return;
theRedrawEntireFrameIndicator = true;
// A resize may mean that the window is no longer centered // A resize may mean that the window is no longer centered
isCentered = false; isCentered = false;
@ -534,6 +545,7 @@ void centerWindow()
info.info.x11.unlock_func(); info.info.x11.unlock_func();
isCentered = true; isCentered = true;
theRedrawEntireFrameIndicator = true;
} }
@ -552,7 +564,7 @@ void toggleFullscreen()
else else
sdlflags &= ~SDL_FULLSCREEN; sdlflags &= ~SDL_FULLSCREEN;
if(!createScreen(width, height)) if(!createScreen())
return; return;
if(isFullscreen) // now in fullscreen mode if(isFullscreen) // now in fullscreen mode
@ -568,8 +580,6 @@ void toggleFullscreen()
if(settings->theCenterWindowFlag) if(settings->theCenterWindowFlag)
centerWindow(); centerWindow();
} }
theRedrawEntireFrameIndicator = true;
} }
@ -592,7 +602,6 @@ void togglePause()
// Show a different palette depending on pause state // Show a different palette depending on pause state
setupPalette(); setupPalette();
theRedrawEntireFrameIndicator = true;
} }
@ -625,27 +634,24 @@ void grabMouse(bool grab)
*/ */
void saveState() void saveState()
{ {
char buf[1024]; ostringstream buf;
string path = getenv("HOME");
path += "/.stella/state";
// First get the name for the current state file
string md5 = theConsole->properties().get("Cartridge.MD5"); string md5 = theConsole->properties().get("Cartridge.MD5");
snprintf(buf, 1023, "%s/%s.st%d", path.c_str(), md5.c_str(), currentState); buf << getenv("HOME") << "/.stella/state/" << md5 << ".st" << currentState;
string fileName = buf; string filename = buf.str();
// Do a state save using the System // Do a state save using the System
int result = theConsole->system().saveState(fileName, md5); int result = theConsole->system().saveState(filename, md5);
// Print appropriate message // Print appropriate message
buf.str("");
if(result == 1) if(result == 1)
snprintf(buf, 1023, "State %d saved", currentState); buf << "State " << currentState << " saved";
else if(result == 2) else if(result == 2)
snprintf(buf, 1023, "Error saving state %d", currentState); buf << "Error saving state " << currentState;
else if(result == 3) else if(result == 3)
snprintf(buf, 1023, "Invalid state %d file", currentState); buf << "Invalid state " << currentState << " file";
string message = buf; string message = buf.str();
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL * theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
settings->theDesiredFrameRate); settings->theDesiredFrameRate);
} }
@ -672,9 +678,9 @@ void changeState(int direction)
} }
// Print appropriate message // Print appropriate message
char buf[40]; ostringstream buf;
snprintf(buf, 39, "Changed to slot %d", currentState); buf << "Changed to slot " << currentState;
string message = buf; string message = buf.str();
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL * theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
settings->theDesiredFrameRate); settings->theDesiredFrameRate);
} }
@ -685,27 +691,24 @@ void changeState(int direction)
*/ */
void loadState() void loadState()
{ {
char buf[1024]; ostringstream buf;
string path = getenv("HOME");
path += "/.stella/state";
// First get the name for the current state file
string md5 = theConsole->properties().get("Cartridge.MD5"); string md5 = theConsole->properties().get("Cartridge.MD5");
snprintf(buf, 1023, "%s/%s.st%d", path.c_str(), md5.c_str(), currentState); buf << getenv("HOME") << "/.stella/state/" << md5 << ".st" << currentState;
string fileName = buf; string filename = buf.str();
// Do a state load using the System // Do a state load using the System
int result = theConsole->system().loadState(fileName, md5); int result = theConsole->system().loadState(filename, md5);
// Print appropriate message // Print appropriate message
buf.str("");
if(result == 1) if(result == 1)
snprintf(buf, 1023, "State %d loaded", currentState); buf << "State " << currentState << " loaded";
else if(result == 2) else if(result == 2)
snprintf(buf, 1023, "Error loading state %d", currentState); buf << "Error loading state " << currentState;
else if(result == 3) else if(result == 3)
snprintf(buf, 1023, "Invalid state %d file", currentState); buf << "Invalid state " << currentState << " file";
string message = buf; string message = buf.str();
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL * theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
settings->theDesiredFrameRate); settings->theDesiredFrameRate);
} }
@ -954,6 +957,69 @@ void handleEvents()
showCursor(!settings->theHideCursorFlag); showCursor(!settings->theHideCursorFlag);
} }
} }
#ifdef DEVELOPER_SUPPORT
if(key == SDLK_f) // Alt-f switches between NTSC and PAL
{
if(mod & KMOD_ALT)
{
theConsole->toggleFormat();
// update the palette
setupPalette();
}
}
else if(key == SDLK_END) // End decreases XStart
{ // Alt-End decreases Width
if(mod & KMOD_ALT)
theConsole->changeWidth(0);
else
theConsole->changeXStart(0);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if(key == SDLK_HOME) // Home increases XStart
{ // Alt-Home increases Width
if(mod & KMOD_ALT)
theConsole->changeWidth(1);
else
theConsole->changeXStart(1);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if(key == SDLK_PAGEDOWN) // PageDown decreases YStart
{ // Alt-PageDown decreases Height
if(mod & KMOD_ALT)
theConsole->changeHeight(0);
else
theConsole->changeYStart(0);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if(key == SDLK_PAGEUP) // PageUp increases YStart
{ // Alt-PageUp increases Height
if(mod & KMOD_ALT)
theConsole->changeHeight(1);
else
theConsole->changeYStart(1);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if(key == SDLK_s) // Alt-s saves properties to a file
{
if(mod & KMOD_ALT)
{
string newPropertiesFile = getenv("HOME");
newPropertiesFile = newPropertiesFile + "/" + \
theConsole->properties().get("Cartridge.Name") + ".pro";
theConsole->saveProperties(newPropertiesFile);
}
}
#endif
else // check all the other keys else // check all the other keys
{ {
for(unsigned int i = 0; i < sizeof(list) / sizeof(Switches); ++i) for(unsigned int i = 0; i < sizeof(list) / sizeof(Switches); ++i)
@ -1211,11 +1277,13 @@ void takeSnapshot()
} }
// Now find the correct name for the snapshot // Now find the correct name for the snapshot
string filename = settings->theSnapShotDir; string path = settings->theSnapShotDir;
string filename;
if(settings->theSnapShotName == "romname") if(settings->theSnapShotName == "romname")
filename = filename + "/" + theConsole->properties().get("Cartridge.Name"); path = path + "/" + theConsole->properties().get("Cartridge.Name");
else if(settings->theSnapShotName == "md5sum") else if(settings->theSnapShotName == "md5sum")
filename = filename + "/" + theConsole->properties().get("Cartridge.MD5"); path = path + "/" + theConsole->properties().get("Cartridge.MD5");
else else
{ {
cerr << "ERROR: unknown name " << settings->theSnapShotName cerr << "ERROR: unknown name " << settings->theSnapShotName
@ -1224,32 +1292,29 @@ void takeSnapshot()
} }
// Replace all spaces in name with underscores // Replace all spaces in name with underscores
replace(filename.begin(), filename.end(), ' ', '_'); replace(path.begin(), path.end(), ' ', '_');
// Check whether we want multiple snapshots created // Check whether we want multiple snapshots created
if(settings->theMultipleSnapShotFlag) if(settings->theMultipleSnapShotFlag)
{ {
// Determine if the file already exists, checking each successive filename // Determine if the file already exists, checking each successive filename
// until one doesn't exist // until one doesn't exist
string extFilename = filename + ".png"; filename = path + ".png";
if(access(extFilename.c_str(), F_OK) == 0 ) if(access(filename.c_str(), F_OK) == 0 )
{ {
uInt32 i; ostringstream buf;
char buffer[1024]; for(uInt32 i = 1; ;++i)
for(i = 1; ;++i)
{ {
snprintf(buffer, 1023, "%s_%d.png", filename.c_str(), i); buf.str("");
if(access(buffer, F_OK) == -1 ) buf << path << "_" << i << ".png";
if(access(buf.str().c_str(), F_OK) == -1 )
break; break;
} }
filename = buffer; filename = buf.str();
}
} }
else else
filename = extFilename; filename = path + ".png";
}
else
filename = filename + ".png";
// Now save the snapshot file // Now save the snapshot file
snapshot->savePNG(filename, theConsole->mediaSource(), settings->theWindowSize); snapshot->savePNG(filename, theConsole->mediaSource(), settings->theWindowSize);
@ -1343,6 +1408,16 @@ void usage()
" -pro <props file> Use the given properties file instead of stella.pro", " -pro <props file> Use the given properties file instead of stella.pro",
" -accurate <0|1> Accurate game timing (uses more CPU)", " -accurate <0|1> Accurate game timing (uses more CPU)",
"", "",
#ifdef DEVELOPER_SUPPORT
" DEVELOPER options (see Stella manual for details)",
" -Dformat Sets \"Display.Format\"",
" -Dxstart Sets \"Display.XStart\"",
" -Dwidth Sets \"Display.Width\"",
" -Dystart Sets \"Display.YStart\"",
" -Dheight Sets \"Display.Height\"",
" -Dcpu Sets \"Emulation.CPU\"",
" -Dhmoveblanks Sets \"Emulation.HmoveBlanks\"",
#endif
0 0
}; };
@ -1569,9 +1644,15 @@ int main(int argc, char* argv[])
// Get just the filename of the file containing the ROM image // Get just the filename of the file containing the ROM image
const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1; const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1;
// Create the 2600 game console // Create the 2600 game console for users or developers
#ifdef DEVELOPER_SUPPORT
theConsole = new Console(image, size, filename,
theEvent, propertiesSet, sound.getSampleRate(),
&settings->userDefinedProperties);
#else
theConsole = new Console(image, size, filename, theConsole = new Console(image, size, filename,
theEvent, propertiesSet, sound.getSampleRate()); theEvent, propertiesSet, sound.getSampleRate());
#endif
// Let the sound object know about the MediaSource. // Let the sound object know about the MediaSource.
// The sound object takes care of getting samples from the MediaSource. // The sound object takes care of getting samples from the MediaSource.

View File

@ -13,14 +13,15 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: mainX11.cxx,v 1.28 2002-10-09 04:38:12 bwmott Exp $ // $Id: mainX11.cxx,v 1.29 2002-11-10 19:18:35 stephena Exp $
//============================================================================ //============================================================================
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <sstream>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include <stdio.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
@ -283,11 +284,10 @@ bool setupDisplay()
hints.min_height = hints.max_height = hints.height = height; hints.min_height = hints.max_height = hints.height = height;
// Set window and icon name, size hints and other properties // Set window and icon name, size hints and other properties
char name[512]; ostringstream name;
sprintf(name, "Stella: \"%s\"", name << "Stella: \"" << theConsole->properties().get("Cartridge.Name") << "\"";
theConsole->properties().get("Cartridge.Name").c_str()); XmbSetWMProperties(theDisplay, theWindow, name.str().c_str(), "stella", 0, 0,
XmbSetWMProperties(theDisplay, theWindow, name, "stella", 0, 0, &hints, &hints, None, None);
None, None);
// Set up the palette for the screen // Set up the palette for the screen
setupPalette(); setupPalette();
@ -406,6 +406,8 @@ void setupPalette()
theGCTable[t] = XCreateGC(theDisplay, theWindow, GCForeground, &values); theGCTable[t] = XCreateGC(theDisplay, theWindow, GCForeground, &values);
} }
theRedrawEntireFrameIndicator = true;
} }
/** /**
@ -626,6 +628,68 @@ void handleEvents()
showCursor(!settings->theHideCursorFlag); showCursor(!settings->theHideCursorFlag);
} }
} }
#ifdef DEVELOPER_SUPPORT
else if((key == XK_f) && (event.type == KeyPress)) // Alt-f switches between NTSC and PAL
{
if(event.xkey.state & Mod1Mask)
{
theConsole->toggleFormat();
// update the palette
setupPalette();
}
}
else if((key == XK_End) && (event.type == KeyPress)) // End decreases XStart
{ // Alt-End decreases Width
if(event.xkey.state & Mod1Mask)
theConsole->changeWidth(0);
else
theConsole->changeXStart(0);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if((key == XK_Home) && (event.type == KeyPress)) // Home increases XStart
{ // Alt-Home increases Width
if(event.xkey.state & Mod1Mask)
theConsole->changeWidth(1);
else
theConsole->changeXStart(1);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if((key == XK_Next) && (event.type == KeyPress)) // PageDown decreases YStart
{ // Alt-PageDown decreases Height
if(event.xkey.state & Mod1Mask)
theConsole->changeHeight(0);
else
theConsole->changeYStart(0);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if((key == XK_Prior) && (event.type == KeyPress)) // PageUp increases YStart
{ // Alt-PageUp increases Height
if(event.xkey.state & Mod1Mask)
theConsole->changeHeight(1);
else
theConsole->changeYStart(1);
// Make sure changes to the properties are reflected onscreen
resizeWindow(-1);
}
else if((key == XK_s) && (event.type == KeyPress)) // Alt-s saves properties to a file
{
if(event.xkey.state & Mod1Mask)
{
string newPropertiesFile = getenv("HOME");
newPropertiesFile = newPropertiesFile + "/" + \
theConsole->properties().get("Cartridge.Name") + ".pro";
theConsole->saveProperties(newPropertiesFile);
}
}
#endif
else else
{ {
for(unsigned int i = 0; i < sizeof(list) / sizeof(Switches); ++i) for(unsigned int i = 0; i < sizeof(list) / sizeof(Switches); ++i)
@ -836,24 +900,36 @@ void doQuit()
/** /**
This routine is called when the user wants to resize the window. This routine is called when the user wants to resize the window.
A '1' argument indicates that the window should increase in size, while '0' A '1' argument indicates that the window should increase in size, while '0'
indicates that the windows should decrease in size. indicates that the windows should decrease in size. A '-1' indicates that
the window should be sized according to the current properties.
Can't resize in fullscreen mode. Will only resize up to the maximum size Can't resize in fullscreen mode. Will only resize up to the maximum size
for the '-zoom' argument. of the screen.
*/ */
void resizeWindow(int mode) void resizeWindow(int mode)
{ {
// reset size to that given in properties
// this is a special case of allowing a resize while in fullscreen mode
if(mode == -1)
{
settings->theWidth = theConsole->mediaSource().width();
settings->theHeight = theConsole->mediaSource().height();
settings->theMaxWindowSize = maxWindowSizeForScreen();
}
else if(mode == 1) // increase size
{
if(isFullscreen) if(isFullscreen)
return; return;
if(mode == 1) // increase size
{
if(settings->theWindowSize == settings->theMaxWindowSize) if(settings->theWindowSize == settings->theMaxWindowSize)
settings->theWindowSize = 1; settings->theWindowSize = 1;
else else
settings->theWindowSize++; settings->theWindowSize++;
} }
else // decrease size else if(mode == 0) // decrease size
{ {
if(isFullscreen)
return;
if(settings->theWindowSize == 1) if(settings->theWindowSize == 1)
settings->theWindowSize = settings->theMaxWindowSize; settings->theWindowSize = settings->theMaxWindowSize;
else else
@ -911,6 +987,7 @@ void centerWindow()
XSetWMNormalHints(theDisplay, theWindow, &hints); XSetWMNormalHints(theDisplay, theWindow, &hints);
isCentered = true; isCentered = true;
theRedrawEntireFrameIndicator = true;
} }
/** /**
@ -941,7 +1018,6 @@ void togglePause()
// Show a different palette depending on pause state // Show a different palette depending on pause state
setupPalette(); setupPalette();
theRedrawEntireFrameIndicator = true;
} }
/** /**
@ -949,27 +1025,24 @@ void togglePause()
*/ */
void saveState() void saveState()
{ {
char buf[1024]; ostringstream buf;
string path = getenv("HOME");
path += "/.stella/state";
// First get the name for the current state file
string md5 = theConsole->properties().get("Cartridge.MD5"); string md5 = theConsole->properties().get("Cartridge.MD5");
snprintf(buf, 1023, "%s/%s.st%d", path.c_str(), md5.c_str(), currentState); buf << getenv("HOME") << "/.stella/state/" << md5 << ".st" << currentState;
string fileName = buf; string filename = buf.str();
// Do a state save using the System // Do a state save using the System
int result = theConsole->system().saveState(fileName, md5); int result = theConsole->system().saveState(filename, md5);
// Print appropriate message // Print appropriate message
buf.str("");
if(result == 1) if(result == 1)
snprintf(buf, 1023, "State %d saved", currentState); buf << "State " << currentState << " saved";
else if(result == 2) else if(result == 2)
snprintf(buf, 1023, "Error saving state %d", currentState); buf << "Error saving state " << currentState;
else if(result == 3) else if(result == 3)
snprintf(buf, 1023, "Invalid state %d file", currentState); buf << "Invalid state " << currentState << " file";
string message = buf; string message = buf.str();
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL * theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
settings->theDesiredFrameRate); settings->theDesiredFrameRate);
} }
@ -995,9 +1068,9 @@ void changeState(int direction)
} }
// Print appropriate message // Print appropriate message
char buf[40]; ostringstream buf;
snprintf(buf, 39, "Changed to slot %d", currentState); buf << "Changed to slot " << currentState;
string message = buf; string message = buf.str();
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL * theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
settings->theDesiredFrameRate); settings->theDesiredFrameRate);
} }
@ -1007,27 +1080,24 @@ void changeState(int direction)
*/ */
void loadState() void loadState()
{ {
char buf[1024]; ostringstream buf;
string path = getenv("HOME");
path += "/.stella/state";
// First get the name for the current state file
string md5 = theConsole->properties().get("Cartridge.MD5"); string md5 = theConsole->properties().get("Cartridge.MD5");
snprintf(buf, 1023, "%s/%s.st%d", path.c_str(), md5.c_str(), currentState); buf << getenv("HOME") << "/.stella/state/" << md5 << ".st" << currentState;
string fileName = buf; string filename = buf.str();
// Do a state load using the System // Do a state load using the System
int result = theConsole->system().loadState(fileName, md5); int result = theConsole->system().loadState(filename, md5);
// Print appropriate message // Print appropriate message
buf.str("");
if(result == 1) if(result == 1)
snprintf(buf, 1023, "State %d loaded", currentState); buf << "State " << currentState << " loaded";
else if(result == 2) else if(result == 2)
snprintf(buf, 1023, "Error loading state %d", currentState); buf << "Error loading state " << currentState;
else if(result == 3) else if(result == 3)
snprintf(buf, 1023, "Invalid state %d file", currentState); buf << "Invalid state " << currentState << " file";
string message = buf; string message = buf.str();
theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL * theConsole->mediaSource().showMessage(message, MESSAGE_INTERVAL *
settings->theDesiredFrameRate); settings->theDesiredFrameRate);
} }
@ -1121,11 +1191,13 @@ void takeSnapshot()
} }
// Now find the correct name for the snapshot // Now find the correct name for the snapshot
string filename = settings->theSnapShotDir; string path = settings->theSnapShotDir;
string filename;
if(settings->theSnapShotName == "romname") if(settings->theSnapShotName == "romname")
filename = filename + "/" + theConsole->properties().get("Cartridge.Name"); path = path + "/" + theConsole->properties().get("Cartridge.Name");
else if(settings->theSnapShotName == "md5sum") else if(settings->theSnapShotName == "md5sum")
filename = filename + "/" + theConsole->properties().get("Cartridge.MD5"); path = path + "/" + theConsole->properties().get("Cartridge.MD5");
else else
{ {
cerr << "ERROR: unknown name " << settings->theSnapShotName cerr << "ERROR: unknown name " << settings->theSnapShotName
@ -1134,36 +1206,32 @@ void takeSnapshot()
} }
// Replace all spaces in name with underscores // Replace all spaces in name with underscores
replace(filename.begin(), filename.end(), ' ', '_'); replace(path.begin(), path.end(), ' ', '_');
// Check whether we want multiple snapshots created // Check whether we want multiple snapshots created
if(settings->theMultipleSnapShotFlag) if(settings->theMultipleSnapShotFlag)
{ {
// Determine if the file already exists, checking each successive filename // Determine if the file already exists, checking each successive filename
// until one doesn't exist // until one doesn't exist
string extFilename = filename + ".png"; filename = path + ".png";
if(access(extFilename.c_str(), F_OK) == 0 ) if(access(filename.c_str(), F_OK) == 0 )
{ {
uInt32 i; ostringstream buf;
char buffer[1024]; for(uInt32 i = 1; ;++i)
for(i = 1; ;++i)
{ {
snprintf(buffer, 1023, "%s_%d.png", filename.c_str(), i); buf.str("");
if(access(buffer, F_OK) == -1 ) buf << path << "_" << i << ".png";
if(access(buf.str().c_str(), F_OK) == -1 )
break; break;
} }
filename = buffer; filename = buf.str();
}
} }
else else
filename = extFilename; filename = path + ".png";
}
else
filename = filename + ".png";
// Now save the snapshot file // Now save the snapshot file
snapshot->savePNG(filename, theConsole->mediaSource(), snapshot->savePNG(filename, theConsole->mediaSource(), settings->theWindowSize);
settings->theWindowSize);
if(access(filename.c_str(), F_OK) == 0) if(access(filename.c_str(), F_OK) == 0)
cerr << "Snapshot saved as " << filename << endl; cerr << "Snapshot saved as " << filename << endl;
@ -1239,6 +1307,16 @@ void usage()
" -pro <props file> Use the given properties file instead of stella.pro", " -pro <props file> Use the given properties file instead of stella.pro",
" -accurate <0|1> Accurate game timing (uses more CPU)", " -accurate <0|1> Accurate game timing (uses more CPU)",
"", "",
#ifdef DEVELOPER_SUPPORT
" DEVELOPER options (see Stella manual for details)",
" -Dformat Sets \"Display.Format\"",
" -Dxstart Sets \"Display.XStart\"",
" -Dwidth Sets \"Display.Width\"",
" -Dystart Sets \"Display.YStart\"",
" -Dheight Sets \"Display.Height\"",
" -Dcpu Sets \"Emulation.CPU\"",
" -Dhmoveblanks Sets \"Emulation.HmoveBlanks\"",
#endif
0 0
}; };
@ -1446,9 +1524,15 @@ int main(int argc, char* argv[])
// Get just the filename of the file containing the ROM image // Get just the filename of the file containing the ROM image
const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1; const char* filename = (!strrchr(file, '/')) ? file : strrchr(file, '/') + 1;
// Create the 2600 game console // Create the 2600 game console for users or developers
#ifdef DEVELOPER_SUPPORT
theConsole = new Console(image, size, filename,
theEvent, propertiesSet, sound.getSampleRate(),
&settings->userDefinedProperties);
#else
theConsole = new Console(image, size, filename, theConsole = new Console(image, size, filename,
theEvent, propertiesSet, sound.getSampleRate()); theEvent, propertiesSet, sound.getSampleRate());
#endif
// Free the image since we don't need it any longer // Free the image since we don't need it any longer
delete[] image; delete[] image;