diff --git a/Announce.txt b/Announce.txt index 6455bcd8c..a374363f2 100644 --- a/Announce.txt +++ b/Announce.txt @@ -9,7 +9,7 @@ SSSS ttt eeeee llll llll aaaaa =========================================================================== - Release 3.1 for Linux, Mac OSX and Windows + Release 3.1 for Linux, MacOSX and Windows =========================================================================== The Atari 2600 Video Computer System (VCS), introduced in 1977, was the @@ -31,7 +31,7 @@ distributions currently available are: * Binary zip for Windows, containing 32 and 64-bit versions : Stella-3.1-windows.zip - * Binary distribution for Mac OSX 32-bit & 64-bit : + * Binary distribution for MacOSX 32-bit & 64-bit : Stella-3.1-macosx.dmg (32-bit Universal Binary) Stella-3.1_intel-macosx.dmg (32/64-bit Intel-only) diff --git a/Changes.txt b/Changes.txt index 78aacfcee..1eec80e7f 100644 --- a/Changes.txt +++ b/Changes.txt @@ -133,6 +133,12 @@ This toggles showing of UI messages overlaid on the screen. Critical messages are still shown, though. + * Added ability to take multiple snapshots in a given interval every + x seconds. This is currently tied to the 'Shift-F12' key and is not + remappable (for now). The interval can be set with the 'ssdelay' + commandline argument, and defaults to 2. Currently, this can't be + changed from within the UI. + * Many changes to the FrameBuffer and UI code for 'smaller' systems. Stella will now scale correctly to small screens, down to 320x240 (which is the absolute lower limit supported). Related to this, diff --git a/docs/index.html b/docs/index.html index a8b4d6576..0741705d3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -918,6 +918,11 @@ snapshot in unscaled (1x) mode. + +
-ssdelay <delay>
+ Set the delay in seconds between taking snapshots in continuous snapshot mode (currently, 1 - 10). + +
-rominfo <rom>
Display detailed information about the given ROM, and then exit @@ -2217,6 +2222,12 @@ Control + l Control + l + + + Save continuous PNG snapshots + Shift-F12 + Shift-F12 +

UI keys in Text Editing areas (cannot be remapped)

