Control-f now cycles between NTSC/PAL/SECAM/NTSC50/PAL60/SECAM60

display modes wrt both palette and display properties (# of scanlines,
size of window, etc).  This means you can now dynamically switch
between these modes at runtime.

Also added 'Shift-Control-f', which cycles through the modes in
reverse order.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2527 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-06-05 16:32:35 +00:00
parent b231dda2a9
commit 6353d118b7
9 changed files with 182 additions and 133 deletions

View File

@ -18,10 +18,19 @@
scanlines; the output is now blanked as on a real TV. Special thanks scanlines; the output is now blanked as on a real TV. Special thanks
to Omegamatrix of AtariAge for test ROMs in this area. to Omegamatrix of AtariAge for test ROMs in this area.
* Modified hotkey for "Change console palette" (Control-f) to also
change the display properties of the TIA. This allows you to switch
between NTSC/PAL/SECAM (and variants) modes dynamically. Related to
this, added Shift-Control-f key to step backwards through the
available modes.
* Fixed several bugs in DPC+ bankswitching scheme, including ability to * Fixed several bugs in DPC+ bankswitching scheme, including ability to
load and save state files. As well, ROMs now work correctly after load and save state files. As well, ROMs now work correctly after
console format autodetection. console format autodetection.
* Note: because of the TIA changes, the state file format has changed
again, and old state files will not work with this release.
-Have fun! -Have fun!

View File

@ -10,7 +10,7 @@
<br><br> <br><br>
<center><h2><b>A multi-platform Atari 2600 VCS emulator</b></h2></center> <center><h2><b>A multi-platform Atari 2600 VCS emulator</b></h2></center>
<center><h4><b>Release 3.7</b></h4></center> <center><h4><b>Release 3.7.1</b></h4></center>
<br><br> <br><br>
<center><h2><b>User's Guide</b></h2></center> <center><h2><b>User's Guide</b></h2></center>
@ -1553,11 +1553,17 @@
</tr> </tr>
<tr> <tr>
<td>Toggle display palette (<i>NTSC/PAL/SECAM</i>)</td> <td>Toggle console type in increasing order (<i>NTSC/PAL/SECAM, etc)</i>)</td>
<td>Control + f</td> <td>Control + f</td>
<td>Control + f</td> <td>Control + f</td>
</tr> </tr>
<tr>
<td>Toggle console type in decreasing order (<i>NTSC/PAL/SECAM, etc)</i>)</td>
<td>Shift-Control + f</td>
<td>Shift-Control + f</td>
</tr>
<tr> <tr>
<td>Save current properties to a new properties file</td> <td>Save current properties to a new properties file</td>
<td>Control + s</td> <td>Control + s</td>

View File

@ -22,7 +22,7 @@
#include <cstdlib> #include <cstdlib>
#define STELLA_VERSION "3.8_svn" #define STELLA_VERSION "3.7.1_pre"
#define STELLA_BUILD atoi("$Rev$" + 6) #define STELLA_BUILD atoi("$Rev$" + 6)
#endif #endif

View File

