Compare commits

..

3 Commits
master ... 7.0b

Author SHA1 Message Date
Stephen Anthony 2128ceb81a For Windows build, remove *all* DLL's before install, and only install
SDL2.dll.
2024-10-07 17:04:18 -02:30
Stephen Anthony 01702f1230 Re-add ZIP build for Windows. 2024-10-07 16:27:13 -02:30
Stephen Anthony 3dbdcd0682 Automatically remove old DLL's for Windows install.
This fixes exe not starting with latest release.
2024-10-06 20:36:06 -02:30
856 changed files with 15991 additions and 24957 deletions

View File

@ -11,46 +11,35 @@ jobs:
linux:
name: Linux
runs-on: ubuntu-latest
env:
SDL3_VERSION: 3.2.14
steps:
- name: Check out the repository
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
- name: Install SDL3
- name: Install SDL2
run: |
wget https://github.com/libsdl-org/SDL/releases/download/release-${SDL3_VERSION}/SDL3-${SDL3_VERSION}.tar.gz
tar -xzf SDL3-${SDL3_VERSION}.tar.gz
mv SDL3-${SDL3_VERSION} SDL3
cd SDL3
cmake -DCMAKE_INSTALL_PREFIX="`pwd`/prefix" -DSDL_UNIX_CONSOLE_BUILD=ON .
make -j2 install
sudo apt-get update
sudo apt-get install libsdl2-dev
- name: Build Stella
run: |
CXXFLAGS="-I `pwd`/SDL3/prefix/include -O2 -g" PKG_CONFIG_PATH="`pwd`/SDL3/prefix/lib/pkgconfig/" ./configure
make -j2 all
./configure && make -j2 all
macos:
name: macOS
runs-on: macos-latest
env:
SDL3_VERSION: 3.2.14
steps:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.2'
xcode-version: '15.4'
- name: Check out the repository
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
- name: Install SDL3
- name: Install SDL2
run: |
wget https://github.com/libsdl-org/SDL/releases/download/release-${SDL3_VERSION}/SDL3-${SDL3_VERSION}.dmg
hdiutil attach SDL3-${SDL3_VERSION}.dmg
mkdir -p src/os/macos/Frameworks
cp -Rv /Volumes/SDL3/SDL3.xcframework src/os/macos/Frameworks
hdiutil detach /Volumes/SDL3
curl https://www.libsdl.org/release/SDL2-2.26.0.tar.gz | tar xzf -
mkdir SDL2-2.26.0/build
cd SDL2-2.26.0/build
../configure && make -j3 && sudo make install
- name: Build Stella
run: |
cd src/os/macos
xcodebuild
./configure && make -j3 all
windows:
name: Windows
@ -60,19 +49,19 @@ jobs:
platform: [x64]
env:
Platform: ${{ matrix.platform }}
SDL3_version: 3.2.14
SDL2_version: 2.26.0
steps:
- name: Check out the repository
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
- name: Set up MSBUILD
uses: microsoft/setup-msbuild@34cfbaee7f672c76950673338facd8a73f637506
- name: Install SDL3
- name: Install SDL2
shell: cmd
run: |
curl -o "C:\SDL3-devel.zip" "https://www.libsdl.org/release/SDL3-devel-%SDL3_version%-VC.zip"
7z x "C:\SDL3-devel.zip" -o"C:\"
xcopy /S "C:\SDL3-%SDL3_version%\include" src\common
if %Platform%==x64 xcopy /S "C:\SDL3-%SDL3_version%\lib\x64" src\os\windows
curl -o "C:\SDL2-devel.zip" "https://www.libsdl.org/release/SDL2-devel-%SDL2_version%-VC.zip"
7z x "C:\SDL2-devel.zip" -o"C:\"
xcopy /S "C:\SDL2-%SDL2_version%\include" src\common
if %Platform%==x64 xcopy /S "C:\SDL2-%SDL2_version%\lib\x64" src\os\windows
- name: Build Stella
run: |

3
.gitignore vendored
View File

@ -5,7 +5,6 @@ src/**/*.so
src/**/*.dylib
src/**/*.dll
src/**/*.o
src/**/*.d
src/**/*.obj
src/**/*.tlog
out
@ -26,7 +25,6 @@ src/os/macos/M6502.ins
.vscode/c_cpp_properties.json
.vscode/settings.json
src/os/windows/sdl/*
src/os/windows/sdl3/*
src/os/windows/x64/*
src/os/windows/Win32/*
src/os/windows/Stella.vcxproj.user
@ -45,4 +43,3 @@ a.out
*.json
*.sqlite3
*.bak
debian/files

View File

@ -28,7 +28,7 @@ distributions currently available are:
Stella-7.0-x64.exe (64-bit EXE installer)
Stella-7.0-windows.zip (64 bit ZIP version)
* Binary distribution for macOS 10.13 and above :
* Binary distribution for macOS 10.12 and above :
Stella-7.0-macos.dmg (ARM M1 and 64-bit Intel)
* Binary distribution for 64-bit Ubuntu :

View File

@ -12,20 +12,6 @@
Release History
===========================================================================
7.x to 8.0 (xxx x, 202x)
* Ported Stella to SDL3
* Added option for switching Stella's theme in sync with OS
7.0 to 7.1 (xxx x, 202x)
* Enhanced PAL-60 detection, searches for signature (e.g. PAL60) in ROM
* Enhanced VSYNC emulation, considers VBLANK now too
* Added developer option for disabling PlusROM support
6.7.1 to 7.0 (October 5, 2024)
* Enhanced ROM launcher to allow multiple images per ROM.

View File

@ -12,7 +12,7 @@
License Information and Copyright Notice
===========================================================================
Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony and the
Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony and the
Stella Team
This program is free software; you can redistribute it and/or modify it

View File

@ -8,7 +8,7 @@
## SS SS tt ee ll ll aa aa
## SSSS ttt eeeee llll llll aaaaa
##
## Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
## Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
## and the Stella Team
##
## See the file "License.txt" for information on usage and redistribution of

65
configure vendored
View File

@ -6,7 +6,7 @@
# * command line options to...
# - override the host settings (for cross compiles
# - whether to do a debug build (with -g) or an optimized build (-O3 etc.)
# * detect whether the chosen backend is available
# * detect whether the chosen backend is available (e.g. call sdl2-config)
# * ....
@ -45,7 +45,6 @@ _ranlib=ranlib
_install=install
_ar="ar cru"
_strip=strip
_pkg_config=pkg-config
_mkdir="mkdir -p"
_echo=printf
_cat=cat
@ -54,6 +53,7 @@ _rm_rec="$_rm -r"
_zip="zip -q"
_cp=cp
_windowspath=""
_sdlconfig=sdl2-config
_sdlpath="$PATH"
_prefix=/usr/local
@ -335,22 +335,20 @@ case $_host in
# _host_os=amigaos
# _host_cpu=ppc
# ;;
retron77)
_host_os=retron77
;;
mingw32-cross)
_host_os=mingw32msvc
_host_cpu=i386
_host_prefix=i386-mingw32msvc
;;
"")
*)
guessed_host=`$_srcdir/config.guess`
_host_cpu=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
_host_os=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
_host_vendor=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
;;
*)
_host_cpu=`echo "$_host" | sed 's/^\([^-]*\)-.*/\1/'`
_host_os=`echo "$_host" | sed 's/-\([^-]*\)-[^-]*$/\1/'`
_host_prefix="$_host"
;;
esac
#
@ -555,6 +553,14 @@ fi
if test -n "$_host"; then
# Cross-compiling mode - add your target here if needed
case "$_host" in
retron77)
echo "Compiling for $_host, disabling windowed mode, debugger and cheats."
_build_gui=yes
_build_windowed=no
_build_debugger=no
_build_cheats=no
_build_httplib=no
;;
mingw32-cross)
echo "Cross-compiling for Windows using MinGW."
DEFINES="$DEFINES -DWIN32"
@ -620,9 +626,6 @@ fi
# Cross-compilers use their own commands for the following functions
if test -n "$_host_prefix"; then
_strip="$_host_prefix-$_strip"
if command -v "$_host_prefix-$_pkg_config" >/dev/null 2>&1; then
_pkg_config="$_host_prefix-$_pkg_config"
fi
fi
#
@ -636,7 +639,7 @@ if test "$_build_zip" = yes ; then
#include <zlib.h>
int main(void) { return strcmp(ZLIB_VERSION, zlibVersion()); }
EOF
cc_check $LDFLAGS $CXXFLAGS $ZLIB_CFLAGS $ZLIB_LIBS `$_pkg_config --libs zlib` && _zlib=yes
cc_check $LDFLAGS $CXXFLAGS $ZLIB_CFLAGS $ZLIB_LIBS `pkg-config --libs zlib` && _zlib=yes
if test "$_zlib" = yes ; then
echo "$_zlib"
@ -662,7 +665,7 @@ if test "$_build_png" = yes ; then
#include <png.h>
int main(void) { return printf("%s\n", PNG_HEADER_VERSION_STRING); }
EOF
cc_check $LDFLAGS $CXXFLAGS $LIBPNG_CFLAGS $LIBPNG_LIBS `$_pkg_config --libs libpng` && _libpng=yes
cc_check $LDFLAGS $CXXFLAGS $LIBPNG_CFLAGS $LIBPNG_LIBS `pkg-config --libs libpng` && _libpng=yes
if test "$_libpng" = yes ; then
echo "$_libpng"
@ -686,7 +689,7 @@ if test "$_build_sqlite3" = yes ; then
#include <sqlite3.h>
int main(void) { return printf("%s\n", SQLITE_VERSION); }
EOF
cc_check $LDFLAGS $CXXFLAGS `$_pkg_config --libs sqlite3` && _libsqlite3=yes
cc_check $LDFLAGS $CXXFLAGS `pkg-config --libs sqlite3` && _libsqlite3=yes
if test "$_libsqlite3" = yes ; then
echo "$_libsqlite3"
@ -805,8 +808,8 @@ fi
#
# Now, add the appropriate defines/libraries/headers
#
#echo
#find_sdlconfig
echo
find_sdlconfig
SRC="src"
SRC_OS="$SRC/os"
@ -833,18 +836,15 @@ HTTP_LIB="$SRC_LIB/httplib"
INCLUDES="-I$CORE -I$COMMON -I$TV -I$TIA -I$TIA_FRAME_MANAGER -I$ELF -I$JSON -I$SQLITE_REPO"
#INCLUDES="$INCLUDES `$_sdlconfig --cflags`"
#if test "$_build_static" = yes ; then
# _sdl_conf_libs="--static-libs"
# LDFLAGS="-static $LDFLAGS"
#else
# _sdl_conf_libs="--libs"
#fi
#if test "$_libpng" = yes ; then #FIXME:
LIBS="$LIBS `$_pkg_config --libs sdl3`"
#fi
INCLUDES="$INCLUDES `$_sdlconfig --cflags`"
if test "$_build_static" = yes ; then
_sdl_conf_libs="--static-libs"
LDFLAGS="-static $LDFLAGS"
else
_sdl_conf_libs="--libs"
fi
LIBS="$LIBS `$_sdlconfig $_sdl_conf_libs`"
LD=$CXX
case $_host_os in
@ -865,6 +865,11 @@ case $_host_os in
fi
_libsqlite3=no
;;
retron77)
DEFINES="$DEFINES -DBSPF_UNIX -DRETRON77"
MODULES="$MODULES $SRC_OS/unix $SRC_OS/unix/r77"
INCLUDES="$INCLUDES -I$SRC_OS/unix -I$SRC_OS/unix/r77"
;;
win32)
DEFINES="$DEFINES -DBSPF_WINDOWS"
MODULES="$MODULES $SRC_OS/windows"
@ -917,7 +922,7 @@ if test "$_build_png" = yes ; then
INCLUDES="$INCLUDES -I$LIBJPG -I$LIBJPGEXIF"
MODULES="$MODULES $LIBJPGEXIF"
if test "$_libpng" = yes ; then
LIBS="$LIBS `$_pkg_config --libs libpng`"
LIBS="$LIBS `pkg-config --libs libpng`"
else
MODULES="$MODULES $LIBPNG"
INCLUDES="$INCLUDES -I$LIBPNG"
@ -925,7 +930,7 @@ if test "$_build_png" = yes ; then
fi
if test "$_libsqlite3" = yes ; then
LIBS="$LIBS `$_pkg_config --libs sqlite3`"
LIBS="$LIBS `pkg-config --libs sqlite3`"
else
MODULES="$MODULES $SQLITE_LIB"
INCLUDES="$INCLUDES -I$SQLITE_LIB"
@ -934,7 +939,7 @@ fi
if test "$_build_zip" = yes ; then
DEFINES="$DEFINES -DZIP_SUPPORT"
if test "$_zlib" = yes ; then
LIBS="$LIBS `$_pkg_config --libs zlib`"
LIBS="$LIBS `pkg-config --libs zlib`"
else
MODULES="$MODULES $ZLIB"
INCLUDES="$INCLUDES -I$ZLIB"

5
debian/control vendored
View File

@ -3,9 +3,8 @@ Maintainer: Stephen Anthony <sa666666@gmail.com>
Section: otherosfs
Priority: optional
Build-Depends: debhelper (>= 10~),
libgtest-dev,
libpng-dev,
libsdl3-dev,
libsdl2-dev,
zlib1g-dev
Standards-Version: 4.5.0
Vcs-Browser: https://github.com/stella-emu/stella/
@ -19,7 +18,7 @@ Depends: ${misc:Depends},
${shlibs:Depends}
Recommends: joystick (>= 1:1.5.1)
Pre-Depends: ${misc:Pre-Depends}
Description: Atari 2600 Emulator for SDL
Description: Atari 2600 Emulator for SDL2
Stella is a portable emulator of the old Atari 2600 video-game
console. You can play most Atari 2600 games with it.
.

6
debian/copyright vendored
View File