diff --git a/src/debugger/CartDebug.cxx b/src/debugger/CartDebug.cxx index f427a7745..e0c89e36f 100644 --- a/src/debugger/CartDebug.cxx +++ b/src/debugger/CartDebug.cxx @@ -206,30 +206,40 @@ bool CartDebug::disassemble(const string& resolvedata, bool force) uInt16 PC = myDebugger.cpuDebug().pc(); int pcline = addressToLine(PC); bool changed = (force || myConsole.cartridge().bankChanged() || - (pcline == -1 && (PC & 0x1000)) || - mySystem.isPageDirty(0x1000, 0x1FFF)); + (pcline == -1) || mySystem.isPageDirty(0x1000, 0x1FFF)); + if(changed) { // Look at previous accesses to this bank to begin // If no previous address exists, use the current program counter uInt16 start = myStartAddresses[getBank()]; - if(start == 0 || pcline == -1) + if(start == 0 || (pcline == -1 && (PC & 0x1000))) start = myStartAddresses[getBank()] = PC; // For now, DiStella can't handle address space below 0x1000 - if(!(start & 0x1000)) - return false; + // However, we want to disassemble at least once, otherwise carts + // that run entirely from ZP RAM will have an empty disassembly + // TODO - this will be removed once Distella properly supports + // access below 0x1000 + uInt16 search = PC; + if(!(PC & 0x1000)) + { + if(myDisassembly.size() == 0) + search = start; + else + return false; + } // Check whether to use the 'resolvedata' functionality from Distella if(resolvedata == "never") - fillDisassemblyList(start, false, PC); + fillDisassemblyList(start, false, search); else if(resolvedata == "always") - fillDisassemblyList(start, true, PC); + fillDisassemblyList(start, true, search); else // 'auto' { // First try with resolvedata on, then turn off if PC isn't found - if(!fillDisassemblyList(start, true, PC)) - fillDisassemblyList(start, false, PC); + if(!fillDisassemblyList(start, true, search)) + fillDisassemblyList(start, false, search); } } diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 6b0986f85..48fd4b39c 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -151,7 +151,7 @@ inline void CartridgeDPCPlus::updateMusicModeDataFetchers() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPCPlus::writeByte(uInt8 value) { - switch (mySelectByte) + switch (mySelectByte & 0x7F) { case 0x00: { @@ -214,6 +214,9 @@ inline void CartridgeDPCPlus::writeByte(uInt8 value) break; } } + + if (mySelectByte & 0x80) + mySelectByte++; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -288,11 +291,10 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address) // Update the music data fetchers (counter & flag) updateMusicModeDataFetchers(); - uInt32 i = 0; - - i = myMusicVolume + ((myMusicVolume >> 12) * (uInt8) (myMusicWaveforms[0] >> 31)) + - ((myMusicVolume >> 16) * (uInt8) (myMusicWaveforms[1] >> 31)) + - ((myMusicVolume >> 24) * (uInt8) (myMusicWaveforms[2] >> 31)); + uInt32 i = myMusicVolume + + (((myMusicWaveforms[0] >> 31) & 1) ? (myMusicVolume >> 12): 0) + + (((myMusicWaveforms[1] >> 31) & 1) ? (myMusicVolume >> 16): 0) + + (((myMusicWaveforms[2] >> 31) & 1) ? (myMusicVolume >> 24): 0); result = (uInt8)i; break; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index fb1939378..04a2bfac0 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -170,6 +170,8 @@ void EventHandler::reset(State state) setEventState(state); myEvent->clear(); myOSystem->state().reset(); + + setContinuousSnapshots(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -448,6 +450,26 @@ void EventHandler::poll(uInt64 time) case SDLK_l: myOSystem->frameBuffer().toggleFrameStats(); break; + + case SDLK_F12: // TODO - make this remappable + if(myContSnapshotInterval == 0) + { + ostringstream buf; + uInt32 delay = myOSystem->settings().getInt("ssdelay"); + buf << "Enabling shotshots in " << delay << " second intervals"; + myOSystem->frameBuffer().showMessage(buf.str()); + setContinuousSnapshots(delay); + } + else + { + ostringstream buf; + buf << "Disabling snapshots, generated " + << (myContSnapshotCounter / myContSnapshotInterval) + << " files"; + myOSystem->frameBuffer().showMessage(buf.str()); + setContinuousSnapshots(0); + } + break; #if 0 // FIXME - these will be removed when a UI is added for event recording case SDLK_e: // Alt-e starts/stops event recording @@ -759,6 +781,11 @@ void EventHandler::poll(uInt64 time) for(unsigned int i = 0; i < cheats.size(); i++) cheats[i]->evaluate(); #endif + + // Handle continuous snapshots + if(myContSnapshotInterval > 0 && + (++myContSnapshotCounter % myContSnapshotInterval == 0)) + takeSnapshot(myContSnapshotCounter / myContSnapshotInterval); } } else if(myOverlay) @@ -1680,7 +1707,7 @@ void EventHandler::saveJoyHatMapping() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool EventHandler::isValidList(string& list, IntArray& map, uInt32 length) +bool EventHandler::isValidList(string& list, IntArray& map, uInt32 length) const { string key; Event::Type event; @@ -1701,7 +1728,7 @@ bool EventHandler::isValidList(string& list, IntArray& map, uInt32 length) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline bool EventHandler::eventIsAnalog(Event::Type event) +inline bool EventHandler::eventIsAnalog(Event::Type event) const { switch((int)event) { @@ -1716,7 +1743,7 @@ inline bool EventHandler::eventIsAnalog(Event::Type event) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -StringList EventHandler::getActionList(EventMode mode) +StringList EventHandler::getActionList(EventMode mode) const { StringList l; @@ -1738,7 +1765,7 @@ StringList EventHandler::getActionList(EventMode mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Event::Type EventHandler::eventAtIndex(int idx, EventMode mode) +Event::Type EventHandler::eventAtIndex(int idx, EventMode mode) const { switch(mode) { @@ -1761,7 +1788,7 @@ Event::Type EventHandler::eventAtIndex(int idx, EventMode mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string EventHandler::actionAtIndex(int idx, EventMode mode) +string EventHandler::actionAtIndex(int idx, EventMode mode) const { switch(mode) { @@ -1784,7 +1811,7 @@ string EventHandler::actionAtIndex(int idx, EventMode mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -string EventHandler::keyAtIndex(int idx, EventMode mode) +string EventHandler::keyAtIndex(int idx, EventMode mode) const { switch(mode) { @@ -1807,11 +1834,12 @@ string EventHandler::keyAtIndex(int idx, EventMode mode) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void EventHandler::takeSnapshot() +void EventHandler::takeSnapshot(uInt32 number) { // Figure out the correct snapshot name string filename; string sspath = myOSystem->snapshotDir(); + bool showmessage = number == 0; if(sspath.length() > 0) if(sspath.substr(sspath.length()-1) != BSPF_PATH_SEPARATOR) @@ -1819,7 +1847,13 @@ void EventHandler::takeSnapshot() sspath += myOSystem->console().properties().get(Cartridge_Name); // Check whether we want multiple snapshots created - if(!myOSystem->settings().getBool("sssingle")) + if(number > 0) + { + ostringstream buf; + buf << sspath << "_" << number << ".png"; + filename = buf.str(); + } + else if(!myOSystem->settings().getBool("sssingle")) { // Determine if the file already exists, checking each successive filename // until one doesn't exist @@ -1848,7 +1882,8 @@ void EventHandler::takeSnapshot() string msg = Snapshot::savePNG(myOSystem->frameBuffer(), myOSystem->console().tia(), myOSystem->console().properties(), filename); - myOSystem->frameBuffer().showMessage(msg); + if(showmessage) + myOSystem->frameBuffer().showMessage(msg); } else { @@ -1860,7 +1895,8 @@ void EventHandler::takeSnapshot() // Re-enable old messages myOSystem->frameBuffer().enableMessages(true); - myOSystem->frameBuffer().showMessage(msg); + if(showmessage) + myOSystem->frameBuffer().showMessage(msg); } } @@ -1882,6 +1918,13 @@ void EventHandler::setPaddleMode(int num, bool showmessage) myMouseEnabled = false; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void EventHandler::setContinuousSnapshots(uInt32 interval) +{ + myContSnapshotInterval = myOSystem->frameRate() * interval; + myContSnapshotCounter = 0; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::enterMenuMode(State state) { diff --git a/src/emucore/EventHandler.hxx b/src/emucore/EventHandler.hxx index 7af133227..f74f54eed 100644 --- a/src/emucore/EventHandler.hxx +++ b/src/emucore/EventHandler.hxx @@ -163,7 +163,7 @@ class EventHandler @return The State type */ - inline State state() { return myState; } + inline State state() const { return myState; } /** Resets the state machine of the EventHandler to the defaults @@ -185,7 +185,16 @@ class EventHandler */ void setPaddleMode(int num, bool showmessage = false); - inline bool kbdAlt(int mod) + /** + Set the number of seconds between taking a snapshot in + continuous snapshot mode. Setting an interval of 0 disables + continuous snapshots. + + @param interval Interval in seconds between snapshots + */ + void setContinuousSnapshots(uInt32 interval); + + inline bool kbdAlt(int mod) const { #ifndef MAC_OSX return (mod & KMOD_ALT); @@ -194,12 +203,12 @@ class EventHandler #endif } - inline bool kbdControl(int mod) + inline bool kbdControl(int mod) const { return (mod & KMOD_CTRL) > 0; } - inline bool kbdShift(int mod) + inline bool kbdShift(int mod) const { return (mod & KMOD_SHIFT); } @@ -208,7 +217,7 @@ class EventHandler void leaveMenuMode(); bool enterDebugMode(); void leaveDebugMode(); - void takeSnapshot(); + void takeSnapshot(uInt32 number = 0); /** Send an event directly to the event handler. @@ -219,24 +228,24 @@ class EventHandler */ void handleEvent(Event::Type type, Int32 value); - inline bool frying() { return myFryingFlag; } + inline bool frying() const { return myFryingFlag; } - inline SDL_Joystick* getJoystick(int i) { return ourJoysticks[i].stick; } + inline SDL_Joystick* getJoystick(int i) const { return ourJoysticks[i].stick; } - StringList getActionList(EventMode mode); + StringList getActionList(EventMode mode) const; - inline Event::Type eventForKey(int key, EventMode mode) + inline Event::Type eventForKey(int key, EventMode mode) const { return myKeyTable[key][mode]; } - inline Event::Type eventForJoyButton(int stick, int button, EventMode mode) + inline Event::Type eventForJoyButton(int stick, int button, EventMode mode) const { return myJoyTable[stick][button][mode]; } - inline Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) + inline Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const { return myJoyAxisTable[stick][axis][(value > 0)][mode]; } - inline Event::Type eventForJoyHat(int stick, int hat, int value, EventMode mode) + inline Event::Type eventForJoyHat(int stick, int hat, int value, EventMode mode) const { return myJoyHatTable[stick][hat][value][mode]; } - Event::Type eventAtIndex(int idx, EventMode mode); - string actionAtIndex(int idx, EventMode mode); - string keyAtIndex(int idx, EventMode mode); + Event::Type eventAtIndex(int idx, EventMode mode) const; + string actionAtIndex(int idx, EventMode mode) const; + string keyAtIndex(int idx, EventMode mode) const; /** Bind a key to an event/action and regenerate the mapping array(s) @@ -384,7 +393,7 @@ class EventHandler @return True if valid list, else false */ - bool isValidList(string& list, IntArray& map, uInt32 length); + bool isValidList(string& list, IntArray& map, uInt32 length) const; /** Tests if a given event should use continuous/analog values. @@ -392,7 +401,7 @@ class EventHandler @param event The event to test for analog processing @return True if analog, else false */ - inline bool eventIsAnalog(Event::Type event); + inline bool eventIsAnalog(Event::Type event) const; void setEventState(State state); @@ -490,6 +499,10 @@ class EventHandler // a Ctrl combo when it isn't wanted) bool myUseCtrlKeyFlag; + // Used for continuous snapshot mode + uInt32 myContSnapshotInterval; + uInt32 myContSnapshotCounter; + // Indicates which paddle the mouse currently emulates Int8 myPaddleMode; diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index e8863b0b2..2e476c316 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -47,8 +47,7 @@ FrameBuffer::FrameBuffer(OSystem* osystem) myUsePhosphor(false), myPhosphorBlend(77), myInitializedCount(0), - myPausedCount(0), - mySurfaceCount(0) + myPausedCount(0) { myMsg.surface = myStatsMsg.surface = NULL; myMsg.surfaceID = myStatsMsg.surfaceID = -1; @@ -317,7 +316,7 @@ void FrameBuffer::enableMessages(bool enable) { if(enable) { - // Only re-anable frame stats if they were already enabled before + // Only re-enable frame stats if they were already enabled before myStatsMsg.enabled = myOSystem->settings().getBool("stats"); } else @@ -483,11 +482,10 @@ int FrameBuffer::allocateSurface(int w, int h, bool useBase) FBSurface* surface = createSurface(w, h, useBase); // Add it to the list - mySurfaceList.insert(make_pair(mySurfaceCount, surface)); - mySurfaceCount++; + mySurfaceList.insert(make_pair(mySurfaceList.size(), surface)); // Return a reference to it - return mySurfaceCount - 1; + return mySurfaceList.size() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx index 5fef132fb..abcf047ff 100644 --- a/src/emucore/FrameBuffer.hxx +++ b/src/emucore/FrameBuffer.hxx @@ -575,7 +575,6 @@ class FrameBuffer // Holds a reference to all the surfaces that have been created map mySurfaceList; - int mySurfaceCount; // Holds static strings for the remap menu (emulation and menu events) static GraphicsMode ourGraphicsModes[GFX_NumModes]; diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx index bba230b7c..8f66d63c6 100644 --- a/src/emucore/Settings.cxx +++ b/src/emucore/Settings.cxx @@ -92,6 +92,7 @@ Settings::Settings(OSystem* osystem) setInternal("ssdir", ""); setInternal("sssingle", "false"); setInternal("ss1x", "false"); + setInternal("ssdelay", "2"); // Config files and paths setInternal("romdir", "~"); @@ -269,6 +270,10 @@ void Settings::validate() if(i < 1) setInternal("pspeed", "1"); else if(i > 15) setInternal("pspeed", "15"); + i = getInt("ssdelay"); + if(i < 1) setInternal("ssdelay", "2"); + else if(i > 10) setInternal("ssdelay", "10"); + s = getString("palette"); if(s != "standard" && s != "z26" && s != "user") setInternal("palette", "standard"); @@ -373,6 +378,7 @@ void Settings::usage() << " -ssdir The directory to save snapshot files to\n" << " -sssingle <1|0> Generate single snapshot instead of many\n" << " -ss1x <1|0> Generate TIA snapshot in 1x mode (ignore scaling/effects)\n" + << " -ssdelay Number of seconds between snapshots in continuous snapshot mode\n" << endl << " -rominfo Display detailed information for the given ROM\n" << " -listrominfo Display contents of stella.pro, one line per ROM entry\n"