Merge branch 'release/5.1'

This commit is contained in:
Christian Speckner 2018-02-04 23:48:45 +01:00
commit f7c445fb7c
34 changed files with 328 additions and 309 deletions

View File

@ -9,7 +9,7 @@
SSSS ttt eeeee llll llll aaaaa SSSS ttt eeeee llll llll aaaaa
=========================================================================== ===========================================================================
Release 5.0.2 for Linux, MacOSX and Windows Release 5.1 for Linux, MacOSX and Windows
=========================================================================== ===========================================================================
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
@ -21,30 +21,30 @@ all of your favourite Atari 2600 games again! Stella was originally
developed for Linux by Bradford W. Mott, however, it has been ported to a developed for Linux by Bradford W. Mott, however, it has been ported to a
number of other platforms and is currently maintained by Stephen Anthony. number of other platforms and is currently maintained by Stephen Anthony.
This is the 5.0.2 release of Stella for Linux, Mac OSX and Windows. The This is the 5.1 release of Stella for Linux, Mac OSX and Windows. The
distributions currently available are: distributions currently available are:
* Binaries for Windows XP_SP3(*)/Vista/7/8/10 : * Binaries for Windows XP_SP3(*)/Vista/7/8/10 :
Stella-5.0.2-win32.exe (32-bit EXE installer) Stella-5.1-win32.exe (32-bit EXE installer)
Stella-5.0.2-x64.exe (64-bit EXE installer) Stella-5.1-x64.exe (64-bit EXE installer)
Stella-5.0.2-windows.zip (32/64 bit versions) Stella-5.1-windows.zip (32/64 bit versions)
(*) Note: Support for Windows XP is problematic on some systems, (*) Note: Support for Windows XP is problematic on some systems,
and will probably be discontinued in a future release. and will probably be discontinued in a future release.
* Binary distribution for MacOS X 10.7 and above : * Binary distribution for MacOS X 10.7 and above :
Stella-5.0.2-macosx.dmg (64-bit Intel) Stella-5.1-macosx.dmg (64-bit Intel)
* Binary distribution in 32-bit & 64-bit Ubuntu DEB format : * Binary distribution in 32-bit & 64-bit Ubuntu DEB format :
stella_5.0.2-1_i386.deb stella_5.1-1_i386.deb
stella_5.0.2-1_amd64.deb stella_5.1-1_amd64.deb
* Binary distribution in 32-bit & 64-bit RPM format : * Binary distribution in 32-bit & 64-bit RPM format :
stella-5.0.2-2.i386.rpm stella-5.1-2.i386.rpm
stella-5.0.2-2.x86_64.rpm stella-5.1-2.x86_64.rpm
* Source code distribution for all platforms : * Source code distribution for all platforms :
stella-5.0.2-src.tar.xz stella-5.1-src.tar.xz
Distribution Site Distribution Site

View File