@ -77,6 +77,7 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
myCMHandler(0), myCMHandler(0),
myDisplayFormat("NTSC"), myDisplayFormat("NTSC"),
myFramerate(60.0), myFramerate(60.0),
myCurrentFormat(0),
myUserPaletteDefined(false) myUserPaletteDefined(false)
{ {
// Load user-defined palette for this ROM // Load user-defined palette for this ROM
@ -118,24 +119,17 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
// We turn off the SuperCharger progress bars, otherwise the SC BIOS // We turn off the SuperCharger progress bars, otherwise the SC BIOS
// will take over 250 frames! // will take over 250 frames!
// The 'fastscbios' option must be changed before the system is reset // The 'fastscbios' option must be changed before the system is reset
// The algorithm used is as follows:
// Run for 60 frames; if there's a frame that has more than 287
// scanlines, count it as PAL
// If at least 25 PAL frames are found, then the format is PAL, else NTSC
bool fastscbios = myOSystem->settings().getBool("fastscbios"); bool fastscbios = myOSystem->settings().getBool("fastscbios");
myOSystem->settings().setBool("fastscbios", true); myOSystem->settings().setBool("fastscbios", true);
mySystem->reset(true); // autodetect in reset enabled mySystem->reset(true); // autodetect in reset enabled
int palCount = 0;
for(int i = 0; i < 60; ++i) for(int i = 0; i < 60; ++i)
{
myTIA->update(); myTIA->update();
if(myTIA->scanlines() >= 287) myDisplayFormat = myTIA->isPAL() ? "PAL" : "NTSC";
++palCount;
}
myDisplayFormat = (palCount >= 25) ? "PAL" : "NTSC";
if(myProperties.get(Display_Format) == "AUTO-DETECT") if(myProperties.get(Display_Format) == "AUTO-DETECT")
{
autodetected = "*"; autodetected = "*";
myCurrentFormat = 0;
}
// Don't forget to reset the SC progress bars again // Don't forget to reset the SC progress bars again
myOSystem->settings().setBool("fastscbios", fastscbios); myOSystem->settings().setBool("fastscbios", fastscbios);
@ -145,48 +139,15 @@ Console::Console(OSystem* osystem, Cartridge* cart, const Properties& props)
// Set up the correct properties used when toggling format // Set up the correct properties used when toggling format
// Note that this can be overridden if a format is forced // Note that this can be overridden if a format is forced
// For example, if a PAL ROM is forced to be NTSC, it will use NTSC-like // For example, if a PAL ROM is forced to be NTSC, it will use NTSC-like
// properties (60Hz, 262 scanlines, etc) and cycle between NTSC-like modes // properties (60Hz, 262 scanlines, etc), but likely result in flicker
// The TIA will self-adjust the framerate if necessary // The TIA will self-adjust the framerate if necessary
setTIAProperties();
// TODO - query these values directly from the TIA if value is 'AUTO' if(myDisplayFormat == "NTSC") myCurrentFormat = 1;
uInt32 ystart = atoi(myProperties.get(Display_YStart).c_str()); else if(myDisplayFormat == "PAL") myCurrentFormat = 2;
if(ystart > 64) ystart = 64; else if(myDisplayFormat == "SECAM") myCurrentFormat = 3;
uInt32 height = atoi(myProperties.get(Display_Height).c_str()); else if(myDisplayFormat == "NTSC50") myCurrentFormat = 4;
if(height < 210) height = 210; else if(myDisplayFormat == "PAL60") myCurrentFormat = 5;
else if(height > 256) height = 256; else if(myDisplayFormat == "SECAM60") myCurrentFormat = 6;
if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" ||
myDisplayFormat == "SECAM60")
{
// Assume we've got ~262 scanlines (NTSC-like format)
myFramerate = 60.0;
myConsoleInfo.InitialFrameRate = "60";
}
else
{
// Assume we've got ~312 scanlines (PAL-like format)
myFramerate = 50.0;
myConsoleInfo.InitialFrameRate = "50";
// PAL ROMs normally need at least 250 lines
height = BSPF_max(height, 250u);
}
// Make sure these values fit within the bounds of the desktop
// If not, attempt to center vertically
if(height <= myOSystem->desktopHeight())
{
myTIA->setYStart(ystart);
myTIA->setHeight(height);
}
else
{
ystart += height - myOSystem->desktopHeight();
ystart = BSPF_min(ystart, 64u);
height = myOSystem->desktopHeight();
myTIA->setYStart(ystart);
myTIA->setHeight(height);
}
// Add the real controllers for this system // Add the real controllers for this system
// This must be done before the debugger is initialized // This must be done before the debugger is initialized
@ -275,54 +236,56 @@ bool Console::load(Serializer& in)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::toggleFormat() void Console::toggleFormat(int direction)
{ {
string format, message; string saveformat, message;
if(myDisplayFormat.compare(0, 4, "NTSC") == 0) if(direction == 1)
{ myCurrentFormat = (myCurrentFormat + 1) % 7;
if(myFramerate > 55.0) else if(direction == -1)
{ myCurrentFormat = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6;
format = "PAL60";
message = "PAL palette (PAL60)"; switch(myCurrentFormat)
} {
else case 0: // auto-detect
{ myTIA->update();
format = "PAL"; myDisplayFormat = myTIA->isPAL() ? "PAL" : "NTSC";
message = "PAL palette (PAL)"; message = "Auto-detect mode: " + myDisplayFormat;
} saveformat = "AUTO-DETECT";
} break;
else if(myDisplayFormat.compare(0, 3, "PAL") == 0) case 1:
{ saveformat = myDisplayFormat = "NTSC";
if(myFramerate > 55.0) message = "NTSC mode";
{ break;
format = "SECAM"; case 2:
message = "SECAM palette (SECAM60)"; saveformat = myDisplayFormat = "PAL";
} message = "PAL mode";
else break;
{ case 3:
format = "SECAM"; saveformat = myDisplayFormat = "SECAM";
message = "SECAM palette (SECAM)"; message = "SECAM mode";
} break;
} case 4:
else if(myDisplayFormat.compare(0, 5, "SECAM") == 0) saveformat = myDisplayFormat = "NTSC50";
{ message = "NTSC50 mode";
if(myFramerate > 55.0) break;
{ case 5:
format = "NTSC"; saveformat = myDisplayFormat = "PAL60";
message = "NTSC palette (NTSC)"; message = "PAL60 mode";
} break;
else case 6:
{ saveformat = myDisplayFormat = "SECAM60";
format = "NTSC50"; message = "SECAM60 mode";
message = "NTSC palette (NTSC50)"; break;
} }
} myProperties.set(Display_Format, saveformat);
myDisplayFormat = format;
myProperties.set(Display_Format, myDisplayFormat);
myOSystem->frameBuffer().showMessage(message);
setPalette(myOSystem->settings().getString("palette")); setPalette(myOSystem->settings().getString("palette"));
setTIAProperties();
myTIA->frameReset();
initializeVideo(); // takes care of refreshing the screen
myOSystem->frameBuffer().showMessage(message);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -605,6 +568,50 @@ void Console::changeHeight(int direction)
myProperties.set(Display_Height, val.str()); myProperties.set(Display_Height, val.str());
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::setTIAProperties()
{
// TODO - query these values directly from the TIA if value is 'AUTO'
uInt32 ystart = atoi(myProperties.get(Display_YStart).c_str());
if(ystart > 64) ystart = 64;
uInt32 height = atoi(myProperties.get(Display_Height).c_str());
if(height < 210) height = 210;
else if(height > 256) height = 256;
if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" ||
myDisplayFormat == "SECAM60")
{
// Assume we've got ~262 scanlines (NTSC-like format)
myFramerate = 60.0;
myConsoleInfo.InitialFrameRate = "60";
}
else
{
// Assume we've got ~312 scanlines (PAL-like format)
myFramerate = 50.0;
myConsoleInfo.InitialFrameRate = "50";
// PAL ROMs normally need at least 250 lines
height = BSPF_max(height, 250u);
}
// Make sure these values fit within the bounds of the desktop
// If not, attempt to center vertically
if(height <= myOSystem->desktopHeight())
{
myTIA->setYStart(ystart);
myTIA->setHeight(height);
}
else
{
ystart += height - myOSystem->desktopHeight();
ystart = BSPF_min(ystart, 64u);
height = myOSystem->desktopHeight();
myTIA->setYStart(ystart);
myTIA->setHeight(height);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::setControllers(const string& rommd5) void Console::setControllers(const string& rommd5)
{ {

View File

@ -182,8 +182,10 @@ class Console : public Serializable
public: public:
/** /**
Toggle between NTSC/PAL/SECAM (and variants) display format. Toggle between NTSC/PAL/SECAM (and variants) display format.
@param direction +1 indicates increase, -1 indicates decrease.
*/ */
void toggleFormat(); void toggleFormat(int direction = 1);
/** /**
Toggle between the available palettes. Toggle between the available palettes.
@ -285,6 +287,12 @@ class Console : public Serializable
void toggleFixedColors() const; void toggleFixedColors() const;
private: private:
/**
Sets various properties of the TIA (YStart, Height, etc) based on
the current display format.
*/
void setTIAProperties();
/** /**
Adds the left and right controllers to the console. Adds the left and right controllers to the console.
*/ */
@ -350,6 +358,9 @@ class Console : public Serializable
// The currently defined display framerate // The currently defined display framerate
float myFramerate; float myFramerate;
// Display format currently in use
uInt32 myCurrentFormat;
// Indicates whether an external palette was found and // Indicates whether an external palette was found and
// successfully loaded // successfully loaded
bool myUserPaletteDefined; bool myUserPaletteDefined;

View File

@ -576,8 +576,8 @@ void EventHandler::poll(uInt64 time)
toggleSAPortOrder(); toggleSAPortOrder();
break; break;
case KBDK_f: // Ctrl-f toggles NTSC/PAL mode case KBDK_f: // (Shift) Ctrl-f toggles NTSC/PAL/SECAM mode
myOSystem->console().toggleFormat(); myOSystem->console().toggleFormat(mod & KMOD_SHIFT ? -1 : 1);
break; break;
case KBDK_g: // Ctrl-g (un)grabs mouse case KBDK_g: // Ctrl-g (un)grabs mouse

View File

@ -30,7 +30,7 @@
#include "StateManager.hxx" #include "StateManager.hxx"
#define STATE_HEADER "03070000state" #define STATE_HEADER "03070100state"
#define MOVIE_HEADER "03030000movie" #define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -54,6 +54,7 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
myPartialFrameFlag(false), myPartialFrameFlag(false),
myAutoFrameEnabled(false), myAutoFrameEnabled(false),
myFrameCounter(0), myFrameCounter(0),
myPALFrameCounter(0),
myBitsEnabled(true), myBitsEnabled(true),
myCollisionsEnabled(true) myCollisionsEnabled(true)
@ -137,8 +138,35 @@ void TIA::reset()
// Should undriven pins be randomly driven high or low? // Should undriven pins be randomly driven high or low?
myTIAPinsDriven = mySettings.getBool("tiadriven"); myTIAPinsDriven = mySettings.getBool("tiadriven");
myFrameCounter = 0; myFrameCounter = myPALFrameCounter = 0;
myScanlineCountForLastFrame = 0; myScanlineCountForLastFrame = 0;
myCurrentP0Mask = &TIATables::PxMask[0][0][0][0];
myCurrentP1Mask = &TIATables::PxMask[0][0][0][0];
myCurrentM0Mask = &TIATables::MxMask[0][0][0][0];
myCurrentM1Mask = &TIATables::MxMask[0][0][0][0];
myCurrentBLMask = &TIATables::BLMask[0][0][0];
myCurrentPFMask = TIATables::PFMask[0];
// Recalculate the size of the display
toggleFixedColors(0);
frameReset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::frameReset()
{
// Clear frame buffers
clearBuffers();
// Reset pixel pointer and drawing flag
myFramePointer = myCurrentFrameBuffer;
// Calculate color clock offsets for starting and stopping frame drawing
// Note that although we always start drawing at scanline zero, the
// framebuffer that is exposed outside the class actually starts at 'ystart'
myFramePointerOffset = 160 * myFrameYStart;
myAutoFrameEnabled = (mySettings.getInt("framerate") <= 0); myAutoFrameEnabled = (mySettings.getInt("framerate") <= 0);
myFramerate = myConsole.getFramerate(); myFramerate = myConsole.getFramerate();
@ -169,32 +197,6 @@ void TIA::reset()
myMaximumNumberOfScanlines = 342; myMaximumNumberOfScanlines = 342;
} }
myCurrentP0Mask = &TIATables::PxMask[0][0][0][0];
myCurrentP1Mask = &TIATables::PxMask[0][0][0][0];
myCurrentM0Mask = &TIATables::MxMask[0][0][0][0];
myCurrentM1Mask = &TIATables::MxMask[0][0][0][0];
myCurrentBLMask = &TIATables::BLMask[0][0][0];
myCurrentPFMask = TIATables::PFMask[0];
// Recalculate the size of the display
toggleFixedColors(0);
frameReset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::frameReset()
{
// Clear frame buffers
clearBuffers();
// Reset pixel pointer and drawing flag
myFramePointer = myCurrentFrameBuffer;
// Calculate color clock offsets for starting and stopping frame drawing
// Note that although we always start drawing at scanline zero, the
// framebuffer that is exposed outside the class actually starts at 'ystart'
myFramePointerOffset = 160 * myFrameYStart;
// NTSC screens will process at least 262 scanlines, // NTSC screens will process at least 262 scanlines,
// while PAL will have at least 312 // while PAL will have at least 312
// In any event, at most 320 lines can be processed // In any event, at most 320 lines can be processed
@ -350,6 +352,7 @@ bool TIA::save(Serializer& out) const
out.putBool(myHMOVEBlankEnabled); out.putBool(myHMOVEBlankEnabled);
out.putInt(myFrameCounter); out.putInt(myFrameCounter);
out.putInt(myPALFrameCounter);
// Save the sound sample stuff ... // Save the sound sample stuff ...
mySound.save(out); mySound.save(out);
@ -452,7 +455,8 @@ bool TIA::load(Serializer& in)
myPreviousHMOVEPos = (Int32) in.getInt(); myPreviousHMOVEPos = (Int32) in.getInt();
myHMOVEBlankEnabled = in.getBool(); myHMOVEBlankEnabled = in.getBool();
myFrameCounter = (Int32) in.getInt(); myFrameCounter = in.getInt();
myPALFrameCounter = in.getInt();
// Load the sound sample stuff ... // Load the sound sample stuff ...
mySound.load(in); mySound.load(in);
@ -603,6 +607,8 @@ inline void TIA::endFrame()
// Stats counters // Stats counters
myFrameCounter++; myFrameCounter++;
if(myScanlineCountForLastFrame >= 287)
myPALFrameCounter++;
// Recalculate framerate. attempting to auto-correct for scanline 'jumps' // Recalculate framerate. attempting to auto-correct for scanline 'jumps'
if(myFrameCounter % 8 == 0 && myAutoFrameEnabled && if(myFrameCounter % 8 == 0 && myAutoFrameEnabled &&

View File

@ -216,6 +216,13 @@ class TIA : public Device
void enableColorLoss(bool mode) void enableColorLoss(bool mode)
{ myColorLossEnabled = myFramerate <= 55 ? mode : false; } { myColorLossEnabled = myFramerate <= 55 ? mode : false; }
/**
Answers whether this TIA runs at NTSC or PAL scanrates,
based on how many frames of out the total count are PAL frames.
*/
bool isPAL()
{ return float(myPALFrameCounter) / myFrameCounter >= (25.0/60.0); }
/** /**
Answers the current color clock we've gotten to on this scanline. Answers the current color clock we've gotten to on this scanline.
@ -605,8 +612,11 @@ class TIA : public Device
// Automatic framerate correction based on number of scanlines // Automatic framerate correction based on number of scanlines
bool myAutoFrameEnabled; bool myAutoFrameEnabled;
// Number of frames displayed by this TIA // Number of total frames displayed by this TIA
int myFrameCounter; uInt32 myFrameCounter;
// Number of PAL frames displayed by this TIA
uInt32 myPALFrameCounter;
// The framerate currently in use by the Console // The framerate currently in use by the Console
float myFramerate; float myFramerate;