@ -1,18 +1,18 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0
Upstream-Name: stella
Source: https://stella-emu.github.io
Copyright: 1995-2025 Bradford W. Mott, Stephen Anthony and the Stella Team
Copyright: 1995-2024 Bradford W. Mott, Stephen Anthony and the Stella Team
License: GPL-2+
Files: *
Copyright: 1995-2025 Bradford W. Mott, Stephen Anthony and the Stella
Copyright: 1995-2024 Bradford W. Mott, Stephen Anthony and the Stella
Team
License: GPL-2+
Files: debian/*
Copyright: 1998-2004 Tom Lear <tom@trap.mtview.ca.us>
2006 Mario Iseli <admin@marioiseli.com>
2010-2025 Stephen Kitt <skitt@debian.org>
2010-2024 Stephen Kitt <skitt@debian.org>
License: GPL-2+
Files:

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -21,7 +21,7 @@
<img src="graphics/stella_icon.png">
<h2><b>A multi-platform Atari 2600 VCS emulator</b></h2>
<h4><b>Release 8.0</b></h4>
<h4><b>Release 7.0</b></h4>
<br>
<h2><b>User's Guide</b></h2>
@ -342,7 +342,7 @@
<p>
<h3><b><u>General</u> (required for all versions of Stella)</b></h3>
<ul>
<li>SDL version 3.2.14 or greater, latest version highly recommended</li>
<li>SDL version 2.0.14 or greater, latest version highly recommended</li>
<li>32 bit color graphics card</li>
<li>Enough RAM for the OS + 256MB RAM for the emulation; 512MB+ highly recommended</li>
<li>Joysticks or gamepads are highly recommended</li>
@ -368,9 +368,9 @@
<p>The Mac version of Stella is designed to work on an Apple Macintosh with
the following:</p>
<ul>
<li>macOS 10.13 or above</li>
<li>macOS 10.11 or above</li>
<li>64-bit ARM or Intel processor</li>
<li>Xcode 16.0 is required to compile the Stella source code</li>
<li>Xcode 13.0 is required to compile the Stella source code</li>
</ul>
<p>
@ -387,7 +387,7 @@
<h3><b><u>Other</u></b></h3>
<p>Stella is extremely portable, and in its lifetime has been ported to almost every
platform where the SDL library exists. It is 64-bit and endian clean in Linux/Unix, macOS
platform where the SDL library exists. It is 32/64-bit and endian clean in Linux/Unix, macOS
and Windows. The Stella Team is interested in hearing about any problems you may
encounter with diverse operating systems and CPU types.</p>
</blockquote></br>
@ -2526,7 +2526,7 @@
<br>
<p><h2>
<a name="HighScores">High Scores Saving</a></h2>
<a name="Highscores">High Scores Saving</a></h2>
<blockquote>
<p>Stella allows the user to save high scores when the required definitions
@ -3249,17 +3249,12 @@
<tr>
<td><pre>-uipalette2 &lt;standard|classic|light|dark&gt;</pre></td>
<td>Define alternative/light palette/theme for UI elements.</td>
<td>Define alternative palette/theme for UI elements.</td>
</tr>
<tr>
<td><pre>-altpalette &lt;1|0&gt;</pre></td>
<td>Use alternative/dark palette/theme for UI elements.</td>
</tr>
<tr>
<td><pre>-autouipalette &lt;1|0&gt;</pre></td>
<td>Automatic switching between light and dark theme in sync with OS.</td>
<td>Use alternative palette/theme for UI elements.</td>
</tr>
<tr>
@ -3640,9 +3635,6 @@
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;console &lt;2600|7800&gt;</pre></td>
<td>Select console for B/W and Pause key handling and RAM initialization.</td>
</tr><tr>
<td><pre>-dev.plusroms.on &lt;1|0&gt;</pre></td>
<td>Enable/disable PlusROM support, e.g. for testing.</td>
</tr><tr>
<td><pre>-&lt;plr.|dev.&gt;bankrandom &lt;1|0&gt;</pre></td>
<td>On reset, randomize the startup bank (only for selected bankswitch types).</td>
@ -4015,9 +4007,8 @@
<td valign="top">
<table border="1" cellpadding="4">
<tr><th>Item</th><th>Brief description</th><th>For more information,<br>see <a href="#CommandLine">Command Line</a></th></tr>
<tr><td>Light theme</td><td>Default theme to use for UI elements (see examples)</td><td>-uipalette</td></tr>
<tr><td>Dark theme</td><td>Alternative theme to use for UI elements (see examples)</td><td>-uipalette2</td></tr>
<tr><td>Auto theme</td><td>Enable for automatic switching between light and dark themes in sync with OS.</td><td>-autouipalette</td></tr>
<tr><td>Theme #1</td><td>Default theme to use for UI elements (see examples)</td><td>-uipalette</td></tr>
<tr><td>Theme #2</td><td>Alternative theme to use for UI elements (see examples)</td><td>-uipalette2</td></tr>
<tr><td>Dialogs font</td><td>The font used in the dialogs</td><td>-dialogfont</td></tr>
<tr><td>HiDPI mode</td><td>Scale the UI by a factor of two when enabled</td><td>-hidpi</td></tr>
<tr><td>Dialogs position</td><td>Position of dialogs with Stella window</td><td>-dialogpos</td></tr>
@ -4585,11 +4576,6 @@
emulation and zero-page RAM initialization</td>
<td>-plr.console <br/>-dev.console</td>
</tr>
<tr>
<td>PlusROM support</td>
<td>Enable/disable PlusROM support, e.g. for testing.</td>
<td>-dev.plusroms.on</td>
</tr>
<tr>
<td>Random startup bank</td>
<td>Randomize the startup bank (only for selected bankswitch types)</td>
@ -5155,9 +5141,7 @@ Ms Pac-Man (Stella extended codes):
<tr><td>NTSC50 &#185;</td><td>NTSC50, NTSC 50, NTSC-50, PAL-N</td></tr>
<tr><td>PAL60 &#185;</td><td>PAL60, PAL 60, PAL-60</td></tr>
<tr><td>SECAM60 &#185;</td><td>SECAM60, SECAM 60, SECAM-60</td></tr>
</table>
Additionally, to detect PAL-60 format games, the ROM is scanned for the following
signature strings: "PAL60", "PAL 60" and "PAL-60"</td>
</table></td>
</tr>
<tr>

View File

@ -264,7 +264,7 @@
<td width="41%">This dialog is similar to the PC version's
<a href="index.html#CommandMenu"><b>Command Menu</b></a>, but with some
commands especially selected for the RetroN&nbsp;77.</td>
<td><p><img src="graphics/commandsmenu_r77.png"></p></td>
<td><p><img src="commandsmenu_r77.png"></p></td>
</tr>
</table>
</p>
@ -309,7 +309,7 @@
</tr>
</table>
</td>
<td><p><img src="graphics/basic_settings.png"></p></td>
<td><p><img src="basic_settings.png"></p></td>
</tr>
</table>
</p>

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -33,7 +33,7 @@ BankRomCheat::BankRomCheat(OSystem& os, string_view name, string_view code)
count = static_cast<uInt8>(BSPF::stoi<16>(myCode.substr(7, 1)) + 1);
// Back up original data; we need this if the cheat is ever disabled
for(int i = 0; std::cmp_less(i, count); ++i)
for(int i = 0; i < count; ++i)
savedRom[i] = myOSystem.console().cartridge().peek(address + i);
}
@ -50,7 +50,7 @@ bool BankRomCheat::disable()
const int oldBank = myOSystem.console().cartridge().getBank(address);
myOSystem.console().cartridge().bank(bank);
for(int i = 0; std::cmp_less(i, count); ++i)
for(int i = 0; i < count; ++i)
myOSystem.console().cartridge().patch(address + i, savedRom[i]);
myOSystem.console().cartridge().bank(oldBank);
@ -66,7 +66,7 @@ void BankRomCheat::evaluate()
const int oldBank = myOSystem.console().cartridge().getBank(address);
myOSystem.console().cartridge().bank(bank);
for(int i = 0; std::cmp_less(i, count); ++i)
for(int i = 0; i < count; ++i)
myOSystem.console().cartridge().patch(address + i, value);
myOSystem.console().cartridge().bank(oldBank);

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -28,7 +28,7 @@ CheetahCheat::CheetahCheat(OSystem& os, string_view name, string_view code)
count{static_cast<uInt8>(BSPF::stoi<16>(code.substr(5, 1)) + 1)}
{
// Back up original data; we need this if the cheat is ever disabled
for(uInt8 i = 0; i < count; ++i)
for(int i = 0; i < count; ++i)
savedRom[i] = myOSystem.console().cartridge().peek(address + i);
}
@ -42,7 +42,7 @@ bool CheetahCheat::enable()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CheetahCheat::disable()
{
for(uInt8 i = 0; i < count; ++i)
for(int i = 0; i < count; ++i)
myOSystem.console().cartridge().patch(address + i, savedRom[i]);
return myEnabled = false;
@ -53,7 +53,7 @@ void CheetahCheat::evaluate()
{
if(!myEnabled)
{
for(uInt8 i = 0; i < count; ++i)
for(int i = 0; i < count; ++i)
myOSystem.console().cartridge().patch(address + i, value);
myEnabled = true;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -67,6 +67,20 @@ void AudioSettings::normalize(Settings& settings)
break;
}
switch (settings.getInt(SETTING_FRAGMENT_SIZE)) {
case 128:
case 256:
case 512:
case 1024:
case 2048:
case 4096:
break;
default:
settings.setValue(SETTING_FRAGMENT_SIZE, DEFAULT_FRAGMENT_SIZE);
break;
}
const int settingBufferSize = settings.getInt(SETTING_BUFFER_SIZE);
if (settingBufferSize < 0 || settingBufferSize > MAX_BUFFER_SIZE) settings.setValue(SETTING_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
@ -101,7 +115,7 @@ uInt32 AudioSettings::sampleRate()
uInt32 AudioSettings::fragmentSize()
{
updatePresetFromSettings();
return myPresetFragmentSize; // No longer configurable in sound backend
return customSettings() ? lboundInt(mySettings.getInt(SETTING_FRAGMENT_SIZE), DEFAULT_FRAGMENT_SIZE) : myPresetFragmentSize;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -141,6 +155,12 @@ uInt32 AudioSettings::volume() const
return lboundInt(mySettings.getInt(SETTING_VOLUME), 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 AudioSettings::device() const
{
return mySettings.getInt(SETTING_DEVICE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool AudioSettings::enabled() const
{
@ -165,6 +185,7 @@ void AudioSettings::setPreset(AudioSettings::Preset preset)
case Preset::lowQualityMediumLag:
myPresetSampleRate = 44100;
myPresetFragmentSize = 1024;
myPresetBufferSize = 6;
myPresetHeadroom = 5;
myPresetResamplingQuality = ResamplingQuality::nearestNeighbour;
@ -172,6 +193,7 @@ void AudioSettings::setPreset(AudioSettings::Preset preset)
case Preset::highQualityMediumLag:
myPresetSampleRate = 44100;
myPresetFragmentSize = 1024;
myPresetBufferSize = 6;
myPresetHeadroom = 5;
myPresetResamplingQuality = ResamplingQuality::lanczos_2;
@ -179,6 +201,7 @@ void AudioSettings::setPreset(AudioSettings::Preset preset)
case Preset::highQualityLowLag:
myPresetSampleRate = 48000;
myPresetFragmentSize = 512;
myPresetBufferSize = 3;
myPresetHeadroom = 2;
myPresetResamplingQuality = ResamplingQuality::lanczos_2;
@ -186,6 +209,7 @@ void AudioSettings::setPreset(AudioSettings::Preset preset)
case Preset::ultraQualityMinimalLag:
myPresetSampleRate = 96000;
myPresetFragmentSize = 128;
myPresetBufferSize = 0;
myPresetHeadroom = 0;
myPresetResamplingQuality = ResamplingQuality::lanczos_3;
@ -207,6 +231,15 @@ void AudioSettings::setSampleRate(uInt32 sampleRate)
normalize(mySettings);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioSettings::setFragmentSize(uInt32 fragmentSize)
{
if (!myIsPersistent) return;
mySettings.setValue(SETTING_FRAGMENT_SIZE, fragmentSize);
normalize(mySettings);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioSettings::setBufferSize(uInt32 bufferSize)
{
@ -259,6 +292,14 @@ void AudioSettings::setVolume(uInt32 volume)
normalize(mySettings);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioSettings::setDevice(uInt32 device)
{
if(!myIsPersistent) return;
mySettings.setValue(SETTING_DEVICE, device);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AudioSettings::setEnabled(bool isEnabled)
{

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -42,11 +42,13 @@ class AudioSettings
static constexpr string_view SETTING_PRESET = "audio.preset";
static constexpr string_view SETTING_SAMPLE_RATE = "audio.sample_rate";
static constexpr string_view SETTING_FRAGMENT_SIZE = "audio.fragment_size";
static constexpr string_view SETTING_BUFFER_SIZE = "audio.buffer_size";
static constexpr string_view SETTING_HEADROOM = "audio.headroom";
static constexpr string_view SETTING_RESAMPLING_QUALITY = "audio.resampling_quality";
static constexpr string_view SETTING_STEREO = "audio.stereo";
static constexpr string_view SETTING_VOLUME = "audio.volume";
static constexpr string_view SETTING_DEVICE = "audio.device";
static constexpr string_view SETTING_ENABLED = "audio.enabled";
static constexpr string_view SETTING_DPC_PITCH = "audio.dpc_pitch";
@ -130,8 +132,7 @@ class AudioSettings
Preset myPreset{Preset::custom};
uInt32 myPresetSampleRate{0};
uInt32 myPresetFragmentSize{1024}; // no longer configurable in sound backend
uInt32 myPresetFragmentSize{0};
uInt32 myPresetBufferSize{0};
uInt32 myPresetHeadroom{0};
ResamplingQuality myPresetResamplingQuality{ResamplingQuality::nearestNeighbour};

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -234,8 +234,9 @@ void Bezel::apply()
// Note: Variable bezel window positions are handled in VideoModeHandler::Mode
// Enable blending to allow overlaying the bezel over the TIA output
mySurface->enableBlend(true);
mySurface->setBlendLevel(100);
mySurface->attributes().blending = true;
mySurface->attributes().blendalpha = 100;
mySurface->applyAttributes();
mySurface->setVisible(true);
}
else

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -46,7 +46,6 @@ void DevSettingsHandler::loadSettings(SettingsSet set)
// AtariVox/SaveKey/PlusROM access
myExternAccess[set] = settings.getBool(prefix + "extaccess");
myConsole[set] = settings.getString(prefix + "console") == "7800" ? 1 : 0;
myPlusROM[set] = devSettings ? settings.getBool("dev.plusroms.on") : true;
// Randomization
myRandomBank[set] = settings.getBool(prefix + "bankrandom");
myRandomizeTIA[set] = settings.getBool(prefix + "tiarandom");
@ -119,7 +118,6 @@ void DevSettingsHandler::saveSettings(SettingsSet set)
if(devSettings)
{
settings.setValue("dev.plusroms.on", myPlusROM[set]);
settings.setValue("dev.hsrandom", myRandomHotspots[set]);
// Undriven TIA pins
settings.setValue("dev.tiadriven", myUndrivenPins[set]);
@ -185,7 +183,6 @@ void DevSettingsHandler::applySettings(SettingsSet set)
{
myOSystem.console().cartridge().enableRandomHotspots(myRandomHotspots[set]);
myOSystem.console().tia().driveUnusedPinsRandom(myUndrivenPins[set]);
myOSystem.console().cartridge().enablePlusROM(myPlusROM[set]);
// Notes:
// - thumb exceptions not updated, because set in cart constructor
// - other missing settings are used on-the-fly

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -51,7 +51,6 @@ class DevSettingsHandler
std::array<bool, numSets> myDetectedInfo{};
std::array<bool, numSets> myExternAccess{};
std::array<int, numSets> myConsole{};
std::array<int, numSets> myPlusROM{};
std::array<bool, numSets> myRandomBank{};
std::array<bool, numSets> myRandomizeTIA{};
std::array<bool, numSets> myRandomizeRAM{};

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -17,12 +17,12 @@
#include "Logger.hxx"
#include "OSystem.hxx"
#include "EventHandlerSDL.hxx"
#include "EventHandlerSDL2.hxx"
#include "ThreadDebugging.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerSDL::EventHandlerSDL(OSystem& osystem)
EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem)
: EventHandler{osystem}
{
ASSERT_MAIN_THREAD;
@ -31,30 +31,28 @@ EventHandlerSDL::EventHandlerSDL(OSystem& osystem)
{
ostringstream buf;
myQwertz = int{'y'} == static_cast<int>
(SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(KBDK_Z), static_cast<SDL_Keymod>(StellaMod::KBDM_NONE), false));
(SDL_GetKeyFromScancode(static_cast<SDL_Scancode>(KBDK_Z)));
buf << "Keyboard: " << (myQwertz ? "QWERTZ" : "QWERTY");
Logger::debug(buf.view());
}
#endif
#ifdef JOYSTICK_SUPPORT
if(!SDL_InitSubSystem(SDL_INIT_JOYSTICK))
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
{
ostringstream buf;
buf << "ERROR: Couldn't initialize SDL joystick support: "
<< SDL_GetError() << '\n';
Logger::error(buf.view());
}
Logger::debug("EventHandlerSDL::EventHandlerSDL SDL_INIT_JOYSTICK");
Logger::debug("EventHandlerSDL2::EventHandlerSDL2 SDL_INIT_JOYSTICK");
#endif
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
//SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, "1");
//SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerSDL::~EventHandlerSDL()
EventHandlerSDL2::~EventHandlerSDL2()
{
ASSERT_MAIN_THREAD;
@ -63,13 +61,24 @@ EventHandlerSDL::~EventHandlerSDL()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandlerSDL::copyText(const string& text) const
void EventHandlerSDL2::enableTextEvents(bool enable)
{
ASSERT_MAIN_THREAD;
if(enable)
SDL_StartTextInput();
else
SDL_StopTextInput();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandlerSDL2::copyText(const string& text) const
{
SDL_SetClipboardText(text.c_str());
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string EventHandlerSDL::pasteText(string& text) const
string EventHandlerSDL2::pasteText(string& text) const
{
if(SDL_HasClipboardText())
text = SDL_GetClipboardText();
@ -80,7 +89,7 @@ string EventHandlerSDL::pasteText(string& text) const
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandlerSDL::pollEvent()
void EventHandlerSDL2::pollEvent()
{
ASSERT_MAIN_THREAD;
@ -89,31 +98,31 @@ void EventHandlerSDL::pollEvent()
switch(myEvent.type)
{
// keyboard events
case SDL_EVENT_KEY_UP:
case SDL_EVENT_KEY_DOWN:
case SDL_KEYUP:
case SDL_KEYDOWN:
{
handleKeyEvent(static_cast<StellaKey>(myEvent.key.scancode),
static_cast<StellaMod>(myEvent.key.mod),
myEvent.type == SDL_EVENT_KEY_DOWN,
handleKeyEvent(static_cast<StellaKey>(myEvent.key.keysym.scancode),
static_cast<StellaMod>(myEvent.key.keysym.mod),
myEvent.key.type == SDL_KEYDOWN,
myEvent.key.repeat);
break;
}
case SDL_EVENT_TEXT_INPUT:
case SDL_TEXTINPUT:
{
handleTextEvent(*(myEvent.text.text));
break;
}
case SDL_EVENT_MOUSE_MOTION:
case SDL_MOUSEMOTION:
{
handleMouseMotionEvent(myEvent.motion.x, myEvent.motion.y,
myEvent.motion.xrel, myEvent.motion.yrel);
break;
}
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
// ToDo: check support of more buttons and double-click
MouseButton b{MouseButton::NONE};
@ -131,43 +140,39 @@ void EventHandlerSDL::pollEvent()
default:
break;
}
handleMouseButtonEvent(b, myEvent.button.type == SDL_EVENT_MOUSE_BUTTON_DOWN,
handleMouseButtonEvent(b, myEvent.button.type == SDL_MOUSEBUTTONDOWN,
myEvent.button.x, myEvent.button.y);
break;
}
case SDL_EVENT_MOUSE_WHEEL:
case SDL_MOUSEWHEEL:
{
// TODO: SDL now uses float for mouse coords, but the core still
// uses int throughout; maybe this is sufficient?
float x{0.F}, y{0.F};
int x{0}, y{0};
SDL_GetMouseState(&x, &y); // we need mouse position too
if(myEvent.wheel.y < 0)
handleMouseButtonEvent(MouseButton::WHEELDOWN, true,
static_cast<int>(x), static_cast<int>(y));
handleMouseButtonEvent(MouseButton::WHEELDOWN, true, x, y);
else if(myEvent.wheel.y > 0)
handleMouseButtonEvent(MouseButton::WHEELUP, true,
static_cast<int>(x), static_cast<int>(y));
handleMouseButtonEvent(MouseButton::WHEELUP, true, x, y);
break;
}
#ifdef JOYSTICK_SUPPORT
case SDL_EVENT_JOYSTICK_BUTTON_UP:
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
{
handleJoyBtnEvent(myEvent.jbutton.which, myEvent.jbutton.button,
myEvent.jbutton.down);
myEvent.jbutton.state == SDL_PRESSED);
break;
}
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
case SDL_JOYAXISMOTION:
{
handleJoyAxisEvent(myEvent.jaxis.which, myEvent.jaxis.axis,
myEvent.jaxis.value);
break;
}
case SDL_EVENT_JOYSTICK_HAT_MOTION:
case SDL_JOYHATMOTION:
{
int value = 0;
const int v = myEvent.jhat.value;
@ -182,82 +187,86 @@ void EventHandlerSDL::pollEvent()
}
handleJoyHatEvent(myEvent.jhat.which, myEvent.jhat.hat, value);
break;
break; // SDL_JOYHATMOTION
}
case SDL_EVENT_JOYSTICK_ADDED:
case SDL_JOYDEVICEADDED:
{
addPhysicalJoystick(make_shared<JoystickSDL>(myEvent.jdevice.which));
break;
addPhysicalJoystick(make_shared<JoystickSDL2>(myEvent.jdevice.which));
break; // SDL_JOYDEVICEADDED
}
case SDL_EVENT_JOYSTICK_REMOVED:
case SDL_JOYDEVICEREMOVED:
{
removePhysicalJoystick(myEvent.jdevice.which);
break;
break; // SDL_JOYDEVICEREMOVED
}
#endif
case SDL_EVENT_QUIT:
case SDL_QUIT:
{
handleEvent(Event::Quit);
break;
break; // SDL_QUIT
}
case SDL_EVENT_WINDOW_SHOWN:
case SDL_WINDOWEVENT:
switch(myEvent.window.event)
{
case SDL_WINDOWEVENT_SHOWN:
handleSystemEvent(SystemEvent::WINDOW_SHOWN);
break;
case SDL_EVENT_WINDOW_HIDDEN:
case SDL_WINDOWEVENT_HIDDEN:
handleSystemEvent(SystemEvent::WINDOW_HIDDEN);
break;
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_WINDOWEVENT_EXPOSED:
handleSystemEvent(SystemEvent::WINDOW_EXPOSED);
break;
case SDL_EVENT_WINDOW_MOVED:
case SDL_WINDOWEVENT_MOVED:
handleSystemEvent(SystemEvent::WINDOW_MOVED,
myEvent.window.data1, myEvent.window.data1);
break;
case SDL_EVENT_WINDOW_RESIZED:
case SDL_WINDOWEVENT_RESIZED:
handleSystemEvent(SystemEvent::WINDOW_RESIZED,
myEvent.window.data1, myEvent.window.data1);
break;
case SDL_EVENT_WINDOW_MINIMIZED:
case SDL_WINDOWEVENT_MINIMIZED:
handleSystemEvent(SystemEvent::WINDOW_MINIMIZED);
break;
case SDL_EVENT_WINDOW_MAXIMIZED:
case SDL_WINDOWEVENT_MAXIMIZED:
handleSystemEvent(SystemEvent::WINDOW_MAXIMIZED);
break;
case SDL_EVENT_WINDOW_RESTORED:
case SDL_WINDOWEVENT_RESTORED:
handleSystemEvent(SystemEvent::WINDOW_RESTORED);
break;
case SDL_EVENT_WINDOW_MOUSE_ENTER:
case SDL_WINDOWEVENT_ENTER:
handleSystemEvent(SystemEvent::WINDOW_ENTER);
break;
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
case SDL_WINDOWEVENT_LEAVE:
handleSystemEvent(SystemEvent::WINDOW_LEAVE);
break;
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_WINDOWEVENT_FOCUS_GAINED:
handleSystemEvent(SystemEvent::WINDOW_FOCUS_GAINED);
break;
case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_WINDOWEVENT_FOCUS_LOST:
handleSystemEvent(SystemEvent::WINDOW_FOCUS_LOST);
break;
case SDL_EVENT_SYSTEM_THEME_CHANGED:
handleSystemEvent(SystemEvent::THEME_CHANGED);
default:
break;
}
break; // SDL_WINDOWEVENT
default:
break;
}
}
}
#ifdef JOYSTICK_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerSDL::JoystickSDL::JoystickSDL(int idx)
EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx)
{
ASSERT_MAIN_THREAD;
// NOLINTNEXTLINE: we want to initialize here, not in the member list
myStick = SDL_OpenJoystick(idx);
myStick = SDL_JoystickOpen(idx);
if(myStick)
{
// In Windows, all XBox controllers using the XInput API seem to name
@ -265,24 +274,21 @@ EventHandlerSDL::JoystickSDL::JoystickSDL(int idx)
// it also appends " #x", where x seems to vary. Obviously this wreaks
// havoc with the idea that a joystick will always have the same name.
// So we truncate the number.
const char* const sdlname = SDL_GetJoystickName(myStick);
const char* const sdlname = SDL_JoystickName(myStick);
const string& desc = BSPF::startsWithIgnoreCase(sdlname, "XInput Controller")
? "XInput Controller" : sdlname;
initialize(SDL_GetJoystickID(myStick), desc,
SDL_GetNumJoystickAxes(myStick),
SDL_GetNumJoystickButtons(myStick),
SDL_GetNumJoystickHats(myStick),
SDL_GetNumJoystickBalls(myStick));
initialize(SDL_JoystickInstanceID(myStick), desc,
SDL_JoystickNumAxes(myStick), SDL_JoystickNumButtons(myStick),
SDL_JoystickNumHats(myStick), SDL_JoystickNumBalls(myStick));
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandlerSDL::JoystickSDL::~JoystickSDL()
EventHandlerSDL2::JoystickSDL2::~JoystickSDL2()
{
ASSERT_MAIN_THREAD;
if(SDL_WasInit(SDL_INIT_JOYSTICK) && myStick)
SDL_CloseJoystick(myStick);
SDL_JoystickClose(myStick);
}
#endif

View File

@ -8,15 +8,15 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 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 EVENTHANDLER_SDL_HXX
#define EVENTHANDLER_SDL_HXX
#ifndef EVENTHANDLER_SDL2_HXX
#define EVENTHANDLER_SDL2_HXX
#include "SDL_lib.hxx"
#include "EventHandler.hxx"
@ -24,21 +24,26 @@
/**
This class handles event collection from the point of view of the specific
backend toolkit (SDL). It converts from SDL-specific events into events
backend toolkit (SDL2). It converts from SDL2-specific events into events
that the Stella core can understand.
@author Stephen Anthony
*/
class EventHandlerSDL : public EventHandler
class EventHandlerSDL2 : public EventHandler
{
public:
/**
Create a new SDL event handler object
Create a new SDL2 event handler object
*/
explicit EventHandlerSDL(OSystem& osystem);
~EventHandlerSDL() override;
explicit EventHandlerSDL2(OSystem& osystem);
~EventHandlerSDL2() override;
private:
/**
Enable/disable text events (distinct from single-key events).
*/
void enableTextEvents(bool enable) override;
/**
Clipboard methods.
*/
@ -46,42 +51,40 @@ class EventHandlerSDL : public EventHandler
string pasteText(string& text) const override;
/**
Collects and dispatches any pending SDL events.
Collects and dispatches any pending SDL2 events.
*/
void pollEvent() override;
private:
SDL_Event myEvent{0};
#ifdef JOYSTICK_SUPPORT
// A thin wrapper around a basic PhysicalJoystick, holding the pointer to
// the underlying SDL joystick device.
class JoystickSDL : public PhysicalJoystick
class JoystickSDL2 : public PhysicalJoystick
{
public:
explicit JoystickSDL(int idx);
virtual ~JoystickSDL();
explicit JoystickSDL2(int idx);
virtual ~JoystickSDL2();
private:
SDL_Joystick* myStick{nullptr};
private:
// Following constructors and assignment operators not supported
JoystickSDL() = delete;
JoystickSDL(const JoystickSDL&) = delete;
JoystickSDL(JoystickSDL&&) = delete;
JoystickSDL& operator=(const JoystickSDL&) = delete;
JoystickSDL& operator=(JoystickSDL&&) = delete;
JoystickSDL2() = delete;
JoystickSDL2(const JoystickSDL2&) = delete;
JoystickSDL2(JoystickSDL2&&) = delete;
JoystickSDL2& operator=(const JoystickSDL2&) = delete;
JoystickSDL2& operator=(JoystickSDL2&&) = delete;
};
#endif
private:
// Following constructors and assignment operators not supported
EventHandlerSDL() = delete;
EventHandlerSDL(const EventHandlerSDL&) = delete;
EventHandlerSDL(EventHandlerSDL&&) = delete;
EventHandlerSDL& operator=(const EventHandlerSDL&) = delete;
EventHandlerSDL& operator=(EventHandlerSDL&&) = delete;
EventHandlerSDL2() = delete;
EventHandlerSDL2(const EventHandlerSDL2&) = delete;
EventHandlerSDL2(EventHandlerSDL2&&) = delete;
EventHandlerSDL2& operator=(const EventHandlerSDL2&) = delete;
EventHandlerSDL2& operator=(EventHandlerSDL2&&) = delete;
};
#endif

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -25,36 +25,38 @@
#include "Settings.hxx"
#include "ThreadDebugging.hxx"
#include "FBSurfaceSDL.hxx"
#include "FBBackendSDL.hxx"
#include "FBSurfaceSDL2.hxx"
#include "FBBackendSDL2.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBBackendSDL::FBBackendSDL(OSystem& osystem)
FBBackendSDL2::FBBackendSDL2(OSystem& osystem)
: myOSystem{osystem}
{
ASSERT_MAIN_THREAD;
// Initialize SDL context
if(!SDL_InitSubSystem(SDL_INIT_VIDEO))
// Initialize SDL2 context
if(SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
{
ostringstream buf;
buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError();
throw runtime_error(buf.str());
}
Logger::debug("FBBackendSDL::FBBackendSDL SDL_Init()");
Logger::debug("FBBackendSDL2::FBBackendSDL2 SDL_Init()");
// We need a pixel format for palette value calculations
// It's done this way (vs directly accessing a FBSurfaceSDL object)
// 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_GetPixelFormatDetails(SDL_PIXELFORMAT_ARGB8888);
myPixelFormat = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBBackendSDL::~FBBackendSDL()
FBBackendSDL2::~FBBackendSDL2()
{
ASSERT_MAIN_THREAD;
SDL_FreeFormat(myPixelFormat);
if(myRenderer)
{
SDL_DestroyRenderer(myRenderer);
@ -62,55 +64,46 @@ FBBackendSDL::~FBBackendSDL()
}
if(myWindow)
{
SDL_SetWindowFullscreen(myWindow, false); // on some systems, a crash occurs
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_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::queryHardware(vector<Common::Size>& fullscreenRes,
void FBBackendSDL2::queryHardware(vector<Common::Size>& fullscreenRes,
vector<Common::Size>& windowedRes,
VariantList& renderers)
{
ASSERT_MAIN_THREAD;
// Get number of displays (for most systems, this will be '1')
int count = 0;
SDL_DisplayID* displays = SDL_GetDisplays(&count);
if(displays && count > 0)
myNumDisplays = static_cast<uInt32>(count);
else
return;
myNumDisplays = SDL_GetNumVideoDisplays();
// Get the maximum fullscreen and windowed desktop resolutions
for(uInt32 i = 0; i < myNumDisplays; ++i)
// First get the maximum fullscreen desktop resolution
SDL_DisplayMode display;
for(int i = 0; i < myNumDisplays; ++i)
{
// Fullscreen mode
const SDL_DisplayMode* display = SDL_GetDesktopDisplayMode(displays[i]);
fullscreenRes.emplace_back(display->w, display->h);
SDL_GetDesktopDisplayMode(i, &display);
fullscreenRes.emplace_back(display.w, display.h);
// Windowed mode
SDL_Rect r{};
if(SDL_GetDisplayUsableBounds(displays[i], &r))
windowedRes.emplace_back(r.w, r.h);
int numModes = 0;
// evaluate fullscreen display modes (debug only for now)
const int numModes = SDL_GetNumDisplayModes(i);
ostringstream s;
string lastRes;
SDL_DisplayMode** modes = SDL_GetFullscreenDisplayModes(displays[i], &numModes);
s << "Supported video modes (" << numModes << ") for display " << i
<< " (" << SDL_GetDisplayName(displays[i]) << "):";
<< " (" << SDL_GetDisplayName(i) << "):";
for(int m = 0; modes != nullptr && modes[m] != nullptr; m++)
string lastRes;
for(int m = 0; m < numModes; ++m)
{
const SDL_DisplayMode* mode = modes[m];
ostringstream res, ref;
SDL_DisplayMode mode;
ostringstream res;
res << std::setw(4) << mode->w << "x" << std::setw(4) << mode->h;
SDL_GetDisplayMode(i, m, &mode);
res << std::setw(4) << mode.w << "x" << std::setw(4) << mode.h;
if(lastRes != res.view())
{
@ -119,23 +112,47 @@ void FBBackendSDL::queryHardware(vector<Common::Size>& fullscreenRes,
lastRes = res.view();
s << " " << lastRes << ": ";
}
ref << mode->refresh_rate << "Hz";
s << std::setw(7) << std::left << ref.str();
if(mode->w == display->w && mode->h == display->h &&
mode->refresh_rate == display->refresh_rate)
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.view());
}
SDL_free(displays);
// 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_view sdlName;
string_view stellaName;
string sdlName;
string stellaName;
};
// Create name map for all currently known SDL renderers
static const std::array<RenderName, 8> RENDERER_NAMES = {{
@ -152,66 +169,68 @@ void FBBackendSDL::queryHardware(vector<Common::Size>& fullscreenRes,
const int numDrivers = SDL_GetNumRenderDrivers();
for(int i = 0; i < numDrivers; ++i)
{
const char* const rendername = SDL_GetRenderDriver(i);
if(rendername)
SDL_RendererInfo info;
if(SDL_GetRenderDriverInfo(i, &info) == 0)
{
// Map SDL names into nicer Stella names (if available)
bool found = false;
for(const auto& render: RENDERER_NAMES)
{
if(render.sdlName == rendername)
if(render.sdlName == info.name)
{
VarList::push_back(renderers, render.stellaName, rendername);
VarList::push_back(renderers, render.stellaName, info.name);
found = true;
break;
}
}
if(!found)
VarList::push_back(renderers, rendername, rendername);
VarList::push_back(renderers, info.name, info.name);
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendSDL::isCurrentWindowPositioned() const
bool FBBackendSDL2::isCurrentWindowPositioned() const
{
ASSERT_MAIN_THREAD;
return myWindow && !fullScreen() && !myCenter;
return !myCenter
&& myWindow && !(SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Common::Point FBBackendSDL::getCurrentWindowPos() const
Common::Point FBBackendSDL2::getCurrentWindowPos() const
{
ASSERT_MAIN_THREAD;
Common::Point pos;
SDL_GetWindowPosition(myWindow, &pos.x, &pos.y);
return pos;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FBBackendSDL::getCurrentDisplayID() const
Int32 FBBackendSDL2::getCurrentDisplayIndex() const
{
ASSERT_MAIN_THREAD;
return SDL_GetDisplayForWindow(myWindow);
return SDL_GetWindowDisplayIndex(myWindow);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendSDL::setVideoMode(const VideoModeHandler::Mode& mode,
bool FBBackendSDL2::setVideoMode(const VideoModeHandler::Mode& mode,
int winIdx, const Common::Point& winPos)
{
ASSERT_MAIN_THREAD;
// cerr << mode << '\n';
// If not initialized by this point, then immediately fail
if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
return false;
const uInt32 displayIndex = std::min<uInt32>(myNumDisplays, winIdx);
const bool fullScreen = mode.fsIndex != -1;
const Int32 displayIndex = std::min(myNumDisplays - 1, winIdx);
int posX = 0, posY = 0;
myCenter = myOSystem.settings().getBool("center");
@ -242,10 +261,10 @@ bool FBBackendSDL::setVideoMode(const VideoModeHandler::Mode& mode,
}
#ifdef ADAPTABLE_REFRESH_SUPPORT
SDL_DisplayMode adaptedSdlMode{};
SDL_DisplayMode adaptedSdlMode;
const int gameRefreshRate =
myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
const bool shouldAdapt = mode.fullscreen
const bool shouldAdapt = fullScreen
&& myOSystem.settings().getBool("tia.fs_refresh")
&& gameRefreshRate
// take care of 59.94 Hz
@ -256,18 +275,20 @@ bool FBBackendSDL::setVideoMode(const VideoModeHandler::Mode& mode,
#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 uInt32 d = getCurrentDisplayID();
const int d = SDL_GetWindowDisplayIndex(myWindow);
int w{0}, h{0};
SDL_GetWindowSize(myWindow, &w, &h);
if(d != displayIndex ||
std::cmp_not_equal(w, mode.screenS.w) ||
std::cmp_not_equal(h, mode.screenS.h) || adaptRefresh)
if(d != displayIndex || static_cast<uInt32>(w) != mode.screenS.w ||
static_cast<uInt32>(h) != mode.screenS.h || adaptRefresh)
{
// Renderer has to be destroyed *before* the window gets destroyed to avoid memory leaks
SDL_DestroyRenderer(myRenderer);
@ -285,25 +306,8 @@ bool FBBackendSDL::setVideoMode(const VideoModeHandler::Mode& mode,
}
else
{
// Re-create with new properties
const SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING,
myScreenTitle.c_str());
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, posX);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, posY);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER,
mode.screenS.w);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER,
mode.screenS.h);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN,
true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN,
mode.fullscreen);
SDL_SetBooleanProperty(props,
SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN,
true);
myWindow = SDL_CreateWindowWithProperties(props);
SDL_DestroyProperties(props);
myWindow = SDL_CreateWindow(myScreenTitle.c_str(), posX, posY,
mode.screenS.w, mode.screenS.h, flags);
if(myWindow == nullptr)
{
const string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError());
@ -311,7 +315,6 @@ bool FBBackendSDL::setVideoMode(const VideoModeHandler::Mode& mode,
return false;
}
enableTextEvents(myTextEventsEnabled);
setWindowIcon();
}
@ -319,7 +322,7 @@ bool FBBackendSDL::setVideoMode(const VideoModeHandler::Mode& mode,
if(adaptRefresh)
{
// Switch to mode for adapted refresh rate
if(!SDL_SetWindowFullscreenMode(myWindow, &adaptedSdlMode))
if(SDL_SetWindowDisplayMode(myWindow, &adaptedSdlMode) != 0)
{
Logger::error("ERROR: Display refresh rate change failed");
}
@ -331,39 +334,31 @@ bool FBBackendSDL::setVideoMode(const VideoModeHandler::Mode& mode,
<< adaptedSdlMode.refresh_rate << " Hz " << "(" << adaptedSdlMode.w << "x" << adaptedSdlMode.h << ")";
Logger::info(msg.view());
const SDL_DisplayMode* setSdlMode = SDL_GetWindowFullscreenMode(myWindow);
cerr << setSdlMode->refresh_rate << "Hz\n";
SDL_DisplayMode setSdlMode;
SDL_GetWindowDisplayMode(myWindow, &setSdlMode);
cerr << setSdlMode.refresh_rate << "Hz\n";
}
}
#endif
const bool result = createRenderer();
if(result)
{
// TODO: Checking for fullscreen status later returns invalid results,
// so we check and cache it here
myIsFullscreen = SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN;
SDL_ShowWindow(myWindow);
}
return result;
return createRenderer();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendSDL::adaptRefreshRate(Int32 displayIndex,
bool FBBackendSDL2::adaptRefreshRate(Int32 displayIndex,
SDL_DisplayMode& adaptedSdlMode)
{
ASSERT_MAIN_THREAD;
const SDL_DisplayMode* sdlMode = SDL_GetCurrentDisplayMode(displayIndex);
SDL_DisplayMode sdlMode;
if(sdlMode == nullptr)
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 currentRefreshRate = sdlMode.refresh_rate;
const int wantedRefreshRate =
myOSystem.hasConsole() ? myOSystem.console().gameRefreshRate() : 0;
// Take care of rounded refresh rates (e.g. 59.94 Hz)
@ -379,19 +374,18 @@ bool FBBackendSDL::adaptRefreshRate(Int32 displayIndex,
// Check for integer factors 1 (60/50 Hz) and 2 (120/100 Hz)
for(int m = 1; m <= 2; ++m)
{
SDL_DisplayMode closestSdlMode{};
const float refresh_rate = wantedRefreshRate * m;
SDL_DisplayMode closestSdlMode;
if(!SDL_GetClosestFullscreenDisplayMode(displayIndex, sdlMode->w, sdlMode->h, refresh_rate, true, &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(
static_cast<float>(refresh_rate) / refresh_rate,
static_cast<float>(refresh_rate) / (refresh_rate - 1));
static_cast<float>(sdlMode.refresh_rate) / sdlMode.refresh_rate,
static_cast<float>(sdlMode.refresh_rate) / (sdlMode.refresh_rate - 1));
const float diff = std::abs(factor - std::round(factor)) / factor;
if(diff < bestDiff)
{
bestDiff = diff;
@ -411,46 +405,38 @@ bool FBBackendSDL::adaptRefreshRate(Int32 displayIndex,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendSDL::createRenderer()
bool FBBackendSDL2::createRenderer()
{
ASSERT_MAIN_THREAD;
// A new renderer is only created when necessary:
// - no renderer existing
// - different renderer flags
// - different renderer name
// - different renderer vsync
const bool enableVSync = myOSystem.settings().getBool("vsync") &&
!myOSystem.settings().getBool("turbo");
const string& video = myOSystem.settings().getString("video");
bool recreate = myRenderer == nullptr;
if(myRenderer)
{
recreate = recreate || video != SDL_GetRendererName(myRenderer);
uInt32 renderFlags = SDL_RENDERER_ACCELERATED;
const string& video = myOSystem.settings().getString("video"); // Render hint
SDL_RendererInfo renderInfo;
const SDL_PropertiesID props = SDL_GetRendererProperties(myRenderer);
const bool currentVSync = SDL_GetNumberProperty(props,
SDL_PROP_RENDERER_VSYNC_NUMBER, 0) != 0;
recreate = recreate || currentVSync != enableVSync;
}
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) << '\n';
if(myRenderer)
SDL_DestroyRenderer(myRenderer);
// Re-create with new properties
const SDL_PropertiesID props = SDL_CreateProperties();
if(!video.empty())
SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING,
video.c_str());
SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER,
enableVSync ? 1 : 0);
SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER,
myWindow);
SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str());
myRenderer = SDL_CreateRendererWithProperties(props);
SDL_DestroyProperties(props);
myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags);
detectFeatures();
determineDimensions();
@ -464,106 +450,85 @@ bool FBBackendSDL::createRenderer()
}
clear();
const char* const detectedvideo = SDL_GetRendererName(myRenderer);
if(detectedvideo)
myOSystem.settings().setValue("video", detectedvideo);
SDL_RendererInfo renderinfo;
if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0)
myOSystem.settings().setValue("video", renderinfo.name);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::setTitle(string_view title)
void FBBackendSDL2::setTitle(string_view title)
{
ASSERT_MAIN_THREAD;
myScreenTitle = title;
if(myWindow)
SDL_SetWindowTitle(myWindow, myScreenTitle.c_str());
SDL_SetWindowTitle(myWindow, string{title}.c_str());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string FBBackendSDL::about() const
string FBBackendSDL2::about() const
{
ASSERT_MAIN_THREAD;
ostringstream out;
out << "Video system: " << SDL_GetCurrentVideoDriver() << '\n';
const SDL_PropertiesID props = SDL_GetRendererProperties(myRenderer);
if(props != 0)
SDL_RendererInfo info;
if(SDL_GetRendererInfo(myRenderer, &info) >= 0)
{
out << " Renderer: "
<< SDL_GetStringProperty(props, SDL_PROP_RENDERER_NAME_STRING, "")
<< '\n';
const uInt64 maxTexSize =
SDL_GetNumberProperty(props, SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 0);
if(maxTexSize > 0)
out << " Max texture: " << maxTexSize << "x" << maxTexSize << '\n';
const bool usingVSync = SDL_GetNumberProperty(props,
SDL_PROP_RENDERER_VSYNC_NUMBER, 0) != 0;
out << " Renderer: " << info.name << '\n';
if(info.max_texture_width > 0 && info.max_texture_height > 0)
out << " Max texture: " << info.max_texture_width << "x"
<< info.max_texture_height << '\n';
out << " Flags: "
<< (usingVSync ? "+" : "-") << "vsync"
<< ((info.flags & SDL_RENDERER_PRESENTVSYNC) ? "+" : "-") << "vsync, "
<< ((info.flags & SDL_RENDERER_ACCELERATED) ? "+" : "-") << "accel"
<< '\n';
}
return out.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::showCursor(bool show)
void FBBackendSDL2::showCursor(bool show)
{
ASSERT_MAIN_THREAD;
if(show) SDL_ShowCursor();
else SDL_HideCursor();
SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::grabMouse(bool grab)
void FBBackendSDL2::grabMouse(bool grab)
{
ASSERT_MAIN_THREAD;
SDL_SetWindowMouseGrab(myWindow, grab);
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_SYSTEM_SCALE, grab ? "1" : "0");
SDL_SetWindowRelativeMouseMode(myWindow, grab);
SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::enableTextEvents(bool enable)
{
ASSERT_MAIN_THREAD;
if(enable)
SDL_StartTextInput(myWindow);
else
SDL_StopTextInput(myWindow);
// myWindows can still be null, so we remember the state and set again when
// the window is created
myTextEventsEnabled = enable;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendSDL::fullScreen() const
bool FBBackendSDL2::fullScreen() const
{
ASSERT_MAIN_THREAD;
#ifdef WINDOWED_SUPPORT
return myIsFullscreen; // TODO: should query SDL directly
return SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP;
#else
return true;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int FBBackendSDL::refreshRate() const
int FBBackendSDL2::refreshRate() const
{
ASSERT_MAIN_THREAD;
const SDL_DisplayID displayID = getCurrentDisplayID();
const SDL_DisplayMode* mode = SDL_GetCurrentDisplayMode(displayID);
const uInt32 displayIndex = SDL_GetWindowDisplayIndex(myWindow);
SDL_DisplayMode sdlMode;
if(mode)
return mode->refresh_rate;
if(SDL_GetCurrentDisplayMode(displayIndex, &sdlMode) == 0)
return sdlMode.refresh_rate;
if(myWindow != nullptr)
Logger::error("Could not retrieve current display mode");
@ -572,7 +537,7 @@ int FBBackendSDL::refreshRate() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::renderToScreen()
void FBBackendSDL2::renderToScreen()
{
ASSERT_MAIN_THREAD;
@ -581,42 +546,35 @@ void FBBackendSDL::renderToScreen()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::setWindowIcon()
void FBBackendSDL2::setWindowIcon()
{
#if !defined(BSPF_MACOS)
#if !defined(BSPF_MACOS) && !defined(RETRON77)
#include "stella_icon.hxx"
ASSERT_MAIN_THREAD;
SDL_Surface* surface =
SDL_CreateSurfaceFrom(32, 32, pixelFormat().format, stella_icon, 32 * 4);
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32,
32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000);
SDL_SetWindowIcon(myWindow, surface);
SDL_DestroySurface(surface);
SDL_FreeSurface(surface);
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unique_ptr<FBSurface> FBBackendSDL::createSurface(
unique_ptr<FBSurface> FBBackendSDL2::createSurface(
uInt32 w,
uInt32 h,
ScalingInterpolation inter,
const uInt32* data
) const
{
unique_ptr<FBSurface> s = make_unique<FBSurfaceSDL>
(const_cast<FBBackendSDL&>(*this), w, h, inter, data);
s->setBlendLevel(100); // by default, disable shading (use full alpha)
return s;
return make_unique<FBSurfaceSDL2>
(const_cast<FBBackendSDL2&>(*this), w, h, inter, data);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::readPixels(uInt8* buffer, size_t pitch,
void FBBackendSDL2::readPixels(uInt8* buffer, size_t pitch,
const Common::Rect& rect) const
{
// FIXME: this method needs to be refactored to return an FBSurface,
// since SDL_RenderReadPixels now returns an SDL_Surface
// PNGLibrary is the only user of this; that will need to be refactored too
#if 0
ASSERT_MAIN_THREAD;
SDL_Rect r;
@ -624,11 +582,10 @@ void FBBackendSDL::readPixels(uInt8* buffer, size_t pitch,
r.w = rect.w(); r.h = rect.h();
SDL_RenderReadPixels(myRenderer, &r, 0, buffer, static_cast<int>(pitch));
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::clear()
void FBBackendSDL2::clear()
{
ASSERT_MAIN_THREAD;
@ -636,7 +593,7 @@ void FBBackendSDL::clear()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::detectFeatures()
void FBBackendSDL2::detectFeatures()
{
myRenderTargetSupport = detectRenderTargetSupport();
@ -645,20 +602,36 @@ void FBBackendSDL::detectFeatures()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBBackendSDL::detectRenderTargetSupport()
bool FBBackendSDL2::detectRenderTargetSupport()
{
ASSERT_MAIN_THREAD;
if(myRenderer == nullptr)
return false;
// All texture modes except software support render targets
const char* const detectedvideo = SDL_GetRendererName(myRenderer);
return detectedvideo && !BSPF::equalsIgnoreCase(detectedvideo, "software");
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;
const int sdlError = SDL_SetRenderTarget(myRenderer, tex);
SDL_SetRenderTarget(myRenderer, nullptr);
SDL_DestroyTexture(tex);
return sdlError == 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBBackendSDL::determineDimensions()
void FBBackendSDL2::determineDimensions()
{
ASSERT_MAIN_THREAD;
@ -670,5 +643,5 @@ void FBBackendSDL::determineDimensions()
myRenderH = myWindowH;
}
else
SDL_GetCurrentRenderOutputSize(myRenderer, &myRenderW, &myRenderH);
SDL_GetRendererOutputSize(myRenderer, &myRenderW, &myRenderH);
}

View File

@ -8,38 +8,38 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 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_SDL_HXX
#define FB_BACKEND_SDL_HXX
#ifndef FB_BACKEND_SDL2_HXX
#define FB_BACKEND_SDL2_HXX
#include "SDL_lib.hxx"
class OSystem;
class FBSurfaceSDL;
class FBSurfaceSDL2;
#include "bspf.hxx"
#include "FBBackend.hxx"
/**
This class implements a standard SDL 2D, hardware accelerated framebuffer
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 FBBackendSDL : public FBBackend
class FBBackendSDL2 : public FBBackend
{
public:
/**
Creates a new SDL framebuffer
Creates a new SDL2 framebuffer
*/
explicit FBBackendSDL(OSystem& osystem);
~FBBackendSDL() override;
explicit FBBackendSDL2(OSystem& osystem);
~FBBackendSDL2() override;
public:
/**
@ -55,7 +55,7 @@ class FBBackendSDL : public FBBackend
/**
Get the SDL pixel format.
*/
const SDL_PixelFormatDetails& pixelFormat() const { return *myPixelFormat; }
const SDL_PixelFormat& pixelFormat() const { return *myPixelFormat; }
/**
Does the renderer support render targets?
@ -99,7 +99,7 @@ class FBBackendSDL : public FBBackend
@param b The blue component of the color
*/
FORCE_INLINE void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override
{ SDL_GetRGB(pixel, myPixelFormat, nullptr, r, g, b); }
{ SDL_GetRGB(pixel, myPixelFormat, r, g, b); }
/**
This method is called to retrieve the R/G/B/A data from the given pixel.
@ -111,7 +111,7 @@ class FBBackendSDL : public FBBackend
@param a The alpha component of the color.
*/
FORCE_INLINE void getRGBA(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b, uInt8* a) const override
{ SDL_GetRGBA(pixel, myPixelFormat, nullptr, r, g, b, a); }
{ SDL_GetRGBA(pixel, myPixelFormat, r, g, b, a); }
/**
This method is called to map a given R/G/B triple to the screen palette.
@ -121,7 +121,7 @@ class FBBackendSDL : public FBBackend
@param b The blue component of the color.
*/
uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override
{ return SDL_MapRGB(myPixelFormat, nullptr, r, g, b); }
{ return SDL_MapRGB(myPixelFormat, r, g, b); }
/**
This method is called to map a given R/G/B/A triple to the screen palette.
@ -132,7 +132,7 @@ class FBBackendSDL : public FBBackend
@param a The alpha component of the color.
*/
uInt32 mapRGBA(uInt8 r, uInt8 g, uInt8 b, uInt8 a) const override
{ return SDL_MapRGBA(myPixelFormat, nullptr, r, g, b, a); }
{ return SDL_MapRGBA(myPixelFormat, r, g, b, a); }
/**
This method is called to get a copy of the specified ARGB data from the
@ -167,9 +167,10 @@ class FBBackendSDL : public FBBackend
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 0 if no window is displayed
@return the current display index or a negative value if no
window is displayed
*/
uInt32 getCurrentDisplayID() const override;
Int32 getCurrentDisplayIndex() const override;
/**
Clear the frame buffer.
@ -222,11 +223,6 @@ class FBBackendSDL : public FBBackend
*/
void grabMouse(bool grab) override;
/**
Enable/disable text events (distinct from single-key events).
*/
void enableTextEvents(bool enable) override;
/**
This method is called to provide information about the backend.
*/
@ -250,20 +246,6 @@ class FBBackendSDL : public FBBackend
*/
int refreshRate() const override;
/**
Checks if the OS theme is set to light.
*/
bool isLightTheme() const override {
return SDL_GetSystemTheme() == SDL_SYSTEM_THEME_LIGHT;
}
/**
Checks if the OS theme is set to dark.
*/
bool isDarkTheme() const override {
return SDL_GetSystemTheme() == SDL_SYSTEM_THEME_DARK;
}
/**
Checks if the display refresh rate should be adapted to game refresh
rate in (real) fullscreen mode.
@ -304,18 +286,7 @@ class FBBackendSDL : public FBBackend
SDL_Renderer* myRenderer{nullptr};
// Used by mapRGB (when palettes are created)
const SDL_PixelFormatDetails* myPixelFormat{nullptr};
// Are we in fullscreen mode?
// There seem to be issues with creating the window and renderer separately,
// and doing so means we can't query the window for fullscreen status
// So we do it at window creation and cache the result
// TODO: Is this a bug in SDL?
bool myIsFullscreen{false};
// Text events are sometimes enabled before a window exists
// So we cache the request here, and honour it after the window has been created
bool myTextEventsEnabled{false};
SDL_PixelFormat* myPixelFormat{nullptr};
// Center setting of current window
bool myCenter{false};
@ -327,18 +298,18 @@ class FBBackendSDL : public FBBackend
string myScreenTitle;
// Number of displays
uInt32 myNumDisplays{0};
int myNumDisplays{1};
// Window and renderer dimensions
int myWindowW{0}, myWindowH{0}, myRenderW{0}, myRenderH{0};
private:
// Following constructors and assignment operators not supported
FBBackendSDL() = delete;
FBBackendSDL(const FBBackendSDL&) = delete;
FBBackendSDL(FBBackendSDL&&) = delete;
FBBackendSDL& operator=(const FBBackendSDL&) = delete;
FBBackendSDL& operator=(FBBackendSDL&&) = delete;
FBBackendSDL2() = delete;
FBBackendSDL2(const FBBackendSDL2&) = delete;
FBBackendSDL2(FBBackendSDL2&&) = delete;
FBBackendSDL2& operator=(const FBBackendSDL2&) = delete;
FBBackendSDL2& operator=(FBBackendSDL2&&) = delete;
};
#endif

View File

@ -8,14 +8,14 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 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 "FBSurfaceSDL.hxx"
#include "FBSurfaceSDL2.hxx"
#include "Logger.hxx"
#include "ThreadDebugging.hxx"
@ -41,7 +41,7 @@ namespace {
} // namespace
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceSDL::FBSurfaceSDL(FBBackendSDL& backend,
FBSurfaceSDL2::FBSurfaceSDL2(FBBackendSDL2& backend,
uInt32 width, uInt32 height,
ScalingInterpolation inter,
const uInt32* staticData)
@ -53,19 +53,19 @@ FBSurfaceSDL::FBSurfaceSDL(FBBackendSDL& backend,
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceSDL::~FBSurfaceSDL()
FBSurfaceSDL2::~FBSurfaceSDL2()
{
ASSERT_MAIN_THREAD;
if(mySurface)
{
SDL_DestroySurface(mySurface);
SDL_FreeSurface(mySurface);
mySurface = nullptr;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color)
void FBSurfaceSDL2::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId color)
{
ASSERT_MAIN_THREAD;
@ -75,49 +75,49 @@ void FBSurfaceSDL::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, ColorId colo
tmp.y = y;
tmp.w = w;
tmp.h = h;
SDL_FillSurfaceRect(mySurface, &tmp, myPalette[color]);
SDL_FillRect(mySurface, &tmp, myPalette[color]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FBSurfaceSDL::width() const
uInt32 FBSurfaceSDL2::width() const
{
return mySurface->w;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 FBSurfaceSDL::height() const
uInt32 FBSurfaceSDL2::height() const
{
return mySurface->h;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Common::Rect& FBSurfaceSDL::srcRect() const
const Common::Rect& FBSurfaceSDL2::srcRect() const
{
return mySrcGUIR;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Common::Rect& FBSurfaceSDL::dstRect() const
const Common::Rect& FBSurfaceSDL2::dstRect() const
{
return myDstGUIR;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setSrcPos(uInt32 x, uInt32 y)
void FBSurfaceSDL2::setSrcPos(uInt32 x, uInt32 y)
{
if(setSrcPosInternal(x, y))
reinitializeBlitter();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setSrcSize(uInt32 w, uInt32 h)
void FBSurfaceSDL2::setSrcSize(uInt32 w, uInt32 h)
{
if(setSrcSizeInternal(w, h))
reinitializeBlitter();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setSrcRect(const Common::Rect& r)
void FBSurfaceSDL2::setSrcRect(const Common::Rect& r)
{
const bool posChanged = setSrcPosInternal(r.x(), r.y()),
sizeChanged = setSrcSizeInternal(r.w(), r.h());
@ -127,21 +127,21 @@ void FBSurfaceSDL::setSrcRect(const Common::Rect& r)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setDstPos(uInt32 x, uInt32 y)
void FBSurfaceSDL2::setDstPos(uInt32 x, uInt32 y)
{
if(setDstPosInternal(x, y))
reinitializeBlitter();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setDstSize(uInt32 w, uInt32 h)
void FBSurfaceSDL2::setDstSize(uInt32 w, uInt32 h)
{
if(setDstSizeInternal(w, h))
reinitializeBlitter();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setDstRect(const Common::Rect& r)
void FBSurfaceSDL2::setDstRect(const Common::Rect& r)
{
const bool posChanged = setDstPosInternal(r.x(), r.y()),
sizeChanged = setDstSizeInternal(r.w(), r.h());
@ -151,23 +151,22 @@ void FBSurfaceSDL::setDstRect(const Common::Rect& r)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setVisible(bool visible)
void FBSurfaceSDL2::setVisible(bool visible)
{
myIsVisible = visible;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::translateCoords(Int32& x, Int32& y) const
void FBSurfaceSDL2::translateCoords(Int32& x, Int32& y) const
{
x -= myDstR.x; x /= myDstR.w / mySrcR.w;
y -= myDstR.y; y /= myDstR.h / mySrcR.h;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FBSurfaceSDL::render()
bool FBSurfaceSDL2::render()
{
if(!myBlitter)
reinitializeBlitter();
if (!myBlitter) reinitializeBlitter();
if(myIsVisible && myBlitter)
{
@ -179,15 +178,15 @@ bool FBSurfaceSDL::render()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::invalidate()
void FBSurfaceSDL2::invalidate()
{
ASSERT_MAIN_THREAD;
SDL_FillSurfaceRect(mySurface, nullptr, 0);
SDL_FillRect(mySurface, nullptr, 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
void FBSurfaceSDL2::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
{
ASSERT_MAIN_THREAD;
@ -199,22 +198,22 @@ void FBSurfaceSDL::invalidateRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
tmp.h = h;
// Note: Transparency has to be 0 to clear the rectangle foreground
// without affecting the background display.
SDL_FillSurfaceRect(mySurface, &tmp, 0);
SDL_FillRect(mySurface, &tmp, 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::reload()
void FBSurfaceSDL2::reload()
{
reinitializeBlitter(true);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::resize(uInt32 width, uInt32 height)
void FBSurfaceSDL2::resize(uInt32 width, uInt32 height)
{
ASSERT_MAIN_THREAD;
if(mySurface)
SDL_DestroySurface(mySurface);
SDL_FreeSurface(mySurface);
// NOTE: Currently, a resize changes a 'static' surface to 'streaming'
// No code currently does this, but we should at least check for it
@ -225,13 +224,17 @@ void FBSurfaceSDL::resize(uInt32 width, uInt32 height)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::createSurface(uInt32 width, uInt32 height, const uInt32* data)
void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height,
const uInt32* data)
{
ASSERT_MAIN_THREAD;
// Create a surface in the same format as the parent GL class
const SDL_PixelFormatDetails& pf = myBackend.pixelFormat();
mySurface = SDL_CreateSurface(width, height, pf.format);
const SDL_PixelFormat& pf = myBackend.pixelFormat();
mySurface = SDL_CreateRGBSurface(0, width, height,
pf.BitsPerPixel, pf.Rmask, pf.Gmask, pf.Bmask, pf.Amask);
//SDL_SetSurfaceBlendMode(mySurface, SDL_BLENDMODE_ADD); // default: SDL_BLENDMODE_BLEND
// We start out with the src and dst rectangles containing the same
// dimensions, indicating no scaling or re-positioning
@ -243,7 +246,7 @@ void FBSurfaceSDL::createSurface(uInt32 width, uInt32 height, const uInt32* data
////////////////////////////////////////////////////
// These *must* be set for the parent class
myPixels = static_cast<uInt32*>(mySurface->pixels);
myPitch = mySurface->pitch / pf.bytes_per_pixel;
myPitch = mySurface->pitch / pf.BytesPerPixel;
////////////////////////////////////////////////////
myIsStatic = data != nullptr;
@ -255,7 +258,7 @@ void FBSurfaceSDL::createSurface(uInt32 width, uInt32 height, const uInt32* data
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::reinitializeBlitter(bool force)
void FBSurfaceSDL2::reinitializeBlitter(bool force)
{
if (force)
myBlitter.reset();
@ -265,28 +268,18 @@ void FBSurfaceSDL::reinitializeBlitter(bool force)
myBackend, scalingAlgorithm(myInterpolationMode));
if (myBlitter)
myBlitter->reinitialize(mySrcR, myDstR, myEnableBlend, myBlendLevel,
myBlitter->reinitialize(mySrcR, myDstR, myAttributes,
myIsStatic ? mySurface : nullptr);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setBlendLevel(uInt32 percent)
void FBSurfaceSDL2::applyAttributes()
{
myBlendLevel = BSPF::clamp(percent, 0U, 100U);
reinitializeBlitter();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::enableBlend(bool enableBlend)
{
myEnableBlend = enableBlend;
reinitializeBlitter();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceSDL::setScalingInterpolation(ScalingInterpolation interpolation)
void FBSurfaceSDL2::setScalingInterpolation(ScalingInterpolation interpolation)
{
if (interpolation == ScalingInterpolation::sharp &&
(
@ -296,8 +289,7 @@ void FBSurfaceSDL::setScalingInterpolation(ScalingInterpolation interpolation)
)
interpolation = ScalingInterpolation::blur;
if(interpolation == myInterpolationMode)
return;
if (interpolation == myInterpolationMode) return;
myInterpolationMode = interpolation;
reload();

View File

@ -8,33 +8,33 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 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 FBSURFACE_SDL_HXX
#define FBSURFACE_SDL_HXX
#ifndef FBSURFACE_SDL2_HXX
#define FBSURFACE_SDL2_HXX
#include "bspf.hxx"
#include "FBSurface.hxx"
#include "FBBackendSDL.hxx"
#include "FBBackendSDL2.hxx"
#include "sdl_blitter/Blitter.hxx"
/**
An FBSurface suitable for the SDL Render2D API, making use of hardware
An FBSurface suitable for the SDL2 Render2D API, making use of hardware
acceleration behind the scenes.
@author Stephen Anthony
*/
class FBSurfaceSDL : public FBSurface
class FBSurfaceSDL2 : public FBSurface
{
public:
FBSurfaceSDL(FBBackendSDL& backend, uInt32 width, uInt32 height,
FBSurfaceSDL2(FBBackendSDL2& backend, uInt32 width, uInt32 height,
ScalingInterpolation inter, const uInt32* staticData);
~FBSurfaceSDL() override;
~FBSurfaceSDL2() override;
// Most of the surface drawing primitives are implemented in FBSurface;
// the ones implemented here use SDL-specific code for extra performance
@ -63,13 +63,14 @@ class FBSurfaceSDL : public FBSurface
void reload() override;
void resize(uInt32 width, uInt32 height) override;
void enableBlend(bool enable) override;
void setBlendLevel(uInt32 percent) override;
void setScalingInterpolation(ScalingInterpolation) override;
protected:
void applyAttributes() override;
private:
bool setSrcPosInternal(uInt32 x, uInt32 y) {
if(std::cmp_not_equal(x, mySrcR.x) || std::cmp_not_equal(y, mySrcR.y))
if(x != static_cast<uInt32>(mySrcR.x) || y != static_cast<uInt32>(mySrcR.y))
{
mySrcR.x = x; mySrcR.y = y;
mySrcGUIR.moveTo(x, y);
@ -78,7 +79,7 @@ class FBSurfaceSDL : public FBSurface
return false;
}
bool setSrcSizeInternal(uInt32 w, uInt32 h) {
if(std::cmp_not_equal(w, mySrcR.w) || std::cmp_not_equal(h, mySrcR.h))
if(w != static_cast<uInt32>(mySrcR.w) || h != static_cast<uInt32>(mySrcR.h))
{
mySrcR.w = w; mySrcR.h = h;
mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h);
@ -87,7 +88,7 @@ class FBSurfaceSDL : public FBSurface
return false;
}
bool setDstPosInternal(uInt32 x, uInt32 y) {
if(std::cmp_not_equal(x, myDstR.x) || std::cmp_not_equal(y, myDstR.y))
if(x != static_cast<uInt32>(myDstR.x) || y != static_cast<uInt32>(myDstR.y))
{
myDstR.x = x; myDstR.y = y;
myDstGUIR.moveTo(x, y);
@ -96,7 +97,7 @@ class FBSurfaceSDL : public FBSurface
return false;
}
bool setDstSizeInternal(uInt32 w, uInt32 h) {
if(std::cmp_not_equal(w, myDstR.w) || std::cmp_not_equal(h, myDstR.h))
if(w != static_cast<uInt32>(myDstR.w) || h != static_cast<uInt32>(myDstR.h))
{
myDstR.w = w; myDstR.h = h;
myDstGUIR.setWidth(w); myDstGUIR.setHeight(h);
@ -110,17 +111,18 @@ class FBSurfaceSDL : public FBSurface
void reinitializeBlitter(bool force = false);
// Following constructors and assignment operators not supported
FBSurfaceSDL() = delete;
FBSurfaceSDL(const FBSurfaceSDL&) = delete;
FBSurfaceSDL(FBSurfaceSDL&&) = delete;
FBSurfaceSDL& operator=(const FBSurfaceSDL&) = delete;
FBSurfaceSDL& operator=(FBSurfaceSDL&&) = delete;
FBSurfaceSDL2() = delete;
FBSurfaceSDL2(const FBSurfaceSDL2&) = delete;
FBSurfaceSDL2(FBSurfaceSDL2&&) = delete;
FBSurfaceSDL2& operator=(const FBSurfaceSDL2&) = delete;
FBSurfaceSDL2& operator=(FBSurfaceSDL2&&) = delete;
private:
FBBackendSDL& myBackend;
FBBackendSDL2& myBackend;
unique_ptr<Blitter> myBlitter;
ScalingInterpolation myInterpolationMode{ScalingInterpolation::none};
ScalingInterpolation myInterpolationMode
{ScalingInterpolation::none};
SDL_Surface* mySurface{nullptr};
SDL_Rect mySrcR{-1, -1, -1, -1}, myDstR{-1, -1, -1, -1};

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -381,7 +381,8 @@ string HighScoresManager::formattedScore(Int32 score, Int32 width) const
if(scoreBCD(jprops))
{
digits = std::max(width, digits);
if(width > digits)
digits = width;
buf << std::setw(digits) << std::setfill(' ') << score;
}
else {

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -132,7 +132,7 @@ class HighScoresManager
@return The number of score address bytes
*/
static constexpr uInt32 numAddrBytes(Int32 digits, Int32 trailing) {
static uInt32 numAddrBytes(Int32 digits, Int32 trailing) {
return (digits - trailing + 1) / 2;
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -188,7 +188,8 @@ json JoyMap::saveMapping(EventMode mode) const
using MapType = std::pair<JoyMapping, Event::Type>;
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
std::ranges::sort(sortedMap, [](const MapType& a, const MapType& b)
std::sort(sortedMap.begin(), sortedMap.end(),
[](const MapType& a, const MapType& b)
{
// Event::Type first
if(a.first.button != b.first.button)
@ -284,17 +285,17 @@ int JoyMap::loadMapping(const json& eventMappings, EventMode mode)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
json JoyMap::convertLegacyMapping(string lst)
json JoyMap::convertLegacyMapping(string list)
{
json eventMappings = json::array();
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
std::ranges::replace(lst, '|', ' ');
std::ranges::replace(lst, ':', ' ');
std::ranges::replace(lst, ',', ' ');
std::replace(list.begin(), list.end(), '|', ' ');
std::replace(list.begin(), list.end(), ':', ' ');
std::replace(list.begin(), list.end(), ',', ' ');
istringstream buf(lst);
istringstream buf(list);
int event = 0, button = 0, axis = 0, adir = 0, hat = 0, hdir = 0;
while(buf >> event && buf >> button

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -112,7 +112,7 @@ class JoyMap
nlohmann::json saveMapping(EventMode mode) const;
int loadMapping(const nlohmann::json& eventMappings, EventMode mode);
static nlohmann::json convertLegacyMapping(string lst);
static nlohmann::json convertLegacyMapping(string list);
/** Erase all mappings for given mode */
void eraseMode(EventMode mode);
@ -129,10 +129,10 @@ class JoyMap
size_t operator()(const JoyMapping& m)const {
return std::hash<uInt64>()((static_cast<uInt64>(m.mode)) // 3 bits
+ ((static_cast<uInt64>(m.button)) * 7) // 3 bits
+ (((static_cast<uInt64>(m.axis)) << 0) // 3 bits
| ((static_cast<uInt64>(m.adir)) << 3) // 2 bits
| ((static_cast<uInt64>(m.hat )) << 5) // 1 bit
| ((static_cast<uInt64>(m.hdir)) << 6) // 2 bits
+ (((static_cast<uInt64>(m.axis)) << 0) // 2 bits
| ((static_cast<uInt64>(m.adir)) << 2) // 2 bits
| ((static_cast<uInt64>(m.hat )) << 4) // 1 bit
| ((static_cast<uInt64>(m.hdir)) << 5) // 2 bits
) * 61
);
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -43,7 +43,8 @@ namespace {
StellaMod::KBDM_RGUI,
StellaMod::KBDM_NUM,
StellaMod::KBDM_CAPS,
StellaMod::KBDM_MODE
StellaMod::KBDM_MODE,
StellaMod::KBDM_RESERVED
}) {
if((mask & mod) != mod) continue;
@ -221,7 +222,8 @@ json KeyMap::saveMapping(EventMode mode) const
using MapType = std::pair<Mapping, Event::Type>;
std::vector<MapType> sortedMap(myMap.begin(), myMap.end());
std::ranges::sort(sortedMap, [](const MapType& a, const MapType& b)
std::sort(sortedMap.begin(), sortedMap.end(),
[](const MapType& a, const MapType& b)
{
// Event::Type first
if(a.first.key != b.first.key)
@ -288,11 +290,11 @@ json KeyMap::convertLegacyMapping(string_view lm)
// Since istringstream swallows whitespace, we have to make the
// delimiters be spaces
string lst{lm};
std::ranges::replace(lst, '|', ' ');
std::ranges::replace(lst, ':', ' ');
std::ranges::replace(lst, ',', ' ');
istringstream buf(lst);
string list{lm};
std::replace(list.begin(), list.end(), '|', ' ');
std::replace(list.begin(), list.end(), ':', ' ');
std::replace(list.begin(), list.end(), ',', ' ');
istringstream buf(list);
int event = 0, key = 0, mod = 0;
while(buf >> event && buf >> key && buf >> mod)

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -17,10 +17,6 @@
#include "Logger.hxx"
#ifdef __LIB_RETRO__
extern void libretro_logger(int log_level, const char *string);
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Logger& Logger::instance()
{
@ -57,10 +53,6 @@ void Logger::logMessage(string_view message, Level level)
{
const std::lock_guard<std::mutex> lock(mutex);
#ifdef __LIB_RETRO__
libretro_logger(static_cast<int>(level), string{message}.c_str());
#endif
if(level == Logger::Level::ERR)
{
cout << message << '\n' << std::flush;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -28,13 +28,21 @@
#include "SerialPort.hxx"
#if defined(BSPF_UNIX)
#include "SerialPortUNIX.hxx"
#if defined(RETRON77)
#include "SettingsR77.hxx"
#include "OSystemR77.hxx"
#else
#include "OSystemUNIX.hxx"
#endif
#elif defined(BSPF_WINDOWS)
#include "SerialPortWINDOWS.hxx"
#include "OSystemWINDOWS.hxx"
#elif defined(BSPF_MACOS)
#include "SerialPortMACOS.hxx"
#include "OSystemMACOS.hxx"
extern "C" {
int stellaMain(int argc, char* argv[]);
}
#elif defined(__LIB_RETRO__)
#include "OSystemLIBRETRO.hxx"
#else
@ -45,8 +53,8 @@
#include "EventHandlerLIBRETRO.hxx"
#include "FBBackendLIBRETRO.hxx"
#elif defined(SDL_SUPPORT)
#include "EventHandlerSDL.hxx"
#include "FBBackendSDL.hxx"
#include "EventHandlerSDL2.hxx"
#include "FBBackendSDL2.hxx"
#else
#error Unsupported backend!
#endif
@ -55,7 +63,7 @@
#if defined(__LIB_RETRO__)
#include "SoundLIBRETRO.hxx"
#elif defined(SDL_SUPPORT)
#include "SoundSDL.hxx"
#include "SoundSDL2.hxx"
#else
#include "SoundNull.hxx"
#endif
@ -70,6 +78,10 @@ class AudioSettings;
implementations for the various ports of Stella, and always returns a
valid object based on the specific port and restrictions on that port.
As of SDL2, this code is greatly simplified. However, it remains here
in case we ever have multiple backend implementations again (should
not be necessary since SDL2 covers this nicely).
@author Stephen Anthony
*/
class MediaFactory
@ -78,7 +90,11 @@ class MediaFactory
static unique_ptr<OSystem> createOSystem()
{
#if defined(BSPF_UNIX)
#if defined(RETRON77)
return make_unique<OSystemR77>();
#else
return make_unique<OSystemUNIX>();
#endif
#elif defined(BSPF_WINDOWS)
return make_unique<OSystemWINDOWS>();
#elif defined(BSPF_MACOS)
@ -92,7 +108,11 @@ class MediaFactory
static unique_ptr<Settings> createSettings()
{
#ifdef RETRON77
return make_unique<SettingsR77>();
#else
return make_unique<Settings>();
#endif
}
static unique_ptr<SerialPort> createSerialPort()
@ -113,7 +133,7 @@ class MediaFactory
#if defined(__LIB_RETRO__)
return make_unique<FBBackendLIBRETRO>(osystem);
#elif defined(SDL_SUPPORT)
return make_unique<FBBackendSDL>(osystem);
return make_unique<FBBackendSDL2>(osystem);
#else
#error Unsupported platform for FrameBuffer!
#endif
@ -125,7 +145,7 @@ class MediaFactory
#if defined(__LIB_RETRO__)
return make_unique<SoundLIBRETRO>(osystem, audioSettings);
#elif defined(SOUND_SUPPORT) && defined(SDL_SUPPORT)
return make_unique<SoundSDL>(osystem, audioSettings);
return make_unique<SoundSDL2>(osystem, audioSettings);
#else
return make_unique<SoundNull>(osystem);
#endif
@ -139,7 +159,7 @@ class MediaFactory
#if defined(__LIB_RETRO__)
return make_unique<EventHandlerLIBRETRO>(osystem);
#elif defined(SDL_SUPPORT)
return make_unique<EventHandlerSDL>(osystem);
return make_unique<EventHandlerSDL2>(osystem);
#else
#error Unsupported platform for EventHandler!
#endif
@ -161,6 +181,15 @@ class MediaFactory
#endif
}
static bool supportsURL()
{
#if defined(SDL_SUPPORT)
return SDLSupportsURL();
#else
return false;
#endif
}
static bool openURL(const string& url)
{
#if defined(SDL_SUPPORT)

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -405,11 +405,18 @@ void PhysicalJoystickHandler::setStickDefaultMapping(
setDefaultAction(stick, item, event, EventMode::kDrivingMode, updateDefaults);
}
#if defined(RETRON77)
constexpr bool retron77 = true;
#else
constexpr bool retron77 = false;
#endif
// Regular joysticks can only be used by one player at a time,
// so we need to separate the paddles onto different
// devices. The Stelladaptor and 2600-daptor controllers support
// two players each when used as paddles, so are different.
const int paddlesPerJoystick = (j->type == PhysicalJoystick::Type::REGULAR) ? 1 : 2;
// devices. The R77 controllers support two players each when
// used as paddles, so are different. Similarly, stelladaptors
// and 2600-daptors support two players natively.
const int paddlesPerJoystick = (j->type == PhysicalJoystick::Type::REGULAR && !retron77) ? 1 : 2;
if(paddlesPerJoystick == 2)
{
@ -1348,11 +1355,17 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRight
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftPaddlesMapping = {
{Event::LeftPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::LeftPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same time
//{Event::LeftPaddleADecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
//{Event::LeftPaddleAIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::LeftPaddleAFire, 0},
{Event::LeftPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::LeftPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same
//{Event::LeftPaddleBDecrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
//{Event::LeftPaddleBIncrease, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
@ -1362,11 +1375,17 @@ PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultLeftP
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PhysicalJoystickHandler::EventMappingArray PhysicalJoystickHandler::DefaultRightPaddlesMapping = {
{Event::RightPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::X, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::RightPaddleAAnalog, JOY_CTRL_NONE, JoyAxis::Z, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same
//{Event::RightPaddleADecrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::POS},
//{Event::RightPaddleAIncrease, JOY_CTRL_NONE, JoyAxis::X, JoyDir::NEG},
{Event::RightPaddleAFire, 0},
{Event::RightPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::Y, JoyDir::ANALOG},
#if defined(RETRON77)
{Event::RightPaddleBAnalog, JOY_CTRL_NONE, JoyAxis::A3, JoyDir::ANALOG},
#endif
// Current code does NOT allow digital and anlog events on the same axis at the same
//{Event::RightPaddleBDecrease,JOY_CTRL_NONE, JoyAxis::Y, JoyDir::POS},
//{Event::RightPaddleBIncrease,JOY_CTRL_NONE, JoyAxis::Y, JoyDir::NEG},
@ -1466,6 +1485,14 @@ PhysicalJoystickHandler::EventMappingArray
PhysicalJoystickHandler::DefaultCommonMapping = {
// valid for all joysticks
// Note: buttons 0..2 are used by controllers!
#if defined(RETRON77)
{Event::CmdMenuMode, 3}, // Button "Y" / "4"
{Event::ExitMode, 4}, // Left Shoulder Button
{Event::OptionsMenuMode, 5}, // Right Shoulder Button
{Event::RewindPause, 7}, // Right Trigger Button
{Event::ConsoleSelect, 8}, // Button "Select"
{Event::ConsoleReset, 9}, // Button "Start"
#else
{Event::ConsoleSelect, 8}, // Button "Select"
{Event::ConsoleReset, 9}, // Button "Start"
{Event::ConsoleColorToggle, 3}, // Button "Y" / "4"
@ -1473,6 +1500,7 @@ PhysicalJoystickHandler::DefaultCommonMapping = {
{Event::ConsoleRightDiffToggle, 5}, // Right Shoulder Button
{Event::CmdMenuMode, 6}, // Left Trigger Button
{Event::OptionsMenuMode, 7}, // Right Trigger Button
#endif
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -806,10 +806,18 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
{ Event::HighScoresMenuMode, KBDK_INSERT },
{ Event::TogglePlayBackMode, KBDK_SPACE, KBDM_SHIFT },
#if defined(RETRON77)
{ Event::ConsoleColorToggle, KBDK_F4 }, // back ("COLOR","B/W")
{ Event::ConsoleLeftDiffToggle, KBDK_F6 }, // front ("SKILL P1")
{ Event::ConsoleRightDiffToggle, KBDK_F8 }, // front ("SKILL P2")
{ Event::CmdMenuMode, KBDK_F13 }, // back ("4:3","16:9")
{ Event::ExitMode, KBDK_BACKSPACE }, // back ("FRY")
#else // defining duplicate keys must be avoided!
{ Event::ConsoleBlackWhite, KBDK_F4 },
{ Event::ConsoleLeftDiffB, KBDK_F6 },
{ Event::ConsoleRightDiffB, KBDK_F8 },
{ Event::Fry, KBDK_BACKSPACE, KBDM_SHIFT }
{ Event::Fry, KBDK_BACKSPACE, KBDM_SHIFT },
#endif
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -854,12 +862,24 @@ PhysicalKeyboardHandler::DefaultMenuMapping = {
{Event::Quit, KBDK_Q, KBDM_CTRL},
#endif
#if defined(RETRON77)
{Event::UIUp, KBDK_F9}, // front ("SAVE")
{Event::UIDown, KBDK_F2}, // front ("RESET")
{Event::UINavPrev, KBDK_F11}, // front ("LOAD")
{Event::UINavNext, KBDK_F1}, // front ("MODE")
{Event::UISelect, KBDK_F6}, // front ("SKILL P1")
{Event::UICancel, KBDK_F8}, // front ("SKILL P2")
//{Event::NoType, KBDK_F4}, // back ("COLOR","B/W")
{Event::UITabPrev, KBDK_F13}, // back ("4:3","16:9")
{Event::UITabNext, KBDK_BACKSPACE}, // back (FRY)
#else // defining duplicate keys must be avoided!
{Event::UIPrevDir, KBDK_BACKSPACE},
#ifdef BSPF_MACOS
{Event::UIHelp, KBDK_SLASH, KBDM_SHIFT | CMD},
#else
{Event::UIHelp, KBDK_F1},
#endif
#endif
};
#ifdef GUI_SUPPORT
@ -1017,8 +1037,6 @@ PhysicalKeyboardHandler::DefaultPaddleMapping = {
{Event::LeftPaddleAFire, KBDK_SPACE},
{Event::LeftPaddleAFire, KBDK_LCTRL},
{Event::LeftPaddleAFire, KBDK_KP_5},
{Event::LeftPaddleAButton1, KBDK_UP, KBDM_SHIFT},
{Event::LeftPaddleAButton2, KBDK_DOWN, KBDM_SHIFT},
{Event::LeftPaddleBDecrease, KBDK_DOWN},
{Event::LeftPaddleBIncrease, KBDK_UP},
@ -1028,8 +1046,6 @@ PhysicalKeyboardHandler::DefaultPaddleMapping = {
{Event::RightPaddleADecrease, KBDK_J},
{Event::RightPaddleAIncrease, KBDK_G},
{Event::RightPaddleAFire, KBDK_F},
{Event::RightPaddleAButton1, KBDK_Y, KBDM_SHIFT},
{Event::RightPaddleAButton2, KBDK_H, KBDM_SHIFT},
{Event::RightPaddleBDecrease, KBDK_H},
{Event::RightPaddleBIncrease, KBDK_Y},
@ -1081,16 +1097,10 @@ PhysicalKeyboardHandler::EventMappingArray PhysicalKeyboardHandler::DefaultDrivi
{Event::LeftDrivingFire, KBDK_SPACE},
{Event::LeftDrivingFire, KBDK_LCTRL},
{Event::LeftDrivingFire, KBDK_KP_5},
{Event::LeftDrivingButton1, KBDK_UP},
{Event::LeftDrivingButton2, KBDK_DOWN},
{Event::LeftDrivingButton1, KBDK_KP_8},
{Event::LeftDrivingButton2, KBDK_KP_2},
{Event::RightDrivingCCW, KBDK_G},
{Event::RightDrivingCW, KBDK_J},
{Event::RightDrivingFire, KBDK_F},
{Event::RightDrivingButton1, KBDK_Y},
{Event::RightDrivingButton2, KBDK_H},
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1147,7 +1157,9 @@ PhysicalKeyboardHandler::CompuMateMapping = {
{Event::CompuMateRightBracket, KBDK_RIGHTBRACKET},
{Event::CompuMateMinus, KBDK_MINUS},
{Event::CompuMateQuote, KBDK_APOSTROPHE, KBDM_SHIFT},
#ifndef RETRON77
{Event::CompuMateBackspace, KBDK_BACKSPACE},
#endif
{Event::CompuMateEquals, KBDK_EQUALS},
{Event::CompuMatePlus, KBDK_EQUALS, KBDM_SHIFT},
{Event::CompuMateSlash, KBDK_SLASH}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -449,15 +449,13 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) const
{
constexpr int NUM_CHROMA = 16;
constexpr int NUM_LUMA = 8;
constexpr float SATURATION = 0.25F; // default saturation
if(timing == ConsoleTiming::ntsc)
{
constexpr float SATURATION = 0.30F; // default NTSC saturation
vector2d IQ[NUM_CHROMA];
// YIQ is YUV shifted by 33°
// -90° + 33° = -57° would create a greenish yellow
// -90° + 53° = -37° creates gold (which is correct according to the documentation)
constexpr float offset = (33 + 20) * BSPF::PI_f / 180;
// YIQ is YUV shifted by 33 degrees
constexpr float offset = 33 * BSPF::PI_f / 180;
const float shift = myPhaseNTSC * BSPF::PI_f / 180;
// color 0 is grayscale
@ -480,9 +478,9 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) const
float G = Y + dotProduct(IQ[chroma], IQG);
float B = Y + dotProduct(IQ[chroma], IQB);
R = std::max(R, 0.F);
G = std::max(G, 0.F);
B = std::max(B, 0.F);
if(R < 0) R = 0;
if(G < 0) G = 0;
if(B < 0) B = 0;
R = powf(R, 0.9F);
G = powf(G, 0.9F);
@ -498,7 +496,6 @@ void PaletteHandler::generateCustomPalette(ConsoleTiming timing) const
}
else if(timing == ConsoleTiming::pal)
{
constexpr float SATURATION = 0.25F; // default PAL saturation
constexpr float offset = BSPF::PI_f;
const float shift = myPhasePAL * BSPF::PI_f / 180;
constexpr float fixedShift = 22.5F * BSPF::PI_f / 180;
@ -672,9 +669,9 @@ const PaletteArray PaletteHandler::ourPALPalette = {
0x6c6c6c, 0, 0x909090, 0, 0xb4b4b4, 0, 0xd8d8d8, 0,
#else
0x0b0b0b, 0, 0x333333, 0, 0x595959, 0, 0x7b7b7b, 0, // 0
0x999999, 0, 0xb6b6b6, 0, 0xcfcfcf, 0, 0xe6e6e6, 0,
0x0b0b0b, 0, 0x333333, 0, 0x595959, 0, 0x7b7b7b, 0, // 1
0x999999, 0, 0xb6b6b6, 0, 0xcfcfcf, 0, 0xe6e6e6, 0,
0x8b8b8b, 0, 0xaaaaaa, 0, 0xc7c7c7, 0, 0xe3e3e3, 0,
0x000000, 0, 0x272727, 0, 0x404040, 0, 0x696969, 0, // 1
0x8b8b8b, 0, 0xaaaaaa, 0, 0xc7c7c7, 0, 0xe3e3e3, 0,
0x3b2400, 0, 0x664700, 0, 0x8b7000, 0, 0xac9200, 0, // 2
0xc5ae36, 0, 0xdec85e, 0, 0xf7e27f, 0, 0xfff19e, 0,
0x004500, 0, 0x006f00, 0, 0x3b9200, 0, 0x65b009, 0, // 3

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -33,7 +33,7 @@ class PaletteHandler
static constexpr string_view SETTING_CUSTOM = "custom";
// Phase shift default and limits
static constexpr float DEF_NTSC_SHIFT = 26.7F; // makes color $fx fall between $1x and $2x
static constexpr float DEF_NTSC_SHIFT = 26.2F;
static constexpr float DEF_PAL_SHIFT = 31.3F; // ~= 360 / 11.5
static constexpr float MAX_PHASE_SHIFT = 4.5F;
static constexpr float DEF_RGB_SHIFT = 0.0F;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -64,15 +64,15 @@ class PhosphorHandler
static constexpr uInt32 getPixel(const uInt32 c, const uInt32 p)
{
// Mix current calculated frame with previous displayed frame
const auto rc = static_cast<uInt8>(c),
const auto rc = static_cast<uInt8>(c >> 16),
gc = static_cast<uInt8>(c >> 8),
bc = static_cast<uInt8>(c >> 16),
rp = static_cast<uInt8>(p),
bc = static_cast<uInt8>(c),
rp = static_cast<uInt8>(p >> 16),
gp = static_cast<uInt8>(p >> 8),
bp = static_cast<uInt8>(p >> 16);
bp = static_cast<uInt8>(p);
return ourPhosphorLUT[rc][rp] | (ourPhosphorLUT[gc][gp] << 8) |
(ourPhosphorLUT[bc][bp] << 16);
return (ourPhosphorLUT[rc][rp] << 16) | (ourPhosphorLUT[gc][gp] << 8) |
ourPhosphorLUT[bc][bp];
}
private:

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -112,26 +112,26 @@ json PhysicalJoystick::convertLegacyMapping(string_view mapping, string_view nam
{
istringstream buf(string{mapping}); // TODO: fixed in C++23
json convertedMapping = json::object();
string lmap;
string map;
// Skip joystick name
getline(buf, lmap, MODE_DELIM);
getline(buf, map, MODE_DELIM);
while (getline(buf, lmap, MODE_DELIM))
while (getline(buf, map, MODE_DELIM))
{
int mode{0};
// Get event mode
std::ranges::replace(lmap, '|', ' ');
istringstream modeBuf(lmap);
std::replace(map.begin(), map.end(), '|', ' ');
istringstream modeBuf(map);
modeBuf >> mode;
// Remove leading "<mode>|" string
lmap.erase(0, 2);
map.erase(0, 2);
const json lmappingForMode = JoyMap::convertLegacyMapping(lmap);
const json mappingForMode = JoyMap::convertLegacyMapping(map);
convertedMapping[jsonName(static_cast<EventMode>(mode))] = lmappingForMode;
convertedMapping[jsonName(static_cast<EventMode>(mode))] = mappingForMode;
}
convertedMapping["name"] = name;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -114,7 +114,7 @@ bool RewindManager::addState(string_view message, bool timeMachine)
interval = interval * scanlines / 262;
}
if(myOSystem.console().system().cycles() - lastState.cycles < interval)
if(myOSystem.console().tia().cycles() - lastState.cycles < interval)
return false;
}
@ -135,7 +135,7 @@ bool RewindManager::addState(string_view message, bool timeMachine)
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
{
state.message = message;
state.cycles = myOSystem.console().system().cycles();
state.cycles = myOSystem.console().tia().cycles();
myLastTimeMachineAdd = timeMachine;
return true;
}
@ -145,7 +145,7 @@ bool RewindManager::addState(string_view message, bool timeMachine)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::rewindStates(uInt32 numStates)
{
const uInt64 startCycles = myOSystem.console().system().cycles();
const uInt64 startCycles = myOSystem.console().tia().cycles();
uInt32 i{0};
string message;
@ -185,7 +185,7 @@ uInt32 RewindManager::rewindStates(uInt32 numStates)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 RewindManager::unwindStates(uInt32 numStates)
{
const uInt64 startCycles = myOSystem.console().system().cycles();
const uInt64 startCycles = myOSystem.console().tia().cycles();
uInt32 i{0};
string message;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -33,30 +33,48 @@
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wreserved-identifier"
#pragma clang diagnostic ignored "-Wswitch-default"
#include <SDL3/SDL.h>
#include <SDL.h>
#pragma clang diagnostic pop
#elif defined(BSPF_WINDOWS)
#pragma warning(push, 0)
#include <SDL3/SDL.h>
#include <SDL.h>
#pragma warning(pop)
#else
#include <SDL3/SDL.h>
#include <SDL.h>
#endif
/*
* Seems to be needed for ppc64le, doesn't hurt other archs
* Note that this is a problem in SDL2, which includes <altivec.h>
* https://bugzilla.redhat.com/show_bug.cgi?id=1419452
*/
#undef vector
#undef pixel
#undef bool
static inline string SDLVersion()
{
ostringstream buf;
const int ver = SDL_GetVersion();
buf << "SDL "
<< SDL_VERSIONNUM_MAJOR(ver) << "."
<< SDL_VERSIONNUM_MINOR(ver) << "."
<< SDL_VERSIONNUM_MICRO(ver);
SDL_version ver;
SDL_GetVersion(&ver);
buf << "SDL " << static_cast<int>(ver.major) << "." << static_cast<int>(ver.minor)
<< "." << static_cast<int>(ver.patch);
return buf.str();
}
static inline bool SDLSupportsURL()
{
return SDL_VERSION_ATLEAST(2,0,14);
}
static inline bool SDLOpenURL(const string& url)
{
return SDL_OpenURL(url.c_str());
#if SDL_VERSION_ATLEAST(2,0,14)
return SDL_OpenURL(url.c_str()) == 0;
#else
cerr << "OpenURL requires at least SDL 2.0.14\n";
return false;
#endif
}
#endif // SDL_LIB_HXX

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -91,9 +91,8 @@ class SoundNull : public Sound
outside this range indicate that the volume shouldn't be changed at all.
@param volume The new volume level for the sound device
@param persist Whether to save the volume change to settings
*/
void setVolume(uInt32 volume, bool persist = true) override { }
void setVolume(uInt32 volume) override { }
/**
Adjusts the volume of the sound device based on the given direction.

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -31,18 +31,18 @@
#include "audio/LanczosResampler.hxx"
#include "ThreadDebugging.hxx"
#include "SoundSDL.hxx"
#include "SoundSDL2.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL::SoundSDL(OSystem& osystem, AudioSettings& audioSettings)
SoundSDL2::SoundSDL2(OSystem& osystem, AudioSettings& audioSettings)
: Sound{osystem},
myAudioSettings{audioSettings}
{
ASSERT_MAIN_THREAD;
Logger::debug("SoundSDL::SoundSDL started ...");
Logger::debug("SoundSDL2::SoundSDL2 started ...");
if(!SDL_InitSubSystem(SDL_INIT_AUDIO))
if(SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
{
ostringstream buf;
@ -52,35 +52,77 @@ SoundSDL::SoundSDL(OSystem& osystem, AudioSettings& audioSettings)
return;
}
SDL_zero(mySpec);
if(!myAudioSettings.enabled())
Logger::info("Sound disabled\n");
queryHardware(myDevices); // NOLINT
Logger::debug("SoundSDL::SoundSDL initialized");
SDL_zero(myHardwareSpec);
if(!openDevice())
return;
// Reserve 8K for the audio buffer; seems to be enough on most systems
myBuffer.reserve(8_KB);
Logger::debug("SoundSDL2::SoundSDL2 initialized");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL::~SoundSDL()
SoundSDL2::~SoundSDL2()
{
ASSERT_MAIN_THREAD;
if(!myIsInitializedFlag)
return;
SDL_DestroyAudioStream(myStream);
SDL_CloseAudioDevice(myDevice);
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL::openDevice()
void SoundSDL2::queryHardware(VariantList& devices)
{
ASSERT_MAIN_THREAD;
auto SOUND_ERROR = [this]() -> bool
const int numDevices = SDL_GetNumAudioDevices(0);
// log the available audio devices
ostringstream s;
s << "Supported audio devices (" << numDevices << "):";
Logger::debug(s.view());
VarList::push_back(devices, "Default", 0);
for(int i = 0; i < numDevices; ++i)
{
ostringstream ss;
ss << " " << i + 1 << ": " << SDL_GetAudioDeviceName(i, 0);
Logger::debug(ss.view());
VarList::push_back(devices, SDL_GetAudioDeviceName(i, 0), i + 1);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL2::openDevice()
{
ASSERT_MAIN_THREAD;
SDL_AudioSpec desired;
desired.freq = myAudioSettings.sampleRate();
desired.format = AUDIO_F32SYS;
desired.channels = 2;
desired.samples = static_cast<Uint16>(myAudioSettings.fragmentSize());
desired.callback = callback;
desired.userdata = this;
if(myIsInitializedFlag)
SDL_CloseAudioDevice(myDevice);
myDeviceId = BSPF::clamp(myAudioSettings.device(), 0U,
static_cast<uInt32>(myDevices.size() - 1));
const char* const device = myDeviceId
? myDevices.at(myDeviceId).first.c_str()
: nullptr;
myDevice = SDL_OpenAudioDevice(device, 0, &desired, &myHardwareSpec,
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if(myDevice == 0)
{
ostringstream buf;
@ -89,72 +131,49 @@ bool SoundSDL::openDevice()
Logger::error(buf.view());
return myIsInitializedFlag = false;
};
if(myIsInitializedFlag)
{
SDL_DestroyAudioStream(myStream);
myStream = nullptr;
}
mySpec = { SDL_AUDIO_F32, 2, static_cast<int>(myAudioSettings.sampleRate()) };
myDevice = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &mySpec);
if(myDevice == 0)
return SOUND_ERROR();
myStream = SDL_CreateAudioStream(&mySpec, nullptr);
if(!myStream)
return SOUND_ERROR();
if(!SDL_BindAudioStream(myDevice, myStream))
return SOUND_ERROR();
if(!SDL_SetAudioStreamGetCallback(myStream, audioCallback, this))
return SOUND_ERROR();
return myIsInitializedFlag = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::setEnabled(bool enable)
{
if(myIsInitializedFlag)
void SoundSDL2::setEnabled(bool enable)
{
mute(!enable);
pause(!enable);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::open(shared_ptr<AudioQueue> audioQueue,
void SoundSDL2::open(shared_ptr<AudioQueue> audioQueue,
shared_ptr<const EmulationTiming> emulationTiming)
{
const string pre_about = myAboutString;
// Do we need to re-open the sound device?
// Only do this when absolutely necessary
if(myAudioSettings.sampleRate() != static_cast<uInt32>(myHardwareSpec.freq) ||
myAudioSettings.fragmentSize() != static_cast<uInt32>(myHardwareSpec.samples) ||
myAudioSettings.device() != myDeviceId)
openDevice();
myEmulationTiming = emulationTiming;
myWavHandler.setSpeed(262 * 60 * 2. / myEmulationTiming->audioSampleRate());
Logger::debug("SoundSDL2::open started ...");
audioQueue->ignoreOverflows(!myAudioSettings.enabled());
if(!myAudioSettings.enabled())
{
Logger::info("Sound disabled\n");
return;
}
pause(true);
const string pre_about = myAboutString;
myAudioQueue = audioQueue;
myEmulationTiming = emulationTiming;
myUnderrun = true;
myCurrentFragment = nullptr;
myAudioQueue->ignoreOverflows(!myAudioSettings.enabled());
myWavHandler.setSpeed(262 * 60 * 2. / myEmulationTiming->audioSampleRate());
// Do we need to re-open the sound device?
// Only do this when absolutely necessary
if(myAudioSettings.sampleRate() != static_cast<uInt32>(mySpec.freq))
openDevice();
Logger::debug("SoundSDL::open started ...");
// Adjust volume to that defined in settings
setVolume(myAudioSettings.volume());
// Initialize resampler; must be done after the sound device has opened
initResampler();
// Show some info
@ -165,20 +184,20 @@ void SoundSDL::open(shared_ptr<AudioQueue> audioQueue,
// And start the SDL sound subsystem ...
pause(false);
Logger::debug("SoundSDL::open finished");
Logger::debug("SoundSDL2::open finished");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::mute(bool enable)
void SoundSDL2::mute(bool enable)
{
if(enable)
setVolume(0, false);
myVolumeFactor = 0;
else
setVolume(myAudioSettings.volume());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::toggleMute()
void SoundSDL2::toggleMute()
{
const bool wasMuted = myVolumeFactor == 0;
mute(!wasMuted);
@ -192,40 +211,31 @@ void SoundSDL::toggleMute()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL::pause(bool enable)
bool SoundSDL2::pause(bool enable)
{
ASSERT_MAIN_THREAD;
const bool wasPaused = SDL_AudioStreamDevicePaused(myStream);
const bool wasPaused = SDL_GetAudioDeviceStatus(myDevice) == SDL_AUDIO_PAUSED;
if(myIsInitializedFlag)
{
if(enable) SDL_PauseAudioStreamDevice(myStream);
else SDL_ResumeAudioStreamDevice(myStream);
SDL_PauseAudioDevice(myDevice, enable ? 1 : 0);
myWavHandler.pause(enable);
}
return wasPaused;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::setVolume(uInt32 volume, bool persist)
void SoundSDL2::setVolume(uInt32 volume)
{
if(myIsInitializedFlag && (volume <= 100))
{
myVolumeFactor = myAudioSettings.enabled()
? static_cast<float>(volume) / 100.F
: 0.F;
SDL_SetAudioStreamGain(myStream, myVolumeFactor);
myWavHandler.setVolumeFactor(myVolumeFactor);
if(persist)
myAudioSettings.setVolume(volume);
myVolumeFactor = myAudioSettings.enabled() ? static_cast<float>(volume) / 100.F : 0;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::adjustVolume(int direction)
void SoundSDL2::adjustVolume(int direction)
{
Int32 percent = myAudioSettings.volume();
percent = BSPF::clamp(percent + direction * 2, 0, 100);
@ -247,12 +257,13 @@ void SoundSDL::adjustVolume(int direction)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string SoundSDL::about() const
string SoundSDL2::about() const
{
ostringstream buf;
buf << "Sound enabled:\n"
<< " Volume: " << myAudioSettings.volume() << "%\n"
<< " Channels: " << static_cast<uInt32>(mySpec.channels)
<< " Device: " << myDevices.at(myDeviceId).first << '\n'
<< " Channels: " << static_cast<uInt32>(myHardwareSpec.channels)
<< (myAudioQueue->isStereo() ? " (Stereo)" : " (Mono)") << '\n'
<< " Preset: ";
switch(myAudioSettings.preset())
@ -276,7 +287,10 @@ string SoundSDL::about() const
default:
break; // Not supposed to get here
}
buf << " Sample rate: " << static_cast<uInt32>(mySpec.freq) << " Hz\n";
buf << " Fragment size: " << static_cast<uInt32>(myHardwareSpec.samples)
<< " bytes\n"
<< " Sample rate: " << static_cast<uInt32>(myHardwareSpec.freq)
<< " Hz\n";
buf << " Resampling: ";
switch(myAudioSettings.resamplingQuality())
{
@ -301,7 +315,7 @@ string SoundSDL::about() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::initResampler()
void SoundSDL2::initResampler()
{
const Resampler::NextFragmentCallback nextFragmentCallback = [this] () -> Int16* {
Int16* nextFragment = nullptr;
@ -319,11 +333,13 @@ void SoundSDL::initResampler()
return nextFragment;
};
const Resampler::Format formatFrom =
Resampler::Format(myEmulationTiming->audioSampleRate(),
myAudioQueue->fragmentSize(), myAudioQueue->isStereo());
const Resampler::Format formatTo =
Resampler::Format(mySpec.freq, 1024, mySpec.channels > 1);
Resampler::Format(myHardwareSpec.freq, myHardwareSpec.samples,
myHardwareSpec.channels > 1);
switch(myAudioSettings.resamplingQuality())
{
@ -349,147 +365,183 @@ void SoundSDL::initResampler()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::audioCallback(void* object, SDL_AudioStream* stream,
int additional_amt, int)
void SoundSDL2::callback(void* object, uInt8* stream, int len)
{
auto* self = static_cast<SoundSDL*>(object);
std::vector<uInt8>& buf = self->myBuffer;
// Make sure we always have enough room in the buffer
if(std::cmp_greater_equal(additional_amt, buf.capacity()))
buf.resize(additional_amt);
auto* self = static_cast<SoundSDL2*>(object);
if(self->myAudioQueue && self->myResampler)
{
// The stream is 32-bit float (even though this callback is 8-bits), since
// the resampler and TIA audio subsystem always generate float samples
auto* s = reinterpret_cast<float*>(buf.data());
self->myResampler->fillFragment(s, additional_amt >> 2);
auto* s = reinterpret_cast<float*>(stream);
const uInt32 length = len >> 2;
self->myResampler->fillFragment(s, length);
SDL_PutAudioStreamData(stream, buf.data(), additional_amt);
for(uInt32 i = 0; i < length; ++i)
s[i] *= SoundSDL2::myVolumeFactor;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL::playWav(const string& fileName, uInt32 position, uInt32 length)
{
if(myStream)
return myWavHandler.play(SDL_GetAudioStreamDevice(myStream),
fileName, position, length);
else
return false;
SDL_memset(stream, 0, len);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::stopWav()
bool SoundSDL2::playWav(const string& fileName, uInt32 position, uInt32 length)
{
const char* const device = myDeviceId
? myDevices.at(myDeviceId).first.c_str()
: nullptr;
return myWavHandler.play(fileName, device, position, length);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL2::stopWav()
{
myWavHandler.stop();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 SoundSDL::wavSize() const
uInt32 SoundSDL2::wavSize() const
{
return myWavHandler.size();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SoundSDL::WavHandler::play(SDL_AudioDeviceID device,
const string& fileName, uInt32 position, uInt32 length)
bool SoundSDL2::WavHandlerSDL2::play(
const string& fileName, const char* device, uInt32 position, uInt32 length)
{
// Load WAV file
if(fileName != myFilename || myBuffer == nullptr)
{
if(myBuffer)
{
SDL_free(myBuffer);
SDL_FreeWAV(myBuffer);
myBuffer = nullptr;
}
SDL_zero(mySpec);
if(!SDL_LoadWAV(fileName.c_str(), &mySpec, &myBuffer, &myLength))
if(SDL_LoadWAV(fileName.c_str(), &mySpec, &myBuffer, &myLength) == nullptr)
return false;
}
// Set the callback function
mySpec.callback = callback;
mySpec.userdata = this;
}
if(position > myLength)
return false;
if(myStream)
SDL_UnbindAudioStream(myStream);
myStream = SDL_CreateAudioStream(&mySpec, nullptr);
if(myStream == nullptr)
return false;
if(!SDL_BindAudioStream(device, myStream))
return false;
if(!SDL_SetAudioStreamGetCallback(myStream, WavHandler::wavCallback, this))
return false;
SDL_SetAudioStreamGain(myStream, myVolumeFactor);
myFilename = fileName;
myRemaining = length
? std::min(length, myLength - position)
: myLength;
myPos = myBuffer + position;
// Open audio device
if(!myDevice)
{
myDevice = SDL_OpenAudioDevice(device, 0, &mySpec, nullptr, 0);
if(!myDevice)
return false;
// Play audio
pause(false);
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::WavHandler::stop()
void SoundSDL2::WavHandlerSDL2::stop()
{
if(myBuffer)
{
// Clean up
myRemaining = 0;
SDL_UnbindAudioStream(myStream); myStream = nullptr;
SDL_free(myBuffer); myBuffer = nullptr;
SDL_CloseAudioDevice(myDevice); myDevice = 0;
SDL_FreeWAV(myBuffer); myBuffer = nullptr;
}
if(myCvtBuffer)
{
myCvtBuffer.reset();
myCvtBufferSize = 0;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::WavHandler::setVolumeFactor(float volumeFactor)
void SoundSDL2::WavHandlerSDL2::processWav(uInt8* stream, uInt32 len)
{
myVolumeFactor = volumeFactor;
if(myStream)
SDL_SetAudioStreamGain(myStream, myVolumeFactor);
}
SDL_memset(stream, mySpec.silence, len);
if(myRemaining)
{
if(mySpeed != 1.0)
{
const int origLen = len;
len = std::round(len / mySpeed);
const int newFreq =
std::round(static_cast<double>(mySpec.freq) * origLen / len);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::WavHandler::pause(bool state) const
if(len > myRemaining)
len = myRemaining;
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, mySpec.format, mySpec.channels, mySpec.freq,
mySpec.format, mySpec.channels, newFreq);
SDL_assert(cvt.needed); // Obviously, this one is always needed.
cvt.len = len * mySpec.channels; // Mono 8 bit sample frames
if(!myCvtBuffer ||
myCvtBufferSize < static_cast<uInt32>(cvt.len * cvt.len_mult))
{
if(myStream)
myCvtBufferSize = cvt.len * cvt.len_mult;
myCvtBuffer = make_unique<uInt8[]>(myCvtBufferSize);
}
cvt.buf = myCvtBuffer.get();
// Read original data into conversion buffer
SDL_memcpy(cvt.buf, myPos, cvt.len);
SDL_ConvertAudio(&cvt);
// Mix volume adjusted WAV data into silent buffer
SDL_MixAudioFormat(stream, cvt.buf, mySpec.format, cvt.len_cvt,
SDL_MIX_MAXVOLUME * SoundSDL2::myVolumeFactor);
}
else
{
if(state) SDL_PauseAudioStreamDevice(myStream);
else SDL_ResumeAudioStreamDevice(myStream);
if(len > myRemaining)
len = myRemaining;
// Mix volume adjusted WAV data into silent buffer
SDL_MixAudioFormat(stream, myPos, mySpec.format, len,
SDL_MIX_MAXVOLUME * myVolumeFactor);
}
myPos += len;
myRemaining -= len;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SoundSDL::WavHandler::wavCallback(void* object, SDL_AudioStream* stream,
int additional_amt, int)
void SoundSDL2::WavHandlerSDL2::callback(void* object, uInt8* stream, int len)
{
auto* self = static_cast<WavHandler*>(object);
auto len = static_cast<uInt32>(additional_amt);
auto& remaining = self->myRemaining;
static_cast<WavHandlerSDL2*>(object)->processWav(
stream, static_cast<uInt32>(len));
}
if(remaining)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL2::WavHandlerSDL2::~WavHandlerSDL2()
{
if(self->mySpeed != 1.0)
len = std::round(len / self->mySpeed);
if(len > remaining) // NOLINT(readability-use-std-min-max)
len = remaining;
SDL_PutAudioStreamData(stream, self->myPos, len);
self->myPos += len;
remaining -= len;
if(myDevice)
{
SDL_CloseAudioDevice(myDevice);
SDL_FreeWAV(myBuffer);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SoundSDL::WavHandler::~WavHandler()
void SoundSDL2::WavHandlerSDL2::pause(bool state) const
{
ASSERT_MAIN_THREAD;
if(myBuffer)
SDL_free(myBuffer);
if(myDevice)
SDL_PauseAudioDevice(myDevice, state ? 1 : 0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float SoundSDL2::myVolumeFactor = 0.F;
#endif // SOUND_SUPPORT

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -17,8 +17,8 @@
#ifdef SOUND_SUPPORT
#ifndef SOUND_SDL_HXX
#define SOUND_SDL_HXX
#ifndef SOUND_SDL2_HXX
#define SOUND_SDL2_HXX
class OSystem;
class AudioQueue;
@ -36,15 +36,15 @@ class Resampler;
@author Stephen Anthony and Christian Speckner (DirtyHairy)
*/
class SoundSDL : public Sound
class SoundSDL2 : public Sound
{
public:
/**
Create a new sound object. The init method must be invoked before
using the object.
*/
SoundSDL(OSystem& osystem, AudioSettings& audioSettings);
~SoundSDL() override;
SoundSDL2(OSystem& osystem, AudioSettings& audioSettings);
~SoundSDL2() override;
public:
/**
@ -93,9 +93,8 @@ class SoundSDL : public Sound
outside this range indicate that the volume shouldn't be changed at all.
@param volume The new volume level for the sound device
@param persist Whether to save the volume change to settings
*/
void setVolume(uInt32 volume, bool persist = true) override;
void setVolume(uInt32 volume) override;
/**
Adjusts the volume of the sound device based on the given direction.
@ -134,6 +133,13 @@ class SoundSDL : public Sound
uInt32 wavSize() const override;
private:
/**
This method is called to query the audio devices.
@param devices List of device names
*/
void queryHardware(VariantList& devices) override;
/**
The actual sound device is opened only when absolutely necessary.
Typically this will only happen once per program run, but it can also
@ -150,14 +156,10 @@ class SoundSDL : public Sound
bool myIsInitializedFlag{false};
// Audio specification structure
SDL_AudioSpec mySpec{};
SDL_AudioSpec myHardwareSpec{};
// Audio device and stream, which handles all interaction with SDL sound backend
SDL_AudioDeviceID myDevice{};
SDL_AudioStream* myStream{nullptr};
// Audio buffer, passed to the audio callback and filled from the resampler
std::vector<uInt8> myBuffer;
SDL_AudioDeviceID myDevice{0};
uInt32 myDeviceId{0};
shared_ptr<AudioQueue> myAudioQueue;
unique_ptr<Resampler> myResampler;
@ -167,66 +169,65 @@ class SoundSDL : public Sound
Int16* myCurrentFragment{nullptr};
bool myUnderrun{false};
float myVolumeFactor{1.F}; // Current volume level (0.F - 1.F)
string myAboutString;
/**
This class implements WAV file playback using the SDL sound API.
This class implements WAV file playback using the SDL2 sound API.
*/
class WavHandler
class WavHandlerSDL2
{
public:
explicit WavHandler() = default;
~WavHandler();
explicit WavHandlerSDL2() = default;
~WavHandlerSDL2();
bool play(SDL_AudioDeviceID device, const string& fileName,
bool play(const string& fileName, const char* device,
uInt32 position, uInt32 length);
void stop();
uInt32 size() const { return myBuffer ? myRemaining : 0; }
void setSpeed(double speed) { mySpeed = speed; }
void setVolumeFactor(float volumeFactor);
void setSpeed(const double speed) { mySpeed = speed; }
void pause(bool state) const;
private:
string myFilename;
SDL_AudioStream* myStream{nullptr};
SDL_AudioSpec mySpec{};
uInt8* myBuffer{nullptr};
uInt32 myLength{0};
SDL_AudioDeviceID myDevice{0};
uInt8* myBuffer{nullptr};
double mySpeed{1.0};
float myVolumeFactor{1.F}; // Current volume level (0.F - 1.F)
unique_ptr<uInt8[]> myCvtBuffer;
uInt32 myCvtBufferSize{0};
SDL_AudioSpec mySpec{}; // audio output format
uInt8* myPos{nullptr}; // pointer to the audio buffer to be played
uInt32 myRemaining{0}; // remaining length of the sample we have to play
private:
// Callback function invoked by the SDL Audio library when it needs data
static void wavCallback(void* object, SDL_AudioStream* stream,
int additional_amt, int);
void processWav(uInt8* stream, uInt32 len);
static void callback(void* object, uInt8* stream, int len);
// Following constructors and assignment operators not supported
WavHandler(const WavHandler&) = delete;
WavHandler(WavHandler&&) = delete;
WavHandler& operator=(const WavHandler&) = delete;
WavHandler& operator=(WavHandler&&) = delete;
WavHandlerSDL2(const WavHandlerSDL2&) = delete;
WavHandlerSDL2(WavHandlerSDL2&&) = delete;
WavHandlerSDL2& operator=(const WavHandlerSDL2&) = delete;
WavHandlerSDL2& operator=(WavHandlerSDL2&&) = delete;
};
WavHandler myWavHandler;
WavHandlerSDL2 myWavHandler;
static float myVolumeFactor; // Current volume level (0 - 100)
private:
// Callback functions invoked by the SDL Audio library when it needs data
static void audioCallback(void* object, SDL_AudioStream* stream,
int additional_amt, int);
static void callback(void* object, uInt8* stream, int len);
// Following constructors and assignment operators not supported
SoundSDL() = delete;
SoundSDL(const SoundSDL&) = delete;
SoundSDL(SoundSDL&&) = delete;
SoundSDL& operator=(const SoundSDL&) = delete;
SoundSDL& operator=(SoundSDL&&) = delete;
SoundSDL2() = delete;
SoundSDL2(const SoundSDL2&) = delete;
SoundSDL2(SoundSDL2&&) = delete;
SoundSDL2& operator=(const SoundSDL2&) = delete;
SoundSDL2& operator=(SoundSDL2&&) = delete;
};
#endif // SOUND_SDL_HXX
#endif
#endif // SOUND_SUPPORT

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -116,9 +116,7 @@ void StaggeredLogger::startInterval()
Int64 msecSinceLastIntervalEnd =
duration_cast<duration<Int64, std::milli>>(now - myLastIntervalEndTimestamp).count();
while (std::cmp_greater(msecSinceLastIntervalEnd, myCooldownTime) &&
myCurrentIntervalFactor > 1)
{
while (msecSinceLastIntervalEnd > myCooldownTime && myCurrentIntervalFactor > 1) {
msecSinceLastIntervalEnd -= myCooldownTime;
decreaseInterval();
}

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -18,7 +18,7 @@
#ifndef STATE_MANAGER_HXX
#define STATE_MANAGER_HXX
#define STATE_HEADER "07000001state"
#define STATE_HEADER "07000000state"
class OSystem;
class RewindManager;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -221,16 +221,16 @@ enum StellaKey // NOLINT: use 32-bit, even though 16-bit is sufficient
KBDK_F23 = 114,
KBDK_F24 = 115,
KBDK_EXECUTE = 116,
KBDK_HELP = 117, /**< AL Integrated Help Center */
KBDK_MENU = 118, /**< Menu (show menu) */
KBDK_HELP = 117,
KBDK_MENU = 118,
KBDK_SELECT = 119,
KBDK_STOP = 120, /**< AC Stop */
KBDK_AGAIN = 121, /**< AC Redo/Repeat */
KBDK_UNDO = 122, /**< AC Undo */
KBDK_CUT = 123, /**< AC Cut */
KBDK_COPY = 124, /**< AC Copy */
KBDK_PASTE = 125, /**< AC Paste */
KBDK_FIND = 126, /**< AC Find */
KBDK_STOP = 120,
KBDK_AGAIN = 121, /**< redo */
KBDK_UNDO = 122,
KBDK_CUT = 123,
KBDK_COPY = 124,
KBDK_PASTE = 125,
KBDK_FIND = 126,
KBDK_MUTE = 127,
KBDK_VOLUMEUP = 128,
KBDK_VOLUMEDOWN = 129,
@ -263,7 +263,7 @@ enum StellaKey // NOLINT: use 32-bit, even though 16-bit is sufficient
KBDK_ALTERASE = 153, /**< Erase-Eaze */
KBDK_SYSREQ = 154,
KBDK_CANCEL = 155, /**< AC Cancel */
KBDK_CANCEL = 155,
KBDK_CLEAR = 156,
KBDK_PRIOR = 157,
KBDK_RETURN2 = 158,
@ -330,9 +330,9 @@ enum StellaKey // NOLINT: use 32-bit, even though 16-bit is sufficient
KBDK_RALT = 230, /**< alt gr, option */
KBDK_RGUI = 231, /**< windows, command (apple), meta */
KBDK_MODE = 257, /**< I'm not sure if this is really not covered
* by any of the above, but since there's a
* special SDL_KMOD_MODE for it I'm adding it here
KBDK_MODE = 257, /**< ALT-GR(aph) key on non-American keyboards
* This is like pressing KBDK_RALT + KBDK_RCTRL
* on some keyboards
*/
/* @} *//* Usage page 0x07 */
@ -341,98 +341,77 @@ enum StellaKey // NOLINT: use 32-bit, even though 16-bit is sufficient
* \name Usage page 0x0C
*
* These values are mapped from usage page 0x0C (USB consumer page).
*
* There are way more keys in the spec than we can represent in the
* current scancode range, so pick the ones that commonly come up in
* real world usage.
*/
/* @{ */
KBDK_SLEEP = 258, /**< Sleep */
KBDK_WAKE = 259, /**< Wake */
KBDK_CHANNEL_INCREMENT = 260, /**< Channel Increment */
KBDK_CHANNEL_DECREMENT = 261, /**< Channel Decrement */
KBDK_MEDIA_PLAY = 262, /**< Play */
KBDK_MEDIA_PAUSE = 263, /**< Pause */
KBDK_MEDIA_RECORD = 264, /**< Record */
KBDK_MEDIA_FAST_FORWARD = 265, /**< Fast Forward */
KBDK_MEDIA_REWIND = 266, /**< Rewind */
KBDK_MEDIA_NEXT_TRACK = 267, /**< Next Track */
KBDK_MEDIA_PREVIOUS_TRACK = 268, /**< Previous Track */
KBDK_MEDIA_STOP = 269, /**< Stop */
KBDK_MEDIA_EJECT = 270, /**< Eject */
KBDK_MEDIA_PLAY_PAUSE = 271, /**< Play / Pause */
KBDK_MEDIA_SELECT = 272, /* Media Select */
KBDK_AC_NEW = 273, /**< AC New */
KBDK_AC_OPEN = 274, /**< AC Open */
KBDK_AC_CLOSE = 275, /**< AC Close */
KBDK_AC_EXIT = 276, /**< AC Exit */
KBDK_AC_SAVE = 277, /**< AC Save */
KBDK_AC_PRINT = 278, /**< AC Print */
KBDK_AC_PROPERTIES = 279, /**< AC Properties */
KBDK_AC_SEARCH = 280, /**< AC Search */
KBDK_AC_HOME = 281, /**< AC Home */
KBDK_AC_BACK = 282, /**< AC Back */
KBDK_AC_FORWARD = 283, /**< AC Forward */
KBDK_AC_STOP = 284, /**< AC Stop */
KBDK_AC_REFRESH = 285, /**< AC Refresh */
KBDK_AC_BOOKMARKS = 286, /**< AC Bookmarks */
KBDK_AUDIONEXT = 258,
KBDK_AUDIOPREV = 259,
KBDK_AUDIOSTOP = 260,
KBDK_AUDIOPLAY = 261,
KBDK_AUDIOMUTE = 262,
KBDK_MEDIASELECT = 263,
KBDK_WWW = 264,
KBDK_MAIL = 265,
KBDK_CALCULATOR = 266,
KBDK_COMPUTER = 267,
KBDK_AC_SEARCH = 268,
KBDK_AC_HOME = 269,
KBDK_AC_BACK = 270,
KBDK_AC_FORWARD = 271,
KBDK_AC_STOP = 272,
KBDK_AC_REFRESH = 273,
KBDK_AC_BOOKMARKS = 274,
/* @} *//* Usage page 0x0C */
/**
* \name Mobile keys
* \name Walther keys
*
* These are values that are often used on mobile phones.
* These are values that Christian Walther added (for mac keyboard?).
*/
/* @{ */
KBDK_SOFTLEFT = 287, /**< Usually situated below the display on phones and
used as a multi-function feature key for selecting
a software defined function shown on the bottom left
of the display. */
KBDK_SOFTRIGHT = 288, /**< Usually situated below the display on phones and
used as a multi-function feature key for selecting
a software defined function shown on the bottom right
of the display. */
KBDK_CALL = 289, /**< Used for accepting phone calls. */
KBDK_ENDCALL = 290, /**< Used for rejecting phone calls. */
KBDK_BRIGHTNESSDOWN = 275,
KBDK_BRIGHTNESSUP = 276,
KBDK_DISPLAYSWITCH = 277, /**< display mirroring/dual display
switch, video mode switch */
KBDK_KBDILLUMTOGGLE = 278,
KBDK_KBDILLUMDOWN = 279,
KBDK_KBDILLUMUP = 280,
KBDK_EJECT = 281,
KBDK_SLEEP = 282,
/* @} *//* Mobile keys */
KBDK_APP1 = 283,
KBDK_APP2 = 284,
/* @} *//* Walther keys */
/* Add any other keys here. */
KBDK_RESERVED = 400, /**< 400-500 reserved for dynamic keycodes */
KBDK_COUNT = 512 /**< not a key, just marks the number of scancodes for array bounds */
KBDK_LAST = 512 /**< not a key, just marks the number of scancodes
for array bounds */
};
// This comes directly from SDL_keycode.h
enum StellaMod: uInt16
{
KBDM_NONE = 0x0000U, /**< no modifier is applicable. */
KBDM_LSHIFT = 0x0001U, /**< the left Shift key is down. */
KBDM_RSHIFT = 0x0002U, /**< the right Shift key is down. */
KBDM_LEVEL5 = 0x0004U, /**< the Level 5 Shift key is down. */
KBDM_LCTRL = 0x0040U, /**< the left Ctrl (Control) key is down. */
KBDM_RCTRL = 0x0080U, /**< the right Ctrl (Control) key is down. */
KBDM_LALT = 0x0100U, /**< the left Alt key is down. */
KBDM_RALT = 0x0200U, /**< the right Alt key is down. */
KBDM_LGUI = 0x0400U, /**< the left GUI key (often the Windows key) is down. */
KBDM_RGUI = 0x0800U, /**< the right GUI key (often the Windows key) is down. */
KBDM_NUM = 0x1000U, /**< the Num Lock key (may be located on an extended keypad) is down. */
KBDM_CAPS = 0x2000U, /**< the Caps Lock key is down. */
KBDM_MODE = 0x4000U, /**< the !AltGr key is down. */
KBDM_SCROLL = 0x8000U, /**< the Scroll Lock key is down. */
KBDM_CTRL = (KBDM_LCTRL | KBDM_RCTRL), /**< Any Ctrl key is down. */
KBDM_SHIFT = (KBDM_LSHIFT | KBDM_RSHIFT), /**< Any Shift key is down. */
KBDM_ALT = (KBDM_LALT | KBDM_RALT), /**< Any Alt key is down. */
KBDM_GUI = (KBDM_LGUI | KBDM_RGUI) /**< Any GUI key is down. */
KBDM_NONE = 0x0000,
KBDM_LSHIFT = 0x0001,
KBDM_RSHIFT = 0x0002,
KBDM_LCTRL = 0x0040,
KBDM_RCTRL = 0x0080,
KBDM_LALT = 0x0100,
KBDM_RALT = 0x0200,
KBDM_LGUI = 0x0400,
KBDM_RGUI = 0x0800,
KBDM_NUM = 0x1000,
KBDM_CAPS = 0x2000,
KBDM_MODE = 0x4000,
KBDM_RESERVED = 0x8000,
KBDM_CTRL = (KBDM_LCTRL|KBDM_RCTRL),
KBDM_SHIFT = (KBDM_LSHIFT|KBDM_RSHIFT),
KBDM_ALT = (KBDM_LALT|KBDM_RALT),
KBDM_GUI = (KBDM_LGUI|KBDM_RGUI)
};
// Test if specified modifier is pressed
@ -463,7 +442,7 @@ namespace StellaKeyName
inline string_view forKey(StellaKey key)
{
#ifdef SDL_SUPPORT
return SDL_GetScancodeName(static_cast<SDL_Scancode>(key));
return SDL_GetScancodeName(SDL_Scancode(key));
#else
return string_view{};
#endif

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_VERSION "8.0_pre"
#define STELLA_VERSION "7.0"
#define STELLA_BUILD "8005"
#endif

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -29,17 +29,17 @@ void VideoModeHandler::setImageSize(const Common::Size& image)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void VideoModeHandler::setDisplaySize(const Common::Size& display, bool fullscreen)
void VideoModeHandler::setDisplaySize(const Common::Size& display, Int32 fsIndex)
{
myDisplay = display;
myFullscreen = fullscreen;
myFSIndex = fsIndex;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const VideoModeHandler::Mode&
VideoModeHandler::buildMode(const Settings& settings, bool inTIAMode, Bezel::Info bezelInfo)
{
const bool windowedRequested = !myFullscreen;
const bool windowedRequested = myFSIndex == -1;
// TIA mode allows zooming at non-integral factors in most cases
if(inTIAMode)
@ -53,7 +53,7 @@ const VideoModeHandler::Mode&
// Image and screen (aka window) dimensions are the same
// Overscan is not applicable in this mode
myMode = Mode(myImage.w, myImage.h,
Mode::Stretch::Fill, myFullscreen,
Mode::Stretch::Fill, myFSIndex,
desc.view(), zoom, bezelInfo);
}
else
@ -74,7 +74,7 @@ const VideoModeHandler::Mode&
{
myMode = Mode(myImage.w, myImage.h,
myDisplay.w, myDisplay.h,
Mode::Stretch::Preserve, myFullscreen,
Mode::Stretch::Preserve, myFSIndex,
"Fullscreen: Preserve aspect, no stretch",
zoom, overscan, bezelInfo);
}
@ -82,7 +82,7 @@ const VideoModeHandler::Mode&
{
myMode = Mode(myImage.w, myImage.h,
myDisplay.w, myDisplay.h,
Mode::Stretch::Fill, myFullscreen,
Mode::Stretch::Fill, myFSIndex,
"Fullscreen: Ignore aspect, full stretch",
zoom, overscan, bezelInfo);
}
@ -94,31 +94,31 @@ const VideoModeHandler::Mode&
myMode = Mode(myImage.w, myImage.h, Mode::Stretch::None);
else
myMode = Mode(myImage.w, myImage.h, myDisplay.w, myDisplay.h,
Mode::Stretch::None, myFullscreen);
Mode::Stretch::None, myFSIndex);
}
return myMode;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, Stretch smode,
bool fullscreen, string_view desc,
Int32 fsindex, string_view desc,
double zoomLevel, Bezel::Info bezelInfo)
: Mode(iw, ih, iw, ih, smode, fullscreen, desc, zoomLevel, 1., bezelInfo)
: Mode(iw, ih, iw, ih, smode, fsindex, desc, zoomLevel, 1., bezelInfo)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VideoModeHandler::Mode::Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh,
Stretch smode, bool fullscreen, string_view desc,
Stretch smode, Int32 fsindex, string_view desc,
double zoomLevel, double overscan, Bezel::Info bezelInfo)
: screenS{sw, sh},
stretch{smode},
description{desc},
zoom{zoomLevel}, //hZoom{zoomLevel}, vZoom{zoomLevel},
fullscreen{fullscreen}
fsIndex{fsindex}
{
// Now resize based on windowed/fullscreen mode and stretch factor
if(fullscreen)
if(fsIndex != -1) // fullscreen mode
{
switch(stretch)
{

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -46,14 +46,14 @@ class VideoModeHandler
Stretch stretch{Mode::Stretch::None};
string description;
double zoom{1.};
bool fullscreen{false}; // false indicates windowed mode
Int32 fsIndex{-1}; // -1 indicates windowed mode
Mode() = default;
Mode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Stretch smode,
bool fullscreen = false, string_view desc = "",
Int32 fsindex = -1, string_view desc = "",
double zoomLevel = 1., double overscan = 1.,
Bezel::Info bezelInfo = Bezel::Info());
Mode(uInt32 iw, uInt32 ih, Stretch smode, bool fullscreen = false,
Mode(uInt32 iw, uInt32 ih, Stretch smode, Int32 fsindex = -1,
string_view desc = "", double zoomLevel = 1.,
Bezel::Info bezelInfo = Bezel::Info());
@ -63,7 +63,7 @@ class VideoModeHandler
<< " stretch=" << (vm.stretch == Stretch::Preserve ? "preserve" :
vm.stretch == Stretch::Fill ? "fill" : "none")
<< " desc=" << vm.description << " zoom=" << vm.zoom
<< " fullscreen= " << vm.fullscreen;
<< " fsIndex= " << vm.fsIndex;
return os;
}
};
@ -85,9 +85,9 @@ class VideoModeHandler
or the size of the monitor currently active.
@param display The dimensions of the enclosing display
@param fullscreen Whether to use fullscreen or windowed mode
@param fsIndex Fullscreen mode in use (-1 indicates windowed mode)
*/
void setDisplaySize(const Common::Size& display, bool fullscreen);
void setDisplaySize(const Common::Size& display, Int32 fsIndex = -1);
/**
Build a video mode based on the given parameters, assuming that
@ -103,7 +103,7 @@ class VideoModeHandler
private:
Common::Size myImage, myDisplay;
bool myFullscreen{false};
Int32 myFSIndex{-1};
Mode myMode;

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
@ -266,7 +266,8 @@ void ZipHandler::ZipFile::readEcd()
uInt64 read_length = 0;
// Max out the buf length at the size of the file
buflen = std::min(buflen, myLength);
if(buflen > myLength)
buflen = myLength;
// Allocate buffer
const ByteBuffer buffer = make_unique<uInt8[]>(buflen + 1);

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

View File

@ -8,7 +8,7 @@
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2025 by Bradford W. Mott, Stephen Anthony
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of

Some files were not shown because too many files have changed in this diff Show More