diff -Nru stella-6.3/Announce.txt stella-6.4/Announce.txt
--- stella-6.3/Announce.txt 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/Announce.txt 2020-11-02 08:08:34.000000000 +0000
@@ -9,7 +9,7 @@
SSSS ttt eeeee llll llll aaaaa
===========================================================================
- Release 6.3 for Linux, macOS and Windows
+ Release 6.4 for Linux, macOS and Windows
===========================================================================
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the
@@ -21,25 +21,25 @@
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.
-This is the 6.3 release of Stella for Linux, macOS and Windows. The
+This is the 6.4 release of Stella for Linux, macOS and Windows. The
distributions currently available are:
- * Binaries for Windows Vista/7/8/10 :
- Stella-6.3-win32.exe (32-bit EXE installer)
- Stella-6.3-x64.exe (64-bit EXE installer)
- Stella-6.3-windows.zip (32/64 bit versions)
+ * Binaries for Windows 7/8/10 :
+ Stella-6.4-win32.exe (32-bit EXE installer)
+ Stella-6.4-x64.exe (64-bit EXE installer)
+ Stella-6.4-windows.zip (32/64 bit versions)
* Binary distribution for macOS 10.7 and above :
- Stella-6.3-macos.dmg (64-bit Intel)
+ Stella-6.4-macos.dmg (64-bit Intel)
* Binary distribution for 64-bit Ubuntu :
- stella_6.3-1_amd64.deb
+ stella_6.4-1_amd64.deb
* Binary distribution for 64-bit Redhat :
- stella-6.3-2.x86_64.rpm
+ stella-6.4-2.x86_64.rpm
* Source code distribution for all platforms :
- stella-6.3-src.tar.xz
+ stella-6.4-src.tar.xz
Distribution Site
diff -Nru stella-6.3/Changes.txt stella-6.4/Changes.txt
--- stella-6.3/Changes.txt 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/Changes.txt 2020-11-02 08:08:34.000000000 +0000
@@ -12,6 +12,39 @@
Release History
===========================================================================
+6.3 to 6.4 (November 2, 2020)
+
+ * Added basic (entire and single line only) text cut/copy and paste.
+
+ * Added color parameters to 'Custom' palette.
+
+ * Some improvements to AtariVox-USB adaptor functionality:
+ - Made serial port used for an AtariVox-USB adaptor editable.
+ - Autodetection of serial ports no longer messes up devices plugged
+ into other serial ports.
+
+ * Added CPU load stats to debugger. Related to this, added debugger
+ pseudo-registers '_ftimreadcycles' and '_fwsynccycles' to show the
+ number of cycles since the start of frame under certain circumstances
+ (see manual for more details).
+
+ * Fixed bug with aspect correction and fullscreen mode; snapshots from
+ such a mode are now pixel-exact.
+
+ * Fixed a bug that caused CDF ROMs to crash on the Retron77 and reduced
+ ARM emulation performance for CDF ROMs on other platforms.
+
+ * Fixed crash with missing or incorrectly sized SaveKey data file, and
+ with certain functions not working (erase pages, erase entire EEPROM).
+
+ * Fixed Atari mouse autodetection.
+
+ * Fixed bug in ROM launcher, with last ROM selected not being remembered
+ when exiting and re-entering a directory.
+
+-Have fun!
+
+
6.2.1 to 6.3 (October 7, 2020)
* Added adjustable autofire.
@@ -65,8 +98,6 @@
* Fixed bug when taking fullscreen snapshots; the dimensions were
sometimes cut off.
--Have fun!
-
6.2.1 to 6.2.2 (August 25, 2020)
diff -Nru stella-6.3/debian/changelog stella-6.4/debian/changelog
--- stella-6.3/debian/changelog 2020-10-16 14:12:06.000000000 +0000
+++ stella-6.4/debian/changelog 2020-11-03 21:34:02.000000000 +0000
@@ -1,3 +1,9 @@
+stella (6.4-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Stephen Kitt Tue, 03 Nov 2020 22:34:02 +0100
+
stella (6.3-1) unstable; urgency=medium
* New upstream release.
diff -Nru stella-6.3/docs/debugger.html stella-6.4/docs/debugger.html
--- stella-6.3/docs/debugger.html 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/docs/debugger.html 2020-11-02 08:08:34.000000000 +0000
@@ -15,7 +15,7 @@
Stella
- Release 6.3
+ Release 6.4
Integrated Debugger
(a work in progress)
@@ -227,6 +227,14 @@
Pressing Tab (or Shift + Tab) cycles between widgets in the current tab (except
for in the Prompt Tab, where 'tab' is used for something else).
+Note for the GUI display:
+
+- Hexadecimal values are either not prefixed or with '$'.
+- Decimal values are prefixed with '#'.
+- Binary values are prefixed with '%'.
+
+
+
You can also enter the debugger at emulator startup by use the 'debug'
command on the command line, or alternatively within the ROM launcher in
'Power-on options':
@@ -753,6 +761,8 @@
_cycleslo | Lower 32 bits of number of cycles since emulation started |
_fcount | Number of frames since emulation started |
_fcycles | Number of cycles since frame started |
+ _ftimreadcycles | Number of cycles used by timer reads since frame started |
+ _fwsynccycles | Number of cycles skipped by WSYNC since frame started |
_icycles | Number of cycles of last instruction |
_scan | Current scanline count |
_scanend | Scanline count at end of last frame |
@@ -1133,16 +1143,20 @@
-To the right of the TIA Display area, TIA information is displayed:
+To the right of the TIA Display area, TIA information is displayed (all values are decimal):
The indicators are as follows (note that all these are read-only):
-- Frame Count: The number of frames since this ROM was loaded or reset.
-- Frame Cycle: The number of CPU cycles that have been executed this frame since
+
- Frame Cycls: The number of CPU cycles that have been executed this frame since
+VSYNC was cleared at scanline 0.
+- WSync Cycls: The number of CPU cycles that have been skipped by WSYNC this frame since
+VSYNC was cleared at scanline 0.
+- Timer Cycls: The number of CPU cycles (approximately) that have been used by timer read loops since
VSYNC was cleared at scanline 0.
- Total: The total number of CPU cycles since this ROM was loaded or reset.
- Delta: The number of CPU cycles that have been executed since the last debugger
interrupt.
+- Frame Cnt.: The number of frames since this ROM was loaded or reset.
- Scanline: The scanline that's currently being drawn, and the count from the
previous frame. Scanline 0 is the one on which VSYNC is cleared (after being set for
3 scanlines, as per the Stella Programmer's Guide).
@@ -1275,10 +1289,9 @@
This is a spreadsheet-like GUI for inspecting and changing the contents
of the 2600's zero-page RAM.
You can navigate with either the mouse or the keyboard arrow keys.
-To change a RAM location, either double-click on it or press Enter while
-it's highlighted. Enter the new value (hex only for now, sorry), then
-press Enter to make the change. If you change your mind, press Escape
-and the original value will be restored. The currently selected RAM cell
+To change a RAM location, either double-click on it or press 'Enter' while
+it's highlighted. Enter the new value (hex, other formats using the bottom textboxes), then
+press 'Enter' to make the change. The currently selected RAM cell
can also be changed by using the
Data Operations Buttons or the associated
shortcut keys.
@@ -1289,7 +1302,8 @@
since you first made a change.
The UI objects at the bottom refer to the currently selected RAM cell.
The 'Label' textbox shows the label attached to this RAM location (if any),
-and the other two textboxes show the decimal and binary equivalent value.
+and the other three textboxes show the hex, decimal and binary equivalent value.
+The values can be edited here too.
The remaining buttons to the right are further explained in the next section.
@@ -1571,7 +1585,7 @@
If applicable, this area shows a detailed breakdown of any extra RAM supported by
the bankswitching scheme. Since the bankswitch schemes can greatly vary in operation,
this tab will be different for each scheme, but its specific functionality should be
-self-explanatory. An example of both F8SC (8K Atari + ram) and DPC (Pitfall II) is
+self-explanatory. An example of both F6SC (16K Atari + ram) and DPC (Pitfall II) is
as follows:
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_bankcomplex.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_bankcomplex.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_banksimple.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_banksimple.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_cpuregs.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_cpuregs.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_iotab.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_iotab.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_main.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_main.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_ram-dpc.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_ram-dpc.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_ram-f8sc.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_ram-f8sc.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_ram.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_ram.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_ramsearch.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_ramsearch.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/debugger_tiainfo.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/debugger_tiainfo.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/eventmapping_combo.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/eventmapping_combo.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/eventmapping_devsports.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/eventmapping_devsports.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/eventmapping_mouse.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/eventmapping_mouse.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/eventmapping.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/eventmapping.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/eventmapping_remap.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/eventmapping_remap.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/launcher_override.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/launcher_override.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/logs.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/logs.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_audio.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_audio.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_developer_debugger.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_developer_debugger.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_developer_emulation.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_developer_emulation.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_developer.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_developer.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_developer_tia.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_developer_tia.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_developer_timemachine.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_developer_timemachine.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_developer_video.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_developer_video.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_gameinfo_controller.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_gameinfo_controller.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_gameinfo_emulation.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_gameinfo_emulation.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_gameinfo_quadtari.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_gameinfo_quadtari.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_misc.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_misc.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_ui.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_ui.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_video_palettes.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_video_palettes.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_video.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_video.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/options_video_tv.png and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/options_video_tv.png differ
Binary files /tmp/tmpwrAI1J/FBo1eaCsQO/stella-6.3/docs/graphics/resources/debugger_main.pdn and /tmp/tmpwrAI1J/VfoEDSt2j5/stella-6.4/docs/graphics/resources/debugger_main.pdn differ
diff -Nru stella-6.3/docs/index.html stella-6.4/docs/index.html
--- stella-6.3/docs/index.html 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/docs/index.html 2020-11-02 08:08:34.000000000 +0000
@@ -19,7 +19,7 @@
A multi-platform Atari 2600 VCS emulator
- Release 6.3
+ Release 6.4
User's Guide
@@ -70,7 +70,7 @@
- February 1999 - June 2020
+ February 1999 - November 2020
The Stella Team
Stella Homepage
@@ -368,7 +368,7 @@
Windows
- The Windows version of Stella is designed to work on Windows Vista/7/8/10
+
The Windows version of Stella is designed to work on Windows 7/8/10
with the following:
@@ -1806,13 +1806,13 @@
Save continuous PNG snapshots(per interval defined in Snapshot Settings) |
- Alt + s |
- Cmd + s |
+ Control-Alt + s |
+ Control-Cmd + s |
Save continuous PNG snapshots (every frame) |
- Shift-Alt + s |
- Shift-Cmd + s |
+ Shift-Control-Alt + s |
+ Shift-Control-Cmd + s |
@@ -1871,20 +1871,18 @@
Key | Editor Function |
- Home | Move cursor to beginning of line |
- End | Move cursor to end of line |
- Delete | Remove character to right of cursor |
+ Home, Control + a | Move cursor to beginning of line |
+ End, Control + e | Move cursor to end of line |
+ Delete, Control + d | Remove character to right of cursor |
Backspace | Remove character to left of cursor |
- Control + a | Same function as 'Home' |
- Control + e | Same function as 'End' |
- Control + d | Same function as 'Delete' |
Control + k | Remove all characters from cursor to end of line |
Control + u | Remove all characters from cursor to beginning of line |
Control + w | Remove entire word to left of cursor |
- Control + Left | Move cursor to beginning of word to the left |
- Control + Right | Move cursor to beginning of word to the right |
- Control + c | Copy entire line to clipboard (not complete) |
- Control + v | Paste clipboard contents (not complete) |
+ Control + Left arrow | Move cursor to beginning of word to the left |
+ Control + Right arrow | Move cursor to beginning of word to the right |
+ Control + c, Control + Insert | Copy entire line to clipboard |
+ Control + v, Shift + Insert | Paste clipboard contents |
+ Control + x, Shift + Delete | Cut entire line to clipboard |
@@ -2132,7 +2130,7 @@
-palette <standard|z26|user|custom> |
Set the palette to either normal Stella, the one used in the z26
emulator, a user-defined palette, or a custom palette generated
- from user-defined phase shifts. |
+ from user-defined parameters.
@@ -2146,6 +2144,36 @@
+ -pal.red_scale <number> |
+ Adjust red scale of 'custom' palette (range -1.0 to 1.0). |
+
+
+
+ -pal.red_shift <number> |
+ Adjust red shift of 'custom' palette (range -22.5 to 22.5). |
+
+
+
+ -pal.green_scale <number> |
+ Adjust green scale of 'custom' palette (range -1.0 to 1.0). |
+
+
+
+ -pal.green_shift <number> |
+ Adjust green shift of 'custom' palette (range -22.5 to 22.5). |
+
+
+
+ -pal.blue_scale <number> |
+ Adjust blue scale of 'custom' palette (range -1.0 to 1.0). |
+
+
+
+ -pal.blue_shift <number> |
+ Adjust blue shift of 'custom' palette (range -22.5 to 22.5). |
+
+
+
-pal.hue <number> |
Adjust hue of current palette (range -1.0 to 1.0). |
@@ -3080,8 +3108,11 @@
Item | Brief description | For more information, see Command Line |
Palette | Palette used for emulation mode | -palette |
- NTSC phase | Adjust phase shift for 'Custom' NTSC palette | -pal.phase_ntsc |
- PAL phase | Adjust phase shift for 'Custom' PAL palette | -pal.phase_pal |
+ NTSC phase | Adjust phase shift of 'Custom' NTSC palette | -pal.phase_ntsc |
+ PAL phase | Adjust phase shift of 'Custom' PAL palette | -pal.phase_pal |
+ R | Adjust red scale and shift of 'Custom' palette | -pal.red_scale, -pal.red_shift |
+ G | Adjust green scale and shift of 'Custom' palette | -pal.green_scale, -pal.green_shift |
+ B | Adjust blue scale and shift of 'Custom' palette | -pal.blue_scale, -pal.blue_shift |
Hue | Adjust hue of currently selected palette | -pal.hue |
Saturation | Adjust saturation of currently selected palette | -pal.saturation |
Contrast | Adjust contrast of currently selected palette | -pal.contrast |
diff -Nru stella-6.3/docs/index_r77.html stella-6.4/docs/index_r77.html
--- stella-6.3/docs/index_r77.html 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/docs/index_r77.html 2020-11-02 08:08:34.000000000 +0000
@@ -58,7 +58,7 @@
Stella for RetroN 77
Atari 2600 VCS emulator
- Release 6.3
+ Release 6.4
Quick Navigation Guide
diff -Nru stella-6.3/.gitlab-ci.yml stella-6.4/.gitlab-ci.yml
--- stella-6.3/.gitlab-ci.yml 1970-01-01 00:00:00.000000000 +0000
+++ stella-6.4/.gitlab-ci.yml 2020-11-02 08:08:34.000000000 +0000
@@ -0,0 +1,68 @@
+.core-defs:
+ variables:
+ JNI_PATH: src/libretro
+ CORENAME: stella
+
+include:
+ - template: Jobs/Code-Quality.gitlab-ci.yml
+ - project: 'libretro-infrastructure/ci-templates'
+ file: '/libnx-static.yml'
+ - project: 'libretro-infrastructure/ci-templates'
+ file: '/linux-x64.yml'
+ - project: 'libretro-infrastructure/ci-templates'
+ file: '/windows-x64-mingw.yml'
+ - project: 'libretro-infrastructure/ci-templates'
+ file: '/android-jni.yml'
+
+stages:
+ - build-prepare
+ - build-shared
+ - build-static
+ - test
+
+#Desktop
+libretro-build-linux-x64:
+ extends:
+ - .core-defs
+ - .libretro-linux-x64-make-default
+ variables:
+ MAKEFILE_PATH: src/libretro
+ MAKEFILE: Makefile
+
+libretro-build-windows-x64:
+ extends:
+ - .core-defs
+ - .libretro-windows-x64-mingw-make-default
+ variables:
+ MAKEFILE_PATH: src/libretro
+ MAKEFILE: Makefile
+
+# Android
+android-armeabi-v7a:
+ extends:
+ - .core-defs
+ - .libretro-android-jni-armeabi-v7a
+
+android-arm64-v8a:
+ extends:
+ - .core-defs
+ - .libretro-android-jni-arm64-v8a
+
+android-x86_64:
+ extends:
+ - .core-defs
+ - .libretro-android-jni-x86_64
+
+android-x86:
+ extends:
+ - .core-defs
+ - .libretro-android-jni-x86
+
+# Static
+libretro-build-libnx-aarch64:
+ extends:
+ - .core-defs
+ - .libretro-libnx-static-retroarch-master
+ variables:
+ MAKEFILE_PATH: src/libretro
+ MAKEFILE: Makefile
diff -Nru stella-6.3/src/common/EventHandlerSDL2.cxx stella-6.4/src/common/EventHandlerSDL2.cxx
--- stella-6.3/src/common/EventHandlerSDL2.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/EventHandlerSDL2.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -59,6 +59,30 @@
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void EventHandlerSDL2::copyText(const string& text) const
+{
+ SDL_SetClipboardText(text.c_str());
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void EventHandlerSDL2::cutText(string& text) const
+{
+ copyText(text);
+ text = "";
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+string EventHandlerSDL2::pasteText(string& text) const
+{
+ if(SDL_HasClipboardText())
+ text = SDL_GetClipboardText();
+ else
+ text = "";
+
+ return text;
+};
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandlerSDL2::pollEvent()
{
ASSERT_MAIN_THREAD;
diff -Nru stella-6.3/src/common/EventHandlerSDL2.hxx stella-6.4/src/common/EventHandlerSDL2.hxx
--- stella-6.3/src/common/EventHandlerSDL2.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/EventHandlerSDL2.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -38,13 +38,20 @@
explicit EventHandlerSDL2(OSystem& osystem);
~EventHandlerSDL2() override;
- private:
+private:
/**
Enable/disable text events (distinct from single-key events).
*/
void enableTextEvents(bool enable) override;
/**
+ Clipboard methods.
+ */
+ void copyText(const string& text) const override;
+ void cutText(string& text) const override;
+ string pasteText(string& text) const override;
+
+ /**
Collects and dispatches any pending SDL2 events.
*/
void pollEvent() override;
diff -Nru stella-6.3/src/common/FBBackendSDL2.cxx stella-6.4/src/common/FBBackendSDL2.cxx
--- stella-6.3/src/common/FBBackendSDL2.cxx 1970-01-01 00:00:00.000000000 +0000
+++ stella-6.4/src/common/FBBackendSDL2.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -0,0 +1,642 @@
+//============================================================================
+//
+// SSSS tt lll lll
+// SS SS tt ll ll
+// SS tttttt eeee ll ll aaaa
+// SSSS tt ee ee ll ll aa
+// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
+// SS SS tt ee ll ll aa aa
+// SSSS ttt eeeee llll llll aaaaa
+//
+// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
+// and the Stella Team
+//
+// See the file "License.txt" for information on usage and redistribution of
+// this file, and for a DISCLAIMER OF ALL WARRANTIES.
+//============================================================================
+
+#include
+
+#include "SDL_lib.hxx"
+#include "bspf.hxx"
+#include "Logger.hxx"
+
+#include "Console.hxx"
+#include "OSystem.hxx"
+#include "Settings.hxx"
+
+#include "ThreadDebugging.hxx"
+#include "FBSurfaceSDL2.hxx"
+#include "FBBackendSDL2.hxx"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+FBBackendSDL2::FBBackendSDL2(OSystem& osystem)
+ : myOSystem(osystem)
+{
+ ASSERT_MAIN_THREAD;
+
+ // Initialize SDL2 context
+ if(SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
+ {
+ ostringstream buf;
+ buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl;
+ Logger::error(buf.str());
+ throw runtime_error("FATAL ERROR");
+ }
+ Logger::debug("FBBackendSDL2::FBBackendSDL2 SDL_Init()");
+
+ // We need a pixel format for palette value calculations
+ // It's done this way (vs directly accessing a FBSurfaceSDL2 object)
+ // since the structure may be needed before any FBSurface's have
+ // been created
+ myPixelFormat = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+FBBackendSDL2::~FBBackendSDL2()
+{
+ ASSERT_MAIN_THREAD;
+
+ SDL_FreeFormat(myPixelFormat);
+
+ if(myRenderer)
+ {
+ SDL_DestroyRenderer(myRenderer);
+ myRenderer = nullptr;
+ }
+ if(myWindow)
+ {
+ SDL_SetWindowFullscreen(myWindow, 0); // on some systems, a crash occurs
+ // when destroying fullscreen window
+ SDL_DestroyWindow(myWindow);
+ myWindow = nullptr;
+ }
+ SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::queryHardware(vector& fullscreenRes,
+ vector& windowedRes,
+ VariantList& renderers)
+{
+ ASSERT_MAIN_THREAD;
+
+ // Get number of displays (for most systems, this will be '1')
+ myNumDisplays = SDL_GetNumVideoDisplays();
+
+ // First get the maximum fullscreen desktop resolution
+ SDL_DisplayMode display;
+ for(int i = 0; i < myNumDisplays; ++i)
+ {
+ SDL_GetDesktopDisplayMode(i, &display);
+ fullscreenRes.emplace_back(display.w, display.h);
+
+ // evaluate fullscreen display modes (debug only for now)
+ int numModes = SDL_GetNumDisplayModes(i);
+ ostringstream s;
+
+ s << "Supported video modes (" << numModes << ") for display " << i << ":";
+
+ string lastRes = "";
+
+ for(int m = 0; m < numModes; ++m)
+ {
+ SDL_DisplayMode mode;
+ ostringstream res;
+
+ SDL_GetDisplayMode(i, m, &mode);
+ res << std::setw(4) << mode.w << "x" << std::setw(4) << mode.h;
+
+ if(lastRes != res.str())
+ {
+ Logger::debug(s.str());
+ s.str("");
+ lastRes = res.str();
+ s << " " << lastRes << ": ";
+ }
+ s << mode.refresh_rate << "Hz";
+ if(mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate)
+ s << "* ";
+ else
+ s << " ";
+ }
+ Logger::debug(s.str());
+ }
+
+ // Now get the maximum windowed desktop resolution
+ // Try to take into account taskbars, etc, if available
+#if SDL_VERSION_ATLEAST(2,0,5)
+ // Take window title-bar into account; SDL_GetDisplayUsableBounds doesn't do that
+ int wTop = 0, wLeft = 0, wBottom = 0, wRight = 0;
+ SDL_Window* tmpWindow = SDL_CreateWindow("", 0, 0, 0, 0, SDL_WINDOW_HIDDEN);
+ if(tmpWindow != nullptr)
+ {
+ SDL_GetWindowBordersSize(tmpWindow, &wTop, &wLeft, &wBottom, &wRight);
+ SDL_DestroyWindow(tmpWindow);
+ }
+
+ SDL_Rect r;
+ for(int i = 0; i < myNumDisplays; ++i)
+ {
+ // Display bounds minus dock
+ SDL_GetDisplayUsableBounds(i, &r); // Requires SDL-2.0.5 or higher
+ r.h -= (wTop + wBottom);
+ windowedRes.emplace_back(r.w, r.h);
+ }
+#else
+ for(int i = 0; i < myNumDisplays; ++i)
+ {
+ SDL_GetDesktopDisplayMode(i, &display);
+ windowedRes.emplace_back(display.w, display.h);
+ }
+#endif
+
+ struct RenderName
+ {
+ string sdlName;
+ string stellaName;
+ };
+ // Create name map for all currently known SDL renderers
+ static const std::array RENDERER_NAMES = {{
+ { "direct3d", "Direct3D" },
+ { "metal", "Metal" },
+ { "opengl", "OpenGL" },
+ { "opengles", "OpenGLES" },
+ { "opengles2", "OpenGLES2" },
+ { "software", "Software" }
+ }};
+
+ int numDrivers = SDL_GetNumRenderDrivers();
+ for(int i = 0; i < numDrivers; ++i)
+ {
+ SDL_RendererInfo info;
+ if(SDL_GetRenderDriverInfo(i, &info) == 0)
+ {
+ // Map SDL names into nicer Stella names (if available)
+ bool found = false;
+ for(size_t j = 0; j < RENDERER_NAMES.size(); ++j)
+ {
+ if(RENDERER_NAMES[j].sdlName == info.name)
+ {
+ VarList::push_back(renderers, RENDERER_NAMES[j].stellaName, info.name);
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ VarList::push_back(renderers, info.name, info.name);
+ }
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool FBBackendSDL2::isCurrentWindowPositioned() const
+{
+ ASSERT_MAIN_THREAD;
+
+ return !myCenter
+ && myWindow && !(SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Common::Point FBBackendSDL2::getCurrentWindowPos() const
+{
+ ASSERT_MAIN_THREAD;
+
+ Common::Point pos;
+
+ SDL_GetWindowPosition(myWindow, &pos.x, &pos.y);
+
+ return pos;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Int32 FBBackendSDL2::getCurrentDisplayIndex() const
+{
+ ASSERT_MAIN_THREAD;
+
+ return SDL_GetWindowDisplayIndex(myWindow);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
+ int winIdx, const Common::Point& winPos)
+{
+ ASSERT_MAIN_THREAD;
+
+ // If not initialized by this point, then immediately fail
+ if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
+ return false;
+
+ const bool fullScreen = mode.fsIndex != -1;
+ bool forceCreateRenderer = false;
+ Int32 displayIndex = std::min(myNumDisplays, winIdx);
+
+ int posX, posY;
+
+ myCenter = myOSystem.settings().getBool("center");
+ if(myCenter)
+ posX = posY = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
+ else
+ {
+ posX = winPos.x;
+ posY = winPos.y;
+
+ // Make sure the window is at least partially visibile
+ int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
+
+ for(int display = SDL_GetNumVideoDisplays() - 1; display >= 0; --display)
+ {
+ SDL_Rect rect;
+
+ if (!SDL_GetDisplayUsableBounds(display, &rect))
+ {
+ x0 = std::min(x0, rect.x);
+ y0 = std::min(y0, rect.y);
+ x1 = std::max(x1, rect.x + rect.w);
+ y1 = std::max(y1, rect.y + rect.h);
+ }
+ }
+ posX = BSPF::clamp(posX, x0 - Int32(mode.screenS.w) + 50, x1 - 50);
+ posY = BSPF::clamp(posY, y0 + 50, y1 - 50);
+ }
+
+#ifdef ADAPTABLE_REFRESH_SUPPORT
+ SDL_DisplayMode adaptedSdlMode;
+ const int gameRefreshRate =
+ myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
+ const bool shouldAdapt = fullScreen
+ && myOSystem.settings().getBool("tia.fs_refresh")
+ && gameRefreshRate
+ // take care of 59.94 Hz
+ && refreshRate() % gameRefreshRate != 0
+ && refreshRate() % (gameRefreshRate - 1) != 0;
+ const bool adaptRefresh = shouldAdapt &&
+ adaptRefreshRate(displayIndex, adaptedSdlMode);
+#else
+ const bool adaptRefresh = false;
+#endif
+ const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI
+ | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN :
+ SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
+
+ // Don't re-create the window if its display and size hasn't changed,
+ // as it's not necessary, and causes flashing in fullscreen mode
+ if(myWindow)
+ {
+ const int d = SDL_GetWindowDisplayIndex(myWindow);
+ int w, h;
+
+ SDL_GetWindowSize(myWindow, &w, &h);
+ if(d != displayIndex || uInt32(w) != mode.screenS.w ||
+ uInt32(h) != mode.screenS.h || adaptRefresh)
+ {
+ SDL_DestroyWindow(myWindow);
+ myWindow = nullptr;
+ }
+ }
+
+ if(myWindow)
+ {
+ // Even though window size stayed the same, the title may have changed
+ SDL_SetWindowTitle(myWindow, myScreenTitle.c_str());
+ SDL_SetWindowPosition(myWindow, posX, posY);
+ }
+ else
+ {
+ forceCreateRenderer = true;
+ myWindow = SDL_CreateWindow(myScreenTitle.c_str(), posX, posY,
+ mode.screenS.w, mode.screenS.h, flags);
+ if(myWindow == nullptr)
+ {
+ string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError());
+ Logger::error(msg);
+ return false;
+ }
+
+ setWindowIcon();
+ }
+
+#ifdef ADAPTABLE_REFRESH_SUPPORT
+ if(adaptRefresh)
+ {
+ // Switch to mode for adapted refresh rate
+ if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0)
+ {
+ Logger::error("ERROR: Display refresh rate change failed");
+ }
+ else
+ {
+ ostringstream msg;
+
+ msg << "Display refresh rate changed to "
+ << adaptedSdlMode.refresh_rate << " Hz";
+ Logger::info(msg.str());
+ }
+ }
+#endif
+
+ return createRenderer(forceCreateRenderer);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
+ SDL_DisplayMode& adaptedSdlMode)
+{
+ ASSERT_MAIN_THREAD;
+
+ SDL_DisplayMode sdlMode;
+
+ if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0)
+ {
+ Logger::error("ERROR: Display mode could not be retrieved");
+ return false;
+ }
+
+ const int currentRefreshRate = sdlMode.refresh_rate;
+ const int wantedRefreshRate =
+ myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
+ // Take care of rounded refresh rates (e.g. 59.94 Hz)
+ float factor = std::min(float(currentRefreshRate) / wantedRefreshRate,
+ float(currentRefreshRate) / (wantedRefreshRate - 1));
+ // Calculate difference taking care of integer factors (e.g. 100/120)
+ float bestDiff = std::abs(factor - std::round(factor)) / factor;
+ bool adapt = false;
+
+ // Display refresh rate should be an integer factor of the game's refresh rate
+ // Note: Modes are scanned with size being first priority,
+ // therefore the size will never change.
+ // Check for integer factors 1 (60/50 Hz) and 2 (120/100 Hz)
+ for(int m = 1; m <= 2; ++m)
+ {
+ SDL_DisplayMode closestSdlMode;
+
+ sdlMode.refresh_rate = wantedRefreshRate * m;
+ if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == nullptr)
+ {
+ Logger::error("ERROR: Closest display mode could not be retrieved");
+ return adapt;
+ }
+ factor = std::min(float(sdlMode.refresh_rate) / sdlMode.refresh_rate,
+ float(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
+ const float diff = std::abs(factor - std::round(factor)) / factor;
+ if(diff < bestDiff)
+ {
+ bestDiff = diff;
+ adaptedSdlMode = closestSdlMode;
+ adapt = true;
+ }
+ }
+ //cerr << "refresh rate adapt ";
+ //if(adapt)
+ // cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)";
+ //else
+ // cerr << "not required/possible";
+ //cerr << endl;
+
+ // Only change if the display supports a better refresh rate
+ return adapt;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool FBBackendSDL2::createRenderer(bool force)
+{
+ ASSERT_MAIN_THREAD;
+
+ // A new renderer is only created when necessary:
+ // - new myWindow (force = true)
+ // - no renderer existing
+ // - different renderer flags
+ // - different renderer name
+ bool recreate = force || myRenderer == nullptr;
+ uInt32 renderFlags = SDL_RENDERER_ACCELERATED;
+ const string& video = myOSystem.settings().getString("video"); // Render hint
+ SDL_RendererInfo renderInfo;
+
+ if(myOSystem.settings().getBool("vsync")
+ && !myOSystem.settings().getBool("turbo")) // V'synced blits option
+ renderFlags |= SDL_RENDERER_PRESENTVSYNC;
+
+ // check renderer flags and name
+ recreate |= (SDL_GetRendererInfo(myRenderer, &renderInfo) != 0)
+ || ((renderInfo.flags & (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) != renderFlags
+ || (video != renderInfo.name));
+
+ if(recreate)
+ {
+ //cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl;
+ if(myRenderer)
+ SDL_DestroyRenderer(myRenderer);
+
+ if(video != "")
+ SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str());
+
+ myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags);
+
+ detectFeatures();
+ determineDimensions();
+
+ if(myRenderer == nullptr)
+ {
+ string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError());
+ Logger::error(msg);
+ return false;
+ }
+ }
+ clear();
+
+ SDL_RendererInfo renderinfo;
+
+ if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0)
+ myOSystem.settings().setValue("video", renderinfo.name);
+
+ return true;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::setTitle(const string& title)
+{
+ ASSERT_MAIN_THREAD;
+
+ myScreenTitle = title;
+
+ if(myWindow)
+ SDL_SetWindowTitle(myWindow, title.c_str());
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+string FBBackendSDL2::about() const
+{
+ ASSERT_MAIN_THREAD;
+
+ ostringstream out;
+ out << "Video system: " << SDL_GetCurrentVideoDriver() << endl;
+ SDL_RendererInfo info;
+ if(SDL_GetRendererInfo(myRenderer, &info) >= 0)
+ {
+ out << " Renderer: " << info.name << endl;
+ if(info.max_texture_width > 0 && info.max_texture_height > 0)
+ out << " Max texture: " << info.max_texture_width << "x"
+ << info.max_texture_height << endl;
+ out << " Flags: "
+ << ((info.flags & SDL_RENDERER_PRESENTVSYNC) ? "+" : "-") << "vsync, "
+ << ((info.flags & SDL_RENDERER_ACCELERATED) ? "+" : "-") << "accel"
+ << endl;
+ }
+ return out.str();
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::showCursor(bool show)
+{
+ ASSERT_MAIN_THREAD;
+
+ SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::grabMouse(bool grab)
+{
+ ASSERT_MAIN_THREAD;
+
+ SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool FBBackendSDL2::fullScreen() const
+{
+ ASSERT_MAIN_THREAD;
+
+#ifdef WINDOWED_SUPPORT
+ return SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP;
+#else
+ return true;
+#endif
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+int FBBackendSDL2::refreshRate() const
+{
+ ASSERT_MAIN_THREAD;
+
+ const uInt32 displayIndex = SDL_GetWindowDisplayIndex(myWindow);
+ SDL_DisplayMode sdlMode;
+
+ if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) == 0)
+ return sdlMode.refresh_rate;
+
+ if(myWindow != nullptr)
+ Logger::error("Could not retrieve current display mode");
+
+ return 0;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::renderToScreen()
+{
+ ASSERT_MAIN_THREAD;
+
+ // Show all changes made to the renderer
+ SDL_RenderPresent(myRenderer);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::setWindowIcon()
+{
+#if !defined(BSPF_MACOS) && !defined(RETRON77)
+#include "stella_icon.hxx"
+ ASSERT_MAIN_THREAD;
+
+ SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32,
+ 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
+ SDL_SetWindowIcon(myWindow, surface);
+ SDL_FreeSurface(surface);
+#endif
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+unique_ptr FBBackendSDL2::createSurface(
+ uInt32 w,
+ uInt32 h,
+ ScalingInterpolation inter,
+ const uInt32* data
+) const
+{
+ return make_unique
+ (const_cast(*this), w, h, inter, data);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::readPixels(uInt8* pixels, uInt32 pitch,
+ const Common::Rect& rect) const
+{
+ ASSERT_MAIN_THREAD;
+
+ SDL_Rect r;
+ r.x = rect.x(); r.y = rect.y();
+ r.w = rect.w(); r.h = rect.h();
+
+ SDL_RenderReadPixels(myRenderer, &r, 0, pixels, pitch);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::clear()
+{
+ ASSERT_MAIN_THREAD;
+
+ SDL_RenderClear(myRenderer);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::detectFeatures()
+{
+ myRenderTargetSupport = detectRenderTargetSupport();
+
+ if(myRenderer && !myRenderTargetSupport)
+ Logger::info("Render targets are not supported --- QIS not available");
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool FBBackendSDL2::detectRenderTargetSupport()
+{
+ ASSERT_MAIN_THREAD;
+
+ if(myRenderer == nullptr)
+ return false;
+
+ SDL_RendererInfo info;
+ SDL_GetRendererInfo(myRenderer, &info);
+
+ if(!(info.flags & SDL_RENDERER_TARGETTEXTURE))
+ return false;
+
+ SDL_Texture* tex =
+ SDL_CreateTexture(myRenderer, myPixelFormat->format,
+ SDL_TEXTUREACCESS_TARGET, 16, 16);
+
+ if(!tex)
+ return false;
+
+ int sdlError = SDL_SetRenderTarget(myRenderer, tex);
+ SDL_SetRenderTarget(myRenderer, nullptr);
+
+ SDL_DestroyTexture(tex);
+
+ return sdlError == 0;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FBBackendSDL2::determineDimensions()
+{
+ ASSERT_MAIN_THREAD;
+
+ SDL_GetWindowSize(myWindow, &myWindowW, &myWindowH);
+
+ if(myRenderer == nullptr)
+ {
+ myRenderW = myWindowW;
+ myRenderH = myWindowH;
+ }
+ else
+ SDL_GetRendererOutputSize(myRenderer, &myRenderW, &myRenderH);
+}
diff -Nru stella-6.3/src/common/FBBackendSDL2.hxx stella-6.4/src/common/FBBackendSDL2.hxx
--- stella-6.3/src/common/FBBackendSDL2.hxx 1970-01-01 00:00:00.000000000 +0000
+++ stella-6.4/src/common/FBBackendSDL2.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -0,0 +1,294 @@
+//============================================================================
+//
+// SSSS tt lll lll
+// SS SS tt ll ll
+// SS tttttt eeee ll ll aaaa
+// SSSS tt ee ee ll ll aa
+// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
+// SS SS tt ee ll ll aa aa
+// SSSS ttt eeeee llll llll aaaaa
+//
+// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
+// and the Stella Team
+//
+// See the file "License.txt" for information on usage and redistribution of
+// this file, and for a DISCLAIMER OF ALL WARRANTIES.
+//============================================================================
+
+#ifndef FB_BACKEND_SDL2_HXX
+#define FB_BACKEND_SDL2_HXX
+
+#include "SDL_lib.hxx"
+
+class OSystem;
+class FBSurfaceSDL2;
+
+#include "bspf.hxx"
+#include "FBBackend.hxx"
+
+/**
+ This class implements a standard SDL2 2D, hardware accelerated framebuffer
+ backend. Behind the scenes, it may be using Direct3D, OpenGL(ES), etc.
+
+ @author Stephen Anthony
+*/
+class FBBackendSDL2 : public FBBackend
+{
+ public:
+ /**
+ Creates a new SDL2 framebuffer
+ */
+ explicit FBBackendSDL2(OSystem& osystem);
+ ~FBBackendSDL2() override;
+
+ public:
+ /**
+ Get a pointer to the SDL renderer.
+ */
+ SDL_Renderer* renderer() { return myRenderer; }
+
+ /**
+ Is the renderer initialized?
+ */
+ bool isInitialized() const { return myRenderer != nullptr; }
+
+ /**
+ Get the SDL pixel format.
+ */
+ const SDL_PixelFormat& pixelFormat() const { return *myPixelFormat; }
+
+ /**
+ Does the renderer support render targets?
+ */
+ bool hasRenderTargetSupport() const { return myRenderTargetSupport; }
+
+ /**
+ Transform from window to renderer coordinates, x direction
+ */
+ int scaleX(int x) const override { return (x * myRenderW) / myWindowW; }
+
+ /**
+ Transform from window to renderer coordinates, y direction
+ */
+ int scaleY(int y) const override { return (y * myRenderH) / myWindowH; }
+
+ protected:
+ /**
+ Updates window title.
+
+ @param title The title of the application / window
+ */
+ void setTitle(const string& title) override;
+
+ /**
+ Shows or hides the cursor based on the given boolean value.
+ */
+ void showCursor(bool show) override;
+
+ /**
+ Answers if the display is currently in fullscreen mode.
+ */
+ bool fullScreen() const override;
+
+ /**
+ This method is called to retrieve the R/G/B data from the given pixel.
+
+ @param pixel The pixel containing R/G/B data
+ @param r The red component of the color
+ @param g The green component of the color
+ @param b The blue component of the color
+ */
+ inline void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
+ { SDL_GetRGB(pixel, myPixelFormat, r, g, b); }
+
+ /**
+ This method is called to map a given R/G/B triple to the screen palette.
+
+ @param r The red component of the color.
+ @param g The green component of the color.
+ @param b The blue component of the color.
+ */
+ inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
+ { return SDL_MapRGB(myPixelFormat, r, g, b); }
+
+ /**
+ This method is called to get a copy of the specified ARGB data from the
+ viewable FrameBuffer area. Note that this isn't the same as any
+ internal surfaces that may be in use; it should return the actual data
+ as it is currently seen onscreen.
+
+ @param buffer A copy of the pixel data in ARGB8888 format
+ @param pitch The pitch (in bytes) for the pixel data
+ @param rect The bounding rectangle for the buffer
+ */
+ void readPixels(uInt8* buffer, uInt32 pitch,
+ const Common::Rect& rect) const override;
+
+ /**
+ This method is called to query if the current window is not centered
+ or fullscreen.
+
+ @return True, if the current window is positioned
+ */
+ bool isCurrentWindowPositioned() const override;
+
+ /**
+ This method is called to query the video hardware for position of
+ the current window
+
+ @return The position of the currently displayed window
+ */
+ Common::Point getCurrentWindowPos() const override;
+
+ /**
+ This method is called to query the video hardware for the index
+ of the display the current window is displayed on
+
+ @return the current display index or a negative value if no
+ window is displayed
+ */
+ Int32 getCurrentDisplayIndex() const override;
+
+ /**
+ Clear the frame buffer.
+ */
+ void clear() override;
+
+ /**
+ This method is called to query and initialize the video hardware
+ for desktop and fullscreen resolution information. Since several
+ monitors may be attached, we need the resolution for all of them.
+
+ @param fullscreenRes Maximum resolution supported in fullscreen mode
+ @param windowedRes Maximum resolution supported in windowed mode
+ @param renderers List of renderer names (internal name -> end-user name)
+ */
+ void queryHardware(vector& fullscreenRes,
+ vector& windowedRes,
+ VariantList& renderers) override;
+
+ /**
+ This method is called to change to the given video mode.
+
+ @param mode The video mode to use
+ @param winIdx The display/monitor that the window last opened on
+ @param winPos The position that the window last opened at
+
+ @return False on any errors, else true
+ */
+ bool setVideoMode(const VideoModeHandler::Mode& mode,
+ int winIdx, const Common::Point& winPos) override;
+
+ /**
+ This method is called to create a surface with the given attributes.
+
+ @param w The requested width of the new surface.
+ @param h The requested height of the new surface.
+ @param inter Interpolation mode
+ @param data If non-null, use the given data values as a static surface
+ */
+ unique_ptr
+ createSurface(
+ uInt32 w,
+ uInt32 h,
+ ScalingInterpolation inter,
+ const uInt32* data
+ ) const override;
+
+ /**
+ Grabs or ungrabs the mouse based on the given boolean value.
+ */
+ void grabMouse(bool grab) override;
+
+ /**
+ This method is called to provide information about the backend.
+ */
+ string about() const override;
+
+ /**
+ Create a new renderer if required.
+
+ @param force If true, force new renderer creation
+
+ @return False on any errors, else true
+ */
+ bool createRenderer(bool force);
+
+ /**
+ This method must be called after all drawing is done, and indicates
+ that the buffers should be pushed to the physical screen.
+ */
+ void renderToScreen() override;
+
+ /**
+ Retrieve the current display's refresh rate, or 0 if no window.
+ */
+ int refreshRate() const override;
+
+ /**
+ Checks if the display refresh rate should be adapted to game refresh
+ rate in (real) fullscreen mode.
+
+ @param displayIndex The display which should be checked
+ @param adaptedSdlMode The best matching mode if the refresh rate
+ should be changed
+
+ @return True if the refresh rate should be changed
+ */
+ bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode);
+
+ /**
+ After the renderer has been created, detect the features it supports.
+ */
+ void detectFeatures();
+
+ /**
+ Detect render target support.
+ */
+ bool detectRenderTargetSupport();
+
+ /**
+ Determine window and renderer dimensions.
+ */
+ void determineDimensions();
+
+ /**
+ Set the icon for the main SDL window.
+ */
+ void setWindowIcon();
+
+ private:
+ OSystem& myOSystem;
+
+ // The SDL video buffer
+ SDL_Window* myWindow{nullptr};
+ SDL_Renderer* myRenderer{nullptr};
+
+ // Used by mapRGB (when palettes are created)
+ SDL_PixelFormat* myPixelFormat{nullptr};
+
+ // Center setting of current window
+ bool myCenter{false};
+
+ // Does the renderer support render targets?
+ bool myRenderTargetSupport{false};
+
+ // Title of the main window/screen
+ string myScreenTitle;
+
+ // Number of displays
+ int myNumDisplays{1};
+
+ // Window and renderer dimensions
+ int myWindowW{0}, myWindowH{0}, myRenderW{0}, myRenderH{0};
+
+ private:
+ // Following constructors and assignment operators not supported
+ FBBackendSDL2() = delete;
+ FBBackendSDL2(const FBBackendSDL2&) = delete;
+ FBBackendSDL2(FBBackendSDL2&&) = delete;
+ FBBackendSDL2& operator=(const FBBackendSDL2&) = delete;
+ FBBackendSDL2& operator=(FBBackendSDL2&&) = delete;
+};
+
+#endif
diff -Nru stella-6.3/src/common/FBSurfaceSDL2.cxx stella-6.4/src/common/FBSurfaceSDL2.cxx
--- stella-6.3/src/common/FBSurfaceSDL2.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/FBSurfaceSDL2.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -22,16 +22,16 @@
#include "sdl_blitter/BlitterFactory.hxx"
namespace {
- BlitterFactory::ScalingAlgorithm scalingAlgorithm(FrameBuffer::ScalingInterpolation interpolation)
+ BlitterFactory::ScalingAlgorithm scalingAlgorithm(ScalingInterpolation inter)
{
- switch (interpolation) {
- case FrameBuffer::ScalingInterpolation::none:
+ switch (inter) {
+ case ScalingInterpolation::none:
return BlitterFactory::ScalingAlgorithm::nearestNeighbour;
- case FrameBuffer::ScalingInterpolation::blur:
+ case ScalingInterpolation::blur:
return BlitterFactory::ScalingAlgorithm::bilinear;
- case FrameBuffer::ScalingInterpolation::sharp:
+ case ScalingInterpolation::sharp:
return BlitterFactory::ScalingAlgorithm::quasiInteger;
default:
@@ -41,12 +41,12 @@
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer,
+FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
uInt32 width, uInt32 height,
- FrameBuffer::ScalingInterpolation interpolation,
+ ScalingInterpolation inter,
const uInt32* staticData)
- : myFB(buffer),
- myInterpolationMode(interpolation)
+ : myBackend(backend),
+ myInterpolationMode(inter)
{
createSurface(width, height, staticData);
}
@@ -214,7 +214,7 @@
ASSERT_MAIN_THREAD;
// Create a surface in the same format as the parent GL class
- const SDL_PixelFormat& pf = myFB.pixelFormat();
+ const SDL_PixelFormat& pf = myBackend.pixelFormat();
mySurface = SDL_CreateRGBSurface(0, width, height,
pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask);
@@ -242,11 +242,13 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL2::reinitializeBlitter()
{
- if (!myBlitter && myFB.isInitialized())
- myBlitter = BlitterFactory::createBlitter(myFB, scalingAlgorithm(myInterpolationMode));
+ if (!myBlitter && myBackend.isInitialized())
+ myBlitter = BlitterFactory::createBlitter(
+ myBackend, scalingAlgorithm(myInterpolationMode));
if (myBlitter)
- myBlitter->reinitialize(mySrcR, myDstR, myAttributes, myIsStatic ? mySurface : nullptr);
+ myBlitter->reinitialize(mySrcR, myDstR, myAttributes,
+ myIsStatic ? mySurface : nullptr);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -256,7 +258,7 @@
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FBSurfaceSDL2::setScalingInterpolation(FrameBuffer::ScalingInterpolation interpolation)
+void FBSurfaceSDL2::setScalingInterpolation(ScalingInterpolation interpolation)
{
if (interpolation == myInterpolationMode) return;
diff -Nru stella-6.3/src/common/FBSurfaceSDL2.hxx stella-6.4/src/common/FBSurfaceSDL2.hxx
--- stella-6.3/src/common/FBSurfaceSDL2.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/FBSurfaceSDL2.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -20,7 +20,7 @@
#include "bspf.hxx"
#include "FBSurface.hxx"
-#include "FrameBufferSDL2.hxx"
+#include "FBBackendSDL2.hxx"
#include "sdl_blitter/Blitter.hxx"
/**
@@ -32,9 +32,8 @@
class FBSurfaceSDL2 : public FBSurface
{
public:
- FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height,
- FrameBuffer::ScalingInterpolation interpolation,
- const uInt32* staticData);
+ FBSurfaceSDL2(FBBackendSDL2& backend, uInt32 width, uInt32 height,
+ ScalingInterpolation inter, const uInt32* staticData);
~FBSurfaceSDL2() override;
// Most of the surface drawing primitives are implemented in FBSurface;
@@ -60,7 +59,7 @@
void reload() override;
void resize(uInt32 width, uInt32 height) override;
- void setScalingInterpolation(FrameBuffer::ScalingInterpolation) override;
+ void setScalingInterpolation(ScalingInterpolation) override;
protected:
void applyAttributes() override;
@@ -95,11 +94,11 @@
FBSurfaceSDL2& operator=(FBSurfaceSDL2&&) = delete;
private:
- FrameBufferSDL2& myFB;
+ FBBackendSDL2& myBackend;
unique_ptr myBlitter;
- FrameBuffer::ScalingInterpolation myInterpolationMode
- {FrameBuffer::ScalingInterpolation::none};
+ ScalingInterpolation myInterpolationMode
+ {ScalingInterpolation::none};
SDL_Surface* mySurface{nullptr};
SDL_Rect mySrcR{0, 0, 0, 0}, myDstR{0, 0, 0, 0};
diff -Nru stella-6.3/src/common/FrameBufferSDL2.cxx stella-6.4/src/common/FrameBufferSDL2.cxx
--- stella-6.3/src/common/FrameBufferSDL2.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/FrameBufferSDL2.cxx 1970-01-01 00:00:00.000000000 +0000
@@ -1,668 +0,0 @@
-//============================================================================
-//
-// SSSS tt lll lll
-// SS SS tt ll ll
-// SS tttttt eeee ll ll aaaa
-// SSSS tt ee ee ll ll aa
-// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
-// SS SS tt ee ll ll aa aa
-// SSSS ttt eeeee llll llll aaaaa
-//
-// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
-// and the Stella Team
-//
-// See the file "License.txt" for information on usage and redistribution of
-// this file, and for a DISCLAIMER OF ALL WARRANTIES.
-//============================================================================
-
-#include
-
-#include "SDL_lib.hxx"
-#include "bspf.hxx"
-#include "Logger.hxx"
-
-#include "Console.hxx"
-#include "OSystem.hxx"
-#include "Settings.hxx"
-
-#include "ThreadDebugging.hxx"
-#include "FBSurfaceSDL2.hxx"
-#include "FrameBufferSDL2.hxx"
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem)
- : FrameBuffer(osystem)
-{
- ASSERT_MAIN_THREAD;
-
- // Initialize SDL2 context
- if(SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
- {
- ostringstream buf;
- buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl;
- Logger::error(buf.str());
- throw runtime_error("FATAL ERROR");
- }
- Logger::debug("FrameBufferSDL2::FrameBufferSDL2 SDL_Init()");
-
- // We need a pixel format for palette value calculations
- // It's done this way (vs directly accessing a FBSurfaceSDL2 object)
- // since the structure may be needed before any FBSurface's have
- // been created
- myPixelFormat = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-FrameBufferSDL2::~FrameBufferSDL2()
-{
- ASSERT_MAIN_THREAD;
-
- SDL_FreeFormat(myPixelFormat);
-
- if(myRenderer)
- {
- // Make sure to free surfaces/textures before destroying the renderer itself
- // Most platforms are fine with doing this in either order, but it seems
- // that OpenBSD in particular crashes when attempting to destroy textures
- // *after* the renderer is already destroyed
- freeSurfaces();
-
- SDL_DestroyRenderer(myRenderer);
- myRenderer = nullptr;
- }
- if(myWindow)
- {
- SDL_SetWindowFullscreen(myWindow, 0); // on some systems, a crash occurs
- // when destroying fullscreen window
- SDL_DestroyWindow(myWindow);
- myWindow = nullptr;
- }
- SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::queryHardware(vector& fullscreenRes,
- vector& windowedRes,
- VariantList& renderers)
-{
- ASSERT_MAIN_THREAD;
-
- // Get number of displays (for most systems, this will be '1')
- myNumDisplays = SDL_GetNumVideoDisplays();
-
- // First get the maximum fullscreen desktop resolution
- SDL_DisplayMode display;
- for(int i = 0; i < myNumDisplays; ++i)
- {
- SDL_GetDesktopDisplayMode(i, &display);
- fullscreenRes.emplace_back(display.w, display.h);
-
- // evaluate fullscreen display modes (debug only for now)
- int numModes = SDL_GetNumDisplayModes(i);
- ostringstream s;
-
- s << "Supported video modes (" << numModes << ") for display " << i << ":";
-
- string lastRes = "";
-
- for (int m = 0; m < numModes; m++)
- {
- SDL_DisplayMode mode;
- ostringstream res;
-
- SDL_GetDisplayMode(i, m, &mode);
- res << std::setw(4) << mode.w << "x" << std::setw(4) << mode.h;
-
- if(lastRes != res.str())
- {
- Logger::debug(s.str());
- s.str("");
- lastRes = res.str();
- s << " " << lastRes << ": ";
- }
- s << mode.refresh_rate << "Hz";
- if(mode.w == display.w && mode.h == display.h && mode.refresh_rate == display.refresh_rate)
- s << "* ";
- else
- s << " ";
- }
- Logger::debug(s.str());
- }
-
- // Now get the maximum windowed desktop resolution
- // Try to take into account taskbars, etc, if available
-#if SDL_VERSION_ATLEAST(2,0,5)
- // Take window title-bar into account; SDL_GetDisplayUsableBounds doesn't do that
- int wTop = 0, wLeft = 0, wBottom = 0, wRight = 0;
- SDL_Window* tmpWindow = SDL_CreateWindow("", 0, 0, 0, 0, SDL_WINDOW_HIDDEN);
- if(tmpWindow != nullptr)
- {
- SDL_GetWindowBordersSize(tmpWindow, &wTop, &wLeft, &wBottom, &wRight);
- SDL_DestroyWindow(tmpWindow);
- }
-
- SDL_Rect r;
- for(int i = 0; i < myNumDisplays; ++i)
- {
- // Display bounds minus dock
- SDL_GetDisplayUsableBounds(i, &r); // Requires SDL-2.0.5 or higher
- r.h -= (wTop + wBottom);
- windowedRes.emplace_back(r.w, r.h);
- }
-#else
- for(int i = 0; i < myNumDisplays; ++i)
- {
- SDL_GetDesktopDisplayMode(i, &display);
- windowedRes.emplace_back(display.w, display.h);
- }
-#endif
-
- struct RenderName
- {
- string sdlName;
- string stellaName;
- };
- // Create name map for all currently known SDL renderers
- static const std::array RENDERER_NAMES = {{
- { "direct3d", "Direct3D" },
- { "metal", "Metal" },
- { "opengl", "OpenGL" },
- { "opengles", "OpenGLES" },
- { "opengles2", "OpenGLES2" },
- { "software", "Software" }
- }};
-
- int numDrivers = SDL_GetNumRenderDrivers();
- for(int i = 0; i < numDrivers; ++i)
- {
- SDL_RendererInfo info;
- if(SDL_GetRenderDriverInfo(i, &info) == 0)
- {
- // Map SDL names into nicer Stella names (if available)
- bool found = false;
- for(size_t j = 0; j < RENDERER_NAMES.size(); ++j)
- {
- if(RENDERER_NAMES[j].sdlName == info.name)
- {
- VarList::push_back(renderers, RENDERER_NAMES[j].stellaName, info.name);
- found = true;
- break;
- }
- }
- if(!found)
- VarList::push_back(renderers, info.name, info.name);
- }
- }
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::isCurrentWindowPositioned() const
-{
- ASSERT_MAIN_THREAD;
-
- return !myCenter
- && myWindow && !(SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Common::Point FrameBufferSDL2::getCurrentWindowPos() const
-{
- ASSERT_MAIN_THREAD;
-
- Common::Point pos;
-
- SDL_GetWindowPosition(myWindow, &pos.x, &pos.y);
-
- return pos;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Int32 FrameBufferSDL2::getCurrentDisplayIndex() const
-{
- ASSERT_MAIN_THREAD;
-
- return SDL_GetWindowDisplayIndex(myWindow);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode)
-{
- ASSERT_MAIN_THREAD;
-
- // If not initialized by this point, then immediately fail
- if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
- return false;
-
- const bool fullScreen = mode.fsIndex != -1;
- bool forceCreateRenderer = false;
-
- // Get windowed window's last display
- Int32 displayIndex = std::min(myNumDisplays, myOSystem.settings().getInt(getDisplayKey()));
- // Get windowed window's last position
- myWindowedPos = myOSystem.settings().getPoint(getPositionKey());
-
- int posX, posY;
-
- myCenter = myOSystem.settings().getBool("center");
- if (myCenter)
- posX = posY = SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex);
- else
- {
- posX = myWindowedPos.x;
- posY = myWindowedPos.y;
-
- // Make sure the window is at least partially visibile
- int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
-
- for (int display = SDL_GetNumVideoDisplays() - 1; display >= 0; display--)
- {
- SDL_Rect rect;
-
- if (!SDL_GetDisplayUsableBounds(display, &rect))
- {
- x0 = std::min(x0, rect.x);
- y0 = std::min(y0, rect.y);
- x1 = std::max(x1, rect.x + rect.w);
- y1 = std::max(y1, rect.y + rect.h);
- }
- }
- posX = BSPF::clamp(posX, x0 - Int32(mode.screen.w) + 50, x1 - 50);
- posY = BSPF::clamp(posY, y0 + 50, y1 - 50);
- }
-
-#ifdef ADAPTABLE_REFRESH_SUPPORT
- SDL_DisplayMode adaptedSdlMode;
- const bool shouldAdapt = fullScreen && myOSystem.settings().getBool("tia.fs_refresh")
- && gameRefreshRate()
- // take care of 59.94 Hz
- && refreshRate() % gameRefreshRate() != 0 && refreshRate() % (gameRefreshRate() - 1) != 0;
- const bool adaptRefresh = shouldAdapt && adaptRefreshRate(displayIndex, adaptedSdlMode);
-#else
- const bool adaptRefresh = false;
-#endif
- const uInt32 flags = SDL_WINDOW_ALLOW_HIGHDPI
- | (fullScreen ? adaptRefresh ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
-
- // Don't re-create the window if its display and size hasn't changed,
- // as it's not necessary, and causes flashing in fullscreen mode
- if(myWindow)
- {
- const int d = SDL_GetWindowDisplayIndex(myWindow);
- int w, h;
-
- SDL_GetWindowSize(myWindow, &w, &h);
- if(d != displayIndex || uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h
- || adaptRefresh)
- {
- SDL_DestroyWindow(myWindow);
- myWindow = nullptr;
- }
- }
-
- if(myWindow)
- {
- // Even though window size stayed the same, the title may have changed
- SDL_SetWindowTitle(myWindow, title.c_str());
- SDL_SetWindowPosition(myWindow, posX, posY);
- }
- else
- {
- forceCreateRenderer = true;
- myWindow = SDL_CreateWindow(title.c_str(), posX, posY,
- mode.screen.w, mode.screen.h, flags);
- if(myWindow == nullptr)
- {
- string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError());
- Logger::error(msg);
- return false;
- }
-
- setWindowIcon();
- }
-
-#ifdef ADAPTABLE_REFRESH_SUPPORT
- if(adaptRefresh)
- {
- // Switch to mode for adapted refresh rate
- if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0)
- {
- Logger::error("ERROR: Display refresh rate change failed");
- }
- else
- {
- ostringstream msg;
-
- msg << "Display refresh rate changed to " << adaptedSdlMode.refresh_rate << " Hz";
- Logger::info(msg.str());
- }
- }
-#endif
-
- return createRenderer(forceCreateRenderer);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode)
-{
- SDL_DisplayMode sdlMode;
-
- if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) != 0)
- {
- Logger::error("ERROR: Display mode could not be retrieved");
- return false;
- }
-
- const int currentRefreshRate = sdlMode.refresh_rate;
- const int wantedRefreshRate = gameRefreshRate();
- // Take care of rounded refresh rates (e.g. 59.94 Hz)
- float factor = std::min(float(currentRefreshRate) / wantedRefreshRate,
- float(currentRefreshRate) / (wantedRefreshRate - 1));
- // Calculate difference taking care of integer factors (e.g. 100/120)
- float bestDiff = std::abs(factor - std::round(factor)) / factor;
- bool adapt = false;
-
- // Display refresh rate should be an integer factor of the game's refresh rate
- // Note: Modes are scanned with size being first priority,
- // therefore the size will never change.
- // Check for integer factors 1 (60/50 Hz) and 2 (120/100 Hz)
- for(int m = 1; m <= 2; ++m)
- {
- SDL_DisplayMode closestSdlMode;
-
- sdlMode.refresh_rate = wantedRefreshRate * m;
- if(SDL_GetClosestDisplayMode(displayIndex, &sdlMode, &closestSdlMode) == nullptr)
- {
- Logger::error("ERROR: Closest display mode could not be retrieved");
- return adapt;
- }
- factor = std::min(float(sdlMode.refresh_rate) / sdlMode.refresh_rate,
- float(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
- const float diff = std::abs(factor - std::round(factor)) / factor;
- if(diff < bestDiff)
- {
- bestDiff = diff;
- adaptedSdlMode = closestSdlMode;
- adapt = true;
- }
- }
- //cerr << "refresh rate adapt ";
- //if(adapt)
- // cerr << "required (" << currentRefreshRate << " Hz -> " << adaptedSdlMode.refresh_rate << " Hz)";
- //else
- // cerr << "not required/possible";
- //cerr << endl;
-
- // Only change if the display supports a better refresh rate
- return adapt;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::createRenderer(bool force)
-{
- // A new renderer is only created when necessary:
- // - new myWindow (force = true)
- // - no renderer existing
- // - different renderer flags
- // - different renderer name
- bool recreate = force || myRenderer == nullptr;
- uInt32 renderFlags = SDL_RENDERER_ACCELERATED;
- const string& video = myOSystem.settings().getString("video"); // Render hint
- SDL_RendererInfo renderInfo;
-
- if(myOSystem.settings().getBool("vsync")
- && !myOSystem.settings().getBool("turbo")) // V'synced blits option
- renderFlags |= SDL_RENDERER_PRESENTVSYNC;
-
- // check renderer flags and name
- recreate |= (SDL_GetRendererInfo(myRenderer, &renderInfo) != 0)
- || ((renderInfo.flags & (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) != renderFlags
- || (video != renderInfo.name));
-
- if(recreate)
- {
- //cerr << "Create new renderer for buffer type #" << int(myBufferType) << endl;
- if(myRenderer)
- SDL_DestroyRenderer(myRenderer);
-
- if(video != "")
- SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str());
-
- myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags);
-
- detectFeatures();
- determineDimensions();
-
- if(myRenderer == nullptr)
- {
- string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError());
- Logger::error(msg);
- return false;
- }
- }
- clear();
-
- SDL_RendererInfo renderinfo;
-
- if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0)
- myOSystem.settings().setValue("video", renderinfo.name);
-
- return true;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::setTitle(const string& title)
-{
- ASSERT_MAIN_THREAD;
-
- myScreenTitle = title;
-
- if(myWindow)
- SDL_SetWindowTitle(myWindow, title.c_str());
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string FrameBufferSDL2::about() const
-{
- ASSERT_MAIN_THREAD;
-
- ostringstream out;
- out << "Video system: " << SDL_GetCurrentVideoDriver() << endl;
- SDL_RendererInfo info;
- if(SDL_GetRendererInfo(myRenderer, &info) >= 0)
- {
- out << " Renderer: " << info.name << endl;
- if(info.max_texture_width > 0 && info.max_texture_height > 0)
- out << " Max texture: " << info.max_texture_width << "x"
- << info.max_texture_height << endl;
- out << " Flags: "
- << ((info.flags & SDL_RENDERER_PRESENTVSYNC) ? "+" : "-") << "vsync, "
- << ((info.flags & SDL_RENDERER_ACCELERATED) ? "+" : "-") << "accel"
- << endl;
- }
- return out.str();
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::showCursor(bool show)
-{
- ASSERT_MAIN_THREAD;
-
- SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::grabMouse(bool grab)
-{
- ASSERT_MAIN_THREAD;
-
- SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::fullScreen() const
-{
- ASSERT_MAIN_THREAD;
-
-#ifdef WINDOWED_SUPPORT
- return SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP;
-#else
- return true;
-#endif
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-int FrameBufferSDL2::refreshRate() const
-{
- ASSERT_MAIN_THREAD;
-
- const uInt32 displayIndex = SDL_GetWindowDisplayIndex(myWindow);
- SDL_DisplayMode sdlMode;
-
- if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) == 0)
- return sdlMode.refresh_rate;
-
- if(myWindow != nullptr)
- Logger::error("Could not retrieve current display mode");
-
- return 0;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-int FrameBufferSDL2::gameRefreshRate() const
-{
- if(myOSystem.hasConsole())
- {
- const string format = myOSystem.console().getFormatString();
- const bool isNtsc = format == "NTSC" || format == "PAL60" || format == "SECAM60";
-
- return isNtsc ? 60 : 50; // The code will take care of 59/49 Hz
- }
- return 0;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::renderToScreen()
-{
- ASSERT_MAIN_THREAD;
-
- // Show all changes made to the renderer
- SDL_RenderPresent(myRenderer);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::setWindowIcon()
-{
-#if !defined(BSPF_MACOS) && !defined(RETRON77)
-#include "stella_icon.hxx"
- ASSERT_MAIN_THREAD;
-
- SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32,
- 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
- SDL_SetWindowIcon(myWindow, surface);
- SDL_FreeSurface(surface);
-#endif
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-unique_ptr FrameBufferSDL2::createSurface(
- uInt32 w,
- uInt32 h,
- FrameBuffer::ScalingInterpolation interpolation,
- const uInt32* data
-) const
-{
- return make_unique(const_cast(*this), w, h, interpolation, data);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch,
- const Common::Rect& rect) const
-{
- ASSERT_MAIN_THREAD;
-
- SDL_Rect r;
- r.x = rect.x(); r.y = rect.y();
- r.w = rect.w(); r.h = rect.h();
-
- SDL_RenderReadPixels(myRenderer, &r, 0, pixels, pitch);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::clear()
-{
- ASSERT_MAIN_THREAD;
-
- SDL_RenderClear(myRenderer);
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-SDL_Renderer* FrameBufferSDL2::renderer()
-{
- return myRenderer;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::isInitialized() const
-{
- return myRenderer != nullptr;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-const SDL_PixelFormat& FrameBufferSDL2::pixelFormat() const
-{
- return *myPixelFormat;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::detectFeatures()
-{
- myRenderTargetSupport = detectRenderTargetSupport();
-
- if (myRenderer) {
- if (!myRenderTargetSupport) {
- Logger::info("Render targets are not supported --- QIS not available");
- }
- }
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::detectRenderTargetSupport()
-{
- if (myRenderer == nullptr) return false;
-
- SDL_RendererInfo info;
-
- SDL_GetRendererInfo(myRenderer, &info);
-
- if (!(info.flags & SDL_RENDERER_TARGETTEXTURE)) return false;
-
- SDL_Texture* tex = SDL_CreateTexture(myRenderer, myPixelFormat->format, SDL_TEXTUREACCESS_TARGET, 16, 16);
-
- if (!tex) return false;
-
- int sdlError = SDL_SetRenderTarget(myRenderer, tex);
- SDL_SetRenderTarget(myRenderer, nullptr);
-
- SDL_DestroyTexture(tex);
-
- return sdlError == 0;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool FrameBufferSDL2::hasRenderTargetSupport() const
-{
- return myRenderTargetSupport;
-}
-
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void FrameBufferSDL2::determineDimensions()
-{
- SDL_GetWindowSize(myWindow, &myWindowW, &myWindowH);
-
- if (myRenderer == nullptr) {
- myRenderW = myWindowW;
- myRenderH = myWindowH;
- } else {
- SDL_GetRendererOutputSize(myRenderer, &myRenderW, &myRenderH);
- }
-}
diff -Nru stella-6.3/src/common/FrameBufferSDL2.hxx stella-6.4/src/common/FrameBufferSDL2.hxx
--- stella-6.3/src/common/FrameBufferSDL2.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/FrameBufferSDL2.hxx 1970-01-01 00:00:00.000000000 +0000
@@ -1,294 +0,0 @@
-//============================================================================
-//
-// SSSS tt lll lll
-// SS SS tt ll ll
-// SS tttttt eeee ll ll aaaa
-// SSSS tt ee ee ll ll aa
-// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
-// SS SS tt ee ll ll aa aa
-// SSSS ttt eeeee llll llll aaaaa
-//
-// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
-// and the Stella Team
-//
-// See the file "License.txt" for information on usage and redistribution of
-// this file, and for a DISCLAIMER OF ALL WARRANTIES.
-//============================================================================
-
-#ifndef FRAMEBUFFER_SDL2_HXX
-#define FRAMEBUFFER_SDL2_HXX
-
-#include "SDL_lib.hxx"
-
-class OSystem;
-class FBSurfaceSDL2;
-
-#include "bspf.hxx"
-#include "FrameBuffer.hxx"
-
-/**
- This class implements a standard SDL2 2D, hardware accelerated framebuffer.
- Behind the scenes, it may be using Direct3D, OpenGL(ES), etc.
-
- @author Stephen Anthony
-*/
-class FrameBufferSDL2 : public FrameBuffer
-{
- public:
- /**
- Creates a new SDL2 framebuffer
- */
- explicit FrameBufferSDL2(OSystem& osystem);
- ~FrameBufferSDL2() override;
-
- //////////////////////////////////////////////////////////////////////
- // The following are derived from public methods in FrameBuffer.hxx
- //////////////////////////////////////////////////////////////////////
-
- /**
- Updates window title.
-
- @param title The title of the application / window
- */
- void setTitle(const string& title) override;
-
- /**
- Shows or hides the cursor based on the given boolean value.
- */
- void showCursor(bool show) override;
-
- /**
- Answers if the display is currently in fullscreen mode.
- */
- bool fullScreen() const override;
-
- /**
- This method is called to retrieve the R/G/B data from the given pixel.
-
- @param pixel The pixel containing R/G/B data
- @param r The red component of the color
- @param g The green component of the color
- @param b The blue component of the color
- */
- inline void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
- { SDL_GetRGB(pixel, myPixelFormat, r, g, b); }
-
- /**
- This method is called to map a given R/G/B triple to the screen palette.
-
- @param r The red component of the color.
- @param g The green component of the color.
- @param b The blue component of the color.
- */
- inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
- { return SDL_MapRGB(myPixelFormat, r, g, b); }
-
- /**
- This method is called to get a copy of the specified ARGB data from the
- viewable FrameBuffer area. Note that this isn't the same as any
- internal surfaces that may be in use; it should return the actual data
- as it is currently seen onscreen.
-
- @param buffer A copy of the pixel data in ARGB8888 format
- @param pitch The pitch (in bytes) for the pixel data
- @param rect The bounding rectangle for the buffer
- */
- void readPixels(uInt8* buffer, uInt32 pitch, const Common::Rect& rect) const override;
-
- /**
- This method is called to query if the current window is not centered
- or fullscreen.
-
- @return True, if the current window is positioned
- */
- bool isCurrentWindowPositioned() const override;
-
- /**
- This method is called to query the video hardware for position of
- the current window
-
- @return The position of the currently displayed window
- */
- Common::Point getCurrentWindowPos() const override;
- /**
- This method is called to query the video hardware for the index
- of the display the current window is displayed on
-
- @return the current display index or a negative value if no
- window is displayed
- */
- Int32 getCurrentDisplayIndex() const override;
-
- /**
- Clear the frame buffer.
- */
- void clear() override;
-
- /**
- Get a pointer to the SDL renderer.
- */
- SDL_Renderer* renderer();
-
- /**
- Get the SDL pixel format.
- */
- const SDL_PixelFormat& pixelFormat() const;
-
- /**
- Is the renderer initialized?
- */
- bool isInitialized() const;
-
- /**
- Does the renderer support render targets?
- */
- bool hasRenderTargetSupport() const;
-
- /**
- Transform from window to renderer coordinates, x direction
- */
- int scaleX(int x) const override { return (x * myRenderW) / myWindowW; }
-
- /**
- Transform from window to renderer coordinates, y direction
- */
- int scaleY(int y) const override { return (y * myRenderH) / myWindowH; }
-
- protected:
- //////////////////////////////////////////////////////////////////////
- // The following are derived from protected methods in FrameBuffer.hxx
- //////////////////////////////////////////////////////////////////////
- /**
- This method is called to query and initialize the video hardware
- for desktop and fullscreen resolution information. Since several
- monitors may be attached, we need the resolution for all of them.
-
- @param fullscreenRes Maximum resolution supported in fullscreen mode
- @param windowedRes Maximum resolution supported in windowed mode
- @param renderers List of renderer names (internal name -> end-user name)
- */
- void queryHardware(vector& fullscreenRes,
- vector& windowedRes,
- VariantList& renderers) override;
-
- /**
- This method is called to change to the given video mode.
-
- @param title The title for the created window
- @param mode The video mode to use
-
- @return False on any errors, else true
- */
- bool setVideoMode(const string& title, const VideoMode& mode) override;
-
- /**
- Checks if the display refresh rate should be adapted to game refresh rate in (real) fullscreen mode
-
- @param displayIndex The display which should be checked
- @param adaptedSdlMode The best matching mode if the refresh rate should be changed
-
- @return True if the refresh rate should be changed
- */
- bool adaptRefreshRate(Int32 displayIndex, SDL_DisplayMode& adaptedSdlMode);
-
- /**
- Create a new renderer if required
-
- @param force If true, force new renderer creation
-
- @return False on any errors, else true
- */
- bool createRenderer(bool force);
-
- /**
- This method is called to create a surface with the given attributes.
-
- @param w The requested width of the new surface.
- @param h The requested height of the new surface.
- @param interpolation Interpolation mode
- @param data If non-null, use the given data values as a static surface
- */
- unique_ptr
- createSurface(
- uInt32 w,
- uInt32 h,
- FrameBuffer::ScalingInterpolation interpolation,
- const uInt32* data
- ) const override;
-
- /**
- Grabs or ungrabs the mouse based on the given boolean value.
- */
- void grabMouse(bool grab) override;
-
- /**
- Set the icon for the main SDL window.
- */
- void setWindowIcon() override;
-
- /**
- This method is called to provide information about the FrameBuffer.
- */
- string about() const override;
-
- /**
- This method must be called after all drawing is done, and indicates
- that the buffers should be pushed to the physical screen.
- */
- void renderToScreen() override;
-
- /**
- After the renderer has been created, detect the features it supports.
- */
- void detectFeatures();
-
- /**
- Detect render target support;
- */
- bool detectRenderTargetSupport();
-
- /**
- Determine window and renderer dimensions.
- */
- void determineDimensions();
-
- /**
- Retrieve the current display's refresh rate, or 0 if no window
- */
- int refreshRate() const override;
-
- /**
- Retrieve the current game's refresh rate, or 60 if no game
- */
- int gameRefreshRate() const;
-
- private:
- // The SDL video buffer
- SDL_Window* myWindow{nullptr};
- SDL_Renderer* myRenderer{nullptr};
-
- // Used by mapRGB (when palettes are created)
- SDL_PixelFormat* myPixelFormat{nullptr};
-
- // Center setting of current window
- bool myCenter{false};
-
- // last position of windowed window
- Common::Point myWindowedPos;
-
- // Does the renderer support render targets?
- bool myRenderTargetSupport{false};
-
- // Window and renderer dimensions
- int myWindowW{0}, myWindowH{0}, myRenderW{0}, myRenderH{0};
-
- private:
- // Following constructors and assignment operators not supported
- FrameBufferSDL2() = delete;
- FrameBufferSDL2(const FrameBufferSDL2&) = delete;
- FrameBufferSDL2(FrameBufferSDL2&&) = delete;
- FrameBufferSDL2& operator=(const FrameBufferSDL2&) = delete;
- FrameBufferSDL2& operator=(FrameBufferSDL2&&) = delete;
-};
-
-#endif
diff -Nru stella-6.3/src/common/MediaFactory.hxx stella-6.4/src/common/MediaFactory.hxx
--- stella-6.3/src/common/MediaFactory.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/MediaFactory.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -51,10 +51,10 @@
#if defined(__LIB_RETRO__)
#include "EventHandlerLIBRETRO.hxx"
- #include "FrameBufferLIBRETRO.hxx"
+ #include "FBBackendLIBRETRO.hxx"
#elif defined(SDL_SUPPORT)
#include "EventHandlerSDL2.hxx"
- #include "FrameBufferSDL2.hxx"
+ #include "FBBackendSDL2.hxx"
#else
#error Unsupported backend!
#endif
@@ -128,12 +128,12 @@
#endif
}
- static unique_ptr createVideo(OSystem& osystem)
+ static unique_ptr createVideoBackend(OSystem& osystem)
{
#if defined(__LIB_RETRO__)
- return make_unique(osystem);
+ return make_unique(osystem);
#elif defined(SDL_SUPPORT)
- return make_unique(osystem);
+ return make_unique(osystem);
#else
#error Unsupported platform for FrameBuffer!
#endif
diff -Nru stella-6.3/src/common/module.mk stella-6.4/src/common/module.mk
--- stella-6.3/src/common/module.mk 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/module.mk 2020-11-02 08:08:34.000000000 +0000
@@ -1,10 +1,13 @@
MODULE := src/common
MODULE_OBJS := \
+ src/common/AudioQueue.o \
+ src/common/AudioSettings.o \
src/common/Base.o \
src/common/EventHandlerSDL2.o \
+ src/common/FBBackendSDL2.o \
src/common/FBSurfaceSDL2.o \
- src/common/FrameBufferSDL2.o \
+ src/common/FpsMeter.o \
src/common/FSNodeZIP.o \
src/common/JoyMap.o \
src/common/KeyMap.o \
@@ -19,14 +22,12 @@
src/common/PNGLibrary.o \
src/common/RewindManager.o \
src/common/SoundSDL2.o \
+ src/common/StaggeredLogger.o \
src/common/StateManager.o \
+ src/common/ThreadDebugging.o \
src/common/TimerManager.o \
+ src/common/VideoModeHandler.o \
src/common/ZipHandler.o \
- src/common/AudioQueue.o \
- src/common/AudioSettings.o \
- src/common/FpsMeter.o \
- src/common/ThreadDebugging.o \
- src/common/StaggeredLogger.o \
src/common/repository/KeyValueRepositoryConfigfile.o \
src/common/sdl_blitter/BilinearBlitter.o \
src/common/sdl_blitter/QisBlitter.o \
diff -Nru stella-6.3/src/common/PaletteHandler.cxx stella-6.4/src/common/PaletteHandler.cxx
--- stella-6.3/src/common/PaletteHandler.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/PaletteHandler.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -75,13 +75,37 @@
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool PaletteHandler::isCustomAdjustable() const
+{
+ return myCurrentAdjustable >= CUSTOM_START
+ && myCurrentAdjustable <= CUSTOM_END;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool PaletteHandler::isPhaseShift() const
+{
+ return myCurrentAdjustable == PHASE_SHIFT;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool PaletteHandler::isRGBScale() const
+{
+ return myCurrentAdjustable >= RED_SCALE && myCurrentAdjustable <= BLUE_SCALE;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+bool PaletteHandler::isRGBShift() const
+{
+ return myCurrentAdjustable >= RED_SHIFT && myCurrentAdjustable <= BLUE_SHIFT;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaletteHandler::showAdjustableMessage()
{
- const bool isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr;
ostringstream msg, buf;
msg << "Palette " << myAdjustables[myCurrentAdjustable].name;
- if(isPhaseShift)
+ if(isPhaseShift())
{
const ConsoleTiming timing = myOSystem.console().timing();
const bool isNTSC = timing == ConsoleTiming::ntsc;
@@ -90,12 +114,22 @@
buf << std::fixed << std::setprecision(1) << value << DEGREE;
myOSystem.frameBuffer().showMessage(
"Palette phase shift", buf.str(), value,
- (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_SHIFT,
- (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_SHIFT);
+ (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) - MAX_PHASE_SHIFT,
+ (isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT) + MAX_PHASE_SHIFT);
+ }
+ else if(isRGBShift())
+ {
+ const float value = *myAdjustables[myCurrentAdjustable].value;
+
+ buf << std::fixed << std::setprecision(1) << value << DEGREE;
+ myOSystem.frameBuffer().showMessage(
+ msg.str(), buf.str(), value, -MAX_RGB_SHIFT, +MAX_RGB_SHIFT);
}
else
{
- const int value = scaleTo100(*myAdjustables[myCurrentAdjustable].value);
+ const int value = isRGBScale()
+ ? scaleRGBTo100(*myAdjustables[myCurrentAdjustable].value)
+ : scaleTo100(*myAdjustables[myCurrentAdjustable].value);
buf << value << "%";
myOSystem.frameBuffer().showMessage(
msg.str(), buf.str(), value);
@@ -106,15 +140,15 @@
void PaletteHandler::cycleAdjustable(int direction)
{
const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette");
- bool isPhaseShift;
+ bool isCustomAdj;
do {
myCurrentAdjustable = BSPF::clampw(int(myCurrentAdjustable + direction), 0, NUM_ADJUSTABLES - 1);
- isPhaseShift = myAdjustables[myCurrentAdjustable].value == nullptr;
+ isCustomAdj = isCustomAdjustable();
// skip phase shift when 'Custom' palette is not selected
- if(!direction && isPhaseShift && !isCustomPalette)
+ if(!direction && isCustomAdj && !isCustomPalette)
myCurrentAdjustable++;
- } while(isPhaseShift && !isCustomPalette);
+ } while(isCustomAdj && !isCustomPalette);
showAdjustableMessage();
}
@@ -122,29 +156,38 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaletteHandler::changeAdjustable(int adjustable, int direction)
{
- const bool isCustomPalette = SETTING_CUSTOM == myOSystem.settings().getString("palette");
- const bool isPhaseShift = myAdjustables[adjustable].value == nullptr;
-
myCurrentAdjustable = adjustable;
- if(isPhaseShift && !isCustomPalette)
- myCurrentAdjustable++;
-
changeCurrentAdjustable(direction);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaletteHandler::changeCurrentAdjustable(int direction)
{
- if(myAdjustables[myCurrentAdjustable].value == nullptr)
+ if(isPhaseShift())
changeColorPhaseShift(direction);
else
{
- int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value);
+ if(isRGBScale())
+ {
+ int newVal = scaleRGBTo100(*myAdjustables[myCurrentAdjustable].value);
- newVal = BSPF::clamp(newVal + direction * 1, 0, 100);
+ newVal = BSPF::clamp(newVal + direction * 1, 0, 100);
+ *myAdjustables[myCurrentAdjustable].value = scaleRGBFrom100(newVal);
+ }
+ else if(isRGBShift())
+ {
+ float newShift = *myAdjustables[myCurrentAdjustable].value;
- *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal);
+ newShift = BSPF::clamp(newShift + direction * 0.5F, -MAX_RGB_SHIFT, MAX_RGB_SHIFT);
+ *myAdjustables[myCurrentAdjustable].value = newShift;
+ }
+ else
+ {
+ int newVal = scaleTo100(*myAdjustables[myCurrentAdjustable].value);
+ newVal = BSPF::clamp(newVal + direction * 1, 0, 100);
+ *myAdjustables[myCurrentAdjustable].value = scaleFrom100(newVal);
+ }
showAdjustableMessage();
setPalette();
}
@@ -162,7 +205,7 @@
const float shift = isNTSC ? DEF_NTSC_SHIFT : DEF_PAL_SHIFT;
float newPhase = isNTSC ? myPhaseNTSC : myPhasePAL;
- newPhase = BSPF::clamp(newPhase + direction * 0.3F, shift - MAX_SHIFT, shift + MAX_SHIFT);
+ newPhase = BSPF::clamp(newPhase + direction * 0.3F, shift - MAX_PHASE_SHIFT, shift + MAX_PHASE_SHIFT);
if(isNTSC)
myPhaseNTSC = newPhase;
@@ -181,15 +224,21 @@
{
// Load adjustables
myPhaseNTSC = BSPF::clamp(settings.getFloat("pal.phase_ntsc"),
- DEF_NTSC_SHIFT - MAX_SHIFT, DEF_NTSC_SHIFT + MAX_SHIFT);
+ DEF_NTSC_SHIFT - MAX_PHASE_SHIFT, DEF_NTSC_SHIFT + MAX_PHASE_SHIFT);
myPhasePAL = BSPF::clamp(settings.getFloat("pal.phase_pal"),
- DEF_PAL_SHIFT - MAX_SHIFT, DEF_PAL_SHIFT + MAX_SHIFT);
-
- myHue = BSPF::clamp(settings.getFloat("pal.hue"), -1.0F, 1.0F);
- mySaturation = BSPF::clamp(settings.getFloat("pal.saturation"), -1.0F, 1.0F);
- myContrast = BSPF::clamp(settings.getFloat("pal.contrast"), -1.0F, 1.0F);
- myBrightness = BSPF::clamp(settings.getFloat("pal.brightness"), -1.0F, 1.0F);
- myGamma = BSPF::clamp(settings.getFloat("pal.gamma"), -1.0F, 1.0F);
+ DEF_PAL_SHIFT - MAX_PHASE_SHIFT, DEF_PAL_SHIFT + MAX_PHASE_SHIFT);
+ myRedScale = BSPF::clamp(settings.getFloat("pal.red_scale"), -1.0F, 1.0F) + 1.F;
+ myGreenScale = BSPF::clamp(settings.getFloat("pal.green_scale"), -1.0F, 1.0F) + 1.F;
+ myBlueScale = BSPF::clamp(settings.getFloat("pal.blue_scale"), -1.0F, 1.0F) + 1.F;
+ myRedShift = BSPF::clamp(settings.getFloat("pal.red_shift"), -MAX_RGB_SHIFT, MAX_RGB_SHIFT);
+ myGreenShift = BSPF::clamp(settings.getFloat("pal.green_shift"), -MAX_RGB_SHIFT, MAX_RGB_SHIFT);
+ myBlueShift = BSPF::clamp(settings.getFloat("pal.blue_shift"), -MAX_RGB_SHIFT, MAX_RGB_SHIFT);
+
+ myHue = BSPF::clamp(settings.getFloat("pal.hue"), -1.0F, 1.0F);
+ mySaturation = BSPF::clamp(settings.getFloat("pal.saturation"), -1.0F, 1.0F);
+ myContrast = BSPF::clamp(settings.getFloat("pal.contrast"), -1.0F, 1.0F);
+ myBrightness = BSPF::clamp(settings.getFloat("pal.brightness"), -1.0F, 1.0F);
+ myGamma = BSPF::clamp(settings.getFloat("pal.gamma"), -1.0F, 1.0F);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -198,6 +247,12 @@
// Save adjustables
settings.setValue("pal.phase_ntsc", myPhaseNTSC);
settings.setValue("pal.phase_pal", myPhasePAL);
+ settings.setValue("pal.red_scale", myRedScale - 1.F);
+ settings.setValue("pal.green_scale", myGreenScale - 1.F);
+ settings.setValue("pal.blue_scale", myBlueScale - 1.F);
+ settings.setValue("pal.red_shift", myRedShift);
+ settings.setValue("pal.green_shift", myGreenShift);
+ settings.setValue("pal.blue_shift", myBlueShift);
settings.setValue("pal.hue", myHue);
settings.setValue("pal.saturation", mySaturation);
@@ -209,8 +264,14 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaletteHandler::setAdjustables(const Adjustable& adjustable)
{
- myPhaseNTSC = adjustable.phaseNtsc / 10.F;
- myPhasePAL = adjustable.phasePal / 10.F;
+ myPhaseNTSC = scaleFromAngles(adjustable.phaseNtsc);
+ myPhasePAL = scaleFromAngles(adjustable.phasePal);
+ myRedScale = scaleRGBFrom100(adjustable.redScale);
+ myGreenScale = scaleRGBFrom100(adjustable.greenScale);
+ myBlueScale = scaleRGBFrom100(adjustable.blueScale);
+ myRedShift = scaleFromAngles(adjustable.redShift);
+ myGreenShift = scaleFromAngles(adjustable.greenShift);
+ myBlueShift = scaleFromAngles(adjustable.blueShift);
myHue = scaleFrom100(adjustable.hue);
mySaturation = scaleFrom100(adjustable.saturation);
@@ -222,8 +283,14 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaletteHandler::getAdjustables(Adjustable& adjustable) const
{
- adjustable.phaseNtsc = myPhaseNTSC * 10.F;
- adjustable.phasePal = myPhasePAL * 10.F;
+ adjustable.phaseNtsc = scaleToAngles(myPhaseNTSC);
+ adjustable.phasePal = scaleToAngles(myPhasePAL);
+ adjustable.redScale = scaleRGBTo100(myRedScale);
+ adjustable.greenScale = scaleRGBTo100(myGreenScale);
+ adjustable.blueScale = scaleRGBTo100(myBlueScale);
+ adjustable.redShift = scaleToAngles(myRedShift);
+ adjustable.greenShift = scaleToAngles(myGreenShift);
+ adjustable.blueShift = scaleToAngles(myBlueShift);
adjustable.hue = scaleTo100(myHue);
adjustable.saturation = scaleTo100(mySaturation);
@@ -371,10 +438,9 @@
constexpr int NUM_LUMA = 8;
constexpr float SATURATION = 0.25F; // default saturation
- float color[NUM_CHROMA][2] = {{0.0F}};
-
if(timing == ConsoleTiming::ntsc)
{
+ vector2d IQ[NUM_CHROMA];
// YIQ is YUV shifted by 33°
constexpr float offset = 33 * BSPF::PI_f / 180;
const float shift = myPhaseNTSC * BSPF::PI_f / 180;
@@ -382,22 +448,23 @@
// color 0 is grayscale
for(int chroma = 1; chroma < NUM_CHROMA; chroma++)
{
- color[chroma][0] = SATURATION * sinf(offset + shift * (chroma - 1));
- color[chroma][1] = SATURATION * cosf(offset + shift * (chroma - 1) - BSPF::PI_f);
+ IQ[chroma] = vector2d(SATURATION * sinf(offset + shift * (chroma - 1)),
+ SATURATION * cosf(offset + shift * (chroma - 1) - BSPF::PI_f));
}
+ const vector2d IQR = scale(rotate(vector2d(+0.956F, +0.621F), myRedShift), myRedScale);
+ const vector2d IQG = scale(rotate(vector2d(-0.272F, -0.647F), myGreenShift), myGreenScale);
+ const vector2d IQB = scale(rotate(vector2d(-1.106F, +1.703F), myBlueShift), myBlueScale);
for(int chroma = 0; chroma < NUM_CHROMA; chroma++)
{
- const float I = color[chroma][0];
- const float Q = color[chroma][1];
-
for(int luma = 0; luma < NUM_LUMA; luma++)
{
const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90
- float R = Y + 0.956F * I + 0.621F * Q;
- float G = Y - 0.272F * I - 0.647F * Q;
- float B = Y - 1.106F * I + 1.703F * Q;
+ float R = Y + dotProduct(IQ[chroma], IQR);
+ float G = Y + dotProduct(IQ[chroma], IQG);
+ float B = Y + dotProduct(IQ[chroma], IQB);
+
if(R < 0) R = 0;
if(G < 0) G = 0;
@@ -420,35 +487,37 @@
constexpr float offset = BSPF::PI_f;
const float shift = myPhasePAL * BSPF::PI_f / 180;
constexpr float fixedShift = 22.5F * BSPF::PI_f / 180;
+ vector2d UV[NUM_CHROMA];
// colors 0, 1, 14 and 15 are grayscale
for(int chroma = 2; chroma < NUM_CHROMA - 2; chroma++)
{
int idx = NUM_CHROMA - 1 - chroma;
- color[idx][0] = SATURATION * sinf(offset - fixedShift * chroma);
+
+ UV[idx].x = SATURATION * sinf(offset - fixedShift * chroma);
if ((idx & 1) == 0)
- color[idx][1] = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F);
+ UV[idx].y = SATURATION * sinf(offset - shift * (chroma - 3.5F) / 2.F);
else
- color[idx][1] = SATURATION * -sinf(offset - shift * chroma / 2.F);
+ UV[idx].y = SATURATION * -sinf(offset - shift * chroma / 2.F);
}
+ // Most sources
+ const vector2d UVR = scale(rotate(vector2d( 0.000F, +1.403F), myRedShift), myRedScale);
+ const vector2d UVG = scale(rotate(vector2d(-0.344F, -0.714F), myGreenShift), myGreenScale);
+ const vector2d UVB = scale(rotate(vector2d(+0.714F, 0.000F), myBlueShift), myBlueScale);
+ // German Wikipedia, huh???
+ //float R = Y + 1 / 0.877 * V;
+ //float B = Y + 1 / 0.493 * U;
+ //float G = 1.704 * Y - 0.590 * R - 0.194 * B;
for(int chroma = 0; chroma < NUM_CHROMA; chroma++)
{
- const float U = color[chroma][0];
- const float V = color[chroma][1];
-
for(int luma = 0; luma < NUM_LUMA; luma++)
{
const float Y = 0.05F + luma / 8.24F; // 0.05..~0.90
- // Most sources
- float R = Y + 1.403F * V;
- float G = Y - 0.344F * U - 0.714F * V;
- float B = Y + 1.770F * U;
- // German Wikipedia, huh???
- //float B = Y + 1 / 0.493 * U;
- //float R = Y + 1 / 0.877 * V;
- //float G = 1.704 * Y - 0.590 * R - 0.194 * B;
+ float R = Y + dotProduct(UV[chroma], UVR);
+ float G = Y + dotProduct(UV[chroma], UVG);
+ float B = Y + dotProduct(UV[chroma], UVB);
if(R < 0) R = 0.0;
if(G < 0) G = 0.0;
@@ -492,6 +561,28 @@
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+PaletteHandler::vector2d PaletteHandler::rotate(const PaletteHandler::vector2d& vec, float angle) const
+{
+ const float r = angle * BSPF::PI_f / 180;
+
+ return PaletteHandler::vector2d(vec.x * cosf(r) - vec.y * sinf(r),
+ vec.x * sinf(r) + vec.y * cosf(r));
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+PaletteHandler::vector2d PaletteHandler::scale(const PaletteHandler::vector2d& vec, float factor) const
+{
+ return PaletteHandler::vector2d(vec.x * factor, vec.y * factor);
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+float PaletteHandler::dotProduct(const PaletteHandler::vector2d& vec1,
+ const PaletteHandler::vector2d& vec2) const
+{
+ return vec1.x * vec2.x + vec1.y * vec2.y;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const PaletteArray PaletteHandler::ourNTSCPalette = {
0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0,
0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0,
diff -Nru stella-6.3/src/common/PaletteHandler.hxx stella-6.4/src/common/PaletteHandler.hxx
--- stella-6.3/src/common/PaletteHandler.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/PaletteHandler.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -35,20 +35,32 @@
// Phase shift default and limits
static constexpr float DEF_NTSC_SHIFT = 26.2F;
static constexpr float DEF_PAL_SHIFT = 31.3F; // ~= 360 / 11.5
- static constexpr float MAX_SHIFT = 4.5F;
+ static constexpr float MAX_PHASE_SHIFT = 4.5F;
+ static constexpr float DEF_RGB_SHIFT = 0.0F;
+ static constexpr float MAX_RGB_SHIFT = 22.5F;
enum Adjustables {
PHASE_SHIFT,
+ RED_SCALE,
+ GREEN_SCALE,
+ BLUE_SCALE,
+ RED_SHIFT,
+ GREEN_SHIFT,
+ BLUE_SHIFT,
HUE,
SATURATION,
CONTRAST,
BRIGHTNESS,
- GAMMA
+ GAMMA,
+ CUSTOM_START = PHASE_SHIFT,
+ CUSTOM_END = BLUE_SHIFT,
};
// Externally used adjustment parameters
struct Adjustable {
- float phaseNtsc{0.F}, phasePal{0.F};
+ float phaseNtsc{0.F}, phasePal{0.F},
+ redScale{0.F}, greenScale{0.F}, blueScale{0.F},
+ redShift{0.F}, greenShift{0.F}, blueShift{0.F};
uInt32 hue{0}, saturation{0}, contrast{0}, brightness{0}, gamma{0};
};
@@ -108,6 +120,7 @@
*/
void setPalette();
+
private:
static constexpr char DEGREE = 0x1c;
@@ -121,6 +134,28 @@
MaxType = Custom
};
+ struct vector2d {
+ float x;
+ float y;
+
+ explicit vector2d()
+ : x(0.F), y(0.F) { }
+ explicit vector2d(float _x, float _y)
+ : x(_x), y(_y) { }
+ };
+
+ /**
+ Convert RGB adjustables from/to 100% scale
+ */
+ static constexpr float scaleRGBFrom100(float x) { return x / 50.F; }
+ static constexpr uInt32 scaleRGBTo100(float x) { return uInt32(50.0001F * (x - 0.F)); }
+
+ /**
+ Convert angles
+ */
+ static constexpr float scaleFromAngles(float x) { return x / 10.F; }
+ static constexpr Int32 scaleToAngles(float x) { return uInt32(10.F * x); }
+
/**
Convert adjustables from/to 100% scale
*/
@@ -128,6 +163,17 @@
static constexpr uInt32 scaleTo100(float x) { return uInt32(50.0001F * (x + 1.F)); }
/**
+ Check for 'Custom' palette only adjustables
+ */
+ bool isCustomAdjustable() const;
+
+ bool isPhaseShift() const;
+
+ bool isRGBScale() const;
+
+ bool isRGBShift() const;
+
+ /**
Convert palette settings name to enumeration.
@param name The given palette's settings name
@@ -187,13 +233,28 @@
void adjustHueSaturation(int& R, int& G, int& B, float H, float S);
/**
+ Rotate a 2D vector.
+ */
+ vector2d rotate(const vector2d& vec, float angle) const;
+
+ /**
+ Scale a 2D vector.
+ */
+ vector2d scale(const vector2d& vec, float factor) const;
+
+ /**
+ Get the dot product of two 2D vectors.
+ */
+ float dotProduct(const vector2d& vec1, const vector2d& vec2) const;
+
+ /**
Loads a user-defined palette file (from OSystem::paletteFile), filling the
appropriate user-defined palette arrays.
*/
void loadUserPalette();
private:
- static constexpr int NUM_ADJUSTABLES = 6;
+ static constexpr int NUM_ADJUSTABLES = 12;
OSystem& myOSystem;
@@ -207,6 +268,12 @@
const std::array myAdjustables =
{ {
{ "phase shift", nullptr },
+ { "red scale", &myRedScale },
+ { "green scale", &myGreenScale },
+ { "blue scale", &myBlueScale },
+ { "red shift", &myRedShift },
+ { "green shift", &myGreenShift },
+ { "blue shift", &myBlueShift },
{ "hue", &myHue },
{ "saturation", &mySaturation },
{ "contrast", &myContrast },
@@ -217,6 +284,14 @@
// NTSC and PAL color phase shifts
float myPhaseNTSC{DEF_NTSC_SHIFT};
float myPhasePAL{DEF_PAL_SHIFT};
+ // Color intensities
+ float myRedScale{1.0F};
+ float myGreenScale{1.0F};
+ float myBlueScale{1.0F};
+ // Color shifts
+ float myRedShift{0.0F};
+ float myGreenShift{0.0F};
+ float myBlueShift{0.0F};
// range -1.0 to +1.0 (as in AtariNTSC)
// Basic parameters
float myHue{0.0F}; // -1 = -180 degrees +1 = +180 degrees
diff -Nru stella-6.3/src/common/PKeyboardHandler.cxx stella-6.4/src/common/PKeyboardHandler.cxx
--- stella-6.3/src/common/PKeyboardHandler.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/PKeyboardHandler.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -534,8 +534,8 @@
{Event::ToggleTimeMachine, KBDK_T, MOD3},
#ifdef PNG_SUPPORT
- {Event::ToggleContSnapshots, KBDK_S, MOD3},
- {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3},
+ {Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL},
+ {Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL},
#endif
{Event::DecreaseAutoFire, KBDK_A, KBDM_SHIFT | KBDM_CTRL},
diff -Nru stella-6.3/src/common/PNGLibrary.cxx stella-6.4/src/common/PNGLibrary.cxx
--- stella-6.3/src/common/PNGLibrary.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/PNGLibrary.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -296,7 +296,6 @@
// Figure out the correct snapshot name
string filename;
- bool showmessage = number == 0;
string sspath = myOSystem.snapshotSaveDir().getPath() +
(myOSystem.settings().getString("snapname") != "int" ?
myOSystem.romFile().getNameWithExt("")
@@ -347,9 +346,9 @@
VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo());
// Now create a PNG snapshot
+ string message = "Snapshot saved";
if(myOSystem.settings().getBool("ss1x"))
{
- string message = "Snapshot saved";
try
{
Common::Rect rect;
@@ -360,8 +359,6 @@
{
message = e.what();
}
- if(showmessage)
- myOSystem.frameBuffer().showMessage(message);
}
else
{
@@ -369,7 +366,6 @@
myOSystem.frameBuffer().enableMessages(false);
myOSystem.frameBuffer().tiaSurface().renderForSnapshot();
- string message = "Snapshot saved";
try
{
myOSystem.png().saveImage(filename, comments);
@@ -381,9 +377,8 @@
// Re-enable old messages
myOSystem.frameBuffer().enableMessages(true);
- if(showmessage)
- myOSystem.frameBuffer().showMessage(message);
}
+ myOSystem.frameBuffer().showMessage(message);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff -Nru stella-6.3/src/common/Rect.hxx stella-6.4/src/common/Rect.hxx
--- stella-6.3/src/common/Rect.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/Rect.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -69,12 +69,17 @@
}
bool valid() const { return w > 0 && h > 0; }
+ void clamp(uInt32 lower_w, uInt32 upper_w, uInt32 lower_h, uInt32 upper_h) {
+ w = BSPF::clamp(w, lower_w, upper_w);
+ h = BSPF::clamp(h, lower_h, upper_h);
+ }
+
bool operator==(const Size& s) const { return w == s.w && h == s.h; }
bool operator!=(const Size& s) const { return w != s.w || h != s.h; }
- bool operator<(const Size& s) const { return w < s.w && h < s.h; }
+ bool operator<(const Size& s) const { return w < s.w && h < s.h; }
bool operator<=(const Size& s) const { return w <= s.w && h <= s.h; }
- bool operator>(const Size& s) const { return w > s.w && h > s.h; }
- bool operator>=(const Size& s) const { return w >= s.w && h >= s.h; }
+ bool operator>(const Size& s) const { return w > s.w || h > s.h; }
+ bool operator>=(const Size& s) const { return w >= s.w || h >= s.h; }
friend ostream& operator<<(ostream& os, const Size& s) {
os << s.w << "x" << s.h;
diff -Nru stella-6.3/src/common/sdl_blitter/BilinearBlitter.cxx stella-6.4/src/common/sdl_blitter/BilinearBlitter.cxx
--- stella-6.3/src/common/sdl_blitter/BilinearBlitter.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/sdl_blitter/BilinearBlitter.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -15,12 +15,12 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
-#include "FrameBufferSDL2.hxx"
+#include "FBBackendSDL2.hxx"
#include "ThreadDebugging.hxx"
#include "BilinearBlitter.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-BilinearBlitter::BilinearBlitter(FrameBufferSDL2& fb, bool interpolate)
+BilinearBlitter::BilinearBlitter(FBBackendSDL2& fb, bool interpolate)
: myFB(fb),
myInterpolate(interpolate)
{
diff -Nru stella-6.3/src/common/sdl_blitter/BilinearBlitter.hxx stella-6.4/src/common/sdl_blitter/BilinearBlitter.hxx
--- stella-6.3/src/common/sdl_blitter/BilinearBlitter.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/sdl_blitter/BilinearBlitter.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -18,7 +18,7 @@
#ifndef BILINEAR_BLITTER_HXX
#define BILINEAR_BLITTER_HXX
-class FrameBufferSDL2;
+class FBBackendSDL2;
#include "Blitter.hxx"
#include "SDL_lib.hxx"
@@ -27,7 +27,7 @@
public:
- BilinearBlitter(FrameBufferSDL2& fb, bool interpolate);
+ BilinearBlitter(FBBackendSDL2& fb, bool interpolate);
~BilinearBlitter() override;
@@ -41,7 +41,7 @@
virtual void blit(SDL_Surface& surface) override;
private:
- FrameBufferSDL2& myFB;
+ FBBackendSDL2& myFB;
SDL_Texture* myTexture{nullptr};
SDL_Texture* mySecondaryTexture{nullptr};
diff -Nru stella-6.3/src/common/sdl_blitter/BlitterFactory.cxx stella-6.4/src/common/sdl_blitter/BlitterFactory.cxx
--- stella-6.3/src/common/sdl_blitter/BlitterFactory.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/sdl_blitter/BlitterFactory.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -21,7 +21,7 @@
#include "BilinearBlitter.hxx"
#include "QisBlitter.hxx"
-unique_ptr BlitterFactory::createBlitter(FrameBufferSDL2& fb, ScalingAlgorithm scaling)
+unique_ptr BlitterFactory::createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling)
{
if (!fb.isInitialized()) {
throw runtime_error("BlitterFactory requires an initialized framebuffer!");
diff -Nru stella-6.3/src/common/sdl_blitter/BlitterFactory.hxx stella-6.4/src/common/sdl_blitter/BlitterFactory.hxx
--- stella-6.3/src/common/sdl_blitter/BlitterFactory.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/sdl_blitter/BlitterFactory.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -21,8 +21,8 @@
#include
#include "Blitter.hxx"
+#include "FBBackendSDL2.hxx"
#include "bspf.hxx"
-#include "FrameBufferSDL2.hxx"
class BlitterFactory {
public:
@@ -35,7 +35,7 @@
public:
- static unique_ptr createBlitter(FrameBufferSDL2& fb, ScalingAlgorithm scaling);
+ static unique_ptr createBlitter(FBBackendSDL2& fb, ScalingAlgorithm scaling);
};
#endif // BLITTER_FACTORY_HXX
diff -Nru stella-6.3/src/common/sdl_blitter/QisBlitter.cxx stella-6.4/src/common/sdl_blitter/QisBlitter.cxx
--- stella-6.3/src/common/sdl_blitter/QisBlitter.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/sdl_blitter/QisBlitter.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -15,12 +15,12 @@
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
-#include "FrameBufferSDL2.hxx"
+#include "FBBackendSDL2.hxx"
#include "ThreadDebugging.hxx"
#include "QisBlitter.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-QisBlitter::QisBlitter(FrameBufferSDL2& fb)
+QisBlitter::QisBlitter(FBBackendSDL2& fb)
: myFB(fb)
{
}
@@ -32,7 +32,7 @@
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-bool QisBlitter::isSupported(FrameBufferSDL2 &fb)
+bool QisBlitter::isSupported(FBBackendSDL2& fb)
{
if (!fb.isInitialized()) throw runtime_error("framebuffer not initialized");
diff -Nru stella-6.3/src/common/sdl_blitter/QisBlitter.hxx stella-6.4/src/common/sdl_blitter/QisBlitter.hxx
--- stella-6.3/src/common/sdl_blitter/QisBlitter.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/sdl_blitter/QisBlitter.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -18,7 +18,7 @@
#ifndef QIS_BLITTER_HXX
#define QIS_BLITTER_HXX
-class FrameBufferSDL2;
+class FBBackendSDL2;
#include "Blitter.hxx"
#include "SDL_lib.hxx"
@@ -27,9 +27,9 @@
public:
- explicit QisBlitter(FrameBufferSDL2& fb);
+ explicit QisBlitter(FBBackendSDL2& fb);
- static bool isSupported(FrameBufferSDL2 &fb);
+ static bool isSupported(FBBackendSDL2& fb);
~QisBlitter() override;
@@ -44,7 +44,7 @@
private:
- FrameBufferSDL2& myFB;
+ FBBackendSDL2& myFB;
SDL_Texture* mySrcTexture{nullptr};
SDL_Texture* mySecondarySrcTexture{nullptr};
diff -Nru stella-6.3/src/common/Version.hxx stella-6.4/src/common/Version.hxx
--- stella-6.3/src/common/Version.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/common/Version.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
-#define STELLA_VERSION "6.3"
-#define STELLA_BUILD "6180"
+#define STELLA_VERSION "6.4"
+#define STELLA_BUILD "6238"
#endif
diff -Nru stella-6.3/src/common/VideoModeHandler.cxx stella-6.4/src/common/VideoModeHandler.cxx
--- stella-6.3/src/common/VideoModeHandler.cxx 1970-01-01 00:00:00.000000000 +0000
+++ stella-6.4/src/common/VideoModeHandler.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -0,0 +1,165 @@
+//============================================================================
+//
+// SSSS tt lll lll
+// SS SS tt ll ll
+// SS tttttt eeee ll ll aaaa
+// SSSS tt ee ee ll ll aa
+// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
+// SS SS tt ee ll ll aa aa
+// SSSS ttt eeeee llll llll aaaaa
+//
+// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
+// and the Stella Team
+//
+// See the file "License.txt" for information on usage and redistribution of
+// this file, and for a DISCLAIMER OF ALL WARRANTIES.
+//============================================================================
+
+#include "Settings.hxx"
+#include "VideoModeHandler.hxx"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void VideoModeHandler::setImageSize(const Common::Size& image)
+{
+ myImage = image;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void VideoModeHandler::setDisplaySize(const Common::Size& display, Int32 fsIndex)
+{
+ myDisplay = display;
+ myFSIndex = fsIndex;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+const VideoModeHandler::Mode&
+VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode)
+{
+ const bool windowedRequested = myFSIndex == -1;
+
+ // TIA mode allows zooming at non-integral factors in most cases
+ if(inTIAMode)
+ {
+ if(windowedRequested)
+ {
+ const float zoom = settings.getFloat("tia.zoom");
+ ostringstream desc;
+ desc << (zoom * 100) << "%";
+
+ // Image and screen (aka window) dimensions are the same
+ // Overscan is not applicable in this mode
+ myMode = Mode(myImage.w * zoom, myImage.h * zoom, Mode::Stretch::Fill,
+ myFSIndex, desc.str(), zoom);
+ }
+ else
+ {
+ const float overscan = 1 - settings.getInt("tia.fs_overscan") / 100.0;
+
+ // First calculate maximum zoom that keeps aspect ratio
+ const float scaleX = float(myImage.w) / myDisplay.w,
+ scaleY = float(myImage.h) / myDisplay.h;
+ float zoom = 1.F / std::max(scaleX, scaleY);
+
+ // When aspect ratio correction is off, we want pixel-exact images,
+ // so we default to integer zooming
+ if(!settings.getBool("tia.correct_aspect"))
+ zoom = static_cast(zoom);
+
+ if(!settings.getBool("tia.fs_stretch")) // preserve aspect, use all space
+ {
+ myMode = Mode(myImage.w * zoom, myImage.h * zoom,
+ myDisplay.w, myDisplay.h,
+ Mode::Stretch::Preserve, myFSIndex,
+ "Fullscreen: Preserve aspect, no stretch", zoom, overscan);
+ }
+ else // ignore aspect, use all space
+ {
+ myMode = Mode(myImage.w * zoom, myImage.h * zoom,
+ myDisplay.w, myDisplay.h,
+ Mode::Stretch::Fill, myFSIndex,
+ "Fullscreen: Ignore aspect, full stretch", zoom, overscan);
+ }
+ }
+ }
+ else // UI mode (no zooming)
+ {
+ if(windowedRequested)
+ myMode = Mode(myImage.w, myImage.h, Mode::Stretch::None);
+ else
+ myMode = Mode(myImage.w, myImage.h, myDisplay.w, myDisplay.h,
+ Mode::Stretch::None, myFSIndex);
+ }
+
+ return myMode;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode,
+ Int32 fsindex, const string& desc,
+ float zoomLevel)
+ : Mode(iw, ih, iw, ih, smode, fsindex, desc, zoomLevel)
+{
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
+ Stretch smode, Int32 fsindex, const string& desc,
+ float zoomLevel, float overscan)
+ : stretch(smode),
+ description(desc),
+ zoom(zoomLevel),
+ fsIndex(fsindex)
+{
+ // First set default size and positioning
+ screenS = Common::Size(sw, sh);
+
+ // Now resize based on windowed/fullscreen mode and stretch factor
+ if(fsIndex != -1) // fullscreen mode
+ {
+ switch(stretch)
+ {
+ case Stretch::Preserve:
+ iw *= overscan;
+ ih *= overscan;
+ break;
+
+ case Stretch::Fill:
+ // Scale to all available space
+ iw = screenS.w * overscan;
+ ih = screenS.h * overscan;
+ break;
+
+ case Stretch::None:
+ // Don't do any scaling at all
+ iw = std::min(iw, screenS.w) * overscan;
+ ih = std::min(ih, screenS.h) * overscan;
+ break;
+ }
+ }
+ else
+ {
+ // In windowed mode, currently the size is scaled to the screen
+ // TODO - this may be updated if/when we allow variable-sized windows
+ switch(stretch)
+ {
+ case Stretch::Preserve:
+ case Stretch::Fill:
+ screenS.w = iw;
+ screenS.h = ih;
+ break;
+
+ case Stretch::None:
+ break; // Do not change image or screen rects whatsoever
+ }
+ }
+
+ // Now re-calculate the dimensions
+ iw = std::min(iw, screenS.w);
+ ih = std::min(ih, screenS.h);
+
+ imageR.moveTo((screenS.w - iw) >> 1, (screenS.h - ih) >> 1);
+ imageR.setWidth(iw);
+ imageR.setHeight(ih);
+
+ screenR = Common::Rect(screenS);
+}
diff -Nru stella-6.3/src/common/VideoModeHandler.hxx stella-6.4/src/common/VideoModeHandler.hxx
--- stella-6.3/src/common/VideoModeHandler.hxx 1970-01-01 00:00:00.000000000 +0000
+++ stella-6.4/src/common/VideoModeHandler.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -0,0 +1,113 @@
+//============================================================================
+//
+// SSSS tt lll lll
+// SS SS tt ll ll
+// SS tttttt eeee ll ll aaaa
+// SSSS tt ee ee ll ll aa
+// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
+// SS SS tt ee ll ll aa aa
+// SSSS ttt eeeee llll llll aaaaa
+//
+// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
+// and the Stella Team
+//
+// See the file "License.txt" for information on usage and redistribution of
+// this file, and for a DISCLAIMER OF ALL WARRANTIES.
+//============================================================================
+
+#ifndef VIDEO_MODE_HANDLER_HXX
+#define VIDEO_MODE_HANDLER_HXX
+
+class Settings;
+
+#include "Rect.hxx"
+#include "bspf.hxx"
+
+class VideoModeHandler
+{
+ public:
+ // Contains all relevant info for the dimensions of a video screen
+ // Also takes care of the case when the image should be 'centered'
+ // within the given screen:
+ // 'image' is the image dimensions into the screen
+ // 'screen' are the dimensions of the screen itself
+ struct Mode
+ {
+ enum class Stretch {
+ Preserve, // Stretch to fill all available space; preserve aspect ratio
+ Fill, // Stretch to fill all available space
+ None // No stretching (1x zoom)
+ };
+
+ Common::Rect imageR;
+ Common::Rect screenR;
+ Common::Size screenS;
+ Stretch stretch{Mode::Stretch::None};
+ string description;
+ float zoom{1.F};
+ Int32 fsIndex{-1}; // -1 indicates windowed mode
+
+ Mode() = default;
+ Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Stretch smode,
+ Int32 fsindex = -1, const string& desc = "",
+ float zoomLevel = 1.F, float overscan = 1.F);
+ Mode(uInt32 iw, uInt32 ih, Stretch smode, Int32 fsindex = -1,
+ const string& desc = "", float zoomLevel = 1.F);
+
+ friend ostream& operator<<(ostream& os, const Mode& vm)
+ {
+ os << "image=" << vm.imageR << " screen=" << vm.screenS
+ << " stretch=" << (vm.stretch == Stretch::Preserve ? "preserve" :
+ vm.stretch == Stretch::Fill ? "fill" : "none")
+ << " desc=" << vm.description << " zoom=" << vm.zoom
+ << " fsIndex= " << vm.fsIndex;
+ return os;
+ }
+ };
+
+ public:
+ VideoModeHandler() = default;
+
+ /**
+ Set the base size of the image. Scaling can be applied to this,
+ which will change the effective size.
+
+ @param image The base dimensions of the image
+ */
+ void setImageSize(const Common::Size& image);
+
+ /**
+ Set the size of the display. This could be either the desktop size,
+ or the size of the monitor currently active.
+
+ @param display The dimensions of the enclosing display
+ @param fsIndex Fullscreen mode in use (-1 indicates windowed mode)
+ */
+ void setDisplaySize(const Common::Size& display, Int32 fsIndex = -1);
+
+ /**
+ Build a video mode based on the given parameters, assuming that
+ setImageSize and setDisplaySize have been previously called.
+
+ @param settings Used to query various options that affect video mode
+ @param inTIAMode Whether the video mode is being used for TIA emulation
+
+ @return A video mode based on the given criteria
+ */
+ const VideoModeHandler::Mode& buildMode(const Settings& settings,
+ bool inTIAMode);
+
+ private:
+ Common::Size myImage, myDisplay;
+ Int32 myFSIndex{-1};
+
+ Mode myMode;
+
+ private:
+ VideoModeHandler(const VideoModeHandler&) = delete;
+ VideoModeHandler(VideoModeHandler&&) = delete;
+ VideoModeHandler& operator=(const VideoModeHandler&) = delete;
+ VideoModeHandler& operator=(const VideoModeHandler&&) = delete;
+};
+
+#endif // VIDEO_MODE_HANDLER_HXX
diff -Nru stella-6.3/src/debugger/Debugger.cxx stella-6.4/src/debugger/Debugger.cxx
--- stella-6.3/src/debugger/Debugger.cxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/debugger/Debugger.cxx 2020-11-02 08:08:34.000000000 +0000
@@ -90,21 +90,18 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::initialize()
{
- const Common::Size& s = myOSystem.settings().getSize("dbg.res");
+ mySize = myOSystem.settings().getSize("dbg.res");
const Common::Size& d = myOSystem.frameBuffer().desktopSize();
- myWidth = s.w; myHeight = s.h;
// The debugger dialog is resizable, within certain bounds
// We check those bounds now
- myWidth = std::max(myWidth, uInt32(DebuggerDialog::kSmallFontMinW));
- myHeight = std::max(myHeight, uInt32(DebuggerDialog::kSmallFontMinH));
- myWidth = std::min(myWidth, uInt32(d.w));
- myHeight = std::min(myHeight, uInt32(d.h));
+ mySize.clamp(uInt32(DebuggerDialog::kSmallFontMinW), d.w,
+ uInt32(DebuggerDialog::kSmallFontMinH), d.h);
- myOSystem.settings().setValue("dbg.res", Common::Size(myWidth, myHeight));
+ myOSystem.settings().setValue("dbg.res", mySize);
delete myDialog; myDialog = nullptr;
- myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight);
+ myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, mySize.w, mySize.h);
myCartDebug->setDebugWidget(&(myDialog->cartDebug()));
@@ -115,8 +112,9 @@
FBInitStatus Debugger::initializeVideo()
{
string title = string("Stella ") + STELLA_VERSION + ": Debugger mode";
- return myOSystem.frameBuffer().createDisplay(title, FrameBuffer::BufferType::Debugger,
- myWidth, myHeight);
+ return myOSystem.frameBuffer().createDisplay(
+ title, BufferType::Debugger, mySize
+ );
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -877,7 +875,7 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Names are defined here, but processed in YaccParser
-std::array Debugger::ourPseudoRegisters = { {
+std::array Debugger::ourPseudoRegisters = { {
// Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = {
{ "_bank", "Currently selected bank" },
{ "_cclocks", "Color clocks on current scanline" },
@@ -885,6 +883,8 @@
{ "_cycleslo", "Lower 32 bits of number of cycles since emulation started" },
{ "_fcount", "Number of frames since emulation started" },
{ "_fcycles", "Number of cycles since frame started" },
+ { "_ftimreadcycles","Number of cycles used by timer reads since frame started" },
+ { "_fwsynccycles", "Number of cycles skipped by WSYNC since frame started" },
{ "_icycles", "Number of cycles of last instruction" },
{ "_scan", "Current scanline count" },
{ "_scanend", "Scanline count at end of last frame" },
diff -Nru stella-6.3/src/debugger/Debugger.hxx stella-6.4/src/debugger/Debugger.hxx
--- stella-6.3/src/debugger/Debugger.hxx 2020-10-06 18:27:49.000000000 +0000
+++ stella-6.4/src/debugger/Debugger.hxx 2020-11-02 08:08:34.000000000 +0000
@@ -44,6 +44,7 @@
#include