@ -1,18 +1,8 @@
5.0.2 to 5.1: (January xx, 2018) 5.0.2 to 5.1: (February 4, 2018)
* Thumbulator support is not conditional any more. * Added "Time Machine" mode, which automatically creates save states
in user-defined intervals. The user can navigate back and forth within
* Don't trap write accesses to the datastream pointers in CDF and BUS. these states inside the emulator and the debugger.
This fixes -dev.thumb.trapfatal 1.
* Complete rework of TV mode and ystart autodetection. The new
implementation is more robust and reduces startup time.
* Add two "grace lines" of black to the top of the frame when
autodetecting ystart.
* Support UNIX style builds (configure / make) on OSX with both
XCode / clang and g++.
* Huge improvements to the disassembly view in the debugger and * Huge improvements to the disassembly view in the debugger and
disassembly files created: disassembly files created:
@ -23,9 +13,30 @@
- improved cycle count (page penalties, sums created in disassembly) - improved cycle count (page penalties, sums created in disassembly)
- improved handling of instruction masking opcodes (e.g. BIT) - improved handling of instruction masking opcodes (e.g. BIT)
* Added "Time Machine" mode, which automatically creates save states * Fixed change tracking bug during rewind; changes were accumulated
in user-defined intervals. The user can navigate back and forth within instead of being displayed only for the last rewind step.
these states inside the emulator and the debugger.
* Extended 'rewind' to take a second parameter which allows rewinding
multiple states.
* Added 'unwind' command, which undoes the latest rewind(s)
* Added '<' (unwind) button to debugger.
* Thumbulator support is not conditional any more.
* Moved various developer related settings in new Developer Settings
dialog. These settings now come in two groups (player/developer) and
allow switching all settings at once.
* Don't trap write accesses to the datastream pointers in CDF and BUS.
This fixes -dev.thumb.trapfatal 1.
* Complete rework of TV mode and ystart autodetection. The new
implementation is more robust and reduces startup time.
* Add two "grace lines" of black to the top of the frame when
autodetecting ystart.
* Fixed Genesis controller autodetect (Stay Frosty 2, Scramble, etc). * Fixed Genesis controller autodetect (Stay Frosty 2, Scramble, etc).
@ -48,9 +59,6 @@
information). In the case of 'saveses', the filename is now named information). In the case of 'saveses', the filename is now named
based on the date and time of when the command was entered. based on the date and time of when the command was entered.
* Fixed change tracking bug during rewind; changes were accumulated
instead of being displayed only for the last rewind step.
* Fixed bug with saving snapshots in 1x mode; there was graphical * Fixed bug with saving snapshots in 1x mode; there was graphical
corruption in some cases. Such snapshots also now include any TV corruption in some cases. Such snapshots also now include any TV
effects / phosphor blending currently in use. effects / phosphor blending currently in use.
@ -72,22 +80,16 @@
all ROMs or only the current one. Also added a message (configurable) all ROMs or only the current one. Also added a message (configurable)
when the flash memory is accessed. when the flash memory is accessed.
* Moved various developer related settings in new Developer Settings * Access to the AtariVox/SaveKey can be signaled with a message.
dialog. These settings now come in two groups (player/developer) and
allow switching all settings at once.
* Added new interface palette 'Light' * Added new interface palette 'Light'.
* Improved tab auto-complete in debugger * Frame stats display made transparent. Also it now displays the real
frame rate and if the developer settings group is enabled.
* Added conditional traps and savestate creation to debugger * Improved tab auto-complete in debugger.
* Extended 'rewind' to take a second parameter which allows rewinding * Added conditional traps and savestate creation to debugger.
multiple states.
* Added 'unwind' command, which undoes the latest rewind(s)
* Added '<' (unwind) button to debugger.
* Added 'Options...' button to debugger which gives access to the options * Added 'Options...' button to debugger which gives access to the options
menu during debugging. menu during debugging.
@ -107,7 +109,7 @@
* Improved change tracking; more values are tracked and change tracking * Improved change tracking; more values are tracked and change tracking
now works in case of a break too. now works in case of a break too.
* Added widgets for trackball and SaveKey/AtariVox controllers * Added widgets for trackball and SaveKey/AtariVox controllers.
* Improved emulation of 'FE' bankswitch scheme (no user-visible changes, * Improved emulation of 'FE' bankswitch scheme (no user-visible changes,
but internally the emulation is much more accurate compared to the but internally the emulation is much more accurate compared to the
@ -122,6 +124,9 @@
* Added ROM properties for 'Zippy the Porcupine' ROMs, and updated * Added ROM properties for 'Zippy the Porcupine' ROMs, and updated
info for all "Chris Spry (Sprybug)" ROMs. info for all "Chris Spry (Sprybug)" ROMs.
* Support UNIX style builds (configure / make) on OSX with both
XCode / clang and g++.
* Fixed error when building with uClibc-ng for ARM (thanks to Sergio * Fixed error when building with uClibc-ng for ARM (thanks to Sergio
Prado). Prado).

7
debian/changelog vendored
View File

@ -1,3 +1,10 @@
stella (5.1-1) stable; urgency=high
* Version 5.1 release
-- Stephen Anthony <stephena@users.sf.net> Sun, 4 Feb 2018 17:09:59 -0230
stella (5.0.2-1) stable; urgency=high stella (5.0.2-1) stable; urgency=high
* Version 5.0.2 release * Version 5.0.2 release

View File

@ -348,27 +348,27 @@ size can be configured e.g. in the
<td>Frame+1</td> <td>Frame+1</td>
</tr> </tr>
<tr> <tr>
<td>Control-r</td> <td>Alt-Left arrow</td>
<td>Rewind 1</td> <td>Rewind 1</td>
</tr> </tr>
<tr> <tr>
<td>Control-Shift-r</td> <td>Shift-Alt-Left arrow</td>
<td>Rewind 10</td> <td>Rewind 10</td>
</tr> </tr>
<tr> <tr>
<td>Control-Alt-r</td> <td>Alt-Down arrow</td>
<td>Rewind all</td> <td>Rewind all</td>
</tr> </tr>
<tr> <tr>
<td>Control-y</td> <td>Alt-Right arrow</td>
<td>Unwind 1</td> <td>Unwind 1</td>
</tr> </tr>
<tr> <tr>
<td>Control-Shift-y</td> <td>Shift-Alt-Right arrow</td>
<td>Unwind 10</td> <td>Unwind 10</td>
</tr> </tr>
<tr> <tr>
<td>Control-Alt-y</td> <td>Alt-Up arrow</td>
<td>Unwind all</td> <td>Unwind all</td>
</tr> </tr>
<tr> <tr>
@ -377,6 +377,7 @@ size can be configured e.g. in the
</tr> </tr>
</table> </table>
</p> </p>
For MacOS use 'Cmd' instead of &nbsp;'Alt' key.
<p>To the left of the global buttons, you find the "Options..." button.</p> <p>To the left of the global buttons, you find the "Options..." button.</p>
<ul> <ul>
<p><img src="graphics/debugger_options.png"></p> <p><img src="graphics/debugger_options.png"></p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -61,7 +61,7 @@
<br><br><br> <br><br><br>
<center><b>February 1999 - January 2018</b></center> <center><b>February 1999 - February 2018</b></center>
<center><b>The Stella Team</b></center> <center><b>The Stella Team</b></center>
<center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center> <center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center>
@ -1622,32 +1622,38 @@
</tr> </tr>
<tr> <tr>
<td>Rewind by one state (pauses emulation)</td> <td>Enter/Exit the <a href="#TimeMachine"><b>Time Machine</b></a> dialog</td>
<td>t to enter, t/Escape/Space to exit</td>
<td>t to enter, t/Escape/Space to exit</td>
</tr>
<tr>
<td>Rewind by one state (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Left arrow</td> <td>Alt + Left arrow</td>
<td>Cmd + Left arrow</td> <td>Cmd + Left arrow</td>
</tr> </tr>
<tr> <tr>
<td>Rewind by 10 states (pauses emulation)</td> <td>Rewind by 10 states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Shift-Alt + Left arrow</td> <td>Shift-Alt + Left arrow</td>
<td>Shift-Cmd + Left arrow</td> <td>Shift-Cmd + Left arrow</td>
</tr> </tr>
<tr> <tr>
<td>Rewind all states (pauses emulation)</td> <td>Rewind all states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Down arrow</td> <td>Alt + Down arrow</td>
<td>Cmd + Down arrow</td> <td>Cmd + Down arrow</td>
</tr> </tr>
<tr> <tr>
<td>Unwind by one state (pauses emulation)</td> <td>Unwind by one state (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Right arrow</td> <td>Alt + Right arrow</td>
<td>Cmd + Right arrow</td> <td>Cmd + Right arrow</td>
</tr> </tr>
<tr> <tr>
<td>Unwind by 10 states (pauses emulation)</td> <td>Unwind by 10 states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Shift-Alt + Right arrow</td> <td>Shift-Alt + Right arrow</td>
<td>Shift-Cmd + Right arrow</td> <td>Shift-Cmd + Right arrow</td>
</tr> </tr>
<tr> <tr>
<td>Unwind all states (pauses emulation)</td> <td>Unwind all states (enters the <a href="#TimeMachine"><b>Time Machine</b></a> dialog)</td>
<td>Alt + Up arrow</td> <td>Alt + Up arrow</td>
<td>Cmd + Up arrow</td> <td>Cmd + Up arrow</td>
</tr> </tr>
@ -1794,36 +1800,49 @@
<a name="TimeMachine">Stella's 'Time Machine'</a></h2> <a name="TimeMachine">Stella's 'Time Machine'</a></h2>
<p>A special feature of Stella is the 'Time Machine' mode. In this mode, Stella <p>A special feature of Stella is the 'Time Machine' mode. In this mode, Stella
automatically creates savestates in regular, user-defined intervals. You can then automatically creates savestates in regular, user-defined intervals. At any time,
interrupt the current emulation and navigate back and forth within the timeline. the user can interrupt the current emulation and navigate back and forth
within the saved timeline.
This can be done either by using the Time Machine hotkeys described in This can be done either by using the Time Machine hotkeys described in
<a href="#Hotkeys"><b>Hotkeys</b> - Other Keys</a> or by using the Time Machine <a href="#Hotkeys"><b>Hotkeys</b> - Other Keys</a> or by using the Time Machine
dialog. To enter this dialog, either use one of the hotkeys or press 'T'.</p> dialog. This dialog is automatically entered when using one of the Time Machine
hotkeys. The hotkeys continue to function within the dialog.</p>
<p><b>Time Machine</b> dialog:</p> <p><b>Time Machine</b> dialog:</p>
<table border="5" cellpadding="2" frame="box" rules="none"> <td><img src="graphics/timemachine.png"></td>
<tr>
<td>TODO: Screenshot</td> <p>The dialog items are explained in the following two tables.</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top"> <p><b>Top row (left to right)</b></p>
<table border="1" cellpadding="4"> <table border="1" cellpadding="4">
<tr><th>Item</th><th>Description</th></tr> <tr><th>Item</th><th>Description</th></tr>
<tr><td>Button</td><td>TODO</td></tr> <tr><td>Current state</td><td>Shows the currently loaded state's number</td></tr>
<tr><td>Button</td><td></td></tr> <tr><td>'Timeline' slider</td><td>Shows the position of the current state in the
<tr><td>Button</td><td></td></tr> recorded timeline. A state can be selected by dragging the slider with the mouse.
<tr><td>Button</td><td></td></tr> To visualize state compression, small marks split the timeline into five, equally
<tr><td>Button</td><td></td></tr> sized state number intervals.</td></tr>
<tr><td>Button</td><td></td></tr> <tr><td>Total states</td><td>Shows the total number of save states in the
<tr><td>Button</td><td></td></tr> Time Machine</td></tr>
</table> </table>
</td> <p><b>Bottom row (left to right)</b></p>
</tr> <table border="1" cellpadding="4">
<tr><th>Item</th><th>Description</th></tr>
<tr><td>Current time</td><td>Shows the time of the currently selected status,
relative to the first one</td></tr>
<tr><td>'Rewind All' button</td><td>Navigates back to the begin of the timeline</td></tr>
<tr><td>'Rewind One' button</td><td>Navigates back by one state</td></tr>
<tr><td>'Continue' button</td><td>Exits the dialog and continues emulation.</td></tr>
<tr><td>Navigation info</td><td>Informs about the interval of the user's last
Time Machine navigation. The interval can vary if the timeline is compressed.</td></tr>
<tr><td>'Unwind One' button</td><td>Navigates forward by one state</td></tr>
<tr><td>'Unwind All' button</td><td>Navigates forward to the end of the timeline</td></tr>
<tr><td>Total time</td><td>Shows the total time covered by the save states
(aka 'Horizon')</td></tr>
</table> </table>
<br> <br>
<p>The 'Time Machine' mode can be configured by the user. For details see <p>The 'Time Machine' mode can be configured by the user. For details see
<a href="#Debugger"><b>Developer Options</b> - Time Machine dialog</a></h2>.</p> <a href="#Debugger"><b>Developer Options</b> - Time Machine</a></h2> tab.</p>
<!-- ///////////////////////////////////////////////////////////////////////// --> <!-- ///////////////////////////////////////////////////////////////////////// -->
<br><br> <br><br>
@ -2540,8 +2559,12 @@
<td>The default of true allows the Thumb ARM emulation to <td>The default of true allows the Thumb ARM emulation to
throw an exception and enter the debugger on fatal errors. When disabled, such throw an exception and enter the debugger on fatal errors. When disabled, such
fatal errors are simply logged, and emulation continues. Do not use this fatal errors are simply logged, and emulation continues. Do not use this
unless you know exactly what you're doing, as it changes the behaviour as compared unless you know exactly what you're doing, as it changes the behaviour as
to real hardware.</td> compared to real hardware.</td>
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;eepromaccess &lt;1|0&gt;</pre></td>
<td>When enabled, each read or write access to the AtariVox/SaveKey EEPROM is
signalled by a message.</td>
</tr><tr> </tr><tr>
<td><pre>-&lt;plr.|dev.&gt;tv.jitter &lt;1|0&gt;</pre></td> <td><pre>-&lt;plr.|dev.&gt;tv.jitter &lt;1|0&gt;</pre></td>
<td>Enable TV jitter/roll effect, when there are too many or too few scanlines <td>Enable TV jitter/roll effect, when there are too many or too few scanlines
@ -2740,13 +2763,15 @@
</td> </td>
</tr> </tr>
</table> </table>
<p><b>Audit ROMs</b> dialog:</p> <br>
<p><b>Developer Settings</b> dialog:</p>
<table border="5" cellpadding="2" frame="box" rules="none"> <table border="5" cellpadding="2" frame="box" rules="none">
<tr> <tr>
<td><img src="graphics/romaudit.png"></td> <td><img src="graphics/options_developer.png"></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top"><br>This dialog is described in further detail in <td valign="top"><br>This tab is described in further detail in
<b>Advanced Configuration - <a href="#ROMAudit">ROM Audit Mode</a></b>.</td> <b>Advanced Configuration - <a href="#Debugger">Developer Options/Integrated Debugger</a></b>.</td>
</td>
</tr> </tr>
</table> </table>
<br> <br>
@ -2760,18 +2785,17 @@
</td> </td>
</tr> </tr>
</table> </table>
<br> <br>
<p><b>Developer Settings</b> dialog:</p> <p><b>Audit ROMs</b> dialog:</p>
<table border="5" cellpadding="2" frame="box" rules="none"> <table border="5" cellpadding="2" frame="box" rules="none">
<tr> <tr>
<td><img src="graphics/options_developer.png"></td> <td><img src="graphics/romaudit.png"></td>
<td>&nbsp;&nbsp;&nbsp;&nbsp;</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;</td>
<td valign="top"><br>This tab is described in further detail in <td valign="top"><br>This dialog is described in further detail in
<b>Advanced Configuration - <a href="#Debugger">Developer Options/Integrated Debugger</a></b>.</td> <b>Advanced Configuration - <a href="#ROMAudit">ROM Audit Mode</a></b>.</td>
</td>
</tr> </tr>
</table> </table>
<br>
</blockquote> </blockquote>
<h2><b><a name="Remapping">Event Remapping/Input Devices</a></b></h2> <h2><b><a name="Remapping">Event Remapping/Input Devices</a></b></h2>
@ -3115,6 +3139,7 @@
<td>Thumb ARM emulation throws an exception and enters the debugger on fatal errors</td> <td>Thumb ARM emulation throws an exception and enters the debugger on fatal errors</td>
<td><span style="white-space:nowrap">-plr.thumb.trapfatal<br/>-dev.thumb.trapfatal</span></td> <td><span style="white-space:nowrap">-plr.thumb.trapfatal<br/>-dev.thumb.trapfatal</span></td>
</tr> </tr>
<tr><td>Display AtariVox...</td><td>Display a message when the AtariVox/SaveKey EEPROM is read or written</td><td>-plr.eepromaccess<br/>-dev.eepromaccess</td></tr>
</table> </table>
</td> </td>
</tr> </tr>

View File

@ -78,6 +78,9 @@ class LinkedObjectPool
SLOW, but only required for messages SLOW, but only required for messages
*/ */
uInt32 currentIdx() const { uInt32 currentIdx() const {
if(empty())
return 0;
iter it = myCurrent; iter it = myCurrent;
uInt32 idx = 1; uInt32 idx = 1;

View File

@ -284,7 +284,6 @@ string RewindManager::getUnitString(Int64 cycles)
const Int32 PAL_FREQ = 1182298; // ~76*312*50 const Int32 PAL_FREQ = 1182298; // ~76*312*50
const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second
// TODO: do we need hours here? don't think so
const Int32 NUM_UNITS = 5; const Int32 NUM_UNITS = 5;
const string UNIT_NAMES[NUM_UNITS] = { "cycle", "scanline", "frame", "second", "minute" }; const string UNIT_NAMES[NUM_UNITS] = { "cycle", "scanline", "frame", "second", "minute" };
const Int64 UNIT_CYCLES[NUM_UNITS + 1] = { 1, 76, 76 * scanlines, freq, freq * 60, Int64(1) << 62 }; const Int64 UNIT_CYCLES[NUM_UNITS + 1] = { 1, 76, 76 * scanlines, freq, freq * 60, Int64(1) << 62 };
@ -298,7 +297,7 @@ string RewindManager::getUnitString(Int64 cycles)
{ {
// use the lower unit up to twice the nextCycles unit, except for an exact match of the nextCycles unit // use the lower unit up to twice the nextCycles unit, except for an exact match of the nextCycles unit
// TODO: does the latter make sense, e.g. for ROMs with changing scanlines? // TODO: does the latter make sense, e.g. for ROMs with changing scanlines?
if(cycles == 0 || cycles < UNIT_CYCLES[i + 1] * 2 && cycles % UNIT_CYCLES[i + 1] != 0) if(cycles == 0 || (cycles < UNIT_CYCLES[i + 1] * 2 && cycles % UNIT_CYCLES[i + 1] != 0))
break; break;
} }
result << cycles / UNIT_CYCLES[i] << " " << UNIT_NAMES[i]; result << cycles / UNIT_CYCLES[i] << " " << UNIT_NAMES[i];
@ -309,14 +308,13 @@ string RewindManager::getUnitString(Int64 cycles)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::getFirstCycles() const uInt64 RewindManager::getFirstCycles() const
{ {
// TODO: check if valid return !myStateList.empty() ? myStateList.first()->cycles : 0;
return Common::LinkedObjectPool<RewindState>::const_iter(myStateList.first())->cycles;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::getCurrentCycles() const uInt64 RewindManager::getCurrentCycles() const
{ {
if(myStateList.currentIsValid()) if(myStateList.currentIsValid())
return myStateList.current().cycles; return myStateList.current().cycles;
@ -325,10 +323,9 @@ uInt32 RewindManager::getCurrentCycles() const
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::getLastCycles() const uInt64 RewindManager::getLastCycles() const
{ {
// TODO: check if valid return !myStateList.empty() ? myStateList.last()->cycles : 0;
return Common::LinkedObjectPool<RewindState>::const_iter(myStateList.last())->cycles;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -149,9 +149,9 @@ class RewindManager
uInt32 getCurrentIdx() { return myStateList.currentIdx(); } uInt32 getCurrentIdx() { return myStateList.currentIdx(); }
uInt32 getLastIdx() { return myStateList.size(); } uInt32 getLastIdx() { return myStateList.size(); }
uInt32 getFirstCycles() const; uInt64 getFirstCycles() const;
uInt32 getCurrentCycles() const; uInt64 getCurrentCycles() const;
uInt32 getLastCycles() const; uInt64 getLastCycles() const;
/** /**
Get a collection of cycle timestamps, offset from the first one in Get a collection of cycle timestamps, offset from the first one in

View File

@ -49,6 +49,15 @@ class FixedStack
T pop() { return std::move(_stack[--_size]); } T pop() { return std::move(_stack[--_size]); }
uInt32 size() const { return _size; } uInt32 size() const { return _size; }
void replace(const T& oldItem, const T& newItem) {
for(uInt32 i = 0; i < _size; ++i) {
if(_stack[i] == oldItem) {
_stack[i] = newItem;
return;
}
}
}
// Apply the given function to every item in the stack // Apply the given function to every item in the stack
// We do it this way so the stack API can be preserved, // We do it this way so the stack API can be preserved,
// and no access to individual elements is allowed outside // and no access to individual elements is allowed outside

View File

@ -27,7 +27,7 @@
#include "StateManager.hxx" #include "StateManager.hxx"
#define STATE_HEADER "05009901state" #define STATE_HEADER "05010000state"
// #define MOVIE_HEADER "03030000movie" // #define MOVIE_HEADER "03030000movie"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -18,7 +18,7 @@
#ifndef VERSION_HXX #ifndef VERSION_HXX
#define VERSION_HXX #define VERSION_HXX
#define STELLA_VERSION "5.1_b1" #define STELLA_VERSION "5.1"
#define STELLA_BUILD "3826" #define STELLA_BUILD "4138"
#endif #endif

View File

@ -76,6 +76,7 @@ using std::memcpy;
// Common array types // Common array types
using IntArray = std::vector<Int32>; using IntArray = std::vector<Int32>;
using uIntArray = std::vector<uInt32>;
using BoolArray = std::vector<bool>; using BoolArray = std::vector<bool>;
using ByteArray = std::vector<uInt8>; using ByteArray = std::vector<uInt8>;
using ShortArray = std::vector<uInt16>; using ShortArray = std::vector<uInt16>;

View File

@ -301,19 +301,19 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
{ {
case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states
enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, false); enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, false);
break; return;
case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states
enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, true); enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, true);
break; return;
case KBDK_DOWN: // Alt-down rewinds to start of list case KBDK_DOWN: // Alt-down rewinds to start of list
enterTimeMachineMenuMode(1000, false); enterTimeMachineMenuMode(1000, false);
break; return;
case KBDK_UP: // Alt-up rewinds to end of list case KBDK_UP: // Alt-up rewinds to end of list
enterTimeMachineMenuMode(1000, true); enterTimeMachineMenuMode(1000, true);
break; return;
// These can work in pause mode too // These can work in pause mode too
case KBDK_EQUALS: case KBDK_EQUALS:
@ -2151,6 +2151,8 @@ void EventHandler::enterTimeMachineMenuMode(uInt32 numWinds, bool unwind)
// add one extra state if we are in Time Machine mode // add one extra state if we are in Time Machine mode
// TODO: maybe remove this state if we leave the menu at this new state // TODO: maybe remove this state if we leave the menu at this new state
myOSystem.state().addExtraState("enter Time Machine dialog"); // force new state myOSystem.state().addExtraState("enter Time Machine dialog"); // force new state
if(numWinds)
myOSystem.state().windStates(numWinds, unwind);
if(numWinds) if(numWinds)
myOSystem.state().windStates(numWinds, unwind); myOSystem.state().windStates(numWinds, unwind);
@ -2197,6 +2199,7 @@ void EventHandler::setEventState(EventHandlerState state)
break; break;
case EventHandlerState::TIMEMACHINE: case EventHandlerState::TIMEMACHINE:
myOSystem.timeMachine().requestResize();
myOverlay = &myOSystem.timeMachine(); myOverlay = &myOSystem.timeMachine();
enableTextEvents(true); enableTextEvents(true);
break; break;

View File

@ -150,7 +150,6 @@ bool FrameBuffer::initialize()
FBSurface::setPalette(myPalette); FBSurface::setPalette(myPalette);
myGrabMouse = myOSystem.settings().getBool("grabmouse"); myGrabMouse = myOSystem.settings().getBool("grabmouse");
myZoomMode = myOSystem.settings().getInt("tia.zoom");
// Create a TIA surface; we need it for rendering TIA images // Create a TIA surface; we need it for rendering TIA images
myTIASurface = make_unique<TIASurface>(myOSystem); myTIASurface = make_unique<TIASurface>(myOSystem);
@ -238,7 +237,7 @@ FBInitStatus FrameBuffer::createDisplay(const string& title,
{ {
myStatsMsg.surface = allocateSurface(myStatsMsg.w, myStatsMsg.h); myStatsMsg.surface = allocateSurface(myStatsMsg.w, myStatsMsg.h);
myStatsMsg.surface->attributes().blending = true; myStatsMsg.surface->attributes().blending = true;
//myStatsMsg.surface->attributes().blendalpha = 80; myStatsMsg.surface->attributes().blendalpha = 92; //aligned with TimeMachineDialog
myStatsMsg.surface->applyAttributes(); myStatsMsg.surface->applyAttributes();
} }
@ -387,9 +386,10 @@ void FrameBuffer::drawFrameStats()
myStatsMsg.surface->invalidate(); myStatsMsg.surface->invalidate();
string bsinfo = info.BankSwitch + string bsinfo = info.BankSwitch +
(myOSystem.settings().getBool("dev.settings") ? "| Developer" : "| Player"); (myOSystem.settings().getBool("dev.settings") ? "| Developer" : "");
// draw shadowed text // draw shadowed text
color = myOSystem.console().tia().scanlinesLastFrame() != myLastScanlines ? kDbgColorRed : myStatsMsg.color; color = myOSystem.console().tia().scanlinesLastFrame() != myLastScanlines ?
uInt32(kDbgColorRed) : myStatsMsg.color;
std::snprintf(msg, 30, "%3u", myOSystem.console().tia().scanlinesLastFrame()); std::snprintf(msg, 30, "%3u", myOSystem.console().tia().scanlinesLastFrame());
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS, myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor); myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor);
@ -404,8 +404,11 @@ void FrameBuffer::drawFrameStats()
float frameRate; float frameRate;
/*if(myOSystem.settings().getInt("framerate") == 0) /*if(myOSystem.settings().getInt("framerate") == 0)
{ {
// if 'Auto' is selected, draw the calculated framerate frameRate = 1000000.0 * (ti.totalFrames - myTotalFrames) / (ti.totalTime - myTotalTime);
frameRate = myOSystem.console().getFramerate(); if(frameRate > myOSystem.console().getFramerate() + 1)
frameRate = 1; // check soon again
myTotalFrames = ti.totalFrames;
myTotalTime = ti.totalTime;
} }
else*/ else*/
{ {
@ -427,13 +430,13 @@ void FrameBuffer::drawFrameStats()
myStatsMsg.surface->drawString(font(), msg, xPos, YPOS, myStatsMsg.surface->drawString(font(), msg, xPos, YPOS,
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
// draw bankswitching type
myStatsMsg.surface->drawString(font(), bsinfo, XPOS, YPOS + font().getFontHeight(), myStatsMsg.surface->drawString(font(), bsinfo, XPOS, YPOS + font().getFontHeight(),
myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor);
myStatsMsg.surface->setDirty(); myStatsMsg.surface->setDirty();
myStatsMsg.surface->setDstPos(myImageRect.x() + 1, myImageRect.y() + 1); myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8);
myStatsMsg.surface->render(); myStatsMsg.surface->render();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -654,7 +657,7 @@ bool FrameBuffer::changeWindowedVidMode(int direction)
resetSurfaces(); resetSurfaces();
showMessage(mode.description); showMessage(mode.description);
myZoomMode = mode.zoom; myOSystem.settings().setValue("tia.zoom", mode.zoom);
return true; return true;
} }
#endif #endif
@ -813,17 +816,11 @@ const VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen)
if(state == EventHandlerState::DEBUGGER || state == EventHandlerState::LAUNCHER) if(state == EventHandlerState::DEBUGGER || state == EventHandlerState::LAUNCHER)
myCurrentModeList->setZoom(1); myCurrentModeList->setZoom(1);
else else
myCurrentModeList->setZoom(myZoomMode); myCurrentModeList->setZoom(myOSystem.settings().getInt("tia.zoom"));
return myCurrentModeList->current(); return myCurrentModeList->current();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBuffer::setZoomMode(uInt32 mode)
{
myZoomMode = mode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// //
// VideoMode implementation // VideoMode implementation

View File

@ -192,11 +192,6 @@ class FrameBuffer
*/ */
const VariantList& supportedTIAZoomLevels() const { return myTIAZoomLevels; } const VariantList& supportedTIAZoomLevels() const { return myTIAZoomLevels; }
/*
Set the current zoom mode.
*/
void setZoomMode(uInt32 mode);
/** /**
Get the font object(s) of the framebuffer Get the font object(s) of the framebuffer
*/ */
@ -528,9 +523,6 @@ class FrameBuffer
// Names of the TIA zoom levels that can be used for this framebuffer // Names of the TIA zoom levels that can be used for this framebuffer
VariantList myTIAZoomLevels; VariantList myTIAZoomLevels;
// curently selected zoom mode
uInt32 myZoomMode;
// Holds a reference to all the surfaces that have been created // Holds a reference to all the surfaces that have been created
vector<shared_ptr<FBSurface>> mySurfaceList; vector<shared_ptr<FBSurface>> mySurfaceList;

View File

@ -1229,6 +1229,8 @@ void TIA::tickHblank()
if (myExtendedHblank) myHstate = HState::frame; if (myExtendedHblank) myHstate = HState::frame;
break; break;
} }
if (myExtendedHblank && myHctr > 67) myPlayfield.tick(myHctr - 68 - myHctrDelta);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1269,6 +1271,7 @@ void TIA::nextLine()
cloneLastLine(); cloneLastLine();
} }
myPlayfield.tick(0);
myHctr = 0; myHctr = 0;
if (!myMovementInProgress && myLinesSinceChange < 2) myLinesSinceChange++; if (!myMovementInProgress && myLinesSinceChange < 2) myLinesSinceChange++;

View File

@ -75,7 +75,8 @@ class Dialog : public GuiObject
/** Returns the base surface associated with this dialog. */ /** Returns the base surface associated with this dialog. */
FBSurface& surface() const { return *_surface; } FBSurface& surface() const { return *_surface; }
/** Adds a surface to this dialog, which is rendered on top of the /**
Adds a surface to this dialog, which is rendered on top of the
base surface whenever the base surface is re-rendered. Since base surface whenever the base surface is re-rendered. Since
the surface render() call will always occur in such a case, the the surface render() call will always occur in such a case, the
surface should call setVisible() to enable/disable its output. surface should call setVisible() to enable/disable its output.
@ -89,6 +90,11 @@ class Dialog : public GuiObject
void setTitle(const string& title); void setTitle(const string& title);
bool hasTitle() { return !_title.empty(); } bool hasTitle() { return !_title.empty(); }
/** Determine the maximum bounds based on the given width and height
Returns whether or not a large font can be used within these bounds.
*/
bool getResizableBounds(uInt32& w, uInt32& h) const;
protected: protected:
virtual void draw() override { } virtual void draw() override { }
void releaseFocus() override; void releaseFocus() override;
@ -123,11 +129,6 @@ class Dialog : public GuiObject
void processCancelWithoutWidget(bool state) { _processCancel = state; } void processCancelWithoutWidget(bool state) { _processCancel = state; }
/** Determine the maximum bounds based on the given width and height
Returns whether or not a large font can be used within these bounds.
*/
bool getResizableBounds(uInt32& w, uInt32& h) const;
void initTitle(const GUI::Font& font, const string& title); void initTitle(const GUI::Font& font, const string& title);
private: private:

View File

@ -119,7 +119,7 @@ void DialogContainer::addDialog(Dialog* d)
const GUI::Rect& r = myOSystem.frameBuffer().imageRect(); const GUI::Rect& r = myOSystem.frameBuffer().imageRect();
if(uInt32(d->getWidth()) > r.width() || uInt32(d->getHeight()) > r.height()) if(uInt32(d->getWidth()) > r.width() || uInt32(d->getHeight()) > r.height())
myOSystem.frameBuffer().showMessage( myOSystem.frameBuffer().showMessage(
"Unable to show dialog box; resize current window"); "Unable to show dialog box; FIX THE CODE");
else else
myDialogStack.push(d); myDialogStack.push(d);
} }

View File

@ -134,6 +134,14 @@ class DialogContainer
*/ */
const Dialog* baseDialog() const { return myBaseDialog; } const Dialog* baseDialog() const { return myBaseDialog; }
/**
Inform the container that it should resize according to the current
screen dimensions. We make this virtual, since the container may or
may not choose to do a resize, and even if it does, *how* it does it
is determined by the specific container.
*/
virtual void requestResize() { }
private: private:
void reset(); void reset();

View File

@ -99,7 +99,6 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
b = ADD_OD_BUTTON("Developer" + ELLIPSIS, kDevelopCmd); b = ADD_OD_BUTTON("Developer" + ELLIPSIS, kDevelopCmd);
wid.push_back(b); wid.push_back(b);
// Move to second column // Move to second column
xoffset += buttonWidth + 10; yoffset = VBORDER; xoffset += buttonWidth + 10; yoffset = VBORDER;

View File

@ -25,18 +25,14 @@
#include "TimeLineWidget.hxx" #include "TimeLineWidget.hxx"
// TODO - remove all references to _stepValue__
// - fix posToValue to use _stepValue
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font, TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, int x, int y, int w, int h,
const string& label, int labelWidth, int cmd) const string& label, uInt32 labelWidth, int cmd)
: ButtonWidget(boss, font, x, y, w, h, label, cmd), : ButtonWidget(boss, font, x, y, w, h, label, cmd),
_value(0), _value(0),
_stepValue__(1),
_valueMin(0), _valueMin(0),
_valueMax(100), _valueMax(0),
_isDragging(false), _isDragging(false),
_labelWidth(labelWidth) _labelWidth(labelWidth)
{ {
@ -53,10 +49,9 @@ TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font,
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setValue(int value) void TimeLineWidget::setValue(uInt32 value)
{ {
if(value < _valueMin) value = _valueMin; value = BSPF::clamp(value, _valueMin, _valueMax);
else if(value > _valueMax) value = _valueMax;
if(value != _value) if(value != _value)
{ {
@ -67,13 +62,13 @@ void TimeLineWidget::setValue(int value)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setMinValue(int value) void TimeLineWidget::setMinValue(uInt32 value)
{ {
_valueMin = value; _valueMin = value;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setMaxValue(int value) void TimeLineWidget::setMaxValue(uInt32 value)
{ {
_valueMax = value; _valueMax = value;
} }
@ -81,12 +76,16 @@ void TimeLineWidget::setMaxValue(int value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::setStepValues(const IntArray& steps) void TimeLineWidget::setStepValues(const IntArray& steps)
{ {
_stepValue.clear();
// If no steps are defined, just use the maximum value
if(steps.size() > 0)
{
// Try to allocate as infrequently as possible // Try to allocate as infrequently as possible
if(steps.size() > _stepValue.capacity()) if(steps.size() > _stepValue.capacity())
_stepValue.reserve(2 * steps.size()); _stepValue.reserve(2 * steps.size());
_stepValue.clear();
double scale = (_w - _labelWidth - 4) / double(steps.back()); double scale = (_w - _labelWidth - 2) / double(steps.back());
// Skip the very last value; we take care of it outside the end of the loop // Skip the very last value; we take care of it outside the end of the loop
for(uInt32 i = 0; i < steps.size() - 1; ++i) for(uInt32 i = 0; i < steps.size() - 1; ++i)
@ -94,14 +93,15 @@ void TimeLineWidget::setStepValues(const IntArray& steps)
// Due to integer <-> double conversion, the last value is sometimes // Due to integer <-> double conversion, the last value is sometimes
// slightly less than the maximum value; we assign it manually to fix this // slightly less than the maximum value; we assign it manually to fix this
_stepValue.push_back(_w - _labelWidth - 4); _stepValue.push_back(_w - _labelWidth - 2);
}
else
_stepValue.push_back(0);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::handleMouseMoved(int x, int y) void TimeLineWidget::handleMouseMoved(int x, int y)
{ {
// TODO: when the mouse is dragged outside the widget, the slider should
// snap back to the old value.
if(isEnabled() && _isDragging && x >= int(_labelWidth)) if(isEnabled() && _isDragging && x >= int(_labelWidth))
setValue(posToValue(x - _labelWidth)); setValue(posToValue(x - _labelWidth));
} }
@ -130,47 +130,13 @@ void TimeLineWidget::handleMouseWheel(int x, int y, int direction)
{ {
if(isEnabled()) if(isEnabled())
{ {
if(direction < 0) if(direction < 0 && _value < _valueMax)
handleEvent(Event::UIUp); setValue(_value + 1);
else if(direction > 0) else if(direction > 0 && _value > _valueMin)
handleEvent(Event::UIDown); setValue(_value - 1);
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TimeLineWidget::handleEvent(Event::Type e)
{
if(!isEnabled())
return false;
switch(e)
{
case Event::UIDown:
case Event::UILeft:
case Event::UIPgDown:
setValue(_value - _stepValue__);
break;
case Event::UIUp:
case Event::UIRight:
case Event::UIPgUp:
setValue(_value + _stepValue__);
break;
case Event::UIHome:
setValue(_valueMin);
break;
case Event::UIEnd:
setValue(_valueMax);
break;
default:
return false;
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeLineWidget::drawWidget(bool hilite) void TimeLineWidget::drawWidget(bool hilite)
{ {
@ -183,13 +149,26 @@ void TimeLineWidget::drawWidget(bool hilite)
isEnabled() ? kTextColor : kColor, TextAlign::Right); isEnabled() ? kTextColor : kColor, TextAlign::Right);
// Draw the box // Draw the box
s.box(_x + _labelWidth, _y, _w - _labelWidth, _h, kColor, kShadowColor); s.frameRect(_x + _labelWidth, _y, _w - _labelWidth, _h, kColor);
// Fill the box // Fill the box
s.fillRect(_x + _labelWidth + 2, _y + 2, _w - _labelWidth - 4, _h - 4, s.fillRect(_x + _labelWidth + 1, _y + 1, _w - _labelWidth - 2, _h - 2,
!isEnabled() ? kBGColorHi : kWidColor); !isEnabled() ? kBGColorHi : kWidColor);
// Draw the 'bar' // Draw the 'bar'
s.fillRect(_x + _labelWidth + 2, _y + 2, valueToPos(_value), _h - 4, int vp = valueToPos(_value);
s.fillRect(_x + _labelWidth + 1, _y + 1, vp, _h - 2,
!isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor);
// add 4 tickmarks for 5 intervals
int numTicks = std::min(5, int(_stepValue.size()));
for(int i = 1; i < numTicks; ++i)
{
int idx = int((_stepValue.size() * i + numTicks / 2) / numTicks);
if(idx > 1)
{
int tp = valueToPos(idx - 1);
s.vLine(_x + _labelWidth + tp, _y + _h / 2, _y + _h - 2, tp > vp ? kSliderColor : kWidColor);
}
}
#else #else
// Draw the label, if any // Draw the label, if any
if(_labelWidth > 0) if(_labelWidth > 0)
@ -208,25 +187,19 @@ void TimeLineWidget::drawWidget(bool hilite)
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TimeLineWidget::valueToPos(int value) uInt32 TimeLineWidget::valueToPos(uInt32 value)
{ {
if(value < _valueMin) value = _valueMin; return _stepValue[BSPF::clamp(value, _valueMin, _valueMax)];
else if(value > _valueMax) value = _valueMax;
int real = _stepValue[BSPF::clamp(value, _valueMin, _valueMax)];
#if 0
int range = std::max(_valueMax - _valueMin, 1); // don't divide by zero
int actual = ((_w - _labelWidth - 4) * (value - _valueMin) / range);
cerr << "i=" << value << " real=" << real << endl << "actual=" << actual << endl << endl;
#endif
return real;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int TimeLineWidget::posToValue(int pos) uInt32 TimeLineWidget::posToValue(uInt32 pos)
{ {
int value = (pos) * (_valueMax - _valueMin) / (_w - _labelWidth - 4) + _valueMin; // Find the interval in which 'pos' falls, and then the endpoint which
// it is closest to
for(uInt32 i = 0; i < _stepValue.size() - 1; ++i)
if(pos >= _stepValue[i] && pos <= _stepValue[i+1])
return (_stepValue[i+1] - pos) < (pos - _stepValue[i]) ? i+1 : i;
// Scale the position to the correct interval (according to step value) return _valueMax;
return value - (value % _stepValue__);
} }

View File

@ -25,15 +25,15 @@ class TimeLineWidget : public ButtonWidget
public: public:
TimeLineWidget(GuiObject* boss, const GUI::Font& font, TimeLineWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, int w, int h, const string& label = "", int x, int y, int w, int h, const string& label = "",
int labelWidth = 0, int cmd = 0); uInt32 labelWidth = 0, int cmd = 0);
void setValue(int value); void setValue(uInt32 value);
int getValue() const { return _value; } uInt32 getValue() const { return _value; }
void setMinValue(int value); void setMinValue(uInt32 value);
int getMinValue() const { return _valueMin; } void setMaxValue(uInt32 value);
void setMaxValue(int value); uInt32 getMinValue() const { return _valueMin; }
int getMaxValue() const { return _valueMax; } uInt32 getMaxValue() const { return _valueMax; }
/** /**
Steps are not necessarily linear in a timeline, so we need info Steps are not necessarily linear in a timeline, so we need info
@ -46,20 +46,19 @@ class TimeLineWidget : public ButtonWidget
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
void handleMouseWheel(int x, int y, int direction) override; void handleMouseWheel(int x, int y, int direction) override;
bool handleEvent(Event::Type event) override;
void drawWidget(bool hilite) override; void drawWidget(bool hilite) override;
int valueToPos(int value); uInt32 valueToPos(uInt32 value);
int posToValue(int pos); uInt32 posToValue(uInt32 pos);
protected: protected:
int _value, _stepValue__; uInt32 _value;
int _valueMin, _valueMax; uInt32 _valueMin, _valueMax;
bool _isDragging; bool _isDragging;
int _labelWidth; uInt32 _labelWidth;
IntArray _stepValue; uIntArray _stepValue;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -22,8 +22,37 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeMachine::TimeMachine(OSystem& osystem) TimeMachine::TimeMachine(OSystem& osystem)
: DialogContainer(osystem) : DialogContainer(osystem),
myWidth(FrameBuffer::kFBMinW)
{ {
myBaseDialog = new TimeMachineDialog(myOSystem, *this, myBaseDialog = new TimeMachineDialog(myOSystem, *this, myWidth);
FrameBuffer::kFBMinW, FrameBuffer::kFBMinH); }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TimeMachine::requestResize()
{
uInt32 w, h;
myBaseDialog->getResizableBounds(w, h);
// If dialog is too large for given area, we need to resize it
// Otherwise, make it 80% of the allowable width
int newWidth = myWidth;
if(w < FrameBuffer::kFBMinW)
newWidth = w;
else if(myBaseDialog->getWidth() != 0.8 * w)
newWidth = uInt32(0.8 * w);
// Only re-create when absolutely necessary
if(myWidth != newWidth)
{
myWidth = newWidth;
Dialog* oldPtr = myBaseDialog;
delete myBaseDialog;
myBaseDialog = new TimeMachineDialog(myOSystem, *this, myWidth);
Dialog* newPtr = myBaseDialog;
// Update the container stack; it may contain a reference to the old pointer
if(oldPtr != newPtr)
myDialogStack.replace(oldPtr, newPtr);
}
} }

View File

@ -33,6 +33,15 @@ class TimeMachine : public DialogContainer
TimeMachine(OSystem& osystem); TimeMachine(OSystem& osystem);
virtual ~TimeMachine() = default; virtual ~TimeMachine() = default;
/**
This dialog has an adjustable size. We need to make sure the
dialog can fit within the given bounds.
*/
void requestResize() override;
private:
int myWidth;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported
TimeMachine() = delete; TimeMachine() = delete;

View File

@ -36,7 +36,7 @@ using Common::Base;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
int max_w, int max_h) int width)
: Dialog(osystem, parent) : Dialog(osystem, parent)
{ {
const int BUTTON_W = 16, BUTTON_H = 14; const int BUTTON_W = 16, BUTTON_H = 14;
@ -75,23 +75,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
0b0110000110000110, 0b0110000110000110,
0 0
}; };
static uInt32 REWIND_10[BUTTON_H] =
{
0,
0b0000010000100110,
0b0000110001100110,
0b0001110011100110,
0b0011110111100110,
0b0111111111100110,
0b1111111111100110,
0b1111111111100110,
0b0111111111100110,
0b0011110111100110,
0b0001110011100110,
0b0000110001100110,
0b0000010000100110,
0
};
static uInt32 REWIND_1[BUTTON_H] = static uInt32 REWIND_1[BUTTON_H] =
{ {
0, 0,
@ -126,23 +109,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
0b0011100011000000, 0b0011100011000000,
0 0
}; };
static uInt32 UNWIND_10[BUTTON_H] =
{
0,
0b0110010000100000,
0b0110011000110000,
0b0110011100111000,
0b0110011110111100,
0b0110011111111110,
0b0110011111111111,
0b0110011111111111,
0b0110011111111110,
0b0110011110111100,
0b0110011100111000,
0b0110011000110000,
0b0110010000100000,
0
};
static uInt32 UNWIND_ALL[BUTTON_H] = static uInt32 UNWIND_ALL[BUTTON_H] =
{ {
0, 0,
@ -170,7 +136,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
int xpos, ypos; int xpos, ypos;
// Set real dimensions // Set real dimensions
_w = 20 * (buttonWidth + BUTTON_GAP) + 20; _w = width; // Parent determines our width (based on window size)
_h = V_BORDER * 2 + rowHeight + buttonHeight + 2; _h = V_BORDER * 2 + rowHeight + buttonHeight + 2;
this->clearFlags(WIDGET_CLEARBG); // does only work combined with blending (0..100)! this->clearFlags(WIDGET_CLEARBG); // does only work combined with blending (0..100)!
@ -189,7 +155,7 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
// Add timeline // Add timeline
const uInt32 tl_h = myCurrentIdxWidget->getHeight() / 2, const uInt32 tl_h = myCurrentIdxWidget->getHeight() / 2,
tl_x = xpos + myCurrentIdxWidget->getWidth() + 8, tl_x = xpos + myCurrentIdxWidget->getWidth() + 8,
tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2, tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2 - 1,
tl_w = myLastIdxWidget->getAbsX() - tl_x - 8; tl_w = myLastIdxWidget->getAbsX() - tl_x - 8;
myTimeline = new TimeLineWidget(this, font, tl_x, tl_y, tl_w, tl_h, "", 0, kTimeline); myTimeline = new TimeLineWidget(this, font, tl_x, tl_y, tl_w, tl_h, "", 0, kTimeline);
myTimeline->setMinValue(0); myTimeline->setMinValue(0);
@ -208,10 +174,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
BUTTON_W, BUTTON_H, kRewindAll); BUTTON_W, BUTTON_H, kRewindAll);
xpos += buttonWidth + BUTTON_GAP; xpos += buttonWidth + BUTTON_GAP;
myRewind10Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_10,
BUTTON_W, BUTTON_H, kRewind10);
xpos += buttonWidth + BUTTON_GAP;
myRewind1Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_1, myRewind1Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_1,
BUTTON_W, BUTTON_H, kRewind1); BUTTON_W, BUTTON_H, kRewind1);
xpos += buttonWidth + BUTTON_GAP*2; xpos += buttonWidth + BUTTON_GAP*2;
@ -224,10 +186,6 @@ TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent,
BUTTON_W, BUTTON_H, kUnwind1); BUTTON_W, BUTTON_H, kUnwind1);
xpos += buttonWidth + BUTTON_GAP; xpos += buttonWidth + BUTTON_GAP;
myUnwind10Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_10,
BUTTON_W, BUTTON_H, kUnwind10);
xpos += buttonWidth + BUTTON_GAP;
myUnwindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_ALL, myUnwindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_ALL,
BUTTON_W, BUTTON_H, kUnwindAll); BUTTON_W, BUTTON_H, kUnwindAll);
xpos = myUnwindAllWidget->getRight() + BUTTON_GAP * 3; xpos = myUnwindAllWidget->getRight() + BUTTON_GAP * 3;
@ -254,14 +212,15 @@ void TimeMachineDialog::loadConfig()
IntArray cycles = r.cyclesList(); IntArray cycles = r.cyclesList();
// Set range and intervals for timeline // Set range and intervals for timeline
myTimeline->setMaxValue(cycles.size() - 1); uInt32 maxValue = cycles.size() > 1 ? uInt32(cycles.size() - 1) : 0;
myTimeline->setMaxValue(maxValue);
myTimeline->setStepValues(cycles); myTimeline->setStepValues(cycles);
// Enable blending (only once is necessary) // Enable blending (only once is necessary)
if(!surface().attributes().blending) if(!surface().attributes().blending)
{ {
surface().attributes().blending = true; surface().attributes().blending = true;
surface().attributes().blendalpha = 80; surface().attributes().blendalpha = 92;
surface().applyAttributes(); surface().applyAttributes();
} }
@ -361,11 +320,11 @@ string TimeMachineDialog::getTimeString(uInt64 cycles)
const Int32 PAL_FREQ = 1182298; // ~76*312*50 const Int32 PAL_FREQ = 1182298; // ~76*312*50
const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second
uInt32 minutes = cycles / (freq * 60); uInt32 minutes = uInt32(cycles / (freq * 60));
cycles -= minutes * (freq * 60); cycles -= minutes * (freq * 60);
uInt32 seconds = cycles / freq; uInt32 seconds = uInt32(cycles / freq);
cycles -= seconds * freq; cycles -= seconds * freq;
uInt32 frames = cycles / (scanlines * 76); uInt32 frames = uInt32(cycles / (scanlines * 76));
stringstream time; stringstream time;
time << Common::Base::toString(minutes, Common::Base::F_10_02) << ":"; time << Common::Base::toString(minutes, Common::Base::F_10_02) << ":";
@ -395,6 +354,7 @@ void TimeMachineDialog::handleWinds(Int32 numWinds)
myMessageWidget->setLabel((numWinds < 0 ? "(-" : "(+") + message + ")"); myMessageWidget->setLabel((numWinds < 0 ? "(-" : "(+") + message + ")");
} }
} }
// Update time // Update time
myCurrentTimeWidget->setLabel(getTimeString(r.getCurrentCycles() - r.getFirstCycles())); myCurrentTimeWidget->setLabel(getTimeString(r.getCurrentCycles() - r.getFirstCycles()));
myLastTimeWidget->setLabel(getTimeString(r.getLastCycles() - r.getFirstCycles())); myLastTimeWidget->setLabel(getTimeString(r.getLastCycles() - r.getFirstCycles()));
@ -404,9 +364,7 @@ void TimeMachineDialog::handleWinds(Int32 numWinds)
myLastIdxWidget->setValue(r.getLastIdx()); myLastIdxWidget->setValue(r.getLastIdx());
// Enable/disable buttons // Enable/disable buttons
myRewindAllWidget->setEnabled(!r.atFirst()); myRewindAllWidget->setEnabled(!r.atFirst());
myRewind10Widget->setEnabled(!r.atFirst());
myRewind1Widget->setEnabled(!r.atFirst()); myRewind1Widget->setEnabled(!r.atFirst());
myUnwindAllWidget->setEnabled(!r.atLast()); myUnwindAllWidget->setEnabled(!r.atLast());
myUnwind10Widget->setEnabled(!r.atLast());
myUnwind1Widget->setEnabled(!r.atLast()); myUnwind1Widget->setEnabled(!r.atLast());
} }

View File

@ -28,7 +28,7 @@ class TimeLineWidget;
class TimeMachineDialog : public Dialog class TimeMachineDialog : public Dialog
{ {
public: public:
TimeMachineDialog(OSystem& osystem, DialogContainer& parent, int max_w, int max_h); TimeMachineDialog(OSystem& osystem, DialogContainer& parent, int width);
virtual ~TimeMachineDialog() = default; virtual ~TimeMachineDialog() = default;
private: private:
@ -61,10 +61,8 @@ class TimeMachineDialog : public Dialog
ButtonWidget* myPlayWidget; ButtonWidget* myPlayWidget;
ButtonWidget* myRewindAllWidget; ButtonWidget* myRewindAllWidget;
ButtonWidget* myRewind10Widget;
ButtonWidget* myRewind1Widget; ButtonWidget* myRewind1Widget;
ButtonWidget* myUnwind1Widget; ButtonWidget* myUnwind1Widget;
ButtonWidget* myUnwind10Widget;
ButtonWidget* myUnwindAllWidget; ButtonWidget* myUnwindAllWidget;
StaticTextWidget* myCurrentTimeWidget; StaticTextWidget* myCurrentTimeWidget;

View File

@ -390,7 +390,6 @@ void VideoDialog::saveConfig()
// TIA Filter // TIA Filter
instance().settings().setValue("tia.zoom", instance().settings().setValue("tia.zoom",
myTIAZoom->getSelectedTag().toString()); myTIAZoom->getSelectedTag().toString());
instance().frameBuffer().setZoomMode(instance().settings().getInt("tia.zoom"));
// TIA Palette // TIA Palette
instance().settings().setValue("palette", instance().settings().setValue("palette",

View File

@ -1,8 +1,8 @@
/* Localized versions of Info.plist keys */ /* Localized versions of Info.plist keys */
CFBundleName = "Stella"; CFBundleName = "Stella";
CFBundleShortVersionString = "Stella version 5.0.2"; CFBundleShortVersionString = "Stella version 5.1";
CFBundleGetInfoString = "Stella version 5.0.2"; CFBundleGetInfoString = "Stella version 5.1";
NSHumanReadableCopyright = "Stella MacOS X version by Stephen Anthony and Mark Grebe."; NSHumanReadableCopyright = "Stella MacOS X version by Stephen Anthony and Mark Grebe.";
"Atari 2600 Cartridge File" = "Atari 2600 Cartridge File"; "Atari 2600 Cartridge File" = "Atari 2600 Cartridge File";

View File

@ -53,7 +53,7 @@
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>StLa</string> <string>StLa</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>5.0.2</string> <string>5.1</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.games</string> <string>public.app-category.games</string>
<key>LSMinimumSystemVersionByArchitecture</key> <key>LSMinimumSystemVersionByArchitecture</key>

View File

@ -1,5 +1,5 @@
%define name stella %define name stella
%define version 5.0.2 %define version 5.1
%define rel 1 %define rel 1
%define enable_sound 1 %define enable_sound 1
@ -101,6 +101,9 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version}
%_datadir/icons/large/%{name}.png %_datadir/icons/large/%{name}.png
%changelog %changelog
* Sun Feb 04 2018 Stephen Anthony <stephena@users.sf.net> 5.1-1
- Version 5.1 release
* Sun Aug 20 2017 Stephen Anthony <stephena@users.sf.net> 5.0.2-1 * Sun Aug 20 2017 Stephen Anthony <stephena@users.sf.net> 5.0.2-1
- Version 5.0.2 release - Version 5.0.2 release

View File

@ -36,8 +36,8 @@ IDI_ICON ICON "stella.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,0,2,0 FILEVERSION 5,1,0,0
PRODUCTVERSION 5,0,2,0 PRODUCTVERSION 5,1,0,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -55,12 +55,12 @@ BEGIN
VALUE "Comments", "The multi-platform Atari 2600 emulator. Stella is released under the GPLv2." VALUE "Comments", "The multi-platform Atari 2600 emulator. Stella is released under the GPLv2."
VALUE "CompanyName", "The Stella Team (https://stella-emu.github.io)" VALUE "CompanyName", "The Stella Team (https://stella-emu.github.io)"
VALUE "FileDescription", "Stella" VALUE "FileDescription", "Stella"
VALUE "FileVersion", "5.0.2" VALUE "FileVersion", "5.1"
VALUE "InternalName", "Stella" VALUE "InternalName", "Stella"
VALUE "LegalCopyright", "Copyright (C) 1995-2018 The Stella Team" VALUE "LegalCopyright", "Copyright (C) 1995-2018 The Stella Team"
VALUE "OriginalFilename", "Stella.exe" VALUE "OriginalFilename", "Stella.exe"
VALUE "ProductName", "Stella" VALUE "ProductName", "Stella"
VALUE "ProductVersion", "5.0.2" VALUE "ProductVersion", "5.1"